ThreadProfile icon indicating copy to clipboard operation
ThreadProfile copied to clipboard

how to script generating a helix and shapebinder ... ??

Open stepheneb opened this issue 3 years ago • 4 comments

Working on figuring out how to script the thread profile workbench. Thanks for any help or tips.

Here's the current state of my test macro.

file: vtp_test.FCMacro

# -*- coding: utf-8 -*-

import FreeCAD as App
import FreeCADGui as Gui
import sys
import Part
import ThreadProfileCmd

minor_diameter = 30
thread_pitch = 2.0
thread_count = 3

try:
    vtp_test = App.getDocument("vtp_test1")
except NameError:
    vtp_test = App.newDocument("vtp_test1")

vtp_body = vtp_test.getObject('vtp_body')
if (id(vtp_body) == id(None)):
    vtp_body = vtp_test.addObject('PartDesign::Body','vtp_body')
else:
    vtp_body.removeObjectsFromDocument()


# make vthreadprofile
vtp = ThreadProfileCmd.ThreadProfileCreateObjectCommandClass().makeThreadProfile('VThreadProfile')
vtp_body.addObject(vtp)
vtp.InternalOrExternal = 'External'
vtp.MinorDiameter = minor_diameter
vtp.Pitch = thread_pitch
vtp.ThreadCount = thread_count
vtp_body.recompute()

# make helix and associates shapebinder
ThreadProfileCmd.ThreadProfileMakeHelixCommandClass();
# ... ??

# sweep shapebinder along thread profile
# ... ??

Gui.ActiveDocument.ActiveView.viewIsometric()
Gui.ActiveDocument.ActiveView.fitAll()

stepheneb avatar Mar 18 '21 06:03 stepheneb

I got a bit further ... new macro code below. Being new to FreeCAD I realize I'm starting with the assumption that I can script the creation and modification of objects without interacting with the GUI -- I suspect now that is an incorrect assumption.

In order to create a VThreadProfile correctly embedded in the body I needed to make the new body active after creating it using this gui command in the macro and before creating the VThreadProfile

Gui.ActiveDocument.ActiveView.setActiveObject('pdbody', vtp_body)

Without doing this the VThreadProfile object appeared to be in the body in the tree view bit when manually adding a helix using the gui only a Helix was made -- not a Helix and ShapeBinder.

The VThreadProfile can then be made correctly in the script.

NOTE: this may be a bug elsewhere. I've also been debugging by comparing the XML Content of objects generated manually to the objects I'm creating with the script. The output to the Python console for a VThreadProfile object is truncated -- presumably because it's large. Should I step into the regular FreeCAD bug reporting/tracking process for this issue?

To make the Helix and ShapeBinder I tried to follow the pattern I used making the VThreadProfile by directly accessing classes like ThreadProfileMakeHelixCommandClass() but wasn't able to get it to work.

The updated macro code below instead works by scripting through GUI commands

It's almost all working but I'm left with the Task dialog still open.

image

# -*- coding: utf-8 -*-

import FreeCAD as App
import FreeCADGui as Gui
import sys
import Part
import ThreadProfileCmd

minor_diameter = 30
thread_pitch = 2.0
thread_count = 3

try:
    vtp_test = App.getDocument("vtp_test1")
except NameError:
    vtp_test = App.newDocument("vtp_test1")

vtp_body = vtp_test.getObject('vtp_body')
if (id(vtp_body) == id(None)):
    vtp_body = vtp_test.addObject('PartDesign::Body','vtp_body')
else:
    vtp_body.removeObjectsFromDocument()

vtp_test.recompute()
names = [o.Name for o in vtp_test.RootObjects if o.Name != 'vtp_body']
[vtp_test.removeObject(o.Name) for o in vtp_test.RootObjects if o.Name != 'vtp_body']

Gui.ActiveDocument.ActiveView.setActiveObject('pdbody', vtp_body)

# make vthreadprofile
vtp = ThreadProfileCmd.ThreadProfileCreateObjectCommandClass().makeThreadProfile('VThreadProfile')
# vtp_body.addObject(vtp)
vtp.InternalOrExternal = 'External'
vtp.MinorDiameter = minor_diameter
vtp.Pitch = thread_pitch
vtp.ThreadCount = thread_count
vtp_body.recompute()


# make helix and associated shapebinder
Gui.Selection.clearSelection()
Gui.Selection.addSelection('vtp_test1','VThreadProfile')
Gui.runCommand('ThreadProfileMakeHelix',0)

# select VThreadProfile and ShapeBinder and sweep shapebinder along thread profile
Gui.Selection.clearSelection()
Gui.Selection.addSelection('vtp_test1','VThreadProfile')
Gui.Selection.addSelection('vtp_test1','vtp_body','ShapeBinder.')
Gui.runCommand('ThreadProfileDoSweep',0)

vtp_test.recompute()
vtp_test.resetEdit()
Gui.activateWorkbench('ThreadProfileWorkbench')
vtp_test1.getObject('AdditivePipe').Visibility = True

# make the result nicely visible
Gui.ActiveDocument.ActiveView.viewIsometric()
Gui.ActiveDocument.ActiveView.fitAll()


stepheneb avatar Mar 18 '21 19:03 stepheneb

Hmmm ... noticed this error without a line number generated in the Report panel before running ThreadProfileDoSweep which is commented out in the macro code below

15:30:54  <Exception> ObjectIdentifier.cpp(1512): Document object 'VThreadProfile' not found in 'VThreadProfile.Placement.Rotation.Axis.z'
in property binding 'Placement'

import FreeCAD as App
import FreeCADGui as Gui
import sys
import Part
import ThreadProfileCmd

minor_diameter = 30
thread_pitch = 2.0
thread_count = 3

try:
    vtp_test = App.getDocument("vtp_test1")
except NameError:
    vtp_test = App.newDocument("vtp_test1")

vtp_body = vtp_test.getObject('vtp_body')
if (id(vtp_body) == id(None)):
    vtp_body = vtp_test.addObject('PartDesign::Body','vtp_body')
else:
    vtp_body.removeObjectsFromDocument()

vtp_test.recompute()
names = [o.Name for o in vtp_test.RootObjects if o.Name != 'vtp_body']
[vtp_test.removeObject(o.Name) for o in vtp_test.RootObjects if o.Name != 'vtp_body']

Gui.ActiveDocument.ActiveView.setActiveObject('pdbody', vtp_body)

# make vthreadprofile
vtp = ThreadProfileCmd.ThreadProfileCreateObjectCommandClass().makeThreadProfile('VThreadProfile')
# vtp_body.addObject(vtp)
vtp.InternalOrExternal = 'External'
vtp.MinorDiameter = minor_diameter
vtp.Pitch = thread_pitch
vtp.ThreadCount = thread_count
vtp_body.recompute()


# make helix and associated shapebinder
Gui.Selection.clearSelection()
Gui.Selection.addSelection('vtp_test1','VThreadProfile')
Gui.runCommand('ThreadProfileMakeHelix',0)

# select VThreadProfile and ShapeBinder and sweep shapebinder along thread profile
#Gui.Selection.clearSelection()
#Gui.Selection.addSelection('vtp_test1','VThreadProfile')
#Gui.Selection.addSelection('vtp_test1','vtp_body','ShapeBinder.')
# Gui.runCommand('ThreadProfileDoSweep',1)

# vtp_test.recompute()
# vtp_test.resetEdit()
# Gui.activateWorkbench('ThreadProfileWorkbench')

# vtp_test.getObject('AdditivePipe').Visibility = True


# make the result nicely visible
Gui.ActiveDocument.ActiveView.viewIsometric()
Gui.ActiveDocument.ActiveView.fitAll()

stepheneb avatar Mar 18 '21 19:03 stepheneb

fyI version info: ThreadProfile: 1.68

FreeCAD: OS: macOS 10.16 Word size of OS: 64-bit Word size of FreeCAD: 64-bit Version: 0.19.24267 (Git) Build type: Release Branch: releases/FreeCAD-0-19 Hash: b2ca86d8d72b636011a73394bf9bcdedb3b109b7 Python version: 3.8.8 Qt version: 5.12.9 Coin version: 4.0.0 OCC version: 7.4.0 Locale: C/Default (C)

stepheneb avatar Mar 18 '21 19:03 stepheneb

Perhaps solved ...

Updated to ThreadProfile 1.6.9 and FreeCAD .19.1

As long as I delete the document vtp_test1 before running the macro it all seems to work.

image

If I run it without deleting vtp_test1 first it works but this error with no line number is generated in the Report panel:

17:33:08  <Exception> ObjectIdentifier.cpp(1512): Document object 'VThreadProfile' not found in 'VThreadProfile.Placement.Rotation.Axis.z'
in property binding 'Placement'

The code at the beginning is intended to empty out the document vtp_test1* every time the macro is run to make iterative development easier.

I also suspect there might also be a simpler method to switch the Combo View from the Task tab back to the Model tabb at the end.

# -*- coding: utf-8 -*-

import FreeCAD as App
import FreeCADGui as Gui
import sys
import Part
import ThreadProfileCmd
from PySide import QtGui

minor_diameter = 30
thread_pitch = 2.0
thread_count = 3

try:
    vtp_test = App.getDocument("vtp_test1")
except NameError:
    vtp_test = App.newDocument("vtp_test1")

vtp_body = vtp_test.getObject('vtp_body')
if (id(vtp_body) == id(None)):
    vtp_body = vtp_test.addObject('PartDesign::Body','vtp_body')
else:
    vtp_body.removeObjectsFromDocument()

vtp_test.recompute()
[vtp_test.removeObject(o.Name) for o in vtp_test.RootObjects if o.Name != 'vtp_body']

Gui.ActiveDocument.ActiveView.setActiveObject('pdbody', vtp_body)

# make vthreadprofile
vtp = ThreadProfileCmd.ThreadProfileCreateObjectCommandClass().makeThreadProfile('VThreadProfile')
# vtp_body.addObject(vtp)
vtp.InternalOrExternal = 'External'
vtp.MinorDiameter = minor_diameter
vtp.Pitch = thread_pitch
vtp.ThreadCount = thread_count
vtp_body.recompute()


# make helix and associated shapebinder
Gui.Selection.clearSelection()
Gui.Selection.addSelection('vtp_test1','VThreadProfile')
Gui.runCommand('ThreadProfileMakeHelix')

# select VThreadProfile and ShapeBinder and sweep shapebinder along thread profile
Gui.Selection.clearSelection()
Gui.Selection.addSelection('vtp_test1','VThreadProfile')
Gui.Selection.addSelection('vtp_test1','vtp_body','ShapeBinder.')
Gui.runCommand('ThreadProfileDoSweep',1)
Gui.activeDocument().resetEdit()

# switch from Task to Model in Combo View
mw = FreeCADGui.getMainWindow()
dws = mw.findChildren(QtGui.QDockWidget)
comboView = next(filter(lambda qw: qw.windowTitle() == 'Combo View', dws), None)
comboView.findChild(QtGui.QTabWidget).setCurrentIndex(0)

# make the result nicely visible
Gui.ActiveDocument.ActiveView.viewIsometric()
Gui.ActiveDocument.ActiveView.fitAll()

stepheneb avatar Mar 18 '21 21:03 stepheneb