diff --git a/Lattice2CodeModules.py b/Lattice2CodeModules.py index b5007d7..25ea80b 100644 --- a/Lattice2CodeModules.py +++ b/Lattice2CodeModules.py @@ -8,4 +8,5 @@ import lattice2Markers as Markers import lattice2ValueSeriesGenerator as ValueSeriesGenerator import lattice2ShapeCopy as ShapeCopy import lattice2Subsequencer as Subsequencer -import lattice2Utils as Utils \ No newline at end of file +import lattice2Utils as Utils +import lattice2CoinGlue as CoinGlue \ No newline at end of file diff --git a/lattice2BaseFeature.py b/lattice2BaseFeature.py index f3ff1f9..f7261af 100644 --- a/lattice2BaseFeature.py +++ b/lattice2BaseFeature.py @@ -33,6 +33,7 @@ import lattice2CompoundExplorer as LCE import lattice2Markers import lattice2Executer from lattice2ShapeCopy import shallowCopy +import lattice2CoinGlue as CoinGlue def getDefLatticeFaceColor(): @@ -130,12 +131,12 @@ class LatticeFeature(object): obj.Proxy = self - def assureProperty(self, selfobj, proptype, propname, defvalue, group, tooltip): + def assureProperty(self, selfobj, proptype, propname, defvalue, group, tooltip, readonly = False, hidden = False): """assureProperty(selfobj, proptype, propname, defvalue, group, tooltip): adds a property if one is missing, and sets its value to default. Does nothing if property already exists. Returns True if property was created, or False if not.""" - return assureProperty(selfobj, proptype, propname, defvalue, group, tooltip) + return assureProperty(selfobj, proptype, propname, defvalue, group, tooltip, readonly, hidden) def setReferencePlm(self, selfobj, refplm): """setReferencePlm(selfobj, refplm): sets reference placement, in internal CS. If refplm is None, the property is removed.""" @@ -154,6 +155,13 @@ class LatticeFeature(object): ) selfobj.ReferencePlacement = refplm + def getReferencePlm(self, selfobj): + """getReferencePlm(self, selfobj): Returns reference placement in internal CS, or None.""" + if hasattr(selfobj, 'ReferencePlacement'): + return selfobj.ReferencePlacement + else: + return None + def derivedInit(self, obj): '''for overriding by derived classes''' pass @@ -172,6 +180,8 @@ class LatticeFeature(object): if markerSize < DistConfusion: markerSize = getMarkerSizeEstimate(plms) marker = lattice2Markers.getPlacementMarker(scale= markerSize, markerID= obj.MarkerShape) + self.assureProperty(obj, 'App::PropertyLength', 'MarkerSizeActual', markerSize, "Lattice", "Size of placement markers of this array", hidden= True) + obj.MarkerSizeActual = markerSize bExposing = False if obj.ExposePlacement: @@ -316,6 +326,27 @@ class ViewProviderLatticeFeature(object): def attach(self, vobj): self.ViewObject = vobj self.Object = vobj.Object + self.refplm_node, self.refplm_tr, self.refplm_sh = None, None, None + self.makeRefplmVisual(vobj) + from pivy import coin + self.modenode = next((node for node in vobj.RootNode.getChildren() if node.isOfType(coin.SoSwitch.getClassTypeId()))) + self.modenode_refplm = None + + def makeRefplmVisual(self, vobj): + import pivy + from pivy import coin + refplm = self.Object.Proxy.getReferencePlm(self.Object) + if refplm is not None: + if not hasattr(self.Object, 'MarkerSizeActual'): return + if self.refplm_node is None: + self.refplm_node, self.refplm_tr, self.refplm_sh = lattice2Markers.getRefPlmMarker(self.Object.MarkerShape) + vobj.RootNode.addChild(self.refplm_node) + self.modenode_refplm = next((node for node in self.refplm_sh.getChildren() if node.isOfType(coin.SoSwitch.getClassTypeId()))) + CoinGlue.cointransform(refplm, float(self.Object.MarkerSizeActual), self.refplm_tr) + else: + if hasattr(self, 'refplm_node') and self.refplm_node is not None: + vobj.RootNode.removeChild(self.refplm_node) + self.refplm_node, self.refplm_tr, self.refplm_sh = None, None, None def __getstate__(self): return None @@ -342,10 +373,19 @@ class ViewProviderLatticeFeature(object): # catch all exceptions, because we don't want to prevent deletion if something goes wrong FreeCAD.Console.PrintError("Error in onDelete: " + str(err)) return True + + def updateData(self, obj, prop): + if prop == 'ReferencePlacement' or prop == 'MarkerSizeActual': + self.makeRefplmVisual(obj.ViewObject) + + def onChanged(self, vobj, prop): + if prop == 'Visibility': + self.modenode_refplm.whichChild.setValue(0 if vobj.Visibility == True else -1) + -def assureProperty(docobj, proptype, propname, defvalue, group, tooltip): - """assureProperty(docobj, proptype, propname, defvalue, group, tooltip): adds +def assureProperty(docobj, proptype, propname, defvalue, group, tooltip, readonly = False, hidden = False): + """assureProperty(docobj, proptype, propname, defvalue, group, tooltip, readonly = False, hidden = False): adds a property if one is missing, and sets its value to default. Does nothing if property already exists. Returns True if property was created, or False if not.""" @@ -353,7 +393,7 @@ def assureProperty(docobj, proptype, propname, defvalue, group, tooltip): #todo: check type match return False - docobj.addProperty(proptype, propname, group, tooltip) + docobj.addProperty(proptype, propname, group, tooltip, 0, readonly, hidden) if defvalue is not None: setattr(docobj, propname, defvalue) return True diff --git a/lattice2CoinGlue.py b/lattice2CoinGlue.py new file mode 100644 index 0000000..09ef20c --- /dev/null +++ b/lattice2CoinGlue.py @@ -0,0 +1,49 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2018 - Victor Titov (DeepSOIC) * +#* * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + +__title__="CoinGlue module of FreeCAD add-on Lattice2" +__author__ = "DeepSOIC" +__url__ = "" +__doc__ = "Glue and conversion routines between coin and freecad" + +def cointransform(placement, scale = 1.0, modifyme = None): + """cointransform(placement, scale = 1.0, modifyme = None): creates/updates SoTransform node from FreeCAD.Placement. + modifyme: the existing node to be modified. + Returns: SoTransform node (new if modifyme is None else modifyme)""" + + from pivy import coin + tr = coin.SoTransform() if modifyme is None else modifyme + tr.scaleFactor.setValue(scale,scale,scale) + tr.translation.setValue(*tuple(placement.Base)) + tr.rotation.setValue(*placement.Rotation.Q) + return tr + +def readNodeFromFile(fullpath): + """readNodeFromFile(fullpath): reads a file. Returns SoSeparator node, containing the read out stuff.""" + from pivy import coin + i = coin.SoInput() + if not i.openFile(fullpath): raise ValueError("Failed to open file: {fn}".format(fn= fullpath)) + import pivy + sep = pivy.SoDB.readAll(i) + i.closeFile() + return sep diff --git a/lattice2Markers.py b/lattice2Markers.py index 305cce5..e9b03fe 100644 --- a/lattice2Markers.py +++ b/lattice2Markers.py @@ -21,15 +21,19 @@ #* * #*************************************************************************** -import Part, os +import Part +import os + +import lattice2CoinGlue as CoinGlue __title__="latticeMarkers module for FreeCAD" __author__ = "DeepSOIC" __url__ = "" __doc__ = "Module for loading marker shapes for Lattice workbench" -_nullShapeShape = 0 +_nullShapeShape = None _ShapeDict = {} +_NodeDict = {} def getShapePath(shapeName): """ @@ -44,7 +48,7 @@ def getNullShapeShape(scale = 1.0): #read shape from file, if not done this before global _nullShapeShape - if not _nullShapeShape: + if _nullShapeShape is None: _nullShapeShape = Part.Shape() f = open(getShapePath("empty-shape.brep")) _nullShapeShape.importBrep(f) @@ -73,8 +77,7 @@ def loadShape(shapeID): FreeCAD.Console.PrintError('Failed to load standard shape "'+shapeID+'". \n' + str(err) + '\n') sh = Part.Point() #Create at least something! _ShapeDict[shapeID] = sh - return sh - + return sh def getPlacementMarker(scale = 1.0, markerID = None): '''getPlacementMarker(scale = 1.0, markerID = None): returns a placement marker shape. @@ -87,3 +90,27 @@ def getPlacementMarker(scale = 1.0, markerID = None): sh = sh.copy() sh.scale(scale) return sh + +def loadNode(shapeID): + global _NodeDict + nd = _NodeDict.get(shapeID) + if nd is None: + nd = CoinGlue.readNodeFromFile(getShapePath(shapeID + '.iv')) + _NodeDict[shapeID] = nd + nd.ref() # not sure if needed, but won't hurt. + return nd + +def getRefPlmMarker(markerID, placement = None, scale = 1.0): + '''getRefPlmMarker(markerID, placement = None, scale = 1.0): returns a coin placement marker shape, as SoSeparator (+ transform node + shape node). + The shape is scaled according to "scale" argument. + markerID sets the marker file name.''' + sh = loadNode(markerID + '-refplm') + from pivy import coin + sep = coin.SoSeparator() + tr = coin.SoTransform() + if placement is not None: + CoinGlue.cointransform(placement, scale, tr) + sep.addChild(tr) + sep.addChild(sh) + return (sep, tr, sh) + diff --git a/shapes/paperplane-orimarker-refplm.FCStd b/shapes/paperplane-orimarker-refplm.FCStd new file mode 100644 index 0000000..cb86ce8 Binary files /dev/null and b/shapes/paperplane-orimarker-refplm.FCStd differ diff --git a/shapes/paperplane-orimarker-refplm.iv b/shapes/paperplane-orimarker-refplm.iv new file mode 100644 index 0000000..109553e --- /dev/null +++ b/shapes/paperplane-orimarker-refplm.iv @@ -0,0 +1,149 @@ +#Inventor V2.1 ascii + +PickStyle { + style UNPICKABLE +} + +Coordinate3 { + point [ 2.4286127e-017 2.3747374e-017 0, + 1 0 0, + -0.28144613 -0.48747897 0, + 2.4286127e-017 2.3747374e-017 0, + -0.28144613 0.48747897 0, + 1 0 0, + 2.4286127e-017 2.3747374e-017 0, + 1 0 0, + 0 -6.3415941e-017 -0.28560001, + 2.4286127e-017 2.3747374e-017 0, + 1 0 0, + -0.28144613 -0.48747897 0, + -0.28144613 0.48747897 0, + 0 -6.3415941e-017 -0.28560001 ] +} + +Switch { + whichChild 0 + + Separator { + + DEF myLines Separator { + + MaterialBinding { + value OVERALL + + } + Material { + ambientColor 0.2 0.2 0.2 + diffuseColor 0.33333334 0.65490198 0.87058824 + specularColor 0 0 0 + emissiveColor 0 0 0 + shininess 1 + transparency 0 + + } + DrawStyle { + style LINES + lineWidth 2 + linePattern 0xffff + + } + SoBrepEdgeSet { + fields [ SFNode vertexProperty, MFInt32 coordIndex, MFInt32 materialIndex, MFInt32 normalIndex, MFInt32 textureCoordIndex, SFInt32 highlightIndex, MFInt32 selectionIndex ] + coordIndex [ 0, 1, -1, 1, 2, -1, 2, 0, + -1, 3, 4, -1, 4, 5, -1, 8, + 6, -1, 7, 8, -1 ] + highlightIndex -1 + selectionIndex -1 + + } + } + PolygonOffset { + + } + DEF myFaces Separator { + + ShapeHints { + vertexOrdering UNKNOWN_ORDERING + shapeType UNKNOWN_SHAPE_TYPE + + } + MaterialBinding { + value OVERALL + + } + Material { + ambientColor 0.2 0.2 0.2 + diffuseColor 0 0.66666669 1 + specularColor 0 0 0 + emissiveColor 0 0 0 + shininess 0.2 + transparency 0.5 + + } + DrawStyle { + style FILLED + + } + Normal { + vector [ 0 0 1, + 0 0 1, + 0 0 1, + 0 0 1, + 0 0 1, + 0 0 1, + 0 -1 2.220446e-016, + 0 -1 2.220446e-016, + 0 -1 2.220446e-016 ] + + } + NormalBinding { + value PER_VERTEX_INDEXED + + } + SoBrepFaceSet { + fields [ SFNode vertexProperty, MFInt32 coordIndex, MFInt32 materialIndex, MFInt32 normalIndex, MFInt32 textureCoordIndex, MFInt32 partIndex, SFInt32 highlightIndex, MFInt32 selectionIndex ] + coordIndex [ 1, 0, 2, -1, 5, 4, 3, -1, + 7, 6, 8, -1 ] + partIndex [ 1, 1, 1 ] + highlightIndex -1 + selectionIndex -1 + + } + } + DEF myPoints Separator { + + MaterialBinding { + value OVERALL + + } + Material { + ambientColor 0.2 0.2 0.2 + diffuseColor 0.25490198 0.67450982 0.89803922 + specularColor 0 0 0 + emissiveColor 0 0 0 + shininess 1 + transparency 0 + + } + DrawStyle { + style POINTS + pointSize 2 + + } + SoBrepPointSet { + fields [ SFNode vertexProperty, SFInt32 startIndex, SFInt32 numPoints, SFInt32 highlightIndex, MFInt32 selectionIndex ] + startIndex 9 + highlightIndex -1 + selectionIndex [ 9, 10, 11, 12, 13 ] + + } + } + } + USE myFaces + Separator { + + USE myLines + USE myPoints + } + USE myPoints +}