File size: 9,566 Bytes
985c397 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | # SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
# * Copyright (c) 2018 Benjamin Alterauge (ageeye) *
# * Copyright (c) 2020 Carlo Pavan <carlopav@gmail.com> *
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
# * *
# * 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 *
# * *
# ***************************************************************************
"""Provides the object code for the PointArray object."""
## @package pointarray
# \ingroup draftobjects
# \brief Provides the object code for the PointArray object.
from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD as App
import DraftVecUtils
import draftutils.utils as utils
from draftutils.messages import _err, _log
from draftutils.translate import translate
from draftobjects.draftlink import DraftLink
## \addtogroup draftobjects
# @{
class PointArray(DraftLink):
"""The Draft Point Array object."""
def __init__(self, obj):
super().__init__(obj, "PointArray")
def attach(self, obj):
"""Set up the properties when the object is attached."""
self.set_properties(obj)
super().attach(obj)
def linkSetup(self, obj):
"""Set up the object as a link object."""
super().linkSetup(obj)
obj.configLinkProperty(ElementCount="Count")
def set_properties(self, obj):
"""Set properties only if they don't exist."""
properties = obj.PropertiesList
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.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)
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)
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)
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
)
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")
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
)
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:
self.props_changed_clear()
return
pt_list = get_point_list(obj.PointObject)
obj.Count = len(pt_list)
pls = build_placements(obj.Base, pt_list, obj.ExtraPlacement)
self.buildShape(obj, obj.Placement, pls)
self.props_changed_clear()
return not self.use_link
def onDocumentRestored(self, obj):
super().onDocumentRestored(obj)
# Fuse property was added in v1.0 and PlacementList property was added
# for non-link arrays in v1.1, obj should be OK if both are present:
if hasattr(obj, "Fuse") and hasattr(obj, "PlacementList"):
return
if not hasattr(obj, "ExtraPlacement"):
_log("v0.19, " + obj.Name + ", added 'ExtraPlacement' property")
if hasattr(obj, "PointList"):
_log("v0.19, " + obj.Name + ", migrated 'PointList' property to 'PointObject'")
if not hasattr(obj, "Fuse"):
_log("v1.0, " + obj.Name + ", added 'Fuse' property")
if not hasattr(obj, "PlacementList"):
_log("v1.1, " + obj.Name + ", added hidden property 'PlacementList'")
self.set_properties(obj)
if hasattr(obj, "PointList"):
obj.PointObject = obj.PointList
obj.removeProperty("PointList")
self.execute(obj) # Required to update PlacementList.
def remove_equal_vecs(vec_list):
"""Remove equal vectors from a list.
Parameters
----------
vec_list: list of App.Vectors
Returns
-------
list of App.Vectors
"""
res_list = []
for vec in vec_list:
for res in res_list:
if DraftVecUtils.equals(vec, res):
break
else:
res_list.append(vec)
return res_list
def get_point_list(point_object):
"""Extract a list of points from a point object.
Parameters
----------
point_object: Part::Feature, Sketcher::SketchObject, Mesh::Feature
or Points::FeatureCustom
The object must have vertices and/or points.
Returns
-------
list of App.Vectors
"""
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"):
place = point_object.Placement
for geo in point_object.Geometry:
if geo.TypeId == "Part::GeomPoint":
pt_list.append(place.multVec(App.Vector(geo.X, geo.Y, geo.Z)))
elif hasattr(point_object, "Mesh"):
pt_list = [p.Vector for p in point_object.Mesh.Points]
elif hasattr(point_object, "Points"):
pt_list = point_object.Points.Points
else:
return []
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.
Returns
-------
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",
)
)
return []
pls = list()
for point in pt_list:
new_pla = base_object.Placement.copy()
original_rotation = new_pla.Rotation
# Reset the position of the copy, and combine the original rotation
# with the provided rotation. Two rotations (quaternions)
# are combined by multiplying them.
new_pla.Base = placement.Base
new_pla.Rotation = original_rotation * placement.Rotation
new_pla.translate(point)
pls.append(new_pla)
return pls
# Alias for compatibility with v0.18 and earlier
_PointArray = PointArray
## @}
|