def derivedExecute(self,obj): self.assureGenerator(obj) self.updateReadonlyness(obj) # Apply links if obj.AxisLink: if lattice2BaseFeature.isObjectLattice(obj.AxisLink): lattice2Executer.warning(obj,"For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape.") #resolve the link if len(obj.AxisLinkSubelement) > 0: linkedShape = obj.AxisLink.Shape.getElement(obj.AxisLinkSubelement) else: linkedShape = obj.AxisLink.Shape #Type check if linkedShape.ShapeType != 'Edge': raise ValueError('Axis link must be an edge; it is '+linkedShape.ShapeType+' instead.') #prepare dir = App.Vector() point = App.Vector() if isinstance(linkedShape.Curve, Part.Line): dir = linkedShape.Curve.EndPoint - linkedShape.Curve.StartPoint point = linkedShape.Curve.StartPoint elif isinstance(linkedShape.Curve, Part.Circle): dir = linkedShape.Curve.Axis point = linkedShape.Curve.Center else: raise ValueError("Edge " + repr(linkedShape) + " can't be used to derive an axis. It must be either a line or a circle/arc.") #apply if obj.AxisDirIsDriven: obj.AxisDir = dir if obj.AxisPointIsDriven: obj.AxisPoint = point self.generator.execute() # cache properties into variables radius = float(obj.Radius) values = [float(strv) for strv in obj.Values] # compute initial vector. It is to be perpendicular to Axis rot_ini = lattice2GeomUtils.makeOrientationFromLocalAxes(ZAx= obj.AxisDir) overallPlacement = App.Placement(obj.AxisPoint, rot_ini) # Make the array output = [] # list of placements for ang in values: p = Part.Vertex() localrot = App.Rotation(App.Vector(0,0,1), ang) localtransl = localrot.multVec(App.Vector(radius,0,0)) localplm = App.Placement(localtransl, localrot) resultplm = overallPlacement.multiply(localplm) if obj.OrientMode == 'None': resultplm.Rotation = App.Rotation() output.append(resultplm) return output
def mirrorPlacement(placement, pivotPlacement, flipX, flipY, flipZ): """mirrorPlacement(placement, pivotPlacement, flipX, flipY, flipZ): mirrors a placement. Y axis of placement is adjusted to keep the placement's CS right-handed.""" plmM = pivotPlacement.toMatrix() mirrM = App.Base.Matrix() if flipX: mirrM.A11 = -1 if flipY: mirrM.A22 = -1 if flipZ: mirrM.A33 = -1 m = plmM.multiply(mirrM.multiply(plmM.inverse())) OX = App.Vector(1, 0, 0) OZ = App.Vector(0, 0, 1) base = m.multiply(placement.Base) xdir = m.submatrix(3).multiply(placement.Rotation.multVec(OX)) zdir = m.submatrix(3).multiply(placement.Rotation.multVec(OZ)) rot = makeOrientationFromLocalAxes(zdir, xdir) return App.Placement(base, rot)
def derivedExecute(self, obj): self.assureGenerator(obj) self.assureProperties(obj) self.updateReadonlyness(obj) # Apply links if screen(obj.Link): if lattice2BaseFeature.isObjectLattice(screen(obj.Link)): lattice2Executer.warning( obj, "For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape." ) #resolve the link if len(obj.LinkSubelement) > 0: linkedShape = screen(obj.Link).Shape.getElement( obj.LinkSubelement) else: linkedShape = screen(obj.Link).Shape #Type check if linkedShape.ShapeType != 'Edge': raise ValueError('Axis link must be an edge; it is ' + linkedShape.ShapeType + ' instead.') if type(linkedShape.Curve) is not Part.Line: raise ValueError('Axis link must be a line; it is ' + type(linkedShape.Curve) + ' instead.') #obtain start_point = linkedShape.valueAt(linkedShape.FirstParameter) end_point = linkedShape.valueAt(linkedShape.LastParameter) dir = end_point - start_point point = start_point if not obj.Reverse else end_point if obj.DirIsDriven: obj.Dir = dir if obj.PointIsDriven: obj.Point = point if obj.DrivenProperty != 'None': if obj.DrivenProperty == 'Span': propname = "SpanEnd" obj.SpanEnd = obj.SpanStart + App.Units.Quantity( 'mm') * dir.Length else: propname = obj.DrivenProperty setattr(obj, propname, dir.Length) if self.generator.isPropertyControlledByGenerator(propname): lattice2Executer.warning( obj, "Property " + propname + " is driven by both generator and link. Generator has priority." ) # Generate series of values self.generator.execute() values = [float(strv) for strv in obj.Values] #Apply reversal if obj.Reverse: obj.Dir = obj.Dir * (-1.0) if not (obj.DirIsDriven and screen(obj.Link)): obj.Reverse = False # precompute orientation if obj.OrientMode == 'Along axis': ori = lattice2GeomUtils.makeOrientationFromLocalAxes( ZAx=obj.Dir).multiply( lattice2GeomUtils.makeOrientationFromLocalAxes( ZAx=App.Vector(1, 0, 0), XAx=App.Vector(0, 0, 1))) else: ori = App.Rotation() dir = obj.Dir dir.normalize() # Make the array output = [] # list of placements for v in values: output.append(App.Placement(obj.Point + obj.Dir * v, ori)) return output
def derivedExecute(self, obj): base_is_lattice = LBF.isObjectLattice(obj.Object) pivot_is_lattice = LBF.isObjectLattice( obj.Pivot[0]) if obj.Pivot else True flipX = obj.FlipX flipY = obj.FlipY flipZ = obj.FlipZ # collect mirror pivot placements pivots = None em = 0 #editormode of PivotPlacement property. 0 = editable, 1 = read-only, 2 = hidden if obj.Pivot: em = 1 #read-only if pivot_is_lattice: pivots = LBF.getPlacementsList(obj.Pivot[0]) else: pivot_shape = resolveSingleSublink(obj.Pivot) if pivot_shape.ShapeType == 'Edge' and type( pivot_shape.Curve) is Part.Line: dir = pivot_shape.Curve.Direction base = pivot_shape.CenterOfMass if flipX != flipY: raise ValueError( "Unsupported combination of flips for mirroring against line. FlipX and FlipY must either be both on or both off." ) rot = makeOrientationFromLocalAxes(dir) pivots = [App.Placement(base, rot)] elif pivot_shape.ShapeType == 'Face' and type( pivot_shape.Surface) is Part.Plane: dir = pivot_shape.Surface.Axis base = pivot_shape.CenterOfMass if flipX != flipY: raise ValueError( "Unsupported combination of flips for mirroring against line. FlipX and FlipY must either be both on or both off." ) rot = makeOrientationFromLocalAxes(dir) pivots = [App.Placement(base, rot)] elif pivot_shape.ShapeType == 'Vertex': base = pivot_shape.Point pivots = [App.Placement(base, obj.PivotPlacement.Rotation)] em = 0 #editable else: raise TypeError("Unsupported geometry for use as mirror") if len(pivots) == 1: obj.PivotPlacement = pivots[0] else: em = 2 #hidden else: pivots = [obj.PivotPlacement] em = 0 obj.setEditorMode('PivotPlacement', em) # collect objects to be mirrored loop = False whole = obj.ObjectTraversal == 'Use whole' children = [] if base_is_lattice: children = LBF.getPlacementsList(obj.Object) else: if obj.ObjectTraversal == 'Use whole': children = [obj.Object.Shape] loop = True elif obj.ObjectTraversal == 'Direct children only': children = obj.Object.Shape.childShapes() elif obj.ObjectTraversal == 'Use whole': children = LCE.AllLeaves(obj.Object.Shape) else: raise ValueError( "Traversal mode not implemented: {mode}".format( mode=obj.ObjectTraversal)) if len(pivots) != len(children) and not loop and not whole: lattice2Executer.warning( obj, "{label}: Number of children ({nch}) doesn't match the number of pivot placements ({npiv})" .format(label=obj.Label, nch=len(children), npiv=len(pivots))) n = min(len(pivots), len(children)) else: n = len(pivots) # actual mirroring! result = [] for i in range(n): piv = pivots[i] ichild = i % len(children) if base_is_lattice: if whole: for plm in children: result.append( mirrorPlacement(plm, piv, flipX, flipY, flipZ)) else: result.append( mirrorPlacement(children[ichild], piv, flipX, flipY, flipZ)) else: result.append( mirrorShape(children[ichild], piv, flipX, flipY, flipZ)) # write out the result if base_is_lattice: return result else: if n == 1: result = ShapeCopy.transformCopy(result[0]) else: result = Part.Compound(result) obj.Shape = result return None
def derivedExecute(self,obj): # cache stuff if lattice2BaseFeature.isObjectLattice(obj.ShapeLink): lattice2Executer.warning(obj,"ShapeLink points to a placement/array of placements. The placement/array will be reinterpreted as a generic shape; the results may be unexpected.") base = obj.ShapeLink.Shape if obj.CompoundTraversal == "Use as a whole": baseChildren = [base] else: if base.ShapeType != 'Compound': base = Part.makeCompound([base]) if obj.CompoundTraversal == "Recursive": baseChildren = LCE.AllLeaves(base) else: baseChildren = base.childShapes() #cache mode comparisons, for speed posIsNone = obj.TranslateMode == '(none)' posIsParent = obj.TranslateMode == 'parent' posIsChild = obj.TranslateMode == 'child' posIsCenterM = obj.TranslateMode == 'child.CenterOfMass' posIsCenterBB = obj.TranslateMode == 'child.CenterOfBoundBox' posIsVertex = obj.TranslateMode == 'child.Vertex' oriIsNone = obj.OrientMode == '(none)' oriIsParent = obj.OrientMode == 'parent' oriIsChild = obj.OrientMode == 'child' oriIsInertial = obj.OrientMode == 'child.InertiaAxes' oriIsEdge = obj.OrientMode == 'child.Edge' oriIsFace = obj.OrientMode == 'child.FaceAxis' # initialize output containers and loop variables outputPlms = [] #list of placements # the essence for child in baseChildren: pos = App.Vector() ori = App.Rotation() if posIsNone: pass elif posIsParent: pos = base.Placement.Base elif posIsChild: pos = child.Placement.Base elif posIsCenterM: leaves = LCE.AllLeaves(child) totalW = 0 weightAttrib = {"Vertex":"", "Edge":"Length", "Wire":"Length", "Face":"Area", "Shell":"Area", "Solid":"Volume", "CompSolid":""}[leaves[0].ShapeType] #Center of mass of a compound is a weghted average of centers # of mass of individual objects. for leaf in leaves: w = 1.0 if not weightAttrib else (getattr(leaf, weightAttrib)) if leaf.ShapeType == 'Vertex': leafCM = leaf.Point #elif child.ShapeType == 'CompSolid': #todo else: leafCM = leaf.CenterOfMass pos += leafCM * w totalW += w pos = pos * (1.0/totalW) elif posIsCenterBB: import lattice2BoundBox bb = lattice2BoundBox.getPrecisionBoundBox(child) pos = bb.Center elif posIsVertex: v = child.Vertexes[obj.TranslateElementIndex - 1] pos = v.Point else: raise ValueError(obj.Name + ": translation mode not implemented: "+obj.TranslateMode) if oriIsNone: pass elif oriIsParent: ori = base.Placement.Rotation elif oriIsChild: ori = child.Placement.Rotation elif oriIsInertial: leaves = LCE.AllLeaves(child) if len(leaves)>1: raise ValueError(obj.Name + ": calculation of principal axes of compounds is not supported yet") props = leaves[0].PrincipalProperties XAx = props['FirstAxisOfInertia'] ZAx = props['ThirdAxisOfInertia'] ori = Utils.makeOrientationFromLocalAxes(ZAx, XAx) elif oriIsEdge: edge = child.Edges[obj.OrientElementIndex - 1] XAx = edge.Curve.tangent(edge.Curve.FirstParameter)[0] ori1 = Utils.makeOrientationFromLocalAxes(ZAx= XAx) ori2 = Utils.makeOrientationFromLocalAxes(ZAx= App.Vector(1,0,0),XAx= App.Vector(0,0,1)) ori = ori1.multiply(ori2) elif oriIsFace: face = child.Faces[obj.OrientElementIndex - 1] ZAx = face.Surface.Axis else: raise ValueError(obj.Name + ": orientation mode not implemented: "+obj.OrientMode) plm = App.Placement(pos, ori) outputPlms.append(plm) return outputPlms
def derivedExecute(self, obj): self.assureGenerator(obj) self.assureProperties(obj) self.updateReadonlyness(obj) # Apply links if screen(obj.AxisLink): if lattice2BaseFeature.isObjectLattice(screen(obj.AxisLink)): lattice2Executer.warning( obj, "For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape." ) #resolve the link if len(obj.AxisLinkSubelement) > 0: linkedShape = screen(obj.AxisLink).Shape.getElement( obj.AxisLinkSubelement) else: linkedShape = screen(obj.AxisLink).Shape #Type check if linkedShape.ShapeType != 'Edge': raise ValueError('Axis link must be an edge; it is ' + linkedShape.ShapeType + ' instead.') #prepare dir = App.Vector() point = App.Vector() if isinstance(linkedShape.Curve, Part.Line): start_point = linkedShape.valueAt(linkedShape.FirstParameter) end_point = linkedShape.valueAt(linkedShape.LastParameter) dir = end_point - start_point point = start_point elif isinstance(linkedShape.Curve, Part.Circle): dir = linkedShape.Curve.Axis point = linkedShape.Curve.Center else: raise ValueError( "Edge " + repr(linkedShape) + " can't be used to derive an axis. It must be either a line or a circle/arc." ) #apply if obj.AxisDirIsDriven: obj.AxisDir = dir if obj.AxisPointIsDriven: obj.AxisPoint = point self.generator.execute() # cache properties into variables radius = float(obj.Radius) values = [float(strv) for strv in obj.Values] # compute initial vector. It is to be perpendicular to Axis rot_ini = lattice2GeomUtils.makeOrientationFromLocalAxes( ZAx=obj.AxisDir) overallPlacement = App.Placement(obj.AxisPoint, rot_ini) # Make the array output = [] # list of placements for ang in values: p = Part.Vertex() localrot = App.Rotation(App.Vector(0, 0, 1), ang) localtransl = localrot.multVec(App.Vector(radius, 0, 0)) localplm = App.Placement(localtransl, localrot) resultplm = overallPlacement.multiply(localplm) if obj.OrientMode == 'None': resultplm.Rotation = App.Rotation() output.append(resultplm) return output
def derivedExecute(self,obj): self.assureGenerator(obj) self.updateReadonlyness(obj) # Apply links if obj.Link: if lattice2BaseFeature.isObjectLattice(obj.Link): lattice2Executer.warning(obj,"For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape.") #resolve the link if len(obj.LinkSubelement) > 0: linkedShape = obj.Link.Shape.getElement(obj.LinkSubelement) else: linkedShape = obj.Link.Shape #Type check if linkedShape.ShapeType != 'Edge': raise ValueError('Axis link must be an edge; it is '+linkedShape.ShapeType+' instead.') if type(linkedShape.Curve) is not Part.Line: raise ValueError('Axis link must be a line; it is '+type(linkedShape.Curve)+' instead.') #obtain dir = linkedShape.Curve.EndPoint - linkedShape.Curve.StartPoint point = linkedShape.Curve.StartPoint if not obj.Reverse else linkedShape.Curve.EndPoint if obj.DirIsDriven: obj.Dir = dir if obj.PointIsDriven: obj.Point = point if obj.DrivenProperty != 'None': if obj.DrivenProperty == 'Span': propname = "SpanEnd" obj.SpanEnd = obj.SpanStart + App.Units.Quantity('mm')*dir.Length else: propname = obj.DrivenProperty setattr(obj, propname, dir.Length) if self.generator.isPropertyControlledByGenerator(propname): lattice2Executer.warning(obj, "Property "+propname+" is driven by both generator and link. Generator has priority.") # Generate series of values self.generator.execute() values = [float(strv) for strv in obj.Values] #Apply reversal if obj.Reverse: obj.Dir = obj.Dir*(-1.0) if not(obj.DirIsDriven and obj.Link): obj.Reverse = False # precompute orientation if obj.OrientMode == 'Along axis': ori = lattice2GeomUtils.makeOrientationFromLocalAxes(ZAx= obj.Dir).multiply( lattice2GeomUtils.makeOrientationFromLocalAxes(ZAx= App.Vector(1,0,0), XAx= App.Vector(0,0,1)) ) else: ori = App.Rotation() dir = obj.Dir dir.normalize() # Make the array output = [] # list of placements for v in values: output.append( App.Placement(obj.Point + obj.Dir*v, ori) ) return output
def derivedExecute(self,obj): # cache stuff if lattice2BaseFeature.isObjectLattice(screen(obj.ShapeLink)): lattice2Executer.warning(obj,"ShapeLink points to a placement/array of placements. The placement/array will be reinterpreted as a generic shape; the results may be unexpected.") base = screen(obj.ShapeLink).Shape if obj.CompoundTraversal == "Use as a whole": baseChildren = [base] else: if base.ShapeType != 'Compound': base = Part.makeCompound([base]) if obj.CompoundTraversal == "Recursive": baseChildren = LCE.AllLeaves(base) else: baseChildren = base.childShapes() #cache mode comparisons, for speed posIsNone = obj.TranslateMode == '(none)' posIsParent = obj.TranslateMode == 'parent' posIsChild = obj.TranslateMode == 'child' posIsCenterM = obj.TranslateMode == 'child.CenterOfMass' posIsCenterBB = obj.TranslateMode == 'child.CenterOfBoundBox' posIsVertex = obj.TranslateMode == 'child.Vertex' oriIsNone = obj.OrientMode == '(none)' oriIsParent = obj.OrientMode == 'parent' oriIsChild = obj.OrientMode == 'child' oriIsInertial = obj.OrientMode == 'child.InertiaAxes' oriIsEdge = obj.OrientMode == 'child.Edge' oriIsFace = obj.OrientMode == 'child.FaceAxis' # initialize output containers and loop variables outputPlms = [] #list of placements # the essence for child in baseChildren: pos = App.Vector() ori = App.Rotation() if posIsNone: pass elif posIsParent: pos = base.Placement.Base elif posIsChild: pos = child.Placement.Base elif posIsCenterM: leaves = LCE.AllLeaves(child) totalW = 0 weightAttrib = {"Vertex":"", "Edge":"Length", "Wire":"Length", "Face":"Area", "Shell":"Area", "Solid":"Volume", "CompSolid":""}[leaves[0].ShapeType] #Center of mass of a compound is a weghted average of centers # of mass of individual objects. for leaf in leaves: w = 1.0 if not weightAttrib else (getattr(leaf, weightAttrib)) if leaf.ShapeType == 'Vertex': leafCM = leaf.Point #elif child.ShapeType == 'CompSolid': #todo else: leafCM = leaf.CenterOfMass pos += leafCM * w totalW += w pos = pos * (1.0/totalW) elif posIsCenterBB: import lattice2BoundBox bb = lattice2BoundBox.getPrecisionBoundBox(child) pos = bb.Center elif posIsVertex: v = child.Vertexes[obj.TranslateElementIndex - 1] pos = v.Point else: raise ValueError(obj.Name + ": translation mode not implemented: "+obj.TranslateMode) if oriIsNone: pass elif oriIsParent: ori = base.Placement.Rotation elif oriIsChild: ori = child.Placement.Rotation elif oriIsInertial: leaves = LCE.AllLeaves(child) if len(leaves)>1: raise ValueError(obj.Name + ": calculation of principal axes of compounds is not supported yet") props = leaves[0].PrincipalProperties XAx = props['FirstAxisOfInertia'] ZAx = props['ThirdAxisOfInertia'] ori = Utils.makeOrientationFromLocalAxes(ZAx, XAx) elif oriIsEdge: edge = child.Edges[obj.OrientElementIndex - 1] XAx = edge.Curve.tangent(edge.Curve.FirstParameter)[0] ori1 = Utils.makeOrientationFromLocalAxes(ZAx= XAx) ori2 = Utils.makeOrientationFromLocalAxes(ZAx= App.Vector(1,0,0),XAx= App.Vector(0,0,1)) ori = ori1.multiply(ori2) elif oriIsFace: face = child.Faces[obj.OrientElementIndex - 1] ZAx = face.Surface.Axis else: raise ValueError(obj.Name + ": orientation mode not implemented: "+obj.OrientMode) plm = App.Placement(pos, ori) outputPlms.append(plm) return outputPlms