class LinearArray(lattice2BaseFeature.LatticeFeature): "The Lattice LinearArray object" def derivedInit(self, obj): self.Type = "LatticeLinearArray" obj.addProperty("App::PropertyVector", "Dir", "Lattice Array", "Vector that defines axis direction") obj.Dir = App.Vector(1, 0, 0) obj.addProperty( "App::PropertyVector", "Point", "Lattice Array", "Position of base (the point through which the axis passes, and from which positions of elements are measured)" ) obj.addProperty("App::PropertyLink", "Link", "Lattice Array", "Link to the axis (Edge1 is used for the axis).") obj.addProperty("App::PropertyString", "LinkSubelement", "Lattice Array", "subelement to take from axis link shape") obj.addProperty("App::PropertyBool", "Reverse", "Lattice Array", "Set to true to reverse direction") obj.addProperty("App::PropertyBool", "DirIsDriven", "Lattice Array", "If True, Dir property is driven by link.") obj.DirIsDriven = True obj.addProperty( "App::PropertyBool", "PointIsDriven", "Lattice Array", "If True, AxisPoint is not updated based on the link.") obj.PointIsDriven = True obj.addProperty( "App::PropertyEnumeration", "DrivenProperty", "Lattice Array", "Select, which property is to be driven by length of axis link.") obj.DrivenProperty = ['None', 'Span', 'SpanStart', 'SpanEnd', 'Step'] obj.DrivenProperty = 'Span' obj.addProperty("App::PropertyEnumeration", "OrientMode", "Lattice Array", "Orientation of elements") obj.OrientMode = ['None', 'Along axis'] obj.OrientMode = 'Along axis' self.assureGenerator(obj) obj.ValuesSource = "Generator" obj.GeneratorMode = "StepN" obj.EndInclusive = True obj.SpanStart = 0.0 obj.SpanEnd = 12.0 obj.Step = 3.0 obj.Count = 5.0 self.assureProperties(obj) def updateReadonlyness(self, obj): link = screen(obj.Link) obj.setEditorMode("Dir", 1 if (link and obj.DirIsDriven) else 0) obj.setEditorMode("Point", 1 if (link and obj.PointIsDriven) else 0) obj.setEditorMode("DirIsDriven", 0 if link else 1) obj.setEditorMode("PointIsDriven", 0 if link else 1) obj.setEditorMode("DrivenProperty", 0 if link else 1) self.generator.updateReadonlyness() def assureGenerator(self, obj): '''Adds an instance of value series generator, if one doesn't exist yet.''' if hasattr(self, "generator"): return self.generator = ValueSeriesGenerator(obj) self.generator.addProperties( groupname="Lattice Array", groupname_gen="Lattice Series Generator", valuesdoc= "List of distances. Distance is measured from Point, along Dir, in millimeters.", valuestype="App::PropertyDistance") self.updateReadonlyness(obj) def assureProperties(self, selfobj): assureProperty( selfobj, "App::PropertyLinkSub", "SubLink", sublinkFromApart(screen(selfobj.Link), selfobj.LinkSubelement), "Lattice Array", "Mirror of Object+SubNames properties") 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 onChanged(self, selfobj, prop): #prop is a string - name of the property # synchronize SubLink and Object+SubNames properties syncSublinkApart(selfobj, prop, 'SubLink', 'Link', 'LinkSubelement') return lattice2BaseFeature.LatticeFeature.onChanged( self, selfobj, prop)
class LinearArray(lattice2BaseFeature.LatticeFeature): "The Lattice LinearArray object" def derivedInit(self,obj): self.Type = "LatticeLinearArray" obj.addProperty("App::PropertyVector","Dir","Lattice Array","Vector that defines axis direction") obj.Dir = App.Vector(1,0,0) obj.addProperty("App::PropertyVector","Point","Lattice Array","Position of base (the point through which the axis passes, and from which positions of elements are measured)") obj.addProperty("App::PropertyLink","Link","Lattice Array","Link to the axis (Edge1 is used for the axis).") obj.addProperty("App::PropertyString","LinkSubelement","Lattice Array","subelement to take from axis link shape") obj.addProperty("App::PropertyBool","Reverse","Lattice Array","Set to true to reverse direction") obj.addProperty("App::PropertyBool","DirIsDriven","Lattice Array","If True, Dir property is driven by link.") obj.DirIsDriven = True obj.addProperty("App::PropertyBool","PointIsDriven","Lattice Array","If True, AxisPoint is not updated based on the link.") obj.PointIsDriven = True obj.addProperty("App::PropertyEnumeration","DrivenProperty","Lattice Array","Select, which property is to be driven by length of axis link.") obj.DrivenProperty = ['None','Span','SpanStart','SpanEnd','Step'] obj.DrivenProperty = 'Span' obj.addProperty("App::PropertyEnumeration","OrientMode","Lattice Array","Orientation of elements") obj.OrientMode = ['None','Along axis'] obj.OrientMode = 'Along axis' self.assureGenerator(obj) obj.ValuesSource = "Generator" obj.GeneratorMode = "StepN" obj.EndInclusive = True obj.SpanStart = 0.0 obj.SpanEnd = 12.0 obj.Step = 3.0 obj.Count = 5.0 def updateReadonlyness(self, obj): obj.setEditorMode("Dir", 1 if (obj.Link and obj.DirIsDriven) else 0) obj.setEditorMode("Point", 1 if (obj.Link and obj.PointIsDriven) else 0) obj.setEditorMode("DirIsDriven", 0 if obj.Link else 1) obj.setEditorMode("PointIsDriven", 0 if obj.Link else 1) obj.setEditorMode("DrivenProperty", 0 if obj.Link else 1) self.generator.updateReadonlyness() def assureGenerator(self, obj): '''Adds an instance of value series generator, if one doesn't exist yet.''' if hasattr(self,"generator"): return self.generator = ValueSeriesGenerator(obj) self.generator.addProperties(groupname= "Lattice Array", groupname_gen= "Lattice Series Generator", valuesdoc= "List of distances. Distance is measured from Point, along Dir, in millimeters.", valuestype= "App::PropertyDistance") self.updateReadonlyness(obj) 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