Add Draft workbench to .pre-commit-config (#24664)
* Add Draft workbench to .pre-commit-config * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -75,7 +75,7 @@ class Array(DraftLink):
|
||||
_log("v1.1, " + obj.Name + ", added hidden property 'PlacementList'")
|
||||
|
||||
self.set_general_properties(obj)
|
||||
self.execute(obj) # Required to update Count and/or PlacementList.
|
||||
self.execute(obj) # Required to update Count and/or PlacementList.
|
||||
|
||||
def set_properties(self, obj):
|
||||
"""Set properties only if they don't exist."""
|
||||
@@ -94,67 +94,57 @@ class Array(DraftLink):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "Base" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The base object that will be duplicated")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The base object that will be duplicated")
|
||||
obj.addProperty("App::PropertyLink", "Base", "Objects", _tip, locked=True)
|
||||
obj.Base = None
|
||||
|
||||
if "ArrayType" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The type of array to create.\n"
|
||||
"- Ortho: places the copies "
|
||||
"in the direction of the global X, "
|
||||
"Y, Z axes.\n"
|
||||
"- Polar: places the copies along "
|
||||
"a circular arc, up to a specified "
|
||||
"angle, and with certain orientation "
|
||||
"defined by a center and an axis.\n"
|
||||
"- Circular: places the copies "
|
||||
"in concentric circles "
|
||||
"around the base object.")
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"ArrayType",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.ArrayType = ['ortho', 'polar', 'circular']
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The type of array to create.\n"
|
||||
"- Ortho: places the copies "
|
||||
"in the direction of the global X, "
|
||||
"Y, Z axes.\n"
|
||||
"- Polar: places the copies along "
|
||||
"a circular arc, up to a specified "
|
||||
"angle, and with certain orientation "
|
||||
"defined by a center and an axis.\n"
|
||||
"- Circular: places the copies "
|
||||
"in concentric circles "
|
||||
"around the base object.",
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "ArrayType", "Objects", _tip, locked=True)
|
||||
obj.ArrayType = ["ortho", "polar", "circular"]
|
||||
|
||||
if "Fuse" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"Fuse",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Fuse", "Objects", _tip, locked=True)
|
||||
obj.Fuse = False
|
||||
|
||||
if "Count" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Total number of elements "
|
||||
"in the array.\n"
|
||||
"This property is read-only, "
|
||||
"as the number depends "
|
||||
"on the parameters of the array.")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"Count",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Total number of elements "
|
||||
"in the array.\n"
|
||||
"This property is read-only, "
|
||||
"as the number depends "
|
||||
"on the parameters of the array.",
|
||||
)
|
||||
obj.addProperty("App::PropertyInteger", "Count", "Objects", _tip, locked=True)
|
||||
obj.Count = 0
|
||||
obj.setEditorMode("Count", 1) # Read only
|
||||
|
||||
if not self.use_link:
|
||||
if "PlacementList" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The placement for each array element")
|
||||
obj.addProperty("App::PropertyPlacementList",
|
||||
"PlacementList",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The placement for each array element")
|
||||
obj.addProperty(
|
||||
"App::PropertyPlacementList", "PlacementList", "Objects", _tip, locked=True
|
||||
)
|
||||
obj.PlacementList = []
|
||||
|
||||
def set_ortho_properties(self, obj):
|
||||
@@ -162,66 +152,51 @@ class Array(DraftLink):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "NumberX" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Number of copies in X-direction")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"NumberX",
|
||||
"Orthogonal array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Number of copies in X-direction")
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "NumberX", "Orthogonal array", _tip, locked=True
|
||||
)
|
||||
obj.NumberX = 2
|
||||
|
||||
if "NumberY" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Number of copies in Y-direction")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"NumberY",
|
||||
"Orthogonal array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Number of copies in Y-direction")
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "NumberY", "Orthogonal array", _tip, locked=True
|
||||
)
|
||||
obj.NumberY = 2
|
||||
|
||||
if "NumberZ" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Number of copies in Z-direction")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"NumberZ",
|
||||
"Orthogonal array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Number of copies in Z-direction")
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "NumberZ", "Orthogonal array", _tip, locked=True
|
||||
)
|
||||
obj.NumberZ = 1
|
||||
|
||||
if "IntervalX" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Distance and orientation "
|
||||
"of intervals in X-direction")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"IntervalX",
|
||||
"Orthogonal array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Distance and orientation " "of intervals in X-direction"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "IntervalX", "Orthogonal array", _tip, locked=True
|
||||
)
|
||||
obj.IntervalX = App.Vector(50, 0, 0)
|
||||
|
||||
if "IntervalY" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Distance and orientation "
|
||||
"of intervals in Y-direction")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"IntervalY",
|
||||
"Orthogonal array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Distance and orientation " "of intervals in Y-direction"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "IntervalY", "Orthogonal array", _tip, locked=True
|
||||
)
|
||||
obj.IntervalY = App.Vector(0, 50, 0)
|
||||
|
||||
if "IntervalZ" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Distance and orientation "
|
||||
"of intervals in Z-direction")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"IntervalZ",
|
||||
"Orthogonal array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Distance and orientation " "of intervals in Z-direction"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "IntervalZ", "Orthogonal array", _tip, locked=True
|
||||
)
|
||||
obj.IntervalZ = App.Vector(0, 0, 50)
|
||||
|
||||
def set_polar_circular_properties(self, obj):
|
||||
@@ -229,47 +204,47 @@ class Array(DraftLink):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "Axis" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The axis direction around which "
|
||||
"the elements in a polar or "
|
||||
"a circular array will be created")
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"Axis",
|
||||
"Polar/circular array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The axis direction around which "
|
||||
"the elements in a polar or "
|
||||
"a circular array will be created",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVector", "Axis", "Polar/circular array", _tip, locked=True
|
||||
)
|
||||
obj.Axis = App.Vector(0, 0, 1)
|
||||
|
||||
if "Center" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Center point for polar and "
|
||||
"circular arrays.\n"
|
||||
"The 'Axis' passes through this point.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"Center",
|
||||
"Polar/circular array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Center point for polar and "
|
||||
"circular arrays.\n"
|
||||
"The 'Axis' passes through this point.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "Center", "Polar/circular array", _tip, locked=True
|
||||
)
|
||||
obj.Center = App.Vector(0, 0, 0)
|
||||
|
||||
# The AxisReference property must be attached after Axis and Center
|
||||
# so that onChanged works properly
|
||||
if "AxisReference" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The axis object that overrides "
|
||||
"the value of 'Axis' and 'Center', "
|
||||
"for example, a datum line.\n"
|
||||
"Its placement, position and rotation, "
|
||||
"will be used when creating polar "
|
||||
"and circular arrays.\n"
|
||||
"Leave this property empty "
|
||||
"to be able to set 'Axis' and 'Center' "
|
||||
"manually.")
|
||||
obj.addProperty("App::PropertyLinkGlobal",
|
||||
"AxisReference",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The axis object that overrides "
|
||||
"the value of 'Axis' and 'Center', "
|
||||
"for example, a datum line.\n"
|
||||
"Its placement, position and rotation, "
|
||||
"will be used when creating polar "
|
||||
"and circular arrays.\n"
|
||||
"Leave this property empty "
|
||||
"to be able to set 'Axis' and 'Center' "
|
||||
"manually.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkGlobal", "AxisReference", "Objects", _tip, locked=True
|
||||
)
|
||||
obj.AxisReference = None
|
||||
|
||||
def set_polar_properties(self, obj):
|
||||
@@ -277,34 +252,22 @@ class Array(DraftLink):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "NumberPolar" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Number of copies in the polar direction")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"NumberPolar",
|
||||
"Polar array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Number of copies in the polar direction")
|
||||
obj.addProperty("App::PropertyInteger", "NumberPolar", "Polar array", _tip, locked=True)
|
||||
obj.NumberPolar = 5
|
||||
|
||||
if "IntervalAxis" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Distance and orientation "
|
||||
"of intervals in 'Axis' direction")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"IntervalAxis",
|
||||
"Polar array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Distance and orientation " "of intervals in 'Axis' direction"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "IntervalAxis", "Polar array", _tip, locked=True
|
||||
)
|
||||
obj.IntervalAxis = App.Vector(0, 0, 0)
|
||||
|
||||
if "Angle" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Angle to cover with copies")
|
||||
obj.addProperty("App::PropertyAngle",
|
||||
"Angle",
|
||||
"Polar array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Angle to cover with copies")
|
||||
obj.addProperty("App::PropertyAngle", "Angle", "Polar array", _tip, locked=True)
|
||||
obj.Angle = 360
|
||||
|
||||
def set_circular_properties(self, obj):
|
||||
@@ -312,47 +275,39 @@ class Array(DraftLink):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "RadialDistance" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Distance between concentric circles")
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"RadialDistance",
|
||||
"Circular array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Distance between concentric circles")
|
||||
obj.addProperty(
|
||||
"App::PropertyDistance", "RadialDistance", "Circular array", _tip, locked=True
|
||||
)
|
||||
obj.RadialDistance = 50
|
||||
|
||||
if "TangentialDistance" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Distance between copies "
|
||||
"in the same circle")
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"TangentialDistance",
|
||||
"Circular array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Distance between copies " "in the same circle"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyDistance", "TangentialDistance", "Circular array", _tip, locked=True
|
||||
)
|
||||
obj.TangentialDistance = 25
|
||||
|
||||
if "NumberCircles" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Number of concentric circle. "
|
||||
"The 'Base' object counts as one circle.")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"NumberCircles",
|
||||
"Circular array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Number of concentric circle. " "The 'Base' object counts as one circle.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "NumberCircles", "Circular array", _tip, locked=True
|
||||
)
|
||||
obj.NumberCircles = 3
|
||||
|
||||
if "Symmetry" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"A parameter that determines "
|
||||
"how many symmetry planes "
|
||||
"the circular array will have")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"Symmetry",
|
||||
"Circular array",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"A parameter that determines "
|
||||
"how many symmetry planes "
|
||||
"the circular array will have",
|
||||
)
|
||||
obj.addProperty("App::PropertyInteger", "Symmetry", "Circular array", _tip, locked=True)
|
||||
obj.Symmetry = 1
|
||||
|
||||
def set_link_properties(self, obj):
|
||||
@@ -361,21 +316,17 @@ class Array(DraftLink):
|
||||
|
||||
if self.use_link:
|
||||
if "ExpandArray" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Show the individual array elements "
|
||||
"(only for Link arrays)")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ExpandArray",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Show the individual array elements " "(only for Link arrays)"
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "ExpandArray", "Objects", _tip, locked=True)
|
||||
obj.ExpandArray = False
|
||||
|
||||
def linkSetup(self, obj):
|
||||
"""Set up the object as a link object."""
|
||||
super(Array, self).linkSetup(obj)
|
||||
obj.configLinkProperty(ElementCount='Count')
|
||||
obj.setPropertyStatus('Count', 'Hidden')
|
||||
obj.configLinkProperty(ElementCount="Count")
|
||||
obj.setPropertyStatus("Count", "Hidden")
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
"""Execute when a property is changed."""
|
||||
@@ -395,42 +346,67 @@ class Array(DraftLink):
|
||||
|
||||
if prop == "ArrayType":
|
||||
if obj.ArrayType == "ortho":
|
||||
for pr in ("NumberX", "NumberY", "NumberZ",
|
||||
"IntervalX", "IntervalY", "IntervalZ"):
|
||||
for pr in ("NumberX", "NumberY", "NumberZ", "IntervalX", "IntervalY", "IntervalZ"):
|
||||
obj.setPropertyStatus(pr, "-Hidden")
|
||||
|
||||
for pr in ("Axis", "Center", "NumberPolar", "Angle",
|
||||
"IntervalAxis", "NumberCircles",
|
||||
"RadialDistance", "TangentialDistance",
|
||||
"Symmetry"):
|
||||
for pr in (
|
||||
"Axis",
|
||||
"Center",
|
||||
"NumberPolar",
|
||||
"Angle",
|
||||
"IntervalAxis",
|
||||
"NumberCircles",
|
||||
"RadialDistance",
|
||||
"TangentialDistance",
|
||||
"Symmetry",
|
||||
):
|
||||
obj.setPropertyStatus(pr, "Hidden")
|
||||
|
||||
if obj.ArrayType == "polar":
|
||||
for pr in ("Axis", "Center", "NumberPolar",
|
||||
"Angle", "IntervalAxis"):
|
||||
for pr in ("Axis", "Center", "NumberPolar", "Angle", "IntervalAxis"):
|
||||
obj.setPropertyStatus(pr, "-Hidden")
|
||||
|
||||
for pr in ("NumberX", "NumberY", "NumberZ",
|
||||
"IntervalX", "IntervalY", "IntervalZ",
|
||||
"NumberCircles", "RadialDistance",
|
||||
"TangentialDistance", "Symmetry"):
|
||||
for pr in (
|
||||
"NumberX",
|
||||
"NumberY",
|
||||
"NumberZ",
|
||||
"IntervalX",
|
||||
"IntervalY",
|
||||
"IntervalZ",
|
||||
"NumberCircles",
|
||||
"RadialDistance",
|
||||
"TangentialDistance",
|
||||
"Symmetry",
|
||||
):
|
||||
obj.setPropertyStatus(pr, "Hidden")
|
||||
|
||||
if obj.ArrayType == "circular":
|
||||
for pr in ("Axis", "Center", "NumberCircles",
|
||||
"RadialDistance", "TangentialDistance",
|
||||
"Symmetry"):
|
||||
for pr in (
|
||||
"Axis",
|
||||
"Center",
|
||||
"NumberCircles",
|
||||
"RadialDistance",
|
||||
"TangentialDistance",
|
||||
"Symmetry",
|
||||
):
|
||||
obj.setPropertyStatus(pr, "-Hidden")
|
||||
|
||||
for pr in ("NumberX", "NumberY", "NumberZ",
|
||||
"IntervalX", "IntervalY", "IntervalZ",
|
||||
"NumberPolar", "Angle", "IntervalAxis"):
|
||||
for pr in (
|
||||
"NumberX",
|
||||
"NumberY",
|
||||
"NumberZ",
|
||||
"IntervalX",
|
||||
"IntervalY",
|
||||
"IntervalZ",
|
||||
"NumberPolar",
|
||||
"Angle",
|
||||
"IntervalAxis",
|
||||
):
|
||||
obj.setPropertyStatus(pr, "Hidden")
|
||||
|
||||
def execute(self, obj):
|
||||
"""Execute when the object is created or recomputed."""
|
||||
if self.props_changed_placement_only(obj) \
|
||||
or not obj.Base:
|
||||
if self.props_changed_placement_only(obj) or not obj.Base:
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
@@ -444,43 +420,49 @@ class Array(DraftLink):
|
||||
axis = reference.Rotation * App.Vector(0, 0, 1)
|
||||
center = reference.Base
|
||||
else:
|
||||
_info = ("'AxisReference' has no 'Placement' property. "
|
||||
"Please select a different object to use as "
|
||||
"reference.")
|
||||
_info = (
|
||||
"'AxisReference' has no 'Placement' property. "
|
||||
"Please select a different object to use as "
|
||||
"reference."
|
||||
)
|
||||
raise TypeError(_info)
|
||||
|
||||
if obj.ArrayType == "ortho":
|
||||
pls = rect_placements(obj.Base.Placement,
|
||||
obj.IntervalX,
|
||||
obj.IntervalY,
|
||||
obj.IntervalZ,
|
||||
obj.NumberX,
|
||||
obj.NumberY,
|
||||
obj.NumberZ)
|
||||
pls = rect_placements(
|
||||
obj.Base.Placement,
|
||||
obj.IntervalX,
|
||||
obj.IntervalY,
|
||||
obj.IntervalZ,
|
||||
obj.NumberX,
|
||||
obj.NumberY,
|
||||
obj.NumberZ,
|
||||
)
|
||||
elif obj.ArrayType == "polar":
|
||||
av = obj.IntervalAxis if hasattr(obj, "IntervalAxis") else None
|
||||
pls = polar_placements(obj.Base.Placement,
|
||||
center, obj.Angle.Value,
|
||||
obj.NumberPolar, axis, av)
|
||||
pls = polar_placements(
|
||||
obj.Base.Placement, center, obj.Angle.Value, obj.NumberPolar, axis, av
|
||||
)
|
||||
elif obj.ArrayType == "circular":
|
||||
pls = circ_placements(obj.Base.Placement,
|
||||
obj.RadialDistance,
|
||||
obj.TangentialDistance,
|
||||
axis, center,
|
||||
obj.NumberCircles, obj.Symmetry)
|
||||
pls = circ_placements(
|
||||
obj.Base.Placement,
|
||||
obj.RadialDistance,
|
||||
obj.TangentialDistance,
|
||||
axis,
|
||||
center,
|
||||
obj.NumberCircles,
|
||||
obj.Symmetry,
|
||||
)
|
||||
|
||||
self.buildShape(obj, pl, pls)
|
||||
self.props_changed_clear()
|
||||
return (not self.use_link)
|
||||
return not self.use_link
|
||||
|
||||
|
||||
# Alias for compatibility with v0.18 and earlier
|
||||
_Array = Array
|
||||
|
||||
|
||||
def rect_placements(base_placement,
|
||||
xvector, yvector, zvector,
|
||||
xnum, ynum, znum):
|
||||
def rect_placements(base_placement, xvector, yvector, zvector, xnum, ynum, znum):
|
||||
"""Determine the placements where the rectangular copies will be."""
|
||||
pl = base_placement
|
||||
placements = [pl.copy()]
|
||||
@@ -513,9 +495,7 @@ def rect_placements(base_placement,
|
||||
return placements
|
||||
|
||||
|
||||
def polar_placements(base_placement,
|
||||
center, angle,
|
||||
number, axis, axisvector):
|
||||
def polar_placements(base_placement, center, angle, number, axis, axisvector):
|
||||
"""Determine the placements where the polar copies will be."""
|
||||
# print("angle ",angle," num ",num)
|
||||
placements = [base_placement.copy()]
|
||||
@@ -540,10 +520,9 @@ def polar_placements(base_placement,
|
||||
return placements
|
||||
|
||||
|
||||
def circ_placements(base_placement,
|
||||
r_distance, tan_distance,
|
||||
axis, center,
|
||||
circle_number, symmetry):
|
||||
def circ_placements(
|
||||
base_placement, r_distance, tan_distance, axis, center, circle_number, symmetry
|
||||
):
|
||||
"""Determine the placements where the circular copies will be."""
|
||||
symmetry = max(1, symmetry)
|
||||
lead = (0, 1, 0)
|
||||
@@ -572,4 +551,5 @@ def circ_placements(base_placement,
|
||||
|
||||
return placements
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -79,7 +79,7 @@ class DraftObject(object):
|
||||
obj.Proxy = self
|
||||
self.Type = tp
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
def onDocumentRestored(self, obj):
|
||||
# Object properties are updated when the document is opened.
|
||||
self.props_changed_clear()
|
||||
|
||||
|
||||
@@ -41,39 +41,32 @@ class BezCurve(DraftObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj, "BezCurve")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The points of the Bezier curve")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The points of the Bezier curve")
|
||||
obj.addProperty("App::PropertyVectorList", "Points", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The degree of the Bezier function")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The degree of the Bezier function")
|
||||
obj.addProperty("App::PropertyInteger", "Degree", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Continuity")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Continuity")
|
||||
obj.addProperty("App::PropertyIntegerList", "Continuity", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If the Bezier curve should be closed or not")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "If the Bezier curve should be closed or not")
|
||||
obj.addProperty("App::PropertyBool", "Closed", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Create a face if this curve is closed")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Create a face if this curve is closed")
|
||||
obj.addProperty("App::PropertyBool", "MakeFace", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The length of this object")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The length of this object")
|
||||
obj.addProperty("App::PropertyLength", "Length", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The area of this object")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The area of this object")
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
|
||||
obj.MakeFace = params.get_param("MakeFaceMode")
|
||||
obj.Closed = False
|
||||
obj.Degree = 3
|
||||
obj.Continuity = []
|
||||
#obj.setEditorMode("Degree", 2)
|
||||
# obj.setEditorMode("Degree", 2)
|
||||
obj.setEditorMode("Continuity", 1)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
@@ -92,67 +85,69 @@ class BezCurve(DraftObject):
|
||||
fp.positionBySupport()
|
||||
self.props_changed_clear()
|
||||
|
||||
def _segpoleslst(self,fp):
|
||||
def _segpoleslst(self, fp):
|
||||
"""Split the points into segments."""
|
||||
if not fp.Closed and len(fp.Points) >= 2: #allow lower degree segment
|
||||
poles=fp.Points[1:]
|
||||
elif fp.Closed and len(fp.Points) >= fp.Degree: #drawable
|
||||
#poles=fp.Points[1:(fp.Degree*(len(fp.Points)//fp.Degree))]+fp.Points[0:1]
|
||||
poles=fp.Points[1:]+fp.Points[0:1]
|
||||
if not fp.Closed and len(fp.Points) >= 2: # allow lower degree segment
|
||||
poles = fp.Points[1:]
|
||||
elif fp.Closed and len(fp.Points) >= fp.Degree: # drawable
|
||||
# poles=fp.Points[1:(fp.Degree*(len(fp.Points)//fp.Degree))]+fp.Points[0:1]
|
||||
poles = fp.Points[1:] + fp.Points[0:1]
|
||||
else:
|
||||
poles=[]
|
||||
return [poles[x:x+fp.Degree] for x in \
|
||||
range(0, len(poles), (fp.Degree or 1))]
|
||||
poles = []
|
||||
return [poles[x : x + fp.Degree] for x in range(0, len(poles), (fp.Degree or 1))]
|
||||
|
||||
def resetcontinuity(self,fp):
|
||||
fp.Continuity = [0]*(len(self._segpoleslst(fp))-1+1*fp.Closed)
|
||||
#nump= len(fp.Points)-1+fp.Closed*1
|
||||
#numsegments = (nump // fp.Degree) + 1 * (nump % fp.Degree > 0) -1
|
||||
#fp.Continuity = [0]*numsegments
|
||||
def resetcontinuity(self, fp):
|
||||
fp.Continuity = [0] * (len(self._segpoleslst(fp)) - 1 + 1 * fp.Closed)
|
||||
# nump= len(fp.Points)-1+fp.Closed*1
|
||||
# numsegments = (nump // fp.Degree) + 1 * (nump % fp.Degree > 0) -1
|
||||
# fp.Continuity = [0]*numsegments
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
self.props_changed_store(prop)
|
||||
|
||||
if prop == 'Closed':
|
||||
if prop == "Closed":
|
||||
# if remove the last entry when curve gets opened
|
||||
oldlen = len(fp.Continuity)
|
||||
newlen = (len(self._segpoleslst(fp))-1+1*fp.Closed)
|
||||
newlen = len(self._segpoleslst(fp)) - 1 + 1 * fp.Closed
|
||||
if oldlen > newlen:
|
||||
fp.Continuity = fp.Continuity[:newlen]
|
||||
if oldlen < newlen:
|
||||
fp.Continuity = fp.Continuity + [0]*(newlen-oldlen)
|
||||
fp.Continuity = fp.Continuity + [0] * (newlen - oldlen)
|
||||
|
||||
if (hasattr(fp,'Closed') and
|
||||
fp.Closed and
|
||||
prop in ['Points','Degree','Closed'] and
|
||||
len(fp.Points) % fp.Degree):
|
||||
if (
|
||||
hasattr(fp, "Closed")
|
||||
and fp.Closed
|
||||
and prop in ["Points", "Degree", "Closed"]
|
||||
and len(fp.Points) % fp.Degree
|
||||
):
|
||||
# the curve editing tools can't handle extra points
|
||||
fp.Points=fp.Points[:(fp.Degree*(len(fp.Points)//fp.Degree))]
|
||||
#for closed curves
|
||||
fp.Points = fp.Points[: (fp.Degree * (len(fp.Points) // fp.Degree))]
|
||||
# for closed curves
|
||||
|
||||
if prop in ["Degree"] and fp.Degree >= 1:
|
||||
self.resetcontinuity(fp)
|
||||
|
||||
if prop in ["Points","Degree","Continuity","Closed"]:
|
||||
if prop in ["Points", "Degree", "Continuity", "Closed"]:
|
||||
self.createGeometry(fp)
|
||||
|
||||
def createGeometry(self,fp):
|
||||
def createGeometry(self, fp):
|
||||
import Part
|
||||
|
||||
plm = fp.Placement
|
||||
if fp.Points:
|
||||
startpoint = fp.Points[0]
|
||||
edges = []
|
||||
for segpoles in self._segpoleslst(fp):
|
||||
# if len(segpoles) == fp.Degree # would skip additional poles
|
||||
c = Part.BezierCurve() #last segment may have lower degree
|
||||
# if len(segpoles) == fp.Degree # would skip additional poles
|
||||
c = Part.BezierCurve() # last segment may have lower degree
|
||||
c.increase(len(segpoles))
|
||||
c.setPoles([startpoint]+segpoles)
|
||||
c.setPoles([startpoint] + segpoles)
|
||||
edges.append(Part.Edge(c))
|
||||
startpoint = segpoles[-1]
|
||||
w = Part.Wire(edges)
|
||||
if fp.Closed and w.isClosed():
|
||||
try:
|
||||
if hasattr(fp,"MakeFace"):
|
||||
if hasattr(fp, "MakeFace"):
|
||||
if fp.MakeFace:
|
||||
w = Part.Face(w)
|
||||
else:
|
||||
@@ -160,31 +155,31 @@ class BezCurve(DraftObject):
|
||||
except Part.OCCError:
|
||||
pass
|
||||
fp.Shape = w
|
||||
if hasattr(fp,"Area") and hasattr(w,"Area"):
|
||||
if hasattr(fp, "Area") and hasattr(w, "Area"):
|
||||
fp.Area = w.Area
|
||||
if hasattr(fp,"Length") and hasattr(w,"Length"):
|
||||
if hasattr(fp, "Length") and hasattr(w, "Length"):
|
||||
fp.Length = w.Length
|
||||
fp.Placement = plm
|
||||
|
||||
@classmethod
|
||||
def symmetricpoles(cls,knot, p1, p2):
|
||||
def symmetricpoles(cls, knot, p1, p2):
|
||||
"""Make two poles symmetric respective to the knot."""
|
||||
p1h = App.Vector(p1)
|
||||
p2h = App.Vector(p2)
|
||||
p1h.multiply(0.5)
|
||||
p2h.multiply(0.5)
|
||||
return ( knot+p1h-p2h , knot+p2h-p1h )
|
||||
return (knot + p1h - p2h, knot + p2h - p1h)
|
||||
|
||||
@classmethod
|
||||
def tangentpoles(cls,knot, p1, p2,allowsameside=False):
|
||||
def tangentpoles(cls, knot, p1, p2, allowsameside=False):
|
||||
"""Make two poles have the same tangent at knot."""
|
||||
p12n = p2.sub(p1)
|
||||
p12n.normalize()
|
||||
p1k = knot-p1
|
||||
p2k = knot-p2
|
||||
p1k_= App.Vector(p12n)
|
||||
kon12=(p1k * p12n)
|
||||
if allowsameside or not (kon12 < 0 or p2k * p12n > 0):# instead of moving
|
||||
p1k = knot - p1
|
||||
p2k = knot - p2
|
||||
p1k_ = App.Vector(p12n)
|
||||
kon12 = p1k * p12n
|
||||
if allowsameside or not (kon12 < 0 or p2k * p12n > 0): # instead of moving
|
||||
p1k_.multiply(kon12)
|
||||
pk_k = knot - p1 - p1k_
|
||||
return (p1 + pk_k, p2 + pk_k)
|
||||
@@ -192,13 +187,13 @@ class BezCurve(DraftObject):
|
||||
return cls.symmetricpoles(knot, p1, p2)
|
||||
|
||||
@staticmethod
|
||||
def modifysymmetricpole(knot,p1):
|
||||
def modifysymmetricpole(knot, p1):
|
||||
"""calculate the coordinates of the opposite pole
|
||||
of a symmetric knot"""
|
||||
return knot + knot - p1
|
||||
|
||||
@staticmethod
|
||||
def modifytangentpole(knot,p1,oldp2):
|
||||
def modifytangentpole(knot, p1, oldp2):
|
||||
"""calculate the coordinates of the opposite pole
|
||||
of a tangent knot"""
|
||||
pn = knot - p1
|
||||
|
||||
@@ -39,9 +39,8 @@ class Block(DraftObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj, "Block")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The components of this block")
|
||||
obj.addProperty("App::PropertyLinkList","Components", "Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The components of this block")
|
||||
obj.addProperty("App::PropertyLinkList", "Components", "Draft", _tip, locked=True)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
super().onDocumentRestored(obj)
|
||||
@@ -56,6 +55,7 @@ class Block(DraftObject):
|
||||
return
|
||||
|
||||
import Part
|
||||
|
||||
plm = obj.Placement
|
||||
shps = []
|
||||
for c in obj.Components:
|
||||
|
||||
@@ -41,20 +41,17 @@ class BSpline(DraftObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj, "BSpline")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The points of the B-spline")
|
||||
obj.addProperty("App::PropertyVectorList","Points", "Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The points of the B-spline")
|
||||
obj.addProperty("App::PropertyVectorList", "Points", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If the B-spline is closed or not")
|
||||
obj.addProperty("App::PropertyBool","Closed", "Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "If the B-spline is closed or not")
|
||||
obj.addProperty("App::PropertyBool", "Closed", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Create a face if this B-spline is closed")
|
||||
obj.addProperty("App::PropertyBool","MakeFace", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Create a face if this B-spline is closed")
|
||||
obj.addProperty("App::PropertyBool", "MakeFace", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The area of this object")
|
||||
obj.addProperty("App::PropertyArea","Area", "Draft", _tip, locked=True)
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
|
||||
obj.MakeFace = params.get_param("MakeFaceMode")
|
||||
obj.Closed = False
|
||||
@@ -63,28 +60,26 @@ class BSpline(DraftObject):
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
super().onDocumentRestored(obj)
|
||||
gui_utils.restore_view_object(
|
||||
obj, vp_module="view_bspline", vp_class="ViewProviderBSpline"
|
||||
)
|
||||
gui_utils.restore_view_object(obj, vp_module="view_bspline", vp_class="ViewProviderBSpline")
|
||||
|
||||
def assureProperties(self, obj): # for Compatibility with older versions
|
||||
def assureProperties(self, obj): # for Compatibility with older versions
|
||||
if not hasattr(obj, "Parameterization"):
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Parameterization factor")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Parameterization factor")
|
||||
obj.addProperty("App::PropertyFloat", "Parameterization", "Draft", _tip, locked=True)
|
||||
obj.Parameterization = 1.0
|
||||
self.knotSeq = []
|
||||
|
||||
def parameterization (self, pts, a, closed):
|
||||
def parameterization(self, pts, a, closed):
|
||||
"""Computes a knot Sequence for a set of points.
|
||||
fac (0-1) : parameterization factor
|
||||
fac = 0 -> Uniform / fac=0.5 -> Centripetal / fac=1.0 -> Chord-Length
|
||||
"""
|
||||
if closed: # we need to add the first point as the end point
|
||||
if closed: # we need to add the first point as the end point
|
||||
pts.append(pts[0])
|
||||
params = [0]
|
||||
for i in range(1,len(pts)):
|
||||
p = pts[i].sub(pts[i-1])
|
||||
pl = pow(p.Length,a)
|
||||
for i in range(1, len(pts)):
|
||||
p = pts[i].sub(pts[i - 1])
|
||||
pl = pow(p.Length, a)
|
||||
params.append(params[-1] + pl)
|
||||
return params
|
||||
|
||||
@@ -92,14 +87,13 @@ class BSpline(DraftObject):
|
||||
self.props_changed_store(prop)
|
||||
|
||||
if prop == "Parameterization":
|
||||
if fp.Parameterization < 0.:
|
||||
fp.Parameterization = 0.
|
||||
if fp.Parameterization < 0.0:
|
||||
fp.Parameterization = 0.0
|
||||
if fp.Parameterization > 1.0:
|
||||
fp.Parameterization = 1.0
|
||||
|
||||
def execute(self, obj):
|
||||
if self.props_changed_placement_only() \
|
||||
or not obj.Points:
|
||||
if self.props_changed_placement_only() or not obj.Points:
|
||||
obj.positionBySupport()
|
||||
self.props_changed_clear()
|
||||
return
|
||||
@@ -112,18 +106,21 @@ class BSpline(DraftObject):
|
||||
plm = obj.Placement
|
||||
if obj.Closed and (len(obj.Points) > 2):
|
||||
if obj.Points[0] == obj.Points[-1]: # should not occur, but OCC will crash
|
||||
_err = QT_TRANSLATE_NOOP('Draft', "_BSpline.createGeometry: "
|
||||
"Closed with same first/last Point. Geometry not updated.")
|
||||
App.Console.PrintError(_err+"\n")
|
||||
_err = QT_TRANSLATE_NOOP(
|
||||
"Draft",
|
||||
"_BSpline.createGeometry: "
|
||||
"Closed with same first/last Point. Geometry not updated.",
|
||||
)
|
||||
App.Console.PrintError(_err + "\n")
|
||||
return
|
||||
spline = Part.BSplineCurve()
|
||||
spline.interpolate(obj.Points, PeriodicFlag = True, Parameters = self.knotSeq)
|
||||
spline.interpolate(obj.Points, PeriodicFlag=True, Parameters=self.knotSeq)
|
||||
# DNC: bug fix: convert to face if closed
|
||||
shape = Part.Wire(spline.toShape())
|
||||
# Creating a face from a closed spline cannot be expected to always work
|
||||
# Usually, if the spline is not flat the call of Part.Face() fails
|
||||
try:
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if hasattr(obj, "MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
@@ -131,14 +128,14 @@ class BSpline(DraftObject):
|
||||
except Part.OCCError:
|
||||
pass
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
if hasattr(obj, "Area") and hasattr(shape, "Area"):
|
||||
obj.Area = shape.Area
|
||||
else:
|
||||
spline = Part.BSplineCurve()
|
||||
spline.interpolate(obj.Points, PeriodicFlag = False, Parameters = self.knotSeq)
|
||||
spline.interpolate(obj.Points, PeriodicFlag=False, Parameters=self.knotSeq)
|
||||
shape = spline.toShape()
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
if hasattr(obj, "Area") and hasattr(shape, "Area"):
|
||||
obj.Area = shape.Area
|
||||
obj.Placement = plm
|
||||
obj.positionBySupport()
|
||||
|
||||
@@ -42,25 +42,23 @@ class Circle(DraftObject):
|
||||
super().__init__(obj, "Circle")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Start angle of the arc")
|
||||
obj.addProperty("App::PropertyAngle", "FirstAngle",
|
||||
"Draft", _tip, locked=True)
|
||||
obj.addProperty("App::PropertyAngle", "FirstAngle", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "End angle of the arc (for a full circle, \
|
||||
give it same value as First Angle)")
|
||||
obj.addProperty("App::PropertyAngle","LastAngle",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"End angle of the arc (for a full circle, \
|
||||
give it same value as First Angle)",
|
||||
)
|
||||
obj.addProperty("App::PropertyAngle", "LastAngle", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Radius of the circle")
|
||||
obj.addProperty("App::PropertyLength", "Radius",
|
||||
"Draft", _tip, locked=True)
|
||||
obj.addProperty("App::PropertyLength", "Radius", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Create a face")
|
||||
obj.addProperty("App::PropertyBool", "MakeFace",
|
||||
"Draft", _tip, locked=True)
|
||||
obj.addProperty("App::PropertyBool", "MakeFace", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The area of this object")
|
||||
obj.addProperty("App::PropertyArea", "Area",
|
||||
"Draft", _tip, locked=True)
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
|
||||
obj.MakeFace = params.get_param("MakeFaceMode")
|
||||
|
||||
@@ -79,20 +77,22 @@ class Circle(DraftObject):
|
||||
|
||||
plm = obj.Placement
|
||||
|
||||
shape = Part.makeCircle(obj.Radius.Value,
|
||||
App.Vector(0,0,0),
|
||||
App.Vector(0,0,1),
|
||||
obj.FirstAngle.Value,
|
||||
obj.LastAngle.Value)
|
||||
shape = Part.makeCircle(
|
||||
obj.Radius.Value,
|
||||
App.Vector(0, 0, 0),
|
||||
App.Vector(0, 0, 1),
|
||||
obj.FirstAngle.Value,
|
||||
obj.LastAngle.Value,
|
||||
)
|
||||
|
||||
if obj.FirstAngle.Value == obj.LastAngle.Value:
|
||||
shape = Part.Wire(shape)
|
||||
if getattr(obj,"MakeFace",True):
|
||||
if getattr(obj, "MakeFace", True):
|
||||
shape = Part.Face(shape)
|
||||
|
||||
obj.Shape = shape
|
||||
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
if hasattr(obj, "Area") and hasattr(shape, "Area"):
|
||||
obj.Area = shape.Area
|
||||
|
||||
obj.Placement = plm
|
||||
|
||||
@@ -43,7 +43,6 @@ class Clone(DraftObject):
|
||||
self.set_properties(obj)
|
||||
super().__init__(obj, "Clone")
|
||||
|
||||
|
||||
def set_properties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
if not "Objects" in pl:
|
||||
@@ -54,9 +53,10 @@ class Clone(DraftObject):
|
||||
obj.addProperty("App::PropertyVector", "Scale", "Draft", _tip, locked=True)
|
||||
obj.Scale = App.Vector(1, 1, 1)
|
||||
if not "Fuse" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If Clones includes several objects,\n"
|
||||
"set True for fusion or False for compound")
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"If Clones includes several objects,\n" "set True for fusion or False for compound",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Fuse", "Draft", _tip, locked=True)
|
||||
if not "ForceCompound" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Always create a compound")
|
||||
@@ -88,6 +88,7 @@ class Clone(DraftObject):
|
||||
tmps += s.Edges
|
||||
shapes = tmps
|
||||
import Part
|
||||
|
||||
if len(shapes) == 1:
|
||||
if force_compound:
|
||||
return Part.makeCompound([shapes[0]])
|
||||
@@ -106,21 +107,24 @@ class Clone(DraftObject):
|
||||
return sh
|
||||
return Part.makeCompound(shapes)
|
||||
|
||||
def execute(self,obj):
|
||||
def execute(self, obj):
|
||||
if self.props_changed_placement_only(obj):
|
||||
if hasattr(obj,"positionBySupport"):
|
||||
if hasattr(obj, "positionBySupport"):
|
||||
obj.positionBySupport()
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
import Part
|
||||
|
||||
pl = obj.Placement
|
||||
shapes = []
|
||||
if obj.isDerivedFrom("Part::Part2DObject"):
|
||||
# if our clone is 2D, make sure all its linked geometry is 2D too
|
||||
for o in obj.Objects:
|
||||
if not o.getLinkedObject(True).isDerivedFrom("Part::Part2DObject"):
|
||||
App.Console.PrintWarning("Warning 2D Clone "+obj.Name+" contains 3D geometry")
|
||||
App.Console.PrintWarning(
|
||||
"Warning 2D Clone " + obj.Name + " contains 3D geometry"
|
||||
)
|
||||
return
|
||||
for o in obj.Objects:
|
||||
sh = Part.getShape(o)
|
||||
@@ -129,7 +133,7 @@ class Clone(DraftObject):
|
||||
if shapes:
|
||||
sh = self.join(obj, shapes)
|
||||
m = App.Matrix()
|
||||
if hasattr(obj,"Scale") and not sh.isNull():
|
||||
if hasattr(obj, "Scale") and not sh.isNull():
|
||||
if not DraftVecUtils.equals(obj.Scale, App.Vector(1, 1, 1)):
|
||||
op = sh.Placement
|
||||
sh.Placement = App.Placement()
|
||||
@@ -139,17 +143,17 @@ class Clone(DraftObject):
|
||||
obj.Shape = sh
|
||||
|
||||
obj.Placement = pl
|
||||
if hasattr(obj,"positionBySupport"):
|
||||
if hasattr(obj, "positionBySupport"):
|
||||
obj.positionBySupport()
|
||||
self.props_changed_clear()
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
self.props_changed_store(prop)
|
||||
|
||||
def getSubVolume(self,obj,placement=None):
|
||||
def getSubVolume(self, obj, placement=None):
|
||||
# this allows clones of arch windows to return a subvolume too
|
||||
if obj.Objects:
|
||||
if hasattr(obj.Objects[0],"Proxy"):
|
||||
if hasattr(obj.Objects[0], "Proxy"):
|
||||
if hasattr(obj.Objects[0].Proxy, "getSubVolume"):
|
||||
if not placement:
|
||||
# clones must displace the original subvolume too
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#
|
||||
#
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
@@ -128,69 +128,60 @@ class DimensionBase(DraftAnnotation):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "Normal" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The normal direction of the text "
|
||||
"of the dimension")
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"Normal",
|
||||
"Dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The normal direction of the text " "of the dimension"
|
||||
)
|
||||
obj.addProperty("App::PropertyVector", "Normal", "Dimension", _tip, locked=True)
|
||||
obj.Normal = App.Vector(0, 0, 1)
|
||||
|
||||
# TODO: remove Support property as it is not used at all.
|
||||
# It is just set at creation time by the make_dimension function
|
||||
# but it is not used.
|
||||
if "Support" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The object measured by this dimension")
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Support",
|
||||
"Dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The object measured by this dimension")
|
||||
obj.addProperty("App::PropertyLink", "Support", "Dimension", _tip, locked=True)
|
||||
obj.Support = None
|
||||
|
||||
if "LinkedGeometry" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The object, and specific subelements "
|
||||
"of it,\n"
|
||||
"that this dimension "
|
||||
"is measuring.\n"
|
||||
"\n"
|
||||
"There are various possibilities:\n"
|
||||
"- An object, and one of its edges.\n"
|
||||
"- An object, and two of its vertices.\n"
|
||||
"- An arc object, and its edge.")
|
||||
obj.addProperty("App::PropertyLinkSubList",
|
||||
"LinkedGeometry",
|
||||
"Dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The object, and specific subelements "
|
||||
"of it,\n"
|
||||
"that this dimension "
|
||||
"is measuring.\n"
|
||||
"\n"
|
||||
"There are various possibilities:\n"
|
||||
"- An object, and one of its edges.\n"
|
||||
"- An object, and two of its vertices.\n"
|
||||
"- An arc object, and its edge.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkSubList", "LinkedGeometry", "Dimension", _tip, locked=True
|
||||
)
|
||||
obj.LinkedGeometry = []
|
||||
|
||||
if "Dimline" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"A point through which the dimension "
|
||||
"line, or an extrapolation of it, "
|
||||
"will pass.\n"
|
||||
"\n"
|
||||
"- For linear dimensions, this property "
|
||||
"controls how close the dimension line\n"
|
||||
"is to the measured object.\n"
|
||||
"- For radial dimensions, this controls "
|
||||
"the direction of the dimension line\n"
|
||||
"that displays the measured radius or "
|
||||
"diameter.\n"
|
||||
"- For angular dimensions, "
|
||||
"this controls the radius of the "
|
||||
"dimension arc\n"
|
||||
"that displays the measured angle.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"Dimline",
|
||||
"Dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"A point through which the dimension "
|
||||
"line, or an extrapolation of it, "
|
||||
"will pass.\n"
|
||||
"\n"
|
||||
"- For linear dimensions, this property "
|
||||
"controls how close the dimension line\n"
|
||||
"is to the measured object.\n"
|
||||
"- For radial dimensions, this controls "
|
||||
"the direction of the dimension line\n"
|
||||
"that displays the measured radius or "
|
||||
"diameter.\n"
|
||||
"- For angular dimensions, "
|
||||
"this controls the radius of the "
|
||||
"dimension arc\n"
|
||||
"that displays the measured angle.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "Dimline", "Dimension", _tip, locked=True
|
||||
)
|
||||
obj.Dimline = App.Vector(0, 1, 0)
|
||||
|
||||
def update_properties_0v21(self, obj, vobj):
|
||||
@@ -223,77 +214,75 @@ class LinearDimension(DimensionBase):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "Start" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Starting point of the dimension line.\n"
|
||||
"\n"
|
||||
"If it is a radius dimension it will be "
|
||||
"the center of the arc.\n"
|
||||
"If it is a diameter dimension "
|
||||
"it will be a point that lies "
|
||||
"on the arc.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"Start",
|
||||
"Linear/radial dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Starting point of the dimension line.\n"
|
||||
"\n"
|
||||
"If it is a radius dimension it will be "
|
||||
"the center of the arc.\n"
|
||||
"If it is a diameter dimension "
|
||||
"it will be a point that lies "
|
||||
"on the arc.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "Start", "Linear/radial dimension", _tip, locked=True
|
||||
)
|
||||
obj.Start = App.Vector(0, 0, 0)
|
||||
|
||||
if "End" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Ending point of the dimension line.\n"
|
||||
"\n"
|
||||
"If it is a radius or diameter "
|
||||
"dimension\n"
|
||||
"it will be a point that lies "
|
||||
"on the arc.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"End",
|
||||
"Linear/radial dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Ending point of the dimension line.\n"
|
||||
"\n"
|
||||
"If it is a radius or diameter "
|
||||
"dimension\n"
|
||||
"it will be a point that lies "
|
||||
"on the arc.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "End", "Linear/radial dimension", _tip, locked=True
|
||||
)
|
||||
obj.End = App.Vector(1, 0, 0)
|
||||
|
||||
if "Direction" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The direction of the dimension line.\n"
|
||||
"If this remains '(0,0,0)', "
|
||||
"the direction will be calculated "
|
||||
"automatically.")
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"Direction",
|
||||
"Linear/radial dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The direction of the dimension line.\n"
|
||||
"If this remains '(0,0,0)', "
|
||||
"the direction will be calculated "
|
||||
"automatically.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVector", "Direction", "Linear/radial dimension", _tip, locked=True
|
||||
)
|
||||
|
||||
if "Distance" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The value of the measurement.\n"
|
||||
"\n"
|
||||
"This property is read-only because "
|
||||
"the value is calculated\n"
|
||||
"from the 'Start' and 'End' properties.\n"
|
||||
"\n"
|
||||
"If the 'Linked Geometry' "
|
||||
"is an arc or circle, this 'Distance'\n"
|
||||
"is the radius or diameter, depending "
|
||||
"on the 'Diameter' property.")
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Distance",
|
||||
"Linear/radial dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The value of the measurement.\n"
|
||||
"\n"
|
||||
"This property is read-only because "
|
||||
"the value is calculated\n"
|
||||
"from the 'Start' and 'End' properties.\n"
|
||||
"\n"
|
||||
"If the 'Linked Geometry' "
|
||||
"is an arc or circle, this 'Distance'\n"
|
||||
"is the radius or diameter, depending "
|
||||
"on the 'Diameter' property.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyLength", "Distance", "Linear/radial dimension", _tip, locked=True
|
||||
)
|
||||
obj.Distance = 0
|
||||
|
||||
if "Diameter" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"When measuring circular arcs, "
|
||||
"it determines whether to display\n"
|
||||
"the radius or the diameter value")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"Diameter",
|
||||
"Radial dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"When measuring circular arcs, "
|
||||
"it determines whether to display\n"
|
||||
"the radius or the diameter value",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Diameter", "Radial dimension", _tip, locked=True)
|
||||
obj.Diameter = False
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
@@ -320,12 +309,12 @@ class LinearDimension(DimensionBase):
|
||||
as they aren't used.
|
||||
"""
|
||||
if hasattr(obj, "Distance"):
|
||||
obj.setPropertyStatus('Distance', 'ReadOnly')
|
||||
obj.setPropertyStatus("Distance", "ReadOnly")
|
||||
|
||||
# if hasattr(obj, "Normal"):
|
||||
# obj.setPropertyStatus('Normal', 'Hidden')
|
||||
if hasattr(obj, "Support"):
|
||||
obj.setPropertyStatus('Support', 'Hidden')
|
||||
obj.setPropertyStatus("Support", "Hidden")
|
||||
|
||||
def transform(self, obj, pla):
|
||||
"""Transform the object by applying a placement."""
|
||||
@@ -353,24 +342,20 @@ class LinearDimension(DimensionBase):
|
||||
# If it has one subelement, we assume an edge
|
||||
# that can be a straight line, or a circular edge
|
||||
subelement = sub_list[0]
|
||||
(obj.Start,
|
||||
obj.End) = measure_one_obj_edge(linked_obj,
|
||||
subelement,
|
||||
obj.Dimline,
|
||||
obj.Diameter)
|
||||
(obj.Start, obj.End) = measure_one_obj_edge(
|
||||
linked_obj, subelement, obj.Dimline, obj.Diameter
|
||||
)
|
||||
elif len(sub_list) == 2:
|
||||
# If it has two subelements, we assume a straight edge
|
||||
# that is measured by two vertices
|
||||
(obj.Start,
|
||||
obj.End) = measure_one_obj_vertices(linked_obj,
|
||||
sub_list)
|
||||
(obj.Start, obj.End) = measure_one_obj_vertices(linked_obj, sub_list)
|
||||
|
||||
elif len(obj.LinkedGeometry) == 2:
|
||||
# If the list has two objects, it measures the distance
|
||||
# between the two vertices in those two objects
|
||||
(obj.Start,
|
||||
obj.End) = measure_two_objects(obj.LinkedGeometry[0],
|
||||
obj.LinkedGeometry[1])
|
||||
(obj.Start, obj.End) = measure_two_objects(
|
||||
obj.LinkedGeometry[0], obj.LinkedGeometry[1]
|
||||
)
|
||||
|
||||
# Update the distance property by comparing the floats
|
||||
# with the precision
|
||||
@@ -521,58 +506,56 @@ class AngularDimension(DimensionBase):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "FirstAngle" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Starting angle of the dimension line "
|
||||
"(circular arc).\n"
|
||||
"The arc is drawn counter-clockwise.")
|
||||
obj.addProperty("App::PropertyAngle",
|
||||
"FirstAngle",
|
||||
"Angular dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Starting angle of the dimension line "
|
||||
"(circular arc).\n"
|
||||
"The arc is drawn counter-clockwise.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyAngle", "FirstAngle", "Angular dimension", _tip, locked=True
|
||||
)
|
||||
obj.FirstAngle = 0
|
||||
|
||||
if "LastAngle" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Ending angle of the dimension line "
|
||||
"(circular arc).\n"
|
||||
"The arc is drawn counter-clockwise.")
|
||||
obj.addProperty("App::PropertyAngle",
|
||||
"LastAngle",
|
||||
"Angular dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Ending angle of the dimension line "
|
||||
"(circular arc).\n"
|
||||
"The arc is drawn counter-clockwise.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyAngle", "LastAngle", "Angular dimension", _tip, locked=True
|
||||
)
|
||||
obj.LastAngle = 90
|
||||
|
||||
if "Center" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The center point of the dimension "
|
||||
"line, which is a circular arc.\n"
|
||||
"\n"
|
||||
"This is normally the point where two "
|
||||
"line segments, or their extensions\n"
|
||||
"intersect, resulting in the "
|
||||
"measured 'Angle' between them.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"Center",
|
||||
"Angular dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The center point of the dimension "
|
||||
"line, which is a circular arc.\n"
|
||||
"\n"
|
||||
"This is normally the point where two "
|
||||
"line segments, or their extensions\n"
|
||||
"intersect, resulting in the "
|
||||
"measured 'Angle' between them.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "Center", "Angular dimension", _tip, locked=True
|
||||
)
|
||||
obj.Center = App.Vector(0, 0, 0)
|
||||
|
||||
if "Angle" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The value of the measurement.\n"
|
||||
"\n"
|
||||
"This property is read-only because "
|
||||
"the value is calculated from\n"
|
||||
"the 'First Angle' and "
|
||||
"'Last Angle' properties.")
|
||||
obj.addProperty("App::PropertyAngle",
|
||||
"Angle",
|
||||
"Angular dimension",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The value of the measurement.\n"
|
||||
"\n"
|
||||
"This property is read-only because "
|
||||
"the value is calculated from\n"
|
||||
"the 'First Angle' and "
|
||||
"'Last Angle' properties.",
|
||||
)
|
||||
obj.addProperty("App::PropertyAngle", "Angle", "Angular dimension", _tip, locked=True)
|
||||
obj.Angle = 0
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
@@ -644,14 +627,14 @@ class AngularDimension(DimensionBase):
|
||||
as they aren't used.
|
||||
"""
|
||||
if hasattr(obj, "Angle"):
|
||||
obj.setPropertyStatus('Angle', 'ReadOnly')
|
||||
obj.setPropertyStatus("Angle", "ReadOnly")
|
||||
|
||||
if hasattr(obj, "Normal"):
|
||||
obj.setPropertyStatus('Normal', 'Hidden')
|
||||
obj.setPropertyStatus("Normal", "Hidden")
|
||||
if hasattr(obj, "Support"):
|
||||
obj.setPropertyStatus('Support', 'Hidden')
|
||||
obj.setPropertyStatus("Support", "Hidden")
|
||||
if hasattr(obj, "LinkedGeometry"):
|
||||
obj.setPropertyStatus('LinkedGeometry', 'Hidden')
|
||||
obj.setPropertyStatus("LinkedGeometry", "Hidden")
|
||||
|
||||
|
||||
def measure_two_obj_angles(link_sub_1, link_sub_2):
|
||||
|
||||
@@ -92,9 +92,7 @@ class DraftAnnotation(object):
|
||||
typ = obj.Proxy.Type
|
||||
if typ == "Label":
|
||||
vobj.ArrowTypeStart = vobj.ArrowType
|
||||
elif typ == "AngularDimension" \
|
||||
or obj.Diameter \
|
||||
or not vobj.Proxy.is_linked_to_circle():
|
||||
elif typ == "AngularDimension" or obj.Diameter or not vobj.Proxy.is_linked_to_circle():
|
||||
vobj.ArrowTypeStart = vobj.ArrowType
|
||||
vobj.ArrowTypeEnd = vobj.ArrowType
|
||||
else: # Radial dimension
|
||||
@@ -115,7 +113,7 @@ class DraftAnnotation(object):
|
||||
|
||||
return
|
||||
|
||||
def loads(self,state):
|
||||
def loads(self, state):
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ class DraftLink(DraftObject):
|
||||
def attach(self, obj):
|
||||
"""Set up the properties when the object is attached."""
|
||||
if self.use_link:
|
||||
obj.addExtension('App::LinkExtensionPython')
|
||||
obj.addExtension("App::LinkExtensionPython")
|
||||
self.linkSetup(obj)
|
||||
|
||||
def canLinkProperties(self, _obj):
|
||||
@@ -92,68 +92,55 @@ class DraftLink(DraftObject):
|
||||
|
||||
def linkSetup(self, obj):
|
||||
"""Set up the link properties on attachment."""
|
||||
obj.configLinkProperty('Placement', LinkedObject='Base')
|
||||
obj.configLinkProperty("Placement", LinkedObject="Base")
|
||||
|
||||
if not hasattr(obj, 'AlwaysSyncPlacement'):
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
'Force sync pattern placements even when array elements are expanded')
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"AlwaysSyncPlacement",
|
||||
"Draft",
|
||||
_tip,
|
||||
locked=True)
|
||||
if not hasattr(obj, "AlwaysSyncPlacement"):
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Force sync pattern placements even when array elements are expanded",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "AlwaysSyncPlacement", "Draft", _tip, locked=True)
|
||||
|
||||
if hasattr(obj, 'ShowElement'):
|
||||
if hasattr(obj, "ShowElement"):
|
||||
# Rename 'ShowElement' property to 'ExpandArray' to avoid conflict
|
||||
# with native App::Link
|
||||
obj.configLinkProperty('ShowElement')
|
||||
obj.configLinkProperty("ShowElement")
|
||||
showElement = obj.ShowElement
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Show the individual array elements")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ExpandArray",
|
||||
"Draft",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Show the individual array elements")
|
||||
obj.addProperty("App::PropertyBool", "ExpandArray", "Draft", _tip, locked=True)
|
||||
|
||||
obj.ExpandArray = showElement
|
||||
obj.configLinkProperty(ShowElement='ExpandArray')
|
||||
obj.removeProperty('ShowElement')
|
||||
obj.configLinkProperty(ShowElement="ExpandArray")
|
||||
obj.removeProperty("ShowElement")
|
||||
else:
|
||||
obj.configLinkProperty(ShowElement='ExpandArray')
|
||||
obj.configLinkProperty(ShowElement="ExpandArray")
|
||||
|
||||
if getattr(obj, 'ExpandArray', False):
|
||||
obj.setPropertyStatus('PlacementList', 'Immutable')
|
||||
if getattr(obj, "ExpandArray", False):
|
||||
obj.setPropertyStatus("PlacementList", "Immutable")
|
||||
else:
|
||||
obj.setPropertyStatus('PlacementList', '-Immutable')
|
||||
obj.setPropertyStatus("PlacementList", "-Immutable")
|
||||
|
||||
if not hasattr(obj, 'LinkTransform'):
|
||||
obj.addProperty('App::PropertyBool',
|
||||
'LinkTransform',
|
||||
' Link',
|
||||
locked=True)
|
||||
if not hasattr(obj, "LinkTransform"):
|
||||
obj.addProperty("App::PropertyBool", "LinkTransform", " Link", locked=True)
|
||||
|
||||
if not hasattr(obj, 'ColoredElements'):
|
||||
obj.addProperty('App::PropertyLinkSubHidden',
|
||||
'ColoredElements',
|
||||
' Link',
|
||||
locked=True)
|
||||
obj.setPropertyStatus('ColoredElements', 'Hidden')
|
||||
if not hasattr(obj, "ColoredElements"):
|
||||
obj.addProperty("App::PropertyLinkSubHidden", "ColoredElements", " Link", locked=True)
|
||||
obj.setPropertyStatus("ColoredElements", "Hidden")
|
||||
|
||||
if not hasattr(obj,'LinkCopyOnChange'):
|
||||
obj.addProperty("App::PropertyEnumeration","LinkCopyOnChange"," Link",locked=True)
|
||||
if not hasattr(obj, "LinkCopyOnChange"):
|
||||
obj.addProperty("App::PropertyEnumeration", "LinkCopyOnChange", " Link", locked=True)
|
||||
|
||||
obj.configLinkProperty('LinkCopyOnChange','LinkTransform','ColoredElements')
|
||||
obj.configLinkProperty("LinkCopyOnChange", "LinkTransform", "ColoredElements")
|
||||
|
||||
if not getattr(obj, 'Fuse', False):
|
||||
obj.setPropertyStatus('Shape', 'Transient')
|
||||
if not getattr(obj, "Fuse", False):
|
||||
obj.setPropertyStatus("Shape", "Transient")
|
||||
|
||||
def getViewProviderName(self, _obj):
|
||||
"""Override the view provider name."""
|
||||
if self.use_link:
|
||||
return 'Gui::ViewProviderLinkPython'
|
||||
return ''
|
||||
return "Gui::ViewProviderLinkPython"
|
||||
return ""
|
||||
|
||||
def migrate_attributes(self, obj):
|
||||
"""Migrate old attribute names to new names if they exist.
|
||||
@@ -177,10 +164,10 @@ class DraftLink(DraftObject):
|
||||
if self.use_link:
|
||||
self.linkSetup(obj)
|
||||
else:
|
||||
obj.setPropertyStatus('Shape', '-Transient')
|
||||
obj.setPropertyStatus("Shape", "-Transient")
|
||||
|
||||
if obj.Shape.isNull():
|
||||
if getattr(obj, 'PlacementList', None):
|
||||
if getattr(obj, "PlacementList", None):
|
||||
self.buildShape(obj, obj.Placement, obj.PlacementList)
|
||||
else:
|
||||
self.execute(obj)
|
||||
@@ -198,14 +185,13 @@ class DraftLink(DraftObject):
|
||||
def buildShape(self, obj, pl, pls):
|
||||
"""Build the shape of the link object."""
|
||||
if self.use_link:
|
||||
if not getattr(obj, 'ExpandArray', False) or obj.Count != len(pls):
|
||||
obj.setPropertyStatus('PlacementList', '-Immutable')
|
||||
if not getattr(obj, "ExpandArray", False) or obj.Count != len(pls):
|
||||
obj.setPropertyStatus("PlacementList", "-Immutable")
|
||||
obj.PlacementList = pls
|
||||
obj.setPropertyStatus('PlacementList', 'Immutable')
|
||||
obj.setPropertyStatus("PlacementList", "Immutable")
|
||||
obj.Count = len(pls)
|
||||
if getattr(obj, 'ExpandArray', False) \
|
||||
and getattr(obj, 'AlwaysSyncPlacement', False):
|
||||
for pla,child in zip(pls,obj.ElementList):
|
||||
if getattr(obj, "ExpandArray", False) and getattr(obj, "AlwaysSyncPlacement", False):
|
||||
for pla, child in zip(pls, obj.ElementList):
|
||||
child.Placement = pla
|
||||
else:
|
||||
obj.PlacementList = pls
|
||||
@@ -213,12 +199,13 @@ class DraftLink(DraftObject):
|
||||
obj.Count = len(pls)
|
||||
|
||||
if obj.Base:
|
||||
shape = getattr(obj.Base, 'Shape', None)
|
||||
shape = getattr(obj.Base, "Shape", None)
|
||||
if not isinstance(shape, Part.Shape):
|
||||
obj.Shape = Part.Shape()
|
||||
elif shape.isNull():
|
||||
_err_msg = ("'{}' cannot build shape "
|
||||
"from '{}'\n".format(obj.Label, obj.Base.Label))
|
||||
_err_msg = "'{}' cannot build shape " "from '{}'\n".format(
|
||||
obj.Label, obj.Base.Label
|
||||
)
|
||||
raise RuntimeError(_err_msg)
|
||||
else:
|
||||
# Resetting the Placement of the copied shape does not work for
|
||||
@@ -228,13 +215,13 @@ class DraftLink(DraftObject):
|
||||
shape.transformShape(place.Matrix.inverse())
|
||||
base = []
|
||||
for i, pla in enumerate(pls):
|
||||
vis = getattr(obj, 'VisibilityList', [])
|
||||
vis = getattr(obj, "VisibilityList", [])
|
||||
if len(vis) > i and not vis[i]:
|
||||
continue
|
||||
|
||||
base.append(shape.transformed(pla.toMatrix()))
|
||||
|
||||
if getattr(obj, 'Fuse', False) and len(base) > 1:
|
||||
if getattr(obj, "Fuse", False) and len(base) > 1:
|
||||
obj.Shape = base[0].multiFuse(base[1:]).removeSplitter()
|
||||
else:
|
||||
obj.Shape = Part.makeCompound(base)
|
||||
@@ -249,20 +236,20 @@ class DraftLink(DraftObject):
|
||||
"""Execute when a property changes."""
|
||||
self.props_changed_store(prop)
|
||||
|
||||
if not getattr(self, 'use_link', False):
|
||||
if not getattr(self, "use_link", False):
|
||||
return
|
||||
|
||||
if prop == 'Fuse':
|
||||
if prop == "Fuse":
|
||||
if obj.Fuse:
|
||||
obj.setPropertyStatus('Shape', '-Transient')
|
||||
obj.setPropertyStatus("Shape", "-Transient")
|
||||
else:
|
||||
obj.setPropertyStatus('Shape', 'Transient')
|
||||
elif prop == 'ExpandArray':
|
||||
if hasattr(obj, 'PlacementList'):
|
||||
obj.setPropertyStatus("Shape", "Transient")
|
||||
elif prop == "ExpandArray":
|
||||
if hasattr(obj, "PlacementList"):
|
||||
if obj.ExpandArray:
|
||||
obj.setPropertyStatus('PlacementList', '-Immutable')
|
||||
obj.setPropertyStatus("PlacementList", "-Immutable")
|
||||
else:
|
||||
obj.setPropertyStatus('PlacementList', 'Immutable')
|
||||
obj.setPropertyStatus("PlacementList", "Immutable")
|
||||
|
||||
|
||||
# Alias for compatibility with old versions of v0.19
|
||||
|
||||
@@ -41,24 +41,27 @@ class Ellipse(DraftObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj, "Ellipse")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Start angle of the elliptical arc")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Start angle of the elliptical arc")
|
||||
obj.addProperty("App::PropertyAngle", "FirstAngle", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","End angle of the elliptical arc \n\
|
||||
(for a full circle, give it same value as First Angle)")
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"End angle of the elliptical arc \n\
|
||||
(for a full circle, give it same value as First Angle)",
|
||||
)
|
||||
obj.addProperty("App::PropertyAngle", "LastAngle", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Minor radius of the ellipse")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Minor radius of the ellipse")
|
||||
obj.addProperty("App::PropertyLength", "MinorRadius", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Major radius of the ellipse")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Major radius of the ellipse")
|
||||
obj.addProperty("App::PropertyLength", "MajorRadius", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Create a face")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Create a face")
|
||||
obj.addProperty("App::PropertyBool", "MakeFace", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Area of this object")
|
||||
obj.addProperty("App::PropertyArea", "Area","Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Area of this object")
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
|
||||
obj.MakeFace = params.get_param("MakeFaceMode")
|
||||
|
||||
@@ -73,24 +76,23 @@ class Ellipse(DraftObject):
|
||||
return
|
||||
|
||||
import Part
|
||||
|
||||
plm = obj.Placement
|
||||
if obj.MajorRadius.Value < obj.MinorRadius.Value:
|
||||
_err = "Error: Major radius is smaller than the minor radius"
|
||||
App.Console.PrintMessage(QT_TRANSLATE_NOOP("Draft", _err))
|
||||
return
|
||||
if obj.MajorRadius.Value and obj.MinorRadius.Value:
|
||||
ell = Part.Ellipse(App.Vector(0, 0, 0),
|
||||
obj.MajorRadius.Value,
|
||||
obj.MinorRadius.Value)
|
||||
ell = Part.Ellipse(App.Vector(0, 0, 0), obj.MajorRadius.Value, obj.MinorRadius.Value)
|
||||
shape = ell.toShape()
|
||||
if hasattr(obj,"FirstAngle"):
|
||||
if hasattr(obj, "FirstAngle"):
|
||||
if obj.FirstAngle.Value != obj.LastAngle.Value:
|
||||
a1 = obj.FirstAngle.getValueAs(App.Units.Radian)
|
||||
a2 = obj.LastAngle.getValueAs(App.Units.Radian)
|
||||
shape = Part.ArcOfEllipse(ell, a1, a2).toShape()
|
||||
shape = Part.Wire(shape)
|
||||
if shape.isClosed():
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if hasattr(obj, "MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
|
||||
@@ -40,26 +40,31 @@ from draftutils.translate import translate
|
||||
|
||||
class Facebinder(DraftObject):
|
||||
"""The Draft Facebinder object"""
|
||||
def __init__(self,obj):
|
||||
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj, "Facebinder")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Linked faces")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Linked faces")
|
||||
obj.addProperty("App::PropertyLinkSubList", "Faces", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Specifies if splitter lines must be removed")
|
||||
obj.addProperty("App::PropertyBool","RemoveSplitter", "Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Specifies if splitter lines must be removed")
|
||||
obj.addProperty("App::PropertyBool", "RemoveSplitter", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","An optional extrusion value to be applied to all faces")
|
||||
obj.addProperty("App::PropertyDistance","Extrusion", "Draft" , _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "An optional extrusion value to be applied to all faces"
|
||||
)
|
||||
obj.addProperty("App::PropertyDistance", "Extrusion", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","An optional offset value to be applied to all faces")
|
||||
obj.addProperty("App::PropertyDistance","Offset", "Draft" , _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "An optional offset value to be applied to all faces"
|
||||
)
|
||||
obj.addProperty("App::PropertyDistance", "Offset", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","This specifies if the shapes sew")
|
||||
obj.addProperty("App::PropertyBool","Sew", "Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "This specifies if the shapes sew")
|
||||
obj.addProperty("App::PropertyBool", "Sew", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","The area of the faces of this Facebinder")
|
||||
obj.addProperty("App::PropertyArea","Area", "Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The area of the faces of this Facebinder")
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
obj.setEditorMode("Area", 1)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
@@ -78,6 +83,7 @@ class Facebinder(DraftObject):
|
||||
return
|
||||
|
||||
import Part
|
||||
|
||||
faces = []
|
||||
try:
|
||||
for sel in obj.Faces:
|
||||
@@ -131,11 +137,16 @@ class Facebinder(DraftObject):
|
||||
_wrn(obj.Label + ": " + translate("draft", "No valid faces for facebinder"))
|
||||
|
||||
def _report_sew_error(self, obj):
|
||||
_wrn(obj.Label + ": " + translate("draft", "Unable to build facebinder, resuming with sew disabled"))
|
||||
_wrn(
|
||||
obj.Label
|
||||
+ ": "
|
||||
+ translate("draft", "Unable to build facebinder, resuming with sew disabled")
|
||||
)
|
||||
|
||||
def _build_shape(self, obj, faces, sew=False):
|
||||
"""returns the built shape and the area of the offset faces"""
|
||||
import Part
|
||||
|
||||
offs_val = getattr(obj, "Offset", 0)
|
||||
extr_val = getattr(obj, "Extrusion", 0)
|
||||
|
||||
@@ -175,6 +186,7 @@ class Facebinder(DraftObject):
|
||||
def _convert_to_planar(self, obj, shp):
|
||||
"""convert flat B-spline faces to planar faces if possible"""
|
||||
import Part
|
||||
|
||||
faces = []
|
||||
for face in shp.Faces:
|
||||
if face.Surface.TypeId == "Part::GeomPlane":
|
||||
@@ -196,9 +208,13 @@ class Facebinder(DraftObject):
|
||||
solid = Part.makeSolid(Part.makeShell(faces))
|
||||
if solid.isValid():
|
||||
return solid
|
||||
_msg(obj.Label + ": " + translate("draft",
|
||||
"Converting flat B-spline faces of facebinder to planar faces failed"
|
||||
))
|
||||
_msg(
|
||||
obj.Label
|
||||
+ ": "
|
||||
+ translate(
|
||||
"draft", "Converting flat B-spline faces of facebinder to planar faces failed"
|
||||
)
|
||||
)
|
||||
return shp
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
|
||||
@@ -47,38 +47,22 @@ class Fillet(DraftObject):
|
||||
"""Set the properties of objects if they don't exist."""
|
||||
if not hasattr(obj, "Start"):
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The start point of this line.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"Start",
|
||||
"Draft",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.addProperty("App::PropertyVectorDistance", "Start", "Draft", _tip, locked=True)
|
||||
obj.Start = App.Vector(0, 0, 0)
|
||||
|
||||
if not hasattr(obj, "End"):
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The end point of this line.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"End",
|
||||
"Draft",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.addProperty("App::PropertyVectorDistance", "End", "Draft", _tip, locked=True)
|
||||
obj.End = App.Vector(0, 0, 0)
|
||||
|
||||
if not hasattr(obj, "Length"):
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The length of this line.")
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Length",
|
||||
"Draft",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.addProperty("App::PropertyLength", "Length", "Draft", _tip, locked=True)
|
||||
obj.Length = 0
|
||||
|
||||
if not hasattr(obj, "FilletRadius"):
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Radius to use to fillet the corner.")
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"FilletRadius",
|
||||
"Draft",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.addProperty("App::PropertyLength", "FilletRadius", "Draft", _tip, locked=True)
|
||||
obj.FilletRadius = 0
|
||||
|
||||
# TODO: these two properties should link two straight lines
|
||||
@@ -117,7 +101,7 @@ class Fillet(DraftObject):
|
||||
obj.End = obj.Shape.Vertexes[-1].Point
|
||||
|
||||
def _update_radius(self, obj, radius):
|
||||
#if (hasattr(obj, "Line1") and hasattr(obj, "Line2")
|
||||
# if (hasattr(obj, "Line1") and hasattr(obj, "Line2")
|
||||
# and obj.Line1 and obj.Line2):
|
||||
# do the unimplemented work
|
||||
pass
|
||||
@@ -131,4 +115,5 @@ class Fillet(DraftObject):
|
||||
if prop in "FilletRadius":
|
||||
self._update_radius(obj, obj.FilletRadius)
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2021 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* 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 *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * *
|
||||
# * 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 *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
"""This module contains FreeCAD commands for the Draft workbench"""
|
||||
@@ -36,37 +36,69 @@ from draftutils.translate import translate
|
||||
|
||||
class Hatch(DraftObject):
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
def __init__(self, obj):
|
||||
|
||||
obj.Proxy = self
|
||||
self.Type = "Hatch"
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self,obj):
|
||||
def setProperties(self, obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Base" in pl:
|
||||
obj.addProperty("App::PropertyLink","Base","Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property","The base object used by this object"), locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyLink",
|
||||
"Base",
|
||||
"Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The base object used by this object"),
|
||||
locked=True,
|
||||
)
|
||||
if not "File" in pl:
|
||||
obj.addProperty("App::PropertyFile","File","Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property","The PAT file used by this object"), locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyFile",
|
||||
"File",
|
||||
"Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The PAT file used by this object"),
|
||||
locked=True,
|
||||
)
|
||||
if not "Pattern" in pl:
|
||||
obj.addProperty("App::PropertyString","Pattern","Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property","The pattern name used by this object"), locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
"Pattern",
|
||||
"Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The pattern name used by this object"),
|
||||
locked=True,
|
||||
)
|
||||
if not "Scale" in pl:
|
||||
obj.addProperty("App::PropertyFloat","Scale","Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property","The pattern scale used by this object"), locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"Scale",
|
||||
"Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The pattern scale used by this object"),
|
||||
locked=True,
|
||||
)
|
||||
if not "Rotation" in pl:
|
||||
obj.addProperty("App::PropertyAngle","Rotation","Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property","The pattern rotation used by this object"), locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyAngle",
|
||||
"Rotation",
|
||||
"Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The pattern rotation used by this object"),
|
||||
locked=True,
|
||||
)
|
||||
if not "Translate" in pl:
|
||||
obj.addProperty("App::PropertyBool","Translate","Hatch",
|
||||
QT_TRANSLATE_NOOP("App::Property","If set to False, hatch is applied as is to the faces, without translation (this might give wrong results for non-XY faces)"), locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"Translate",
|
||||
"Hatch",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"If set to False, hatch is applied as is to the faces, without translation (this might give wrong results for non-XY faces)",
|
||||
),
|
||||
locked=True,
|
||||
)
|
||||
obj.Translate = True
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
def onDocumentRestored(self, obj):
|
||||
self.setProperties(obj)
|
||||
super().onDocumentRestored(obj)
|
||||
gui_utils.restore_view_object(
|
||||
@@ -79,15 +111,17 @@ class Hatch(DraftObject):
|
||||
def loads(self, state):
|
||||
self.Type = "Hatch"
|
||||
|
||||
def execute(self,obj):
|
||||
def execute(self, obj):
|
||||
|
||||
if self.props_changed_placement_only(obj) \
|
||||
or not obj.Base \
|
||||
or not obj.File \
|
||||
or not obj.Pattern \
|
||||
or not obj.Scale \
|
||||
or not obj.Base.isDerivedFrom("Part::Feature") \
|
||||
or not obj.Base.Shape.Faces:
|
||||
if (
|
||||
self.props_changed_placement_only(obj)
|
||||
or not obj.Base
|
||||
or not obj.File
|
||||
or not obj.Pattern
|
||||
or not obj.Scale
|
||||
or not obj.Base.isDerivedFrom("Part::Feature")
|
||||
or not obj.Base.Shape.Faces
|
||||
):
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
@@ -131,7 +165,7 @@ class Hatch(DraftObject):
|
||||
|
||||
shapes = []
|
||||
for face in obj.Base.Shape.Faces:
|
||||
if face.findPlane(): # Only planar faces.
|
||||
if face.findPlane(): # Only planar faces.
|
||||
face = face.copy()
|
||||
if obj.Translate:
|
||||
mtx = None
|
||||
@@ -183,8 +217,7 @@ class Hatch(DraftObject):
|
||||
|
||||
self.props_changed_store(prop)
|
||||
|
||||
def getPatterns(self,filename):
|
||||
|
||||
def getPatterns(self, filename):
|
||||
"""returns a list of pattern names found in a PAT file"""
|
||||
patterns = []
|
||||
if os.path.exists(filename):
|
||||
|
||||
@@ -58,31 +58,27 @@ class Label(DraftAnnotation):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "TargetPoint" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The position of the tip of the leader "
|
||||
"line.\n"
|
||||
"This point can be decorated "
|
||||
"with an arrow or another symbol.")
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"TargetPoint",
|
||||
"Target",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The position of the tip of the leader "
|
||||
"line.\n"
|
||||
"This point can be decorated "
|
||||
"with an arrow or another symbol.",
|
||||
)
|
||||
obj.addProperty("App::PropertyVector", "TargetPoint", "Target", _tip, locked=True)
|
||||
obj.TargetPoint = App.Vector(2, -1, 0)
|
||||
|
||||
if "Target" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Object, and optionally subelement, "
|
||||
"whose properties will be displayed\n"
|
||||
"as 'Text', depending on 'Label Type'.\n"
|
||||
"\n"
|
||||
"'Target' won't be used "
|
||||
"if 'Label Type' is set to 'Custom'.")
|
||||
obj.addProperty("App::PropertyLinkSub",
|
||||
"Target",
|
||||
"Target",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Object, and optionally subelement, "
|
||||
"whose properties will be displayed\n"
|
||||
"as 'Text', depending on 'Label Type'.\n"
|
||||
"\n"
|
||||
"'Target' won't be used "
|
||||
"if 'Label Type' is set to 'Custom'.",
|
||||
)
|
||||
obj.addProperty("App::PropertyLinkSub", "Target", "Target", _tip, locked=True)
|
||||
obj.Target = None
|
||||
|
||||
def set_leader_properties(self, obj):
|
||||
@@ -90,65 +86,63 @@ class Label(DraftAnnotation):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "Points" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The list of points defining the leader "
|
||||
"line; normally a list of three points.\n"
|
||||
"\n"
|
||||
"The first point should be the position "
|
||||
"of the text, that is, the 'Placement',\n"
|
||||
"and the last point should be "
|
||||
"the tip of the line, that is, "
|
||||
"the 'Target Point'.\n"
|
||||
"The middle point is calculated "
|
||||
"automatically depending on the chosen\n"
|
||||
"'Straight Direction' "
|
||||
"and the 'Straight Distance' value "
|
||||
"and sign.\n"
|
||||
"\n"
|
||||
"If 'Straight Direction' is set to "
|
||||
"'Custom', the 'Points' property\n"
|
||||
"can be set as a list "
|
||||
"of arbitrary points.")
|
||||
obj.addProperty("App::PropertyVectorList",
|
||||
"Points",
|
||||
"Leader",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The list of points defining the leader "
|
||||
"line; normally a list of three points.\n"
|
||||
"\n"
|
||||
"The first point should be the position "
|
||||
"of the text, that is, the 'Placement',\n"
|
||||
"and the last point should be "
|
||||
"the tip of the line, that is, "
|
||||
"the 'Target Point'.\n"
|
||||
"The middle point is calculated "
|
||||
"automatically depending on the chosen\n"
|
||||
"'Straight Direction' "
|
||||
"and the 'Straight Distance' value "
|
||||
"and sign.\n"
|
||||
"\n"
|
||||
"If 'Straight Direction' is set to "
|
||||
"'Custom', the 'Points' property\n"
|
||||
"can be set as a list "
|
||||
"of arbitrary points.",
|
||||
)
|
||||
obj.addProperty("App::PropertyVectorList", "Points", "Leader", _tip, locked=True)
|
||||
obj.Points = []
|
||||
|
||||
if "StraightDirection" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The direction of the straight segment "
|
||||
"of the leader line.\n"
|
||||
"\n"
|
||||
"If 'Custom' is chosen, the points "
|
||||
"of the leader can be specified by\n"
|
||||
"assigning a custom list "
|
||||
"to the 'Points' attribute.")
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"StraightDirection",
|
||||
"Leader",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The direction of the straight segment "
|
||||
"of the leader line.\n"
|
||||
"\n"
|
||||
"If 'Custom' is chosen, the points "
|
||||
"of the leader can be specified by\n"
|
||||
"assigning a custom list "
|
||||
"to the 'Points' attribute.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "StraightDirection", "Leader", _tip, locked=True
|
||||
)
|
||||
obj.StraightDirection = ["Horizontal", "Vertical", "Custom"]
|
||||
|
||||
if "StraightDistance" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The length of the straight segment "
|
||||
"of the leader line.\n"
|
||||
"\n"
|
||||
"This is an oriented distance; "
|
||||
"if it is negative, the line will "
|
||||
"be drawn\n"
|
||||
"to the left or below the 'Text', "
|
||||
"otherwise to the right or above it,\n"
|
||||
"depending on the value of "
|
||||
"'Straight Direction'.")
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"StraightDistance",
|
||||
"Leader",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The length of the straight segment "
|
||||
"of the leader line.\n"
|
||||
"\n"
|
||||
"This is an oriented distance; "
|
||||
"if it is negative, the line will "
|
||||
"be drawn\n"
|
||||
"to the left or below the 'Text', "
|
||||
"otherwise to the right or above it,\n"
|
||||
"depending on the value of "
|
||||
"'Straight Direction'.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyDistance", "StraightDistance", "Leader", _tip, locked=True
|
||||
)
|
||||
obj.StraightDistance = 1
|
||||
|
||||
def set_label_properties(self, obj):
|
||||
@@ -156,41 +150,31 @@ class Label(DraftAnnotation):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "Placement" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The placement of the 'Text' element "
|
||||
"in 3D space")
|
||||
obj.addProperty("App::PropertyPlacement",
|
||||
"Placement",
|
||||
"Label",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The placement of the 'Text' element " "in 3D space"
|
||||
)
|
||||
obj.addProperty("App::PropertyPlacement", "Placement", "Label", _tip, locked=True)
|
||||
obj.Placement = App.Placement()
|
||||
|
||||
if "CustomText" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The text to display when 'Label Type' "
|
||||
"is set to 'Custom'")
|
||||
obj.addProperty("App::PropertyStringList",
|
||||
"CustomText",
|
||||
"Label",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The text to display when 'Label Type' " "is set to 'Custom'"
|
||||
)
|
||||
obj.addProperty("App::PropertyStringList", "CustomText", "Label", _tip, locked=True)
|
||||
obj.CustomText = "Label"
|
||||
|
||||
if "Text" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The text displayed by this label.\n"
|
||||
"\n"
|
||||
"This property is read-only, as the "
|
||||
"final text depends on 'Label Type',\n"
|
||||
"and the object defined in 'Target'.\n"
|
||||
"The 'Custom Text' is displayed only "
|
||||
"if 'Label Type' is set to 'Custom'.")
|
||||
obj.addProperty("App::PropertyStringList",
|
||||
"Text",
|
||||
"Label",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The text displayed by this label.\n"
|
||||
"\n"
|
||||
"This property is read-only, as the "
|
||||
"final text depends on 'Label Type',\n"
|
||||
"and the object defined in 'Target'.\n"
|
||||
"The 'Custom Text' is displayed only "
|
||||
"if 'Label Type' is set to 'Custom'.",
|
||||
)
|
||||
obj.addProperty("App::PropertyStringList", "Text", "Label", _tip, locked=True)
|
||||
obj.setEditorMode("Text", 1) # Read only
|
||||
|
||||
# TODO: maybe here we can define a second and third 'label type'
|
||||
@@ -203,30 +187,28 @@ class Label(DraftAnnotation):
|
||||
# This would also require updating the `return_info` function
|
||||
# to handle any combination that we want.
|
||||
if "LabelType" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The type of information displayed "
|
||||
"by this label.\n"
|
||||
"\n"
|
||||
"If 'Custom' is chosen, the contents of "
|
||||
"'Custom Text' will be used.\n"
|
||||
"For other types, the string will be "
|
||||
"calculated automatically from the "
|
||||
"object defined in 'Target'.\n"
|
||||
"'Tag' and 'Material' only work "
|
||||
"for objects that have these properties, "
|
||||
"like BIM objects.\n"
|
||||
"\n"
|
||||
"For 'Position', 'Length', and 'Area' "
|
||||
"these properties will be extracted "
|
||||
"from the main object in 'Target',\n"
|
||||
"or from the subelement "
|
||||
"'VertexN', 'EdgeN', or 'FaceN', "
|
||||
"respectively, if it is specified.")
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"LabelType",
|
||||
"Label",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The type of information displayed "
|
||||
"by this label.\n"
|
||||
"\n"
|
||||
"If 'Custom' is chosen, the contents of "
|
||||
"'Custom Text' will be used.\n"
|
||||
"For other types, the string will be "
|
||||
"calculated automatically from the "
|
||||
"object defined in 'Target'.\n"
|
||||
"'Tag' and 'Material' only work "
|
||||
"for objects that have these properties, "
|
||||
"like BIM objects.\n"
|
||||
"\n"
|
||||
"For 'Position', 'Length', and 'Area' "
|
||||
"these properties will be extracted "
|
||||
"from the main object in 'Target',\n"
|
||||
"or from the subelement "
|
||||
"'VertexN', 'EdgeN', or 'FaceN', "
|
||||
"respectively, if it is specified.",
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "LabelType", "Label", _tip, locked=True)
|
||||
obj.LabelType = get_label_types()
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
@@ -327,20 +309,22 @@ DraftLabel = Label
|
||||
|
||||
|
||||
def get_label_types():
|
||||
return [QT_TRANSLATE_NOOP("Draft","Custom"),
|
||||
QT_TRANSLATE_NOOP("Draft","Name"),
|
||||
QT_TRANSLATE_NOOP("Draft","Label"),
|
||||
QT_TRANSLATE_NOOP("Draft","Position"),
|
||||
QT_TRANSLATE_NOOP("Draft","Length"),
|
||||
QT_TRANSLATE_NOOP("Draft","Area"),
|
||||
QT_TRANSLATE_NOOP("Draft","Volume"),
|
||||
QT_TRANSLATE_NOOP("Draft","Tag"),
|
||||
QT_TRANSLATE_NOOP("Draft","Material"),
|
||||
QT_TRANSLATE_NOOP("Draft","Label + Position"),
|
||||
QT_TRANSLATE_NOOP("Draft","Label + Length"),
|
||||
QT_TRANSLATE_NOOP("Draft","Label + Area"),
|
||||
QT_TRANSLATE_NOOP("Draft","Label + Volume"),
|
||||
QT_TRANSLATE_NOOP("Draft","Label + Material")]
|
||||
return [
|
||||
QT_TRANSLATE_NOOP("Draft", "Custom"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Name"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Label"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Position"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Length"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Area"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Volume"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Tag"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Material"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Label + Position"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Label + Length"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Label + Area"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Label + Volume"),
|
||||
QT_TRANSLATE_NOOP("Draft", "Label + Material"),
|
||||
]
|
||||
|
||||
|
||||
def return_info(target, typ, subelement=None):
|
||||
@@ -420,7 +404,7 @@ def _get_tag(target):
|
||||
|
||||
|
||||
def _get_material(target):
|
||||
if (hasattr(target, "Material") and hasattr(target.Material, "Label")):
|
||||
if hasattr(target, "Material") and hasattr(target.Material, "Label"):
|
||||
return [target.Material.Label]
|
||||
else:
|
||||
return [translate("draft", "Material not available for object")]
|
||||
|
||||
@@ -52,16 +52,11 @@ class Layer:
|
||||
def set_properties(self, obj):
|
||||
"""Set properties only if they don't exist."""
|
||||
if "Group" not in obj.PropertiesList:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The objects that are part of this layer")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The objects that are part of this layer")
|
||||
# "App::PropertyLinkListHidden" instead of "App::PropertyLinkList" has 2 advantages:
|
||||
# 1. No 'might break' warning when deleting an object nested in a layer.
|
||||
# 2. No 'out of scope' warning for objects also nested in f.e. a Std_Part.
|
||||
obj.addProperty("App::PropertyLinkListHidden",
|
||||
"Group",
|
||||
"Layer",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.addProperty("App::PropertyLinkListHidden", "Group", "Layer", _tip, locked=True)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Execute code when the document is restored."""
|
||||
@@ -93,7 +88,7 @@ class Layer:
|
||||
material = App.Material() # Material with default v0.21 properties.
|
||||
material.DiffuseColor = vobj.ShapeColor
|
||||
material.Transparency = vobj.Transparency / 100
|
||||
vobj.ShapeAppearance = (material, )
|
||||
vobj.ShapeAppearance = (material,)
|
||||
vobj.setPropertyStatus("ShapeColor", "Hidden")
|
||||
if hasattr(vobj, "OverrideShapeColorChildren"): # v0.19 - v0.21
|
||||
vobj.OverrideShapeAppearanceChildren = vobj.OverrideShapeColorChildren
|
||||
@@ -214,4 +209,5 @@ def get_layer(obj):
|
||||
return find
|
||||
return None
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -69,7 +69,12 @@ import lazy_loader.lazy_loader as lz
|
||||
|
||||
from draftutils.messages import _err, _log, _wrn
|
||||
from draftutils.translate import translate
|
||||
def QT_TRANSLATE_NOOP(ctx,txt): return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctx, txt):
|
||||
return txt
|
||||
|
||||
|
||||
from draftobjects.base import DraftObject
|
||||
from draftobjects.draftlink import DraftLink
|
||||
|
||||
@@ -212,21 +217,16 @@ class PathArray(DraftLink):
|
||||
def set_general_properties(self, obj, properties):
|
||||
"""Set general properties only if they don't exist."""
|
||||
if "Base" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","The base object that will be duplicated")
|
||||
obj.addProperty("App::PropertyLinkGlobal",
|
||||
"Base",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The base object that will be duplicated")
|
||||
obj.addProperty("App::PropertyLinkGlobal", "Base", "Objects", _tip, locked=True)
|
||||
obj.Base = None
|
||||
|
||||
if "PathObject" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","The object along which the copies will be distributed. It must contain 'Edges'.")
|
||||
obj.addProperty("App::PropertyLinkGlobal",
|
||||
"PathObject",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The object along which the copies will be distributed. It must contain 'Edges'.",
|
||||
)
|
||||
obj.addProperty("App::PropertyLinkGlobal", "PathObject", "Objects", _tip, locked=True)
|
||||
obj.PathObject = None
|
||||
|
||||
# TODO: the 'PathSubelements' property must be changed,
|
||||
@@ -237,199 +237,161 @@ class PathArray(DraftLink):
|
||||
# as this property can be used to select a single object,
|
||||
# or a single object with its subelements.
|
||||
if "PathSubelements" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","List of connected edges in the 'Path Object'.\nIf these are present, the copies will be created along these subelements only.\nLeave this property empty to create copies along the entire 'Path Object'.")
|
||||
obj.addProperty("App::PropertyLinkSubListGlobal",
|
||||
"PathSubelements",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"List of connected edges in the 'Path Object'.\nIf these are present, the copies will be created along these subelements only.\nLeave this property empty to create copies along the entire 'Path Object'.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkSubListGlobal", "PathSubelements", "Objects", _tip, locked=True
|
||||
)
|
||||
obj.PathSubelements = []
|
||||
|
||||
if "Fuse" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"Fuse",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Fuse", "Objects", _tip, locked=True)
|
||||
obj.Fuse = False
|
||||
|
||||
if self.use_link and "ExpandArray" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Show the individual array elements (only for Link arrays)")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ExpandArray",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Show the individual array elements (only for Link arrays)"
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "ExpandArray", "Objects", _tip, locked=True)
|
||||
obj.ExpandArray = False
|
||||
obj.setPropertyStatus('Shape', 'Transient')
|
||||
obj.setPropertyStatus("Shape", "Transient")
|
||||
|
||||
if not self.use_link:
|
||||
if "PlacementList" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The placement for each array element")
|
||||
obj.addProperty("App::PropertyPlacementList",
|
||||
"PlacementList",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The placement for each array element")
|
||||
obj.addProperty(
|
||||
"App::PropertyPlacementList", "PlacementList", "Objects", _tip, locked=True
|
||||
)
|
||||
obj.PlacementList = []
|
||||
|
||||
def set_align_properties(self, obj, properties):
|
||||
"""Set general properties only if they don't exist."""
|
||||
if "ExtraTranslation" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Additional translation that will be applied to each copy.\nThis is useful to adjust for the difference between shape centre and shape reference point.")
|
||||
obj.addProperty("App::PropertyVectorDistance",
|
||||
"ExtraTranslation",
|
||||
"Alignment",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Additional translation that will be applied to each copy.\nThis is useful to adjust for the difference between shape centre and shape reference point.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorDistance", "ExtraTranslation", "Alignment", _tip, locked=True
|
||||
)
|
||||
obj.ExtraTranslation = App.Vector(0, 0, 0)
|
||||
|
||||
if "TangentVector" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Alignment vector for 'Tangent' mode")
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"TangentVector",
|
||||
"Alignment",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Alignment vector for 'Tangent' mode")
|
||||
obj.addProperty("App::PropertyVector", "TangentVector", "Alignment", _tip, locked=True)
|
||||
obj.TangentVector = App.Vector(1, 0, 0)
|
||||
|
||||
if "ForceVertical" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Force use of 'Vertical Vector' as local Z-direction when using 'Original' or 'Tangent' alignment mode")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ForceVertical",
|
||||
"Alignment",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Force use of 'Vertical Vector' as local Z-direction when using 'Original' or 'Tangent' alignment mode",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "ForceVertical", "Alignment", _tip, locked=True)
|
||||
obj.ForceVertical = False
|
||||
|
||||
if "VerticalVector" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Direction of the local Z axis when 'Force Vertical' is true")
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"VerticalVector",
|
||||
"Alignment",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Direction of the local Z axis when 'Force Vertical' is true"
|
||||
)
|
||||
obj.addProperty("App::PropertyVector", "VerticalVector", "Alignment", _tip, locked=True)
|
||||
obj.VerticalVector = App.Vector(0, 0, 1)
|
||||
|
||||
if "AlignMode" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Method to orient the copies along the path.\n- Original: X is curve tangent, Y is normal, and Z is the cross product.\n- Frenet: aligns the object following the local coordinate system along the path.\n- Tangent: similar to 'Original' but the local X axis is pre-aligned to 'Tangent Vector'.\n\nTo get better results with 'Original' or 'Tangent' you may have to set 'Force Vertical' to true.")
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"AlignMode",
|
||||
"Alignment",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Method to orient the copies along the path.\n- Original: X is curve tangent, Y is normal, and Z is the cross product.\n- Frenet: aligns the object following the local coordinate system along the path.\n- Tangent: similar to 'Original' but the local X axis is pre-aligned to 'Tangent Vector'.\n\nTo get better results with 'Original' or 'Tangent' you may have to set 'Force Vertical' to true.",
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "AlignMode", "Alignment", _tip, locked=True)
|
||||
obj.AlignMode = ["Original", "Frenet", "Tangent"]
|
||||
obj.AlignMode = "Original"
|
||||
|
||||
if "ReversePath" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Walk the path backwards.")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ReversePath",
|
||||
"Alignment",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Walk the path backwards.")
|
||||
obj.addProperty("App::PropertyBool", "ReversePath", "Alignment", _tip, locked=True)
|
||||
obj.ReversePath = False
|
||||
|
||||
# The Align property must be attached after other align properties
|
||||
# so that onChanged works properly
|
||||
if "Align" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Orient the copies along the path depending on the 'Align Mode'.\nOtherwise the copies will have the same orientation as the original Base object.")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"Align",
|
||||
"Alignment",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Orient the copies along the path depending on the 'Align Mode'.\nOtherwise the copies will have the same orientation as the original Base object.",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Align", "Alignment", _tip, locked=True)
|
||||
obj.Align = False
|
||||
|
||||
def set_spacing_properties(self, obj, properties):
|
||||
|
||||
if "Count" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Number of copies to create")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"Count",
|
||||
"Spacing",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Number of copies to create")
|
||||
obj.addProperty("App::PropertyInteger", "Count", "Spacing", _tip, locked=True)
|
||||
obj.Count = 4
|
||||
|
||||
if "SpacingMode" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"How copies are spaced.\n" +
|
||||
" - Fixed count: available path length (minus start and end offsets) is evenly divided into n.\n" +
|
||||
" - Fixed spacing: start at \"Start offset\" and place new copies after traveling a fixed distance along the path.\n" +
|
||||
" - Fixed count and spacing: same as \"Fixed spacing\", but also stop at given number of copies."
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"SpacingMode",
|
||||
"Spacing",
|
||||
_tip,
|
||||
locked=True)
|
||||
"How copies are spaced.\n"
|
||||
+ " - Fixed count: available path length (minus start and end offsets) is evenly divided into n.\n"
|
||||
+ ' - Fixed spacing: start at "Start offset" and place new copies after traveling a fixed distance along the path.\n'
|
||||
+ ' - Fixed count and spacing: same as "Fixed spacing", but also stop at given number of copies.',
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "SpacingMode", "Spacing", _tip, locked=True)
|
||||
obj.SpacingMode = ["Fixed count", "Fixed spacing", "Fixed count and spacing"]
|
||||
obj.SpacingMode = "Fixed count"
|
||||
|
||||
if "SpacingUnit" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Base fixed distance between elements.")
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"SpacingUnit",
|
||||
"Spacing",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Base fixed distance between elements.")
|
||||
obj.addProperty("App::PropertyLength", "SpacingUnit", "Spacing", _tip, locked=True)
|
||||
obj.SpacingUnit = 20.0
|
||||
obj.setPropertyStatus("SpacingUnit", "Hidden")
|
||||
|
||||
if "UseSpacingPattern" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Use repeating spacing patterns instead of uniform spacing.")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"UseSpacingPattern",
|
||||
"Spacing",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Use repeating spacing patterns instead of uniform spacing."
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "UseSpacingPattern", "Spacing", _tip, locked=True)
|
||||
obj.UseSpacingPattern = False
|
||||
|
||||
if "SpacingPattern" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Spacing is multiplied by a corresponding number in this sequence.")
|
||||
obj.addProperty("App::PropertyFloatList",
|
||||
"SpacingPattern",
|
||||
"Spacing",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Spacing is multiplied by a corresponding number in this sequence."
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatList", "SpacingPattern", "Spacing", _tip, locked=True
|
||||
)
|
||||
obj.SpacingPattern = [1, 2]
|
||||
obj.setPropertyStatus("SpacingPattern", "Hidden")
|
||||
|
||||
if "StartOffset" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Length from the start of the path to the first copy.")
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"StartOffset",
|
||||
"Spacing",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Length from the start of the path to the first copy."
|
||||
)
|
||||
obj.addProperty("App::PropertyLength", "StartOffset", "Spacing", _tip, locked=True)
|
||||
obj.StartOffset = 0.0
|
||||
|
||||
if "EndOffset" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property","Length from the end of the path to the last copy.")
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"EndOffset",
|
||||
"Spacing",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Length from the end of the path to the last copy."
|
||||
)
|
||||
obj.addProperty("App::PropertyLength", "EndOffset", "Spacing", _tip, locked=True)
|
||||
obj.EndOffset = 0.0
|
||||
|
||||
def linkSetup(self, obj):
|
||||
"""Set up the object as a link object."""
|
||||
super().linkSetup(obj)
|
||||
obj.configLinkProperty(ElementCount='Count')
|
||||
obj.configLinkProperty(ElementCount="Count")
|
||||
|
||||
def execute(self, obj):
|
||||
"""Execute when the object is created or recomputed."""
|
||||
if self.props_changed_placement_only(obj) \
|
||||
or not obj.Base \
|
||||
or not obj.PathObject:
|
||||
if self.props_changed_placement_only(obj) or not obj.Base or not obj.PathObject:
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
@@ -438,15 +400,13 @@ class PathArray(DraftLink):
|
||||
|
||||
w = self.get_wires(obj.PathObject, obj.PathSubelements)
|
||||
if not w:
|
||||
_err(obj.PathObject.Label
|
||||
+ translate("draft",", path object does not have 'Edges'."))
|
||||
_err(obj.PathObject.Label + translate("draft", ", path object does not have 'Edges'."))
|
||||
return
|
||||
|
||||
base_rotation = obj.Base.Shape.Placement.Rotation
|
||||
final_rotation = base_rotation
|
||||
|
||||
if (obj.Align and obj.AlignMode == "Tangent"
|
||||
and hasattr(obj, "TangentVector")):
|
||||
if obj.Align and obj.AlignMode == "Tangent" and hasattr(obj, "TangentVector"):
|
||||
Xaxis = App.Vector(1.0, 0.0, 0.0) # default TangentVector
|
||||
|
||||
if not DraftVecUtils.equals(Xaxis, obj.TangentVector):
|
||||
@@ -454,30 +414,33 @@ class PathArray(DraftLink):
|
||||
pre_rotation = App.Rotation(obj.TangentVector, Xaxis)
|
||||
final_rotation = base_rotation.multiply(pre_rotation)
|
||||
|
||||
copy_placements = placements_on_path(final_rotation,
|
||||
w, obj.Count,
|
||||
obj.ExtraTranslation,
|
||||
obj.Align, obj.AlignMode,
|
||||
obj.ForceVertical,
|
||||
obj.VerticalVector,
|
||||
obj.StartOffset.Value,
|
||||
obj.EndOffset.Value,
|
||||
obj.ReversePath,
|
||||
obj.SpacingMode,
|
||||
obj.SpacingUnit.Value,
|
||||
obj.UseSpacingPattern,
|
||||
obj.SpacingPattern)
|
||||
copy_placements = placements_on_path(
|
||||
final_rotation,
|
||||
w,
|
||||
obj.Count,
|
||||
obj.ExtraTranslation,
|
||||
obj.Align,
|
||||
obj.AlignMode,
|
||||
obj.ForceVertical,
|
||||
obj.VerticalVector,
|
||||
obj.StartOffset.Value,
|
||||
obj.EndOffset.Value,
|
||||
obj.ReversePath,
|
||||
obj.SpacingMode,
|
||||
obj.SpacingUnit.Value,
|
||||
obj.UseSpacingPattern,
|
||||
obj.SpacingPattern,
|
||||
)
|
||||
|
||||
self.buildShape(obj, array_placement, copy_placements)
|
||||
self.props_changed_clear()
|
||||
return (not self.use_link)
|
||||
return not self.use_link
|
||||
|
||||
def get_wires(self, path_object, subelements):
|
||||
"""Get wires from the path object."""
|
||||
if subelements:
|
||||
w = self.get_wire_from_subelements(subelements)
|
||||
elif (hasattr(path_object.Shape, 'Wires')
|
||||
and path_object.Shape.Wires):
|
||||
elif hasattr(path_object.Shape, "Wires") and path_object.Shape.Wires:
|
||||
w = path_object.Shape.Wires[0]
|
||||
elif path_object.Shape.Edges:
|
||||
w = Part.Wire(path_object.Shape.Edges)
|
||||
@@ -511,10 +474,7 @@ class PathArray(DraftLink):
|
||||
if prop == "SpacingMode":
|
||||
|
||||
# Check if all referenced properties are available:
|
||||
for pr in ("SpacingMode",
|
||||
"SpacingUnit",
|
||||
"UseSpacingPattern",
|
||||
"SpacingPattern"):
|
||||
for pr in ("SpacingMode", "SpacingUnit", "UseSpacingPattern", "SpacingPattern"):
|
||||
if not hasattr(obj, pr):
|
||||
return
|
||||
|
||||
@@ -544,8 +504,7 @@ class PathArray(DraftLink):
|
||||
if prop in ("Align", "AlignMode"):
|
||||
|
||||
# Check if all referenced properties are available:
|
||||
for pr in ("Align", "AlignMode", "ForceVertical",
|
||||
"VerticalVector", "TangentVector"):
|
||||
for pr in ("Align", "AlignMode", "ForceVertical", "VerticalVector", "TangentVector"):
|
||||
if not hasattr(obj, pr):
|
||||
return
|
||||
|
||||
@@ -565,8 +524,7 @@ class PathArray(DraftLink):
|
||||
obj.setPropertyStatus("TangentVector", "Hidden")
|
||||
|
||||
else:
|
||||
for pr in ("AlignMode", "ForceVertical",
|
||||
"VerticalVector", "TangentVector"):
|
||||
for pr in ("AlignMode", "ForceVertical", "VerticalVector", "TangentVector"):
|
||||
obj.setPropertyStatus(pr, "Hidden")
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
@@ -609,22 +567,30 @@ class PathArray(DraftLink):
|
||||
if hasattr(obj, "Xlate"):
|
||||
obj.ExtraTranslation = obj.Xlate
|
||||
obj.removeProperty("Xlate")
|
||||
self.execute(obj) # Required to update PlacementList.
|
||||
self.execute(obj) # Required to update PlacementList.
|
||||
|
||||
|
||||
# Alias for compatibility with v0.18 and earlier
|
||||
_PathArray = PathArray
|
||||
|
||||
|
||||
def placements_on_path(shapeRotation, pathwire, count, xlate, align,
|
||||
mode="Original", forceNormal=False,
|
||||
normalOverride=None,
|
||||
startOffset=0.0, endOffset=0.0,
|
||||
reversePath=False,
|
||||
spacingMode="Fixed count",
|
||||
spacingUnit=20.0,
|
||||
useSpacingPattern=False,
|
||||
spacingPattern=[1, 1, 1, 1]):
|
||||
def placements_on_path(
|
||||
shapeRotation,
|
||||
pathwire,
|
||||
count,
|
||||
xlate,
|
||||
align,
|
||||
mode="Original",
|
||||
forceNormal=False,
|
||||
normalOverride=None,
|
||||
startOffset=0.0,
|
||||
endOffset=0.0,
|
||||
reversePath=False,
|
||||
spacingMode="Fixed count",
|
||||
spacingUnit=20.0,
|
||||
useSpacingPattern=False,
|
||||
spacingPattern=[1, 1, 1, 1],
|
||||
):
|
||||
"""Calculate the placements of a shape along a given path.
|
||||
|
||||
Copies will be distributed according to spacing mode - evenly or in fixed offsets.
|
||||
@@ -658,12 +624,7 @@ def placements_on_path(shapeRotation, pathwire, count, xlate, align,
|
||||
|
||||
if startOffset > (totalDist - minLength):
|
||||
if startOffset != 0:
|
||||
_wrn(
|
||||
translate(
|
||||
"draft",
|
||||
"Start Offset too large for path length. Using 0 instead."
|
||||
)
|
||||
)
|
||||
_wrn(translate("draft", "Start Offset too large for path length. Using 0 instead."))
|
||||
startOffset = 0
|
||||
|
||||
if endOffset > (totalDist - startOffset - minLength):
|
||||
@@ -671,7 +632,7 @@ def placements_on_path(shapeRotation, pathwire, count, xlate, align,
|
||||
_wrn(
|
||||
translate(
|
||||
"draft",
|
||||
"End Offset too large for path length minus Start Offset. Using 0 instead."
|
||||
"End Offset too large for path length minus Start Offset. Using 0 instead.",
|
||||
)
|
||||
)
|
||||
endOffset = 0
|
||||
@@ -728,7 +689,6 @@ def placements_on_path(shapeRotation, pathwire, count, xlate, align,
|
||||
# Each interval will be the same:
|
||||
steps = [spacingUnit]
|
||||
|
||||
|
||||
remains = 0
|
||||
travel = startOffset
|
||||
endTravel = startOffset + totalDist
|
||||
@@ -750,18 +710,27 @@ def placements_on_path(shapeRotation, pathwire, count, xlate, align,
|
||||
|
||||
# place shape at proper spot on proper edge
|
||||
pt = path[iend].valueAt(get_parameter_from_v0(path[iend], offset))
|
||||
place = calculate_placement(shapeRotation,
|
||||
path[iend], offset,
|
||||
pt, xlate, align, normal,
|
||||
mode, forceNormal,
|
||||
reversePath)
|
||||
place = calculate_placement(
|
||||
shapeRotation,
|
||||
path[iend],
|
||||
offset,
|
||||
pt,
|
||||
xlate,
|
||||
align,
|
||||
normal,
|
||||
mode,
|
||||
forceNormal,
|
||||
reversePath,
|
||||
)
|
||||
placements.append(place)
|
||||
travel += steps[i % len(steps)]
|
||||
i = i + 1
|
||||
|
||||
# End conditions:
|
||||
if stopAfterDistance and travel > endTravel: break
|
||||
if stopAfterCount and i >= count: break
|
||||
if stopAfterDistance and travel > endTravel:
|
||||
break
|
||||
if stopAfterCount and i >= count:
|
||||
break
|
||||
|
||||
# Failsafe:
|
||||
if i > 10_000:
|
||||
@@ -774,11 +743,18 @@ def placements_on_path(shapeRotation, pathwire, count, xlate, align,
|
||||
calculatePlacementsOnPath = placements_on_path
|
||||
|
||||
|
||||
def calculate_placement(globalRotation,
|
||||
edge, offset, RefPt, xlate, align,
|
||||
normal=App.Vector(0.0, 0.0, 1.0),
|
||||
mode="Original", overrideNormal=False,
|
||||
reversePath=False):
|
||||
def calculate_placement(
|
||||
globalRotation,
|
||||
edge,
|
||||
offset,
|
||||
RefPt,
|
||||
xlate,
|
||||
align,
|
||||
normal=App.Vector(0.0, 0.0, 1.0),
|
||||
mode="Original",
|
||||
overrideNormal=False,
|
||||
reversePath=False,
|
||||
):
|
||||
"""Orient shape in the local coordinate system at parameter offset.
|
||||
|
||||
http://en.wikipedia.org/wiki/Euler_angles (previous version)
|
||||
@@ -792,7 +768,7 @@ def calculate_placement(globalRotation,
|
||||
if not align:
|
||||
return placement
|
||||
|
||||
tol = 1e-6 # App.Rotation() tolerance is 1e-7. Shorter vectors are ignored.
|
||||
tol = 1e-6 # App.Rotation() tolerance is 1e-7. Shorter vectors are ignored.
|
||||
nullv = App.Vector()
|
||||
|
||||
t = edge.tangentAt(get_parameter_from_v0(edge, offset))
|
||||
@@ -821,19 +797,28 @@ def calculate_placement(globalRotation,
|
||||
n_nor = n.normalize()
|
||||
t_nor = t.normalize()
|
||||
if n_nor.isEqual(t_nor, tol) or n_nor.isEqual(t_nor.negative(), tol):
|
||||
_wrn(translate("draft", "Tangent and normal vectors are parallel. Normal replaced by a default axis."))
|
||||
_wrn(
|
||||
translate(
|
||||
"draft",
|
||||
"Tangent and normal vectors are parallel. Normal replaced by a default axis.",
|
||||
)
|
||||
)
|
||||
n = t
|
||||
|
||||
if overrideNormal:
|
||||
onPathRotation = App.Rotation(t, nullv, n, "XZY") # priority = "XZY"
|
||||
onPathRotation = App.Rotation(t, nullv, n, "XZY") # priority = "XZY"
|
||||
else:
|
||||
onPathRotation = App.Rotation(t, n, nullv, "XYZ") # priority = "XYZ"
|
||||
onPathRotation = App.Rotation(t, n, nullv, "XYZ") # priority = "XYZ"
|
||||
|
||||
elif mode == "Frenet":
|
||||
try:
|
||||
n = edge.normalAt(get_parameter_from_v0(edge, offset))
|
||||
except App.Base.FreeCADError: # no/infinite normals here
|
||||
_wrn(translate("draft", "Cannot calculate normal vector. Using the default normal instead."))
|
||||
except App.Base.FreeCADError: # no/infinite normals here
|
||||
_wrn(
|
||||
translate(
|
||||
"draft", "Cannot calculate normal vector. Using the default normal instead."
|
||||
)
|
||||
)
|
||||
n = normal
|
||||
|
||||
if n.isEqual(nullv, tol):
|
||||
@@ -843,10 +828,15 @@ def calculate_placement(globalRotation,
|
||||
n_nor = n.normalize()
|
||||
t_nor = t.normalize()
|
||||
if n_nor.isEqual(t_nor, tol) or n_nor.isEqual(t_nor.negative(), tol):
|
||||
_wrn(translate("draft", "Tangent and normal vectors are parallel. Normal replaced by a default axis."))
|
||||
_wrn(
|
||||
translate(
|
||||
"draft",
|
||||
"Tangent and normal vectors are parallel. Normal replaced by a default axis.",
|
||||
)
|
||||
)
|
||||
n = t
|
||||
|
||||
onPathRotation = App.Rotation(t, n, nullv, "XYZ") # priority = "XYZ"
|
||||
onPathRotation = App.Rotation(t, n, nullv, "XYZ") # priority = "XYZ"
|
||||
|
||||
else:
|
||||
_err(translate("draft", "AlignMode {} is not implemented").format(mode))
|
||||
@@ -860,6 +850,7 @@ def calculate_placement(globalRotation,
|
||||
|
||||
calculatePlacement = calculate_placement
|
||||
|
||||
|
||||
def get_parameter_from_v0(edge, offset):
|
||||
"""Return parameter at distance offset from edge.Vertexes[0].
|
||||
|
||||
|
||||
@@ -49,7 +49,12 @@ object in the Arch Workbench.
|
||||
|
||||
import draftgeoutils.geo_arrays as geo
|
||||
from draftutils.messages import _log
|
||||
def QT_TRANSLATE_NOOP(ctx,txt): return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctx, txt):
|
||||
return txt
|
||||
|
||||
|
||||
from draftobjects.draftlink import DraftLink
|
||||
|
||||
## \addtogroup draftobjects
|
||||
@@ -80,73 +85,83 @@ class PathTwistedArray(DraftLink):
|
||||
properties = []
|
||||
|
||||
if "Base" not in properties:
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Base",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property","The base object that will be duplicated."),
|
||||
locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyLink",
|
||||
"Base",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The base object that will be duplicated."),
|
||||
locked=True,
|
||||
)
|
||||
obj.Base = None
|
||||
|
||||
if "PathObject" not in properties:
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"PathObject",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property","The object along which the copies will be distributed. It must contain 'Edges'."),
|
||||
locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyLink",
|
||||
"PathObject",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The object along which the copies will be distributed. It must contain 'Edges'.",
|
||||
),
|
||||
locked=True,
|
||||
)
|
||||
obj.PathObject = None
|
||||
|
||||
if "Fuse" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"Fuse",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Fuse", "Objects", _tip, locked=True)
|
||||
obj.Fuse = False
|
||||
|
||||
if "Count" not in properties:
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"Count",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property","Number of copies to create."),
|
||||
locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger",
|
||||
"Count",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Number of copies to create."),
|
||||
locked=True,
|
||||
)
|
||||
obj.Count = 15
|
||||
|
||||
if "RotationFactor" not in properties:
|
||||
obj.addProperty("App::PropertyFloat",
|
||||
"RotationFactor",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property","Rotation factor of the twisted array."),
|
||||
locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"RotationFactor",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Rotation factor of the twisted array."),
|
||||
locked=True,
|
||||
)
|
||||
obj.RotationFactor = 0.25
|
||||
|
||||
if self.use_link and "ExpandArray" not in properties:
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ExpandArray",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP("App::Property","Show the individual array elements (only for Link arrays)"),
|
||||
locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ExpandArray",
|
||||
"Objects",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Show the individual array elements (only for Link arrays)"
|
||||
),
|
||||
locked=True,
|
||||
)
|
||||
obj.ExpandArray = False
|
||||
obj.setPropertyStatus('Shape', 'Transient')
|
||||
obj.setPropertyStatus("Shape", "Transient")
|
||||
|
||||
if not self.use_link:
|
||||
if "PlacementList" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The placement for each array element")
|
||||
obj.addProperty("App::PropertyPlacementList",
|
||||
"PlacementList",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The placement for each array element")
|
||||
obj.addProperty(
|
||||
"App::PropertyPlacementList", "PlacementList", "Objects", _tip, locked=True
|
||||
)
|
||||
obj.PlacementList = []
|
||||
|
||||
def linkSetup(self, obj):
|
||||
"""Set up the object as a link object."""
|
||||
super().linkSetup(obj)
|
||||
obj.configLinkProperty(ElementCount='Count')
|
||||
obj.configLinkProperty(ElementCount="Count")
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
super().onDocumentRestored(obj)
|
||||
@@ -161,13 +176,11 @@ class PathTwistedArray(DraftLink):
|
||||
_log("v1.1, " + obj.Name + ", added hidden property 'PlacementList'")
|
||||
|
||||
self.set_properties(obj)
|
||||
self.execute(obj) # Required to update PlacementList.
|
||||
self.execute(obj) # Required to update PlacementList.
|
||||
|
||||
def execute(self, obj):
|
||||
"""Execute when the object is created or recomputed."""
|
||||
if self.props_changed_placement_only(obj) \
|
||||
or not obj.Base \
|
||||
or not obj.PathObject:
|
||||
if self.props_changed_placement_only(obj) or not obj.Base or not obj.PathObject:
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
@@ -178,12 +191,11 @@ class PathTwistedArray(DraftLink):
|
||||
count = obj.Count
|
||||
rot_factor = obj.RotationFactor
|
||||
|
||||
copy_placements, _ = geo.get_twisted_placements(path,
|
||||
count=count,
|
||||
rot_factor=rot_factor)
|
||||
copy_placements, _ = geo.get_twisted_placements(path, count=count, rot_factor=rot_factor)
|
||||
|
||||
self.buildShape(obj, array_placement, copy_placements)
|
||||
self.props_changed_clear()
|
||||
return (not self.use_link)
|
||||
return not self.use_link
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -54,7 +54,7 @@ class Point(DraftObject):
|
||||
obj.Y = y
|
||||
obj.Z = z
|
||||
|
||||
obj.setPropertyStatus('Placement', 'Hidden')
|
||||
obj.setPropertyStatus("Placement", "Hidden")
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
super().onDocumentRestored(obj)
|
||||
@@ -73,6 +73,7 @@ class Point(DraftObject):
|
||||
return
|
||||
|
||||
import Part
|
||||
|
||||
obj.Shape = Part.Vertex(App.Vector(0, 0, 0))
|
||||
if base != xyz_vec:
|
||||
obj.Placement.Base = xyz_vec
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides the object code for the PointArray object.
|
||||
"""
|
||||
"""Provides the object code for the PointArray object."""
|
||||
## @package pointarray
|
||||
# \ingroup draftobjects
|
||||
# \brief Provides the object code for the PointArray object.
|
||||
@@ -56,7 +55,7 @@ class PointArray(DraftLink):
|
||||
def linkSetup(self, obj):
|
||||
"""Set up the object as a link object."""
|
||||
super().linkSetup(obj)
|
||||
obj.configLinkProperty(ElementCount='Count')
|
||||
obj.configLinkProperty(ElementCount="Count")
|
||||
|
||||
def set_properties(self, obj):
|
||||
"""Set properties only if they don't exist."""
|
||||
@@ -64,78 +63,63 @@ class PointArray(DraftLink):
|
||||
|
||||
if "Base" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Base object that will be duplicated")
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Base",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.addProperty("App::PropertyLink", "Base", "Objects", _tip, locked=True)
|
||||
obj.Base = None
|
||||
|
||||
if "PointObject" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Object containing points used to distribute the copies.")
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"PointObject",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Object containing points used to distribute the copies."
|
||||
)
|
||||
obj.addProperty("App::PropertyLink", "PointObject", "Objects", _tip, locked=True)
|
||||
obj.PointObject = None
|
||||
|
||||
if "Fuse" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"Fuse",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Specifies if the copies "
|
||||
"should be fused together "
|
||||
"if they touch each other (slower)",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Fuse", "Objects", _tip, locked=True)
|
||||
obj.Fuse = False
|
||||
|
||||
if "Count" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Number of copies in the array.\nThis property is read-only, as the number depends on the points in 'Point Object'.")
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"Count",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Number of copies in the array.\nThis property is read-only, as the number depends on the points in 'Point Object'.",
|
||||
)
|
||||
obj.addProperty("App::PropertyInteger", "Count", "Objects", _tip, locked=True)
|
||||
obj.Count = 0
|
||||
obj.setEditorMode("Count", 1) # Read only
|
||||
|
||||
if "ExtraPlacement" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Additional placement, shift and rotation, that will be applied to each copy")
|
||||
obj.addProperty("App::PropertyPlacement",
|
||||
"ExtraPlacement",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Additional placement, shift and rotation, that will be applied to each copy",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyPlacement", "ExtraPlacement", "Objects", _tip, locked=True
|
||||
)
|
||||
obj.ExtraPlacement = App.Placement()
|
||||
|
||||
if self.use_link and "ExpandArray" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Show the individual array elements (only for Link arrays)")
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ExpandArray",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
obj.setPropertyStatus('Shape', 'Transient')
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Show the individual array elements (only for Link arrays)"
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "ExpandArray", "Objects", _tip, locked=True)
|
||||
obj.setPropertyStatus("Shape", "Transient")
|
||||
|
||||
if not self.use_link:
|
||||
if "PlacementList" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The placement for each array element")
|
||||
obj.addProperty("App::PropertyPlacementList",
|
||||
"PlacementList",
|
||||
"Objects",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The placement for each array element")
|
||||
obj.addProperty(
|
||||
"App::PropertyPlacementList", "PlacementList", "Objects", _tip, locked=True
|
||||
)
|
||||
obj.PlacementList = []
|
||||
|
||||
def execute(self, obj):
|
||||
"""Run when the object is created or recomputed."""
|
||||
if self.props_changed_placement_only(obj) \
|
||||
or not obj.Base \
|
||||
or not obj.PointObject:
|
||||
if self.props_changed_placement_only(obj) or not obj.Base or not obj.PointObject:
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
@@ -145,7 +129,7 @@ class PointArray(DraftLink):
|
||||
|
||||
self.buildShape(obj, obj.Placement, pls)
|
||||
self.props_changed_clear()
|
||||
return (not self.use_link)
|
||||
return not self.use_link
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
super().onDocumentRestored(obj)
|
||||
@@ -167,9 +151,10 @@ class PointArray(DraftLink):
|
||||
if hasattr(obj, "PointList"):
|
||||
obj.PointObject = obj.PointList
|
||||
obj.removeProperty("PointList")
|
||||
self.execute(obj) # Required to update PlacementList.
|
||||
self.execute(obj) # Required to update PlacementList.
|
||||
|
||||
def remove_equal_vecs (vec_list):
|
||||
|
||||
def remove_equal_vecs(vec_list):
|
||||
"""Remove equal vectors from a list.
|
||||
|
||||
Parameters
|
||||
@@ -189,6 +174,7 @@ def remove_equal_vecs (vec_list):
|
||||
res_list.append(vec)
|
||||
return res_list
|
||||
|
||||
|
||||
def get_point_list(point_object):
|
||||
"""Extract a list of points from a point object.
|
||||
|
||||
@@ -205,7 +191,7 @@ def get_point_list(point_object):
|
||||
if hasattr(point_object, "Shape") and hasattr(point_object.Shape, "Vertexes"):
|
||||
pt_list = [v.Point for v in point_object.Shape.Vertexes]
|
||||
# For compatibility with previous versions: add all points from sketch (including construction geometry):
|
||||
if hasattr(point_object, 'Geometry'):
|
||||
if hasattr(point_object, "Geometry"):
|
||||
place = point_object.Placement
|
||||
for geo in point_object.Geometry:
|
||||
if geo.TypeId == "Part::GeomPoint":
|
||||
@@ -219,6 +205,7 @@ def get_point_list(point_object):
|
||||
|
||||
return remove_equal_vecs(pt_list)
|
||||
|
||||
|
||||
def build_placements(base_object, pt_list=None, placement=App.Placement()):
|
||||
"""Build a placements from the base object and list of points.
|
||||
|
||||
@@ -227,9 +214,12 @@ def build_placements(base_object, pt_list=None, placement=App.Placement()):
|
||||
list of App.Placements
|
||||
"""
|
||||
if not pt_list:
|
||||
_err(translate("Draft",
|
||||
"Point object does not have a discrete point, "
|
||||
"it cannot be used for an array"))
|
||||
_err(
|
||||
translate(
|
||||
"Draft",
|
||||
"Point object does not have a discrete point, " "it cannot be used for an array",
|
||||
)
|
||||
)
|
||||
return []
|
||||
|
||||
pls = list()
|
||||
|
||||
@@ -43,36 +43,31 @@ class Polygon(DraftObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj, "Polygon")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Number of faces")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Number of faces")
|
||||
obj.addProperty("App::PropertyInteger", "FacesNumber", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Radius of the control circle")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Radius of the control circle")
|
||||
obj.addProperty("App::PropertyLength", "Radius", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"How the polygon must be drawn from the control circle")
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "How the polygon must be drawn from the control circle"
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "DrawMode", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Radius to use to fillet the corners")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Radius to use to fillet the corners")
|
||||
obj.addProperty("App::PropertyLength", "FilletRadius", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Size of the chamfer to give to the corners")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Size of the chamfer to give to the corners")
|
||||
obj.addProperty("App::PropertyLength", "ChamferSize", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Create a face")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Create a face")
|
||||
obj.addProperty("App::PropertyBool", "MakeFace", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The area of this object")
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The area of this object")
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
|
||||
obj.MakeFace = params.get_param("MakeFaceMode")
|
||||
obj.DrawMode = ['inscribed','circumscribed']
|
||||
obj.DrawMode = ["inscribed", "circumscribed"]
|
||||
obj.FacesNumber = 0
|
||||
obj.Radius = 1
|
||||
|
||||
@@ -88,33 +83,30 @@ class Polygon(DraftObject):
|
||||
|
||||
if (obj.FacesNumber >= 3) and (obj.Radius.Value > 0):
|
||||
import Part
|
||||
|
||||
plm = obj.Placement
|
||||
angle = (math.pi * 2) / obj.FacesNumber
|
||||
if obj.DrawMode == 'inscribed':
|
||||
if obj.DrawMode == "inscribed":
|
||||
delta = obj.Radius.Value
|
||||
else:
|
||||
delta = obj.Radius.Value / math.cos(angle / 2.0)
|
||||
pts = [App.Vector(delta, 0, 0)]
|
||||
for i in range(obj.FacesNumber - 1):
|
||||
ang = (i + 1) * angle
|
||||
pts.append(App.Vector(delta * math.cos(ang),
|
||||
delta*math.sin(ang),
|
||||
0))
|
||||
pts.append(App.Vector(delta * math.cos(ang), delta * math.sin(ang), 0))
|
||||
pts.append(pts[0])
|
||||
shape = Part.makePolygon(pts)
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.ChamferSize.Value,
|
||||
chamfer=True)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.ChamferSize.Value, chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,
|
||||
obj.FilletRadius.Value)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if hasattr(obj, "MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
|
||||
@@ -67,10 +67,10 @@ class Rectangle(DraftObject):
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
|
||||
obj.MakeFace = params.get_param("MakeFaceMode")
|
||||
obj.Length=1
|
||||
obj.Height=1
|
||||
obj.Rows=1
|
||||
obj.Columns=1
|
||||
obj.Length = 1
|
||||
obj.Height = 1
|
||||
obj.Rows = 1
|
||||
obj.Columns = 1
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
super().onDocumentRestored(obj)
|
||||
@@ -95,7 +95,7 @@ class Rectangle(DraftObject):
|
||||
|
||||
shape = None
|
||||
|
||||
if hasattr(obj,"Rows") and hasattr(obj,"Columns"):
|
||||
if hasattr(obj, "Rows") and hasattr(obj, "Columns"):
|
||||
# TODO: verify if this is needed:
|
||||
if obj.Rows > 1:
|
||||
rows = obj.Rows
|
||||
@@ -109,29 +109,28 @@ class Rectangle(DraftObject):
|
||||
|
||||
if (rows > 1) or (columns > 1):
|
||||
shapes = []
|
||||
l = obj.Length.Value/columns
|
||||
h = obj.Height.Value/rows
|
||||
l = obj.Length.Value / columns
|
||||
h = obj.Height.Value / rows
|
||||
for i in range(columns):
|
||||
for j in range(rows):
|
||||
p1 = App.Vector(i*l,j*h,0)
|
||||
p2 = App.Vector(p1.x+l,p1.y,p1.z)
|
||||
p3 = App.Vector(p1.x+l,p1.y+h,p1.z)
|
||||
p4 = App.Vector(p1.x,p1.y+h,p1.z)
|
||||
p = Part.makePolygon([p1,p2,p3,p4,p1])
|
||||
p1 = App.Vector(i * l, j * h, 0)
|
||||
p2 = App.Vector(p1.x + l, p1.y, p1.z)
|
||||
p3 = App.Vector(p1.x + l, p1.y + h, p1.z)
|
||||
p4 = App.Vector(p1.x, p1.y + h, p1.z)
|
||||
p = Part.makePolygon([p1, p2, p3, p4, p1])
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(p,
|
||||
obj.ChamferSize.Value,
|
||||
chamfer=True)
|
||||
w = DraftGeomUtils.filletWire(
|
||||
p, obj.ChamferSize.Value, chamfer=True
|
||||
)
|
||||
if w:
|
||||
p = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(p,
|
||||
obj.FilletRadius.Value)
|
||||
w = DraftGeomUtils.filletWire(p, obj.FilletRadius.Value)
|
||||
if w:
|
||||
p = w
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if hasattr(obj, "MakeFace"):
|
||||
if obj.MakeFace:
|
||||
p = Part.Face(p)
|
||||
shapes.append(p)
|
||||
@@ -139,31 +138,22 @@ class Rectangle(DraftObject):
|
||||
shape = Part.makeCompound(shapes)
|
||||
|
||||
if not shape:
|
||||
p1 = App.Vector(0,0,0)
|
||||
p2 = App.Vector(p1.x+obj.Length.Value,
|
||||
p1.y,
|
||||
p1.z)
|
||||
p3 = App.Vector(p1.x+obj.Length.Value,
|
||||
p1.y+obj.Height.Value,
|
||||
p1.z)
|
||||
p4 = App.Vector(p1.x,
|
||||
p1.y+obj.Height.Value,
|
||||
p1.z)
|
||||
p1 = App.Vector(0, 0, 0)
|
||||
p2 = App.Vector(p1.x + obj.Length.Value, p1.y, p1.z)
|
||||
p3 = App.Vector(p1.x + obj.Length.Value, p1.y + obj.Height.Value, p1.z)
|
||||
p4 = App.Vector(p1.x, p1.y + obj.Height.Value, p1.z)
|
||||
shape = Part.makePolygon([p1, p2, p3, p4, p1])
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,
|
||||
obj.ChamferSize.Value,
|
||||
chamfer=True)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.ChamferSize.Value, chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,
|
||||
obj.FilletRadius.Value)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if hasattr(obj, "MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
@@ -171,7 +161,7 @@ class Rectangle(DraftObject):
|
||||
|
||||
obj.Shape = shape
|
||||
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
if hasattr(obj, "Area") and hasattr(shape, "Area"):
|
||||
obj.Area = shape.Area
|
||||
|
||||
obj.Placement = plm
|
||||
|
||||
@@ -41,7 +41,7 @@ from draftutils.translate import translate
|
||||
class Shape2DView(DraftObject):
|
||||
"""The Shape2DView object"""
|
||||
|
||||
def __init__(self,obj):
|
||||
def __init__(self, obj):
|
||||
|
||||
self.setProperties(obj)
|
||||
super().__init__(obj, "Shape2DView")
|
||||
@@ -53,101 +53,108 @@ class Shape2DView(DraftObject):
|
||||
obj, vp_module="view_base", vp_class="ViewProviderDraftAlt", format=False
|
||||
)
|
||||
|
||||
def setProperties(self,obj):
|
||||
def setProperties(self, obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not "Base" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The base object this 2D view must represent")
|
||||
obj.addProperty("App::PropertyLink", "Base",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The base object this 2D view must represent")
|
||||
obj.addProperty("App::PropertyLink", "Base", "Draft", _tip, locked=True)
|
||||
if not "Projection" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The projection vector of this object")
|
||||
obj.addProperty("App::PropertyVector", "Projection",
|
||||
"Draft", _tip, locked=True)
|
||||
obj.Projection = App.Vector(0,0,1)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The projection vector of this object")
|
||||
obj.addProperty("App::PropertyVector", "Projection", "Draft", _tip, locked=True)
|
||||
obj.Projection = App.Vector(0, 0, 1)
|
||||
if not "ProjectionMode" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The way the viewed object must be projected")
|
||||
obj.addProperty("App::PropertyEnumeration", "ProjectionMode",
|
||||
"Draft", _tip, locked=True)
|
||||
obj.ProjectionMode = ["Solid", "Individual Faces",
|
||||
"Cutlines", "Cutfaces","Solid faces"]
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The way the viewed object must be projected")
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "ProjectionMode", "Draft", _tip, locked=True
|
||||
)
|
||||
obj.ProjectionMode = [
|
||||
"Solid",
|
||||
"Individual Faces",
|
||||
"Cutlines",
|
||||
"Cutfaces",
|
||||
"Solid faces",
|
||||
]
|
||||
if not "FaceNumbers" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The indices of the faces to be projected in Individual Faces mode")
|
||||
obj.addProperty("App::PropertyIntegerList", "FaceNumbers",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The indices of the faces to be projected in Individual Faces mode"
|
||||
)
|
||||
obj.addProperty("App::PropertyIntegerList", "FaceNumbers", "Draft", _tip, locked=True)
|
||||
if not "HiddenLines" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Show hidden lines")
|
||||
obj.addProperty("App::PropertyBool", "HiddenLines",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Show hidden lines")
|
||||
obj.addProperty("App::PropertyBool", "HiddenLines", "Draft", _tip, locked=True)
|
||||
obj.HiddenLines = False
|
||||
if not "FuseArch" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Fuse wall and structure objects of same type and material")
|
||||
obj.addProperty("App::PropertyBool", "FuseArch",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Fuse wall and structure objects of same type and material"
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "FuseArch", "Draft", _tip, locked=True)
|
||||
if not "Tessellation" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Tessellate Ellipses and B-splines into line segments")
|
||||
obj.addProperty("App::PropertyBool", "Tessellation",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "Tessellate Ellipses and B-splines into line segments"
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Tessellation", "Draft", _tip, locked=True)
|
||||
obj.Tessellation = False
|
||||
if not "InPlace" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"For Cutlines and Cutfaces modes, this leaves the faces at the cut location")
|
||||
obj.addProperty("App::PropertyBool", "InPlace",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"For Cutlines and Cutfaces modes, this leaves the faces at the cut location",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "InPlace", "Draft", _tip, locked=True)
|
||||
obj.InPlace = True
|
||||
if not "SegmentLength" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Length of line segments if tessellating Ellipses or B-splines into line segments")
|
||||
obj.addProperty("App::PropertyFloat", "SegmentLength",
|
||||
"Draft", _tip, locked=True)
|
||||
obj.SegmentLength = .05
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Length of line segments if tessellating Ellipses or B-splines into line segments",
|
||||
)
|
||||
obj.addProperty("App::PropertyFloat", "SegmentLength", "Draft", _tip, locked=True)
|
||||
obj.SegmentLength = 0.05
|
||||
if not "VisibleOnly" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If this is True, this object will include only visible objects")
|
||||
obj.addProperty("App::PropertyBool", "VisibleOnly",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "If this is True, this object will include only visible objects"
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "VisibleOnly", "Draft", _tip, locked=True)
|
||||
obj.VisibleOnly = False
|
||||
if not "ExclusionPoints" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"A list of exclusion points. Any edge touching any of those points will not be drawn.")
|
||||
obj.addProperty("App::PropertyVectorList", "ExclusionPoints",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"A list of exclusion points. Any edge touching any of those points will not be drawn.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorList", "ExclusionPoints", "Draft", _tip, locked=True
|
||||
)
|
||||
if not "ExclusionNames" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"A list of exclusion object names. Any object viewed that matches a name from the list will not be drawn.")
|
||||
obj.addProperty("App::PropertyStringList", "ExclusionNames",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"A list of exclusion object names. Any object viewed that matches a name from the list will not be drawn.",
|
||||
)
|
||||
obj.addProperty("App::PropertyStringList", "ExclusionNames", "Draft", _tip, locked=True)
|
||||
if not "OnlySolids" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If this is True, only solid geometry is handled. This overrides the base object's Only Solids property")
|
||||
obj.addProperty("App::PropertyBool", "OnlySolids",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"If this is True, only solid geometry is handled. This overrides the base object's Only Solids property",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "OnlySolids", "Draft", _tip, locked=True)
|
||||
if not "Clip" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If this is True, the contents are clipped to the borders of the section plane, if applicable. This overrides the base object's Clip property")
|
||||
obj.addProperty("App::PropertyBool", "Clip",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"If this is True, the contents are clipped to the borders of the section plane, if applicable. This overrides the base object's Clip property",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Clip", "Draft", _tip, locked=True)
|
||||
if not "AutoUpdate" in pl:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"This object will be recomputed only if this is True.")
|
||||
obj.addProperty("App::PropertyBool", "AutoUpdate",
|
||||
"Draft", _tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "This object will be recomputed only if this is True."
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "AutoUpdate", "Draft", _tip, locked=True)
|
||||
obj.AutoUpdate = True
|
||||
|
||||
def getProjected(self,obj,shape,direction):
|
||||
|
||||
def getProjected(self, obj, shape, direction):
|
||||
"returns projected edges from a shape and a direction"
|
||||
import Part
|
||||
import TechDraw
|
||||
import DraftGeomUtils
|
||||
|
||||
edges = []
|
||||
_groups = TechDraw.projectEx(shape, direction)
|
||||
for g in _groups[0:5]:
|
||||
@@ -157,22 +164,22 @@ class Shape2DView(DraftObject):
|
||||
for g in _groups[5:]:
|
||||
if not g.isNull():
|
||||
edges.append(g)
|
||||
edges = self.cleanExcluded(obj,edges)
|
||||
edges = self.cleanExcluded(obj, edges)
|
||||
if getattr(obj, "Tessellation", False):
|
||||
return DraftGeomUtils.cleanProjection(Part.makeCompound(edges),
|
||||
obj.Tessellation,
|
||||
obj.SegmentLength)
|
||||
return DraftGeomUtils.cleanProjection(
|
||||
Part.makeCompound(edges), obj.Tessellation, obj.SegmentLength
|
||||
)
|
||||
else:
|
||||
return Part.makeCompound(edges)
|
||||
|
||||
def cleanExcluded(self,obj,shapes):
|
||||
|
||||
def cleanExcluded(self, obj, shapes):
|
||||
"""removes any edge touching exclusion points"""
|
||||
import Part
|
||||
|
||||
MAXDIST = 0.0001
|
||||
if (not hasattr(obj,"ExclusionPoints")) or (not obj.ExclusionPoints):
|
||||
if (not hasattr(obj, "ExclusionPoints")) or (not obj.ExclusionPoints):
|
||||
return shapes
|
||||
#verts = [Part.Vertex(obj.Placement.multVec(p)) for p in obj.ExclusionPoints]
|
||||
# verts = [Part.Vertex(obj.Placement.multVec(p)) for p in obj.ExclusionPoints]
|
||||
verts = [Part.Vertex(p) for p in obj.ExclusionPoints]
|
||||
nedges = []
|
||||
for s in shapes:
|
||||
@@ -183,14 +190,16 @@ class Shape2DView(DraftObject):
|
||||
if d and (d[0] <= MAXDIST):
|
||||
break
|
||||
except RuntimeError:
|
||||
print("FIXME: shape2dview: distance unavailable for edge",e,"in",obj.Label)
|
||||
print(
|
||||
"FIXME: shape2dview: distance unavailable for edge", e, "in", obj.Label
|
||||
)
|
||||
else:
|
||||
nedges.append(e)
|
||||
return nedges
|
||||
|
||||
def excludeNames(self,obj,objs):
|
||||
if hasattr(obj,"ExclusionNames"):
|
||||
objs = [o for o in objs if not(o.Name in obj.ExclusionNames)]
|
||||
def excludeNames(self, obj, objs):
|
||||
if hasattr(obj, "ExclusionNames"):
|
||||
objs = [o for o in objs if not (o.Name in obj.ExclusionNames)]
|
||||
return objs
|
||||
|
||||
def _get_shapes(self, shape, onlysolids=False):
|
||||
@@ -203,39 +212,39 @@ class Shape2DView(DraftObject):
|
||||
return [shape.copy()]
|
||||
|
||||
def execute(self, obj):
|
||||
if self.props_changed_placement_only(obj) \
|
||||
or not getattr(obj, "AutoUpdate", True):
|
||||
if self.props_changed_placement_only(obj) or not getattr(obj, "AutoUpdate", True):
|
||||
obj.positionBySupport()
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
|
||||
pl = obj.Placement
|
||||
if obj.Base:
|
||||
if utils.get_type(obj.Base) in ["BuildingPart","SectionPlane","IfcAnnotation"]:
|
||||
if utils.get_type(obj.Base) in ["BuildingPart", "SectionPlane", "IfcAnnotation"]:
|
||||
objs = []
|
||||
if utils.get_type(obj.Base) == "SectionPlane":
|
||||
objs = self.excludeNames(obj,obj.Base.Objects)
|
||||
objs = self.excludeNames(obj, obj.Base.Objects)
|
||||
cutplane = obj.Base.Shape
|
||||
elif utils.get_type(obj.Base) == "IfcAnnotation":
|
||||
# this is a NativeIFC section plane
|
||||
objs, cutplane = obj.Base.Proxy.get_section_data(obj.Base)
|
||||
objs = self.excludeNames(obj, objs)
|
||||
else:
|
||||
objs = self.excludeNames(obj,obj.Base.Group)
|
||||
objs = self.excludeNames(obj, obj.Base.Group)
|
||||
cutplane = Part.makePlane(1000, 1000, App.Vector(-500, -500, 0))
|
||||
m = 1
|
||||
if obj.Base.ViewObject and hasattr(obj.Base.ViewObject,"CutMargin"):
|
||||
if obj.Base.ViewObject and hasattr(obj.Base.ViewObject, "CutMargin"):
|
||||
m = obj.Base.ViewObject.CutMargin.Value
|
||||
cutplane.translate(App.Vector(0,0,m))
|
||||
cutplane.translate(App.Vector(0, 0, m))
|
||||
cutplane.Placement = cutplane.Placement.multiply(obj.Base.Placement)
|
||||
if objs:
|
||||
onlysolids = True
|
||||
# TODO Fix this : 2025.1.26, why test obj.Base.OnlySolids if override by obj.OnlySolids
|
||||
if hasattr(obj.Base,"OnlySolids"):
|
||||
if hasattr(obj.Base, "OnlySolids"):
|
||||
onlysolids = obj.Base.OnlySolids
|
||||
if hasattr(obj,"OnlySolids"): # override base object
|
||||
if hasattr(obj, "OnlySolids"): # override base object
|
||||
onlysolids = obj.OnlySolids
|
||||
try:
|
||||
import Arch
|
||||
@@ -243,17 +252,20 @@ class Shape2DView(DraftObject):
|
||||
print("Shape2DView: BIM not present, unable to recompute")
|
||||
return
|
||||
objs = groups.get_group_contents(objs, walls=True)
|
||||
if getattr(obj,"VisibleOnly",True):
|
||||
if getattr(obj, "VisibleOnly", True):
|
||||
objs = gui_utils.remove_hidden(objs)
|
||||
shapes = []
|
||||
if getattr(obj,"FuseArch", False):
|
||||
if getattr(obj, "FuseArch", False):
|
||||
shtypes = {}
|
||||
for o in objs:
|
||||
if utils.get_type(o) in ["Wall","Structure"]:
|
||||
if utils.get_type(o) in ["Wall", "Structure"]:
|
||||
shtypes.setdefault(
|
||||
o.Material.Name
|
||||
if (hasattr(o,"Material") and o.Material) else "None",
|
||||
[]
|
||||
(
|
||||
o.Material.Name
|
||||
if (hasattr(o, "Material") and o.Material)
|
||||
else "None"
|
||||
),
|
||||
[],
|
||||
).extend(self._get_shapes(o.Shape, onlysolids))
|
||||
elif hasattr(o, "Shape"):
|
||||
shapes.extend(self._get_shapes(o.Shape, onlysolids))
|
||||
@@ -281,18 +293,18 @@ class Shape2DView(DraftObject):
|
||||
shapes.extend(self._get_shapes(o.Shape, onlysolids))
|
||||
clip = False
|
||||
# TODO Fix this : 2025.1.26, why test obj.Base.Clip if override by obj.Clip
|
||||
if hasattr(obj.Base,"Clip"):
|
||||
if hasattr(obj.Base, "Clip"):
|
||||
clip = obj.Base.Clip
|
||||
if hasattr(obj,"Clip"): #override base object
|
||||
if hasattr(obj, "Clip"): # override base object
|
||||
clip = obj.Clip
|
||||
depth = None
|
||||
if hasattr(obj.Base,"Depth"):
|
||||
if hasattr(obj.Base, "Depth"):
|
||||
depth = obj.Base.Depth.Value
|
||||
cutp, cutv, iv = Arch.getCutVolume(cutplane, shapes, clip, depth)
|
||||
cuts = []
|
||||
opl = App.Placement(obj.Base.Placement)
|
||||
proj = opl.Rotation.multVec(App.Vector(0, 0, 1))
|
||||
if obj.ProjectionMode in ["Solid","Solid faces"]:
|
||||
if obj.ProjectionMode in ["Solid", "Solid faces"]:
|
||||
shapes_to_cut = shapes
|
||||
if obj.ProjectionMode == "Solid faces":
|
||||
shapes_to_cut = []
|
||||
@@ -302,9 +314,9 @@ class Shape2DView(DraftObject):
|
||||
if cutv and (not cutv.isNull()) and (not sh.isNull()):
|
||||
if sh.Volume < 0:
|
||||
sh.reverse()
|
||||
#if cutv.BoundBox.intersect(sh.BoundBox):
|
||||
# if cutv.BoundBox.intersect(sh.BoundBox):
|
||||
# c = sh.cut(cutv)
|
||||
#else:
|
||||
# else:
|
||||
# c = sh.copy()
|
||||
try:
|
||||
c = sh.cut(cutv)
|
||||
@@ -316,7 +328,7 @@ class Shape2DView(DraftObject):
|
||||
else:
|
||||
cuts.extend(self._get_shapes(sh, onlysolids))
|
||||
comp = Part.makeCompound(cuts)
|
||||
obj.Shape = self.getProjected(obj,comp,proj)
|
||||
obj.Shape = self.getProjected(obj, comp, proj)
|
||||
elif obj.ProjectionMode in ["Cutlines", "Cutfaces"]:
|
||||
if not cutp: # Cutfaces and Cutlines needs cutp
|
||||
obj.Shape = Part.Shape()
|
||||
@@ -332,7 +344,7 @@ class Shape2DView(DraftObject):
|
||||
facesOrg = sc.Faces
|
||||
if not facesOrg:
|
||||
continue
|
||||
if hasattr(obj,"InPlace"):
|
||||
if hasattr(obj, "InPlace"):
|
||||
if obj.InPlace:
|
||||
faces = facesOrg
|
||||
# Alternative approach in https://forum.freecad.org/viewtopic.php?p=807314#p807314, not adopted
|
||||
@@ -340,7 +352,7 @@ class Shape2DView(DraftObject):
|
||||
for faceOrg in facesOrg:
|
||||
if len(faceOrg.Wires) == 1:
|
||||
wireProj = self.getProjected(obj, faceOrg, proj)
|
||||
#return Compound
|
||||
# return Compound
|
||||
wireProjWire = Part.Wire(wireProj.Edges)
|
||||
faceProj = Part.Face(wireProjWire)
|
||||
elif len(faceOrg.Wires) == 2:
|
||||
@@ -349,22 +361,28 @@ class Shape2DView(DraftObject):
|
||||
if not w.isEqual(wireClosedOuter):
|
||||
wireClosedInner = w
|
||||
break
|
||||
wireProjOuter = self.getProjected(obj, wireClosedOuter, proj)
|
||||
#return Compound
|
||||
wireProjOuter = self.getProjected(
|
||||
obj, wireClosedOuter, proj
|
||||
)
|
||||
# return Compound
|
||||
wireProjOuterWire = Part.Wire(wireProjOuter.Edges)
|
||||
faceProj = Part.Face(wireProjOuterWire)
|
||||
wireProjInner = self.getProjected(obj, wireClosedInner, proj)
|
||||
#return Compound
|
||||
wireProjInner = self.getProjected(
|
||||
obj, wireClosedInner, proj
|
||||
)
|
||||
# return Compound
|
||||
wireProjInnerWire = Part.Wire(wireProjInner.Edges)
|
||||
faceProj.cutHoles([wireProjInnerWire]) # (list of wires)
|
||||
faceProj.cutHoles(
|
||||
[wireProjInnerWire]
|
||||
) # (list of wires)
|
||||
faces.append(faceProj)
|
||||
else:
|
||||
c = sh.section(cutp)
|
||||
if hasattr(obj,"InPlace"):
|
||||
if hasattr(obj, "InPlace"):
|
||||
if not obj.InPlace:
|
||||
c = self.getProjected(obj, c, proj)
|
||||
#faces = []
|
||||
#if (obj.ProjectionMode == "Cutfaces") and (sh.ShapeType == "Solid"):
|
||||
# faces = []
|
||||
# if (obj.ProjectionMode == "Cutfaces") and (sh.ShapeType == "Solid"):
|
||||
# wires = DraftGeomUtils.findWires(c.Edges)
|
||||
# for w in wires:
|
||||
# if w.isClosed():
|
||||
@@ -381,21 +399,23 @@ class Shape2DView(DraftObject):
|
||||
|
||||
elif obj.Base.isDerivedFrom("App::DocumentObjectGroup"):
|
||||
shapes = []
|
||||
objs = self.excludeNames(obj,groups.get_group_contents(obj.Base))
|
||||
objs = self.excludeNames(obj, groups.get_group_contents(obj.Base))
|
||||
for o in objs:
|
||||
if hasattr(o, "Shape"):
|
||||
shapes.extend(self._get_shapes(o.Shape))
|
||||
if shapes:
|
||||
import Part
|
||||
|
||||
comp = Part.makeCompound(shapes)
|
||||
obj.Shape = self.getProjected(obj,comp,obj.Projection)
|
||||
obj.Shape = self.getProjected(obj, comp, obj.Projection)
|
||||
|
||||
elif hasattr(obj.Base, "Shape"):
|
||||
if not DraftVecUtils.isNull(obj.Projection):
|
||||
if obj.ProjectionMode == "Solid":
|
||||
obj.Shape = self.getProjected(obj,obj.Base.Shape,obj.Projection)
|
||||
obj.Shape = self.getProjected(obj, obj.Base.Shape, obj.Projection)
|
||||
elif obj.ProjectionMode == "Individual Faces":
|
||||
import Part
|
||||
|
||||
if obj.FaceNumbers:
|
||||
faces = []
|
||||
for i in obj.FaceNumbers:
|
||||
@@ -403,11 +423,11 @@ class Shape2DView(DraftObject):
|
||||
faces.append(obj.Base.Shape.Faces[i])
|
||||
views = []
|
||||
for f in faces:
|
||||
views.append(self.getProjected(obj,f,obj.Projection))
|
||||
views.append(self.getProjected(obj, f, obj.Projection))
|
||||
if views:
|
||||
obj.Shape = Part.makeCompound(views)
|
||||
else:
|
||||
App.Console.PrintWarning(obj.ProjectionMode+" mode not implemented\n")
|
||||
App.Console.PrintWarning(obj.ProjectionMode + " mode not implemented\n")
|
||||
|
||||
obj.Placement = pl
|
||||
obj.positionBySupport()
|
||||
|
||||
@@ -66,24 +66,41 @@ class ShapeString(DraftObject):
|
||||
if "Justification" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Horizontal and vertical alignment")
|
||||
obj.addProperty("App::PropertyEnumeration", "Justification", "Draft", _tip, locked=True)
|
||||
obj.Justification = ["Top-Left", "Top-Center", "Top-Right",
|
||||
"Middle-Left", "Middle-Center", "Middle-Right",
|
||||
"Bottom-Left", "Bottom-Center", "Bottom-Right"]
|
||||
obj.Justification = [
|
||||
"Top-Left",
|
||||
"Top-Center",
|
||||
"Top-Right",
|
||||
"Middle-Left",
|
||||
"Middle-Center",
|
||||
"Middle-Right",
|
||||
"Bottom-Left",
|
||||
"Bottom-Center",
|
||||
"Bottom-Right",
|
||||
]
|
||||
obj.Justification = "Bottom-Left"
|
||||
|
||||
if "JustificationReference" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Height reference used for justification")
|
||||
obj.addProperty("App::PropertyEnumeration", "JustificationReference", "Draft", _tip, locked=True)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "JustificationReference", "Draft", _tip, locked=True
|
||||
)
|
||||
obj.JustificationReference = ["Cap Height", "Shape Height"]
|
||||
obj.JustificationReference = "Cap Height"
|
||||
|
||||
if "KeepLeftMargin" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Keep left margin and leading white space when justification is left")
|
||||
obj.addProperty("App::PropertyBool", "KeepLeftMargin", "Draft", _tip, locked=True).KeepLeftMargin = False
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Keep left margin and leading white space when justification is left",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "KeepLeftMargin", "Draft", _tip, locked=True
|
||||
).KeepLeftMargin = False
|
||||
|
||||
if "ScaleToSize" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Scale to ensure cap height is equal to size")
|
||||
obj.addProperty("App::PropertyBool", "ScaleToSize", "Draft", _tip, locked=True).ScaleToSize = True
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "ScaleToSize", "Draft", _tip, locked=True
|
||||
).ScaleToSize = True
|
||||
|
||||
if "Tracking" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Inter-character spacing")
|
||||
@@ -95,10 +112,15 @@ class ShapeString(DraftObject):
|
||||
|
||||
if "MakeFace" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Fill letters with faces")
|
||||
obj.addProperty("App::PropertyBool", "MakeFace", "Draft", _tip, locked=True).MakeFace = True
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "MakeFace", "Draft", _tip, locked=True
|
||||
).MakeFace = True
|
||||
|
||||
if "Fuse" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Fuse faces if faces overlap, usually not required (can be very slow)")
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"Fuse faces if faces overlap, usually not required (can be very slow)",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Fuse", "Draft", _tip, locked=True).Fuse = False
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
@@ -106,12 +128,12 @@ class ShapeString(DraftObject):
|
||||
gui_utils.restore_view_object(
|
||||
obj, vp_module="view_shapestring", vp_class="ViewProviderShapeString"
|
||||
)
|
||||
if not hasattr(obj, "ObliqueAngle"): # several more properties were added
|
||||
if not hasattr(obj, "ObliqueAngle"): # several more properties were added
|
||||
self.update_properties_1v0(obj)
|
||||
|
||||
def update_properties_1v0(self, obj):
|
||||
"""Update view properties."""
|
||||
old_tracking = obj.Tracking # no need for obj.getTypeIdOfProperty("Tracking")
|
||||
old_tracking = obj.Tracking # no need for obj.getTypeIdOfProperty("Tracking")
|
||||
obj.removeProperty("Tracking")
|
||||
self.set_properties(obj)
|
||||
obj.KeepLeftMargin = True
|
||||
@@ -123,13 +145,11 @@ class ShapeString(DraftObject):
|
||||
+ ", "
|
||||
+ "added 'Fuse', 'Justification', 'JustificationReference', 'KeepLeftMargin', "
|
||||
+ "'ObliqueAngle' and 'ScaleToSize' properties"
|
||||
)
|
||||
)
|
||||
_log("v1.0, " + obj.Name + ", changed 'Tracking' property type")
|
||||
|
||||
def execute(self, obj):
|
||||
if self.props_changed_placement_only() \
|
||||
or not obj.String \
|
||||
or not obj.FontFile:
|
||||
if self.props_changed_placement_only() or not obj.String or not obj.FontFile:
|
||||
obj.positionBySupport()
|
||||
self.props_changed_clear()
|
||||
return
|
||||
@@ -174,10 +194,11 @@ class ShapeString(DraftObject):
|
||||
# https://github.com/FreeCAD/FreeCAD/issues/21501
|
||||
char_comp = Part.Compound(char)
|
||||
factor = 1 / char_comp.BoundBox.YLength
|
||||
fill = sum([shape.Area for shape in shapes]) > (0.03 / factor ** 2) \
|
||||
and math.isclose(char_comp.BoundBox.DiagonalLength,
|
||||
Part.Compound(shapes).BoundBox.DiagonalLength,
|
||||
rel_tol=1e-7)
|
||||
fill = sum([shape.Area for shape in shapes]) > (0.03 / factor**2) and math.isclose(
|
||||
char_comp.BoundBox.DiagonalLength,
|
||||
Part.Compound(shapes).BoundBox.DiagonalLength,
|
||||
rel_tol=1e-7,
|
||||
)
|
||||
|
||||
chars = Part.makeWireString(obj.String, font_file, obj.Size, obj.Tracking)
|
||||
shapes = []
|
||||
@@ -208,13 +229,21 @@ class ShapeString(DraftObject):
|
||||
mtx.A12 = math.tan(math.radians(obj.ObliqueAngle))
|
||||
ss_shape = ss_shape.transformGeometry(mtx)
|
||||
else:
|
||||
wrn = translate("draft", "ShapeString: oblique angle must be in the -80 to +80 degree range") + "\n"
|
||||
wrn = (
|
||||
translate(
|
||||
"draft",
|
||||
"ShapeString: oblique angle must be in the -80 to +80 degree range",
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
App.Console.PrintWarning(wrn)
|
||||
just_vec = self.justification_vector(ss_shape,
|
||||
cap_height,
|
||||
obj.Justification,
|
||||
obj.JustificationReference,
|
||||
obj.KeepLeftMargin)
|
||||
just_vec = self.justification_vector(
|
||||
ss_shape,
|
||||
cap_height,
|
||||
obj.Justification,
|
||||
obj.JustificationReference,
|
||||
obj.KeepLeftMargin,
|
||||
)
|
||||
shapes = ss_shape.SubShapes
|
||||
for shape in shapes:
|
||||
shape.translate(just_vec)
|
||||
@@ -229,13 +258,17 @@ class ShapeString(DraftObject):
|
||||
def onChanged(self, obj, prop):
|
||||
self.props_changed_store(prop)
|
||||
|
||||
def justification_vector(self, ss_shape, cap_height, just, just_ref, keep_left_margin): # ss_shape is a compound
|
||||
def justification_vector(
|
||||
self, ss_shape, cap_height, just, just_ref, keep_left_margin
|
||||
): # ss_shape is a compound
|
||||
box = ss_shape.optimalBoundingBox()
|
||||
if keep_left_margin is True and "Left" in just:
|
||||
vec = App.Vector(0, 0, 0)
|
||||
else:
|
||||
vec = App.Vector(-box.XMin, 0, 0) # remove left margin caused by kerning and white space characters
|
||||
width = box.XLength
|
||||
vec = App.Vector(
|
||||
-box.XMin, 0, 0
|
||||
) # remove left margin caused by kerning and white space characters
|
||||
width = box.XLength
|
||||
if "Shape" in just_ref:
|
||||
vec = vec + App.Vector(0, -box.YMin, 0)
|
||||
height = box.YLength
|
||||
@@ -244,11 +277,11 @@ class ShapeString(DraftObject):
|
||||
if "Top" in just:
|
||||
vec = vec + App.Vector(0, -height, 0)
|
||||
elif "Middle" in just:
|
||||
vec = vec + App.Vector(0, -height/2, 0)
|
||||
vec = vec + App.Vector(0, -height / 2, 0)
|
||||
if "Right" in just:
|
||||
vec = vec + App.Vector(-width, 0, 0)
|
||||
elif "Center" in just:
|
||||
vec = vec + App.Vector(-width/2, 0, 0)
|
||||
vec = vec + App.Vector(-width / 2, 0, 0)
|
||||
return vec
|
||||
|
||||
def make_faces(self, wireChar):
|
||||
@@ -307,7 +340,7 @@ class ShapeString(DraftObject):
|
||||
for face in faces:
|
||||
try:
|
||||
# some fonts fail here
|
||||
if face.normalAt(0, 0).z < 0: # Does not seem to occur for FaceMakerBullseye.
|
||||
if face.normalAt(0, 0).z < 0: # Does not seem to occur for FaceMakerBullseye.
|
||||
face.reverse()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -49,30 +49,24 @@ class Text(DraftAnnotation):
|
||||
properties = obj.PropertiesList
|
||||
|
||||
if "Placement" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The placement of the base point "
|
||||
"of the first line")
|
||||
obj.addProperty("App::PropertyPlacement",
|
||||
"Placement",
|
||||
"Base",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The placement of the base point " "of the first line"
|
||||
)
|
||||
obj.addProperty("App::PropertyPlacement", "Placement", "Base", _tip, locked=True)
|
||||
obj.Placement = App.Placement()
|
||||
|
||||
if "Text" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The text displayed by this object.\n"
|
||||
"It is a list of strings; each element "
|
||||
"in the list will be displayed "
|
||||
"in its own line.")
|
||||
obj.addProperty("App::PropertyStringList",
|
||||
"Text",
|
||||
"Base",
|
||||
_tip,
|
||||
locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The text displayed by this object.\n"
|
||||
"It is a list of strings; each element "
|
||||
"in the list will be displayed "
|
||||
"in its own line.",
|
||||
)
|
||||
obj.addProperty("App::PropertyStringList", "Text", "Base", _tip, locked=True)
|
||||
obj.Text = []
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Execute code when the document is restored."""
|
||||
super().onDocumentRestored(obj)
|
||||
gui_utils.restore_view_object(obj, vp_module="view_text", vp_class="ViewProviderText")
|
||||
|
||||
@@ -45,53 +45,45 @@ class Wire(DraftObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj, "Wire")
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The vertices of the wire")
|
||||
obj.addProperty("App::PropertyVectorList","Points", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The vertices of the wire")
|
||||
obj.addProperty("App::PropertyVectorList", "Points", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If the wire is closed or not")
|
||||
obj.addProperty("App::PropertyBool","Closed", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "If the wire is closed or not")
|
||||
obj.addProperty("App::PropertyBool", "Closed", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The base object is the wire, it's formed from 2 objects")
|
||||
obj.addProperty("App::PropertyLink","Base", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The base object is the wire, it's formed from 2 objects"
|
||||
)
|
||||
obj.addProperty("App::PropertyLink", "Base", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The tool object is the wire, it's formed from 2 objects")
|
||||
obj.addProperty("App::PropertyLink","Tool", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The tool object is the wire, it's formed from 2 objects"
|
||||
)
|
||||
obj.addProperty("App::PropertyLink", "Tool", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The start point of this line")
|
||||
obj.addProperty("App::PropertyVectorDistance","Start", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The start point of this line")
|
||||
obj.addProperty("App::PropertyVectorDistance", "Start", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The end point of this line")
|
||||
obj.addProperty("App::PropertyVectorDistance","End", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The end point of this line")
|
||||
obj.addProperty("App::PropertyVectorDistance", "End", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The length of this line")
|
||||
obj.addProperty("App::PropertyLength","Length", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The length of this line")
|
||||
obj.addProperty("App::PropertyLength", "Length", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Radius to use to fillet the corners")
|
||||
obj.addProperty("App::PropertyLength","FilletRadius", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Radius to use to fillet the corners")
|
||||
obj.addProperty("App::PropertyLength", "FilletRadius", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Size of the chamfer to give to the corners")
|
||||
obj.addProperty("App::PropertyLength","ChamferSize", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Size of the chamfer to give to the corners")
|
||||
obj.addProperty("App::PropertyLength", "ChamferSize", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"Create a face if this object is closed")
|
||||
obj.addProperty("App::PropertyBool","MakeFace", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "Create a face if this object is closed")
|
||||
obj.addProperty("App::PropertyBool", "MakeFace", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The number of subdivisions of each edge")
|
||||
obj.addProperty("App::PropertyInteger","Subdivisions", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The number of subdivisions of each edge")
|
||||
obj.addProperty("App::PropertyInteger", "Subdivisions", "Draft", _tip, locked=True)
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The area of this object")
|
||||
obj.addProperty("App::PropertyArea","Area", "Draft",_tip, locked=True)
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The area of this object")
|
||||
obj.addProperty("App::PropertyArea", "Area", "Draft", _tip, locked=True)
|
||||
|
||||
obj.MakeFace = params.get_param("MakeFaceMode")
|
||||
obj.Closed = False
|
||||
@@ -126,23 +118,26 @@ class Wire(DraftObject):
|
||||
_log("v1.1, " + obj.Name + ", migrated view properties")
|
||||
|
||||
def execute(self, obj):
|
||||
if self.props_changed_placement_only(obj): # Supplying obj is required because of `Base` and `Tool`.
|
||||
if self.props_changed_placement_only(
|
||||
obj
|
||||
): # Supplying obj is required because of `Base` and `Tool`.
|
||||
obj.positionBySupport()
|
||||
self.update_start_end(obj)
|
||||
self.props_changed_clear()
|
||||
return
|
||||
|
||||
import Part
|
||||
|
||||
plm = obj.Placement
|
||||
if obj.Base and (not obj.Tool):
|
||||
if obj.Base.isDerivedFrom("Sketcher::SketchObject"):
|
||||
shape = obj.Base.Shape.copy()
|
||||
if obj.Base.Shape.isClosed():
|
||||
if getattr(obj,"MakeFace",True):
|
||||
if getattr(obj, "MakeFace", True):
|
||||
shape = Part.Face(shape)
|
||||
obj.Shape = shape
|
||||
elif obj.Base and obj.Tool:
|
||||
if hasattr(obj.Base,'Shape') and hasattr(obj.Tool,'Shape'):
|
||||
if hasattr(obj.Base, "Shape") and hasattr(obj.Tool, "Shape"):
|
||||
if (not obj.Base.Shape.isNull()) and (not obj.Tool.Shape.isNull()):
|
||||
sh1 = obj.Base.Shape.copy()
|
||||
sh2 = obj.Tool.Shape.copy()
|
||||
@@ -151,41 +146,44 @@ class Wire(DraftObject):
|
||||
shape = DraftGeomUtils.concatenate(shape)
|
||||
obj.Shape = shape
|
||||
p = []
|
||||
for v in shape.Vertexes: p.append(v.Point)
|
||||
if obj.Points != p: obj.Points = p
|
||||
for v in shape.Vertexes:
|
||||
p.append(v.Point)
|
||||
if obj.Points != p:
|
||||
obj.Points = p
|
||||
elif obj.Points:
|
||||
if obj.Points[0] == obj.Points[-1]:
|
||||
if not obj.Closed: obj.Closed = True
|
||||
if not obj.Closed:
|
||||
obj.Closed = True
|
||||
obj.Points.pop()
|
||||
if obj.Closed and (len(obj.Points) > 2):
|
||||
pts = obj.Points
|
||||
if getattr(obj,"Subdivisions",0) > 0:
|
||||
if getattr(obj, "Subdivisions", 0) > 0:
|
||||
npts = []
|
||||
for i in range(len(pts)):
|
||||
p1 = pts[i]
|
||||
npts.append(pts[i])
|
||||
if i == len(pts)-1:
|
||||
if i == len(pts) - 1:
|
||||
p2 = pts[0]
|
||||
else:
|
||||
p2 = pts[i+1]
|
||||
p2 = pts[i + 1]
|
||||
v = p2.sub(p1)
|
||||
v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
|
||||
v = DraftVecUtils.scaleTo(v, v.Length / (obj.Subdivisions + 1))
|
||||
for j in range(obj.Subdivisions):
|
||||
npts.append(p1.add(App.Vector(v).multiply(j+1)))
|
||||
npts.append(p1.add(App.Vector(v).multiply(j + 1)))
|
||||
pts = npts
|
||||
shape = Part.makePolygon(pts+[pts[0]])
|
||||
shape = Part.makePolygon(pts + [pts[0]])
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.ChamferSize.Value,chamfer=True)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.ChamferSize.Value, chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.FilletRadius.Value)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
try:
|
||||
if getattr(obj,"MakeFace",True):
|
||||
if getattr(obj, "MakeFace", True):
|
||||
shape = Part.Face(shape)
|
||||
except Part.OCCError:
|
||||
pass
|
||||
@@ -194,18 +192,18 @@ class Wire(DraftObject):
|
||||
pts = obj.Points[1:]
|
||||
lp = obj.Points[0]
|
||||
for p in pts:
|
||||
if not DraftVecUtils.equals(lp,p):
|
||||
if getattr(obj,"Subdivisions",0) > 0:
|
||||
if not DraftVecUtils.equals(lp, p):
|
||||
if getattr(obj, "Subdivisions", 0) > 0:
|
||||
npts = []
|
||||
v = p.sub(lp)
|
||||
v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
|
||||
edges.append(Part.LineSegment(lp,lp.add(v)).toShape())
|
||||
v = DraftVecUtils.scaleTo(v, v.Length / (obj.Subdivisions + 1))
|
||||
edges.append(Part.LineSegment(lp, lp.add(v)).toShape())
|
||||
lv = lp.add(v)
|
||||
for j in range(obj.Subdivisions):
|
||||
edges.append(Part.LineSegment(lv,lv.add(v)).toShape())
|
||||
edges.append(Part.LineSegment(lv, lv.add(v)).toShape())
|
||||
lv = lv.add(v)
|
||||
else:
|
||||
edges.append(Part.LineSegment(lp,p).toShape())
|
||||
edges.append(Part.LineSegment(lp, p).toShape())
|
||||
lp = p
|
||||
try:
|
||||
shape = Part.Wire(edges)
|
||||
@@ -214,19 +212,19 @@ class Wire(DraftObject):
|
||||
shape = None
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.ChamferSize.Value,chamfer=True)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.ChamferSize.Value, chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.FilletRadius.Value)
|
||||
w = DraftGeomUtils.filletWire(shape, obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
if shape:
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
if hasattr(obj, "Area") and hasattr(shape, "Area"):
|
||||
obj.Area = shape.Area
|
||||
if hasattr(obj,"Length"):
|
||||
if hasattr(obj, "Length"):
|
||||
obj.Length = shape.Length
|
||||
|
||||
obj.Placement = plm
|
||||
|
||||
@@ -36,13 +36,13 @@ from draftutils import gui_utils
|
||||
class WorkingPlaneProxy:
|
||||
"""The Draft working plane proxy object"""
|
||||
|
||||
def __init__(self,obj):
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property", "The placement of this object")
|
||||
obj.addProperty("App::PropertyPlacement", "Placement", "Base", _tip, locked=True)
|
||||
|
||||
obj.addProperty("Part::PropertyPartShape","Shape","Base","", locked=True)
|
||||
obj.addProperty("Part::PropertyPartShape", "Shape", "Base", "", locked=True)
|
||||
|
||||
obj.addExtension("Part::AttachExtensionPython")
|
||||
obj.changeAttacherType("Attacher::AttachEnginePlane")
|
||||
@@ -54,33 +54,32 @@ class WorkingPlaneProxy:
|
||||
obj, vp_module="view_wpproxy", vp_class="ViewProviderWorkingPlaneProxy", format=False
|
||||
)
|
||||
|
||||
def execute(self,obj):
|
||||
def execute(self, obj):
|
||||
import Part
|
||||
|
||||
l = 1
|
||||
if obj.ViewObject:
|
||||
if hasattr(obj.ViewObject,"DisplaySize"):
|
||||
if hasattr(obj.ViewObject, "DisplaySize"):
|
||||
l = obj.ViewObject.DisplaySize.Value
|
||||
p = Part.makePlane(l,
|
||||
l,
|
||||
App.Vector(l/2, -l/2, 0),
|
||||
App.Vector(0, 0, -1))
|
||||
p = Part.makePlane(l, l, App.Vector(l / 2, -l / 2, 0), App.Vector(0, 0, -1))
|
||||
# make sure the normal direction is pointing outwards, you never know what OCC will decide...
|
||||
if p.normalAt(0,0).getAngle(obj.Placement.Rotation.multVec(App.Vector(0,0,1))) > 1:
|
||||
if p.normalAt(0, 0).getAngle(obj.Placement.Rotation.multVec(App.Vector(0, 0, 1))) > 1:
|
||||
p.reverse()
|
||||
p.Placement = obj.Placement
|
||||
obj.Shape = p
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
def onChanged(self, obj, prop):
|
||||
pass
|
||||
|
||||
def getNormal(self,obj):
|
||||
return obj.Shape.Faces[0].normalAt(0,0)
|
||||
def getNormal(self, obj):
|
||||
return obj.Shape.Faces[0].normalAt(0, 0)
|
||||
|
||||
def dumps(self):
|
||||
return self.Type
|
||||
|
||||
def loads(self,state):
|
||||
def loads(self, state):
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
Reference in New Issue
Block a user