diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index ab2c29f011..37233ffba4 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -91,6 +91,7 @@ SET(Draft_make_functions draftmake/make_facebinder.py draftmake/make_fillet.py draftmake/make_line.py + draftmake/make_patharray.py draftmake/make_polygon.py draftmake/make_point.py draftmake/make_rectangle.py @@ -120,6 +121,7 @@ SET(Draft_objects draftobjects/draftlink.py draftobjects/label.py draftobjects/dimension.py + draftobjects/patharray.py draftobjects/point.py draftobjects/polygon.py draftobjects/rectangle.py @@ -133,6 +135,7 @@ SET(Draft_objects SET(Draft_view_providers draftviewproviders/__init__.py + draftviewproviders/view_array.py draftviewproviders/view_base.py draftviewproviders/view_bezcurve.py draftviewproviders/view_bspline.py diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 3eb33281c1..7397471b2e 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -304,6 +304,13 @@ if FreeCAD.GuiUp: from draftviewproviders.view_point import ViewProviderPoint from draftviewproviders.view_point import _ViewProviderPoint +# arrays +from draftmake.make_patharray import make_path_array, makePathArray +from draftobjects.patharray import PathArray, _PathArray +if FreeCAD.GuiUp: + from draftviewproviders.view_array import ViewProviderDraftArray + from draftviewproviders.view_array import _ViewProviderDraftArray + # facebinder from draftmake.make_facebinder import make_facebinder, makeFacebinder from draftobjects.facebinder import Facebinder, _Facebinder @@ -471,44 +478,6 @@ def makeArray(baseobject,arg1,arg2,arg3,arg4=None,arg5=None,arg6=None,name="Arra select(obj) return obj -def makePathArray(baseobject,pathobject,count,xlate=None,align=False,pathobjsubs=[],use_link=False): - """makePathArray(docobj,path,count,xlate,align,pathobjsubs,use_link): distribute - count copies of a document baseobject along a pathobject or subobjects of a - pathobject. Optionally translates each copy by FreeCAD.Vector xlate direction - and distance to adjust for difference in shape centre vs shape reference point. - Optionally aligns baseobject to tangent/normal/binormal of path.""" - if not FreeCAD.ActiveDocument: - FreeCAD.Console.PrintError("No active document. Aborting\n") - return - if use_link: - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","PathArray",_PathArray(None),None,True) - else: - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","PathArray") - _PathArray(obj) - obj.Base = baseobject - obj.PathObj = pathobject - if pathobjsubs: - sl = [] - for sub in pathobjsubs: - sl.append((obj.PathObj,sub)) - obj.PathSubs = list(sl) - if count > 1: - obj.Count = count - if xlate: - obj.Xlate = xlate - obj.Align = align - if gui: - if use_link: - _ViewProviderDraftLink(obj.ViewObject) - else: - _ViewProviderDraftArray(obj.ViewObject) - formatObject(obj,obj.Base) - if len(obj.Base.ViewObject.DiffuseColor) > 1: - obj.ViewObject.Proxy.resetColors(obj.ViewObject) - baseobject.ViewObject.hide() - select(obj) - return obj - def makePointArray(base, ptlst): """makePointArray(base,pointlist):""" obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","PointArray") @@ -667,124 +636,6 @@ def makeDrawingView(obj,page,lwmod=None,tmod=None,otherProjection=None): -def getParameterFromV0(edge, offset): - """return parameter at distance offset from edge.Vertexes[0] - sb method in Part.TopoShapeEdge???""" - - lpt = edge.valueAt(edge.getParameterByLength(0)) - vpt = edge.Vertexes[0].Point - - if not DraftVecUtils.equals(vpt, lpt): - # this edge is flipped - length = edge.Length - offset - else: - # this edge is right way around - length = offset - - return (edge.getParameterByLength(length)) - - -def calculatePlacement(globalRotation, edge, offset, RefPt, xlate, align, normal=None): - """Orient shape to tangent at parm offset along edge.""" - import functools - # http://en.wikipedia.org/wiki/Euler_angles - # start with null Placement point so translate goes to right place. - placement = FreeCAD.Placement() - # preserve global orientation - placement.Rotation = globalRotation - - placement.move(RefPt + xlate) - - if not align: - return placement - - nullv = FreeCAD.Vector(0, 0, 0) - - # get a local coord system (tangent, normal, binormal) at parameter offset (normally length) - t = edge.tangentAt(getParameterFromV0(edge, offset)) - t.normalize() - - try: - n = edge.normalAt(getParameterFromV0(edge, offset)) - n.normalize() - b = (t.cross(n)) - b.normalize() - # no normal defined here - except FreeCAD.Base.FreeCADError: - n = nullv - b = nullv - FreeCAD.Console.PrintMessage( - "Draft PathArray.orientShape - Cannot calculate Path normal.\n") - - priority = "ZXY" #the default. Doesn't seem to affect results. - newRot = FreeCAD.Rotation(t, n, b, priority); - newGRot = newRot.multiply(globalRotation) - - placement.Rotation = newGRot - return placement - - -def calculatePlacementsOnPath(shapeRotation, pathwire, count, xlate, align): - """Calculates the placements of a shape along a given path so that each copy will be distributed evenly""" - import Part - import DraftGeomUtils - - closedpath = DraftGeomUtils.isReallyClosed(pathwire) - normal = DraftGeomUtils.getNormal(pathwire) - path = Part.__sortEdges__(pathwire.Edges) - ends = [] - cdist = 0 - - for e in path: # find cumulative edge end distance - cdist += e.Length - ends.append(cdist) - - placements = [] - - # place the start shape - pt = path[0].Vertexes[0].Point - placements.append(calculatePlacement( - shapeRotation, path[0], 0, pt, xlate, align, normal)) - - # closed path doesn't need shape on last vertex - if not(closedpath): - # place the end shape - pt = path[-1].Vertexes[-1].Point - placements.append(calculatePlacement( - shapeRotation, path[-1], path[-1].Length, pt, xlate, align, normal)) - - if count < 3: - return placements - - # place the middle shapes - if closedpath: - stop = count - else: - stop = count - 1 - step = float(cdist) / stop - remains = 0 - travel = step - for i in range(1, stop): - # which edge in path should contain this shape? - # avoids problems with float math travel > ends[-1] - iend = len(ends) - 1 - - for j in range(0, len(ends)): - if travel <= ends[j]: - iend = j - break - - # place shape at proper spot on proper edge - remains = ends[iend] - travel - offset = path[iend].Length - remains - pt = path[iend].valueAt(getParameterFromV0(path[iend], offset)) - - placements.append(calculatePlacement( - shapeRotation, path[iend], offset, pt, xlate, align, normal)) - - travel += step - - return placements #--------------------------------------------------------------------------- # Python Features definitions @@ -1016,95 +867,6 @@ class _Array(_DraftLink): base.append(npl) return base -class _PathArray(_DraftLink): - """The Draft Path Array object""" - - def __init__(self,obj): - _DraftLink.__init__(self,obj,"PathArray") - - def attach(self,obj): - obj.addProperty("App::PropertyLinkGlobal","Base","Draft",QT_TRANSLATE_NOOP("App::Property","The base object that must be duplicated")) - obj.addProperty("App::PropertyLinkGlobal","PathObj","Draft",QT_TRANSLATE_NOOP("App::Property","The path object along which to distribute objects")) - obj.addProperty("App::PropertyLinkSubListGlobal","PathSubs",QT_TRANSLATE_NOOP("App::Property","Selected subobjects (edges) of PathObj")) - obj.addProperty("App::PropertyInteger","Count","Draft",QT_TRANSLATE_NOOP("App::Property","Number of copies")) - obj.addProperty("App::PropertyVectorDistance","Xlate","Draft",QT_TRANSLATE_NOOP("App::Property","Optional translation vector")) - obj.addProperty("App::PropertyBool","Align","Draft",QT_TRANSLATE_NOOP("App::Property","Orientation of Base along path")) - obj.addProperty("App::PropertyVector","TangentVector","Draft",QT_TRANSLATE_NOOP("App::Property","Alignment of copies")) - - obj.Count = 2 - obj.PathSubs = [] - obj.Xlate = FreeCAD.Vector(0,0,0) - obj.Align = False - obj.TangentVector = FreeCAD.Vector(1.0, 0.0, 0.0) - - if self.use_link: - obj.addProperty("App::PropertyBool","ExpandArray","Draft", - QT_TRANSLATE_NOOP("App::Property","Show array element as children object")) - obj.ExpandArray = False - obj.setPropertyStatus('Shape','Transient') - - _DraftLink.attach(self,obj) - - def linkSetup(self,obj): - _DraftLink.linkSetup(self,obj) - obj.configLinkProperty(ElementCount='Count') - - def execute(self,obj): - import FreeCAD - import Part - import DraftGeomUtils - if obj.Base and obj.PathObj: - pl = obj.Placement - if obj.PathSubs: - w = self.getWireFromSubs(obj) - elif (hasattr(obj.PathObj.Shape,'Wires') and obj.PathObj.Shape.Wires): - w = obj.PathObj.Shape.Wires[0] - elif obj.PathObj.Shape.Edges: - w = Part.Wire(obj.PathObj.Shape.Edges) - else: - FreeCAD.Console.PrintLog ("_PathArray.createGeometry: path " + obj.PathObj.Name + " has no edges\n") - return - if (hasattr(obj, "TangentVector")) and (obj.Align): - basePlacement = obj.Base.Shape.Placement - baseRotation = basePlacement.Rotation - stdX = FreeCAD.Vector(1.0, 0.0, 0.0) - preRotation = FreeCAD.Rotation(stdX, obj.TangentVector) #make rotation from X to TangentVector - netRotation = baseRotation.multiply(preRotation) - base = calculatePlacementsOnPath( - netRotation,w,obj.Count,obj.Xlate,obj.Align) - else: - base = calculatePlacementsOnPath( - obj.Base.Shape.Placement.Rotation,w,obj.Count,obj.Xlate,obj.Align) - return _DraftLink.buildShape(self,obj,pl,base) - - def getWireFromSubs(self,obj): - '''Make a wire from PathObj subelements''' - import Part - sl = [] - for sub in obj.PathSubs: - edgeNames = sub[1] - for n in edgeNames: - e = sub[0].Shape.getElement(n) - sl.append(e) - return Part.Wire(sl) - - def pathArray(self,shape,pathwire,count,xlate,align): - '''Distribute shapes along a path.''' - import Part - - placements = calculatePlacementsOnPath( - shape.Placement.Rotation, pathwire, count, xlate, align) - - base = [] - - for placement in placements: - ns = shape.copy() - ns.Placement = placement - - base.append(ns) - - return (Part.makeCompound(base)) - class _PointArray(_DraftObject): """The Draft Point Array object""" def __init__(self, obj, bobj, ptlst): @@ -1157,47 +919,4 @@ class _PointArray(_DraftObject): obj.Shape = obj.Base.Shape.copy() -class _ViewProviderDraftArray(_ViewProviderDraft): - """a view provider that displays a Array icon instead of a Draft icon""" - - def __init__(self,vobj): - _ViewProviderDraft.__init__(self,vobj) - - def getIcon(self): - if hasattr(self.Object, "ArrayType"): - if self.Object.ArrayType == 'ortho': - return ":/icons/Draft_Array.svg" - elif self.Object.ArrayType == 'polar': - return ":/icons/Draft_PolarArray.svg" - elif self.Object.ArrayType == 'circular': - return ":/icons/Draft_CircularArray.svg" - elif hasattr(self.Object, "PointList"): - return ":/icons/Draft_PointArray.svg" - else: - return ":/icons/Draft_PathArray.svg" - - def resetColors(self, vobj): - colors = [] - if vobj.Object.Base: - if vobj.Object.Base.isDerivedFrom("Part::Feature"): - if len(vobj.Object.Base.ViewObject.DiffuseColor) > 1: - colors = vobj.Object.Base.ViewObject.DiffuseColor - else: - c = vobj.Object.Base.ViewObject.ShapeColor - c = (c[0],c[1],c[2],vobj.Object.Base.ViewObject.Transparency/100.0) - for f in vobj.Object.Base.Shape.Faces: - colors.append(c) - if colors: - n = 1 - if hasattr(vobj.Object,"ArrayType"): - if vobj.Object.ArrayType == "ortho": - n = vobj.Object.NumberX * vobj.Object.NumberY * vobj.Object.NumberZ - else: - n = vobj.Object.NumberPolar - elif hasattr(vobj.Object,"Count"): - n = vobj.Object.Count - colors = colors * n - vobj.DiffuseColor = colors - - ## @} diff --git a/src/Mod/Draft/draftmake/make_patharray.py b/src/Mod/Draft/draftmake/make_patharray.py new file mode 100644 index 0000000000..ddfa2a6aea --- /dev/null +++ b/src/Mod/Draft/draftmake/make_patharray.py @@ -0,0 +1,113 @@ +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * Copyright (c) 2020 FreeCAD Developers * +# * * +# * 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 provides the code for Draft make_path_array function. +""" +## @package make_patharray +# \ingroup DRAFT +# \brief This module provides the code for Draft make_path_array function. + +import FreeCAD as App + +import draftutils.utils as utils +import draftutils.gui_utils as gui_utils + +from draftobjects.patharray import PathArray + +from draftviewproviders.view_draftlink import ViewProviderDraftLink +if App.GuiUp: + from draftviewproviders.view_array import ViewProviderDraftArray + + +def make_path_array(baseobject,pathobject,count,xlate=None,align=False,pathobjsubs=[],use_link=False): + """make_path_array(docobj, path, count, xlate, align, pathobjsubs, use_link) + + Make a Draft PathArray object. + + Distribute count copies of a document baseobject along a pathobject + or subobjects of a pathobject. + + + Parameters + ---------- + docobj : + Object to array + + path : + Path object + + pathobjsubs : + TODO: Complete documentation + + align : + Optionally aligns baseobject to tangent/normal/binormal of path. TODO: verify + + count : + TODO: Complete documentation + + xlate : Base.Vector + Optionally translates each copy by FreeCAD.Vector xlate direction + and distance to adjust for difference in shape centre vs shape reference point. + + use_link : + TODO: Complete documentation + """ + if not App.ActiveDocument: + App.Console.PrintError("No active document. Aborting\n") + return + + if use_link: + obj = App.ActiveDocument.addObject("Part::FeaturePython","PathArray", PathArray(None), None, True) + else: + obj = App.ActiveDocument.addObject("Part::FeaturePython","PathArray") + PathArray(obj) + + obj.Base = baseobject + obj.PathObj = pathobject + + if pathobjsubs: + sl = [] + for sub in pathobjsubs: + sl.append((obj.PathObj,sub)) + obj.PathSubs = list(sl) + + if count > 1: + obj.Count = count + + if xlate: + obj.Xlate = xlate + + obj.Align = align + + if App.GuiUp: + if use_link: + ViewProviderDraftLink(obj.ViewObject) + else: + ViewProviderDraftArray(obj.ViewObject) + gui_utils.formatObject(obj,obj.Base) + if len(obj.Base.ViewObject.DiffuseColor) > 1: + obj.ViewObject.Proxy.resetColors(obj.ViewObject) + baseobject.ViewObject.hide() + gui_utils.select(obj) + return obj + +makePathArray = make_path_array \ No newline at end of file diff --git a/src/Mod/Draft/draftobjects/patharray.py b/src/Mod/Draft/draftobjects/patharray.py new file mode 100644 index 0000000000..f765dd1557 --- /dev/null +++ b/src/Mod/Draft/draftobjects/patharray.py @@ -0,0 +1,272 @@ +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * Copyright (c) 2020 FreeCAD Developers * +# * * +# * 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 provides the object code for the Draft PathArray object. +""" +## @package patharray +# \ingroup DRAFT +# \brief This module provides the object code for the Draft PathArray object. + +from PySide.QtCore import QT_TRANSLATE_NOOP + +import FreeCAD as App +import DraftVecUtils + +from draftutils.utils import get_param + +from draftobjects.draftlink import DraftLink + + +class PathArray(DraftLink): + """The Draft Path Array object""" + + def __init__(self,obj): + super(PathArray, self).__init__(obj, "PathArray") + + def attach(self,obj): + _tip = "The base object that must be duplicated" + obj.addProperty("App::PropertyLinkGlobal", "Base", + "Objects", QT_TRANSLATE_NOOP("App::Property", _tip)) + + _tip = "The path object along which to distribute objects" + obj.addProperty("App::PropertyLinkGlobal", "PathObj", + "Objects", QT_TRANSLATE_NOOP("App::Property", _tip)) + + _tip = "Selected subobjects (edges) of PathObj" + obj.addProperty("App::PropertyLinkSubListGlobal", "PathSubs", + "Objects", QT_TRANSLATE_NOOP("App::Property", _tip)) + + _tip = "Number of copies" + obj.addProperty("App::PropertyInteger", "Count", + "Parameters", QT_TRANSLATE_NOOP("App::Property", _tip)) + + _tip = "Orientation of Base along path" + obj.addProperty("App::PropertyBool", "Align", + "Parameters", QT_TRANSLATE_NOOP("App::Property", _tip)) + + _tip = "Alignment of copies" + obj.addProperty("App::PropertyVector", "TangentVector", + "Parameters", QT_TRANSLATE_NOOP("App::Property", _tip)) + + _tip = "Optional translation vector" # why? placement is not enough? + obj.addProperty("App::PropertyVectorDistance", "Xlate", + "Parameters", QT_TRANSLATE_NOOP("App::Property", _tip)) + + obj.Count = 2 + obj.PathSubs = [] + obj.Xlate = App.Vector(0,0,0) + obj.Align = False + obj.TangentVector = App.Vector(1.0, 0.0, 0.0) + + if self.use_link: + _tip = "Show array element as children object" + obj.addProperty("App::PropertyBool","ExpandArray", + "Parameters", QT_TRANSLATE_NOOP("App::Property", _tip)) + + obj.ExpandArray = False + obj.setPropertyStatus('Shape','Transient') + + super(PathArray, self).attach(obj) + + def linkSetup(self,obj): + super(PathArray, self).linkSetup(obj) + obj.configLinkProperty(ElementCount='Count') + + def execute(self,obj): + import Part + import DraftGeomUtils + if obj.Base and obj.PathObj: + pl = obj.Placement + if obj.PathSubs: + w = self.getWireFromSubs(obj) + elif (hasattr(obj.PathObj.Shape,'Wires') and obj.PathObj.Shape.Wires): + w = obj.PathObj.Shape.Wires[0] + elif obj.PathObj.Shape.Edges: + w = Part.Wire(obj.PathObj.Shape.Edges) + else: + App.Console.PrintLog ("_PathArray.createGeometry: path " + obj.PathObj.Name + " has no edges\n") + return + if (hasattr(obj, "TangentVector")) and (obj.Align): + basePlacement = obj.Base.Shape.Placement + baseRotation = basePlacement.Rotation + stdX = App.Vector(1.0, 0.0, 0.0) + preRotation = App.Rotation(stdX, obj.TangentVector) #make rotation from X to TangentVector + netRotation = baseRotation.multiply(preRotation) + base = calculatePlacementsOnPath( + netRotation,w,obj.Count,obj.Xlate,obj.Align) + else: + base = calculatePlacementsOnPath( + obj.Base.Shape.Placement.Rotation,w,obj.Count,obj.Xlate,obj.Align) + return super(PathArray, self).buildShape(obj, pl, base) + + def getWireFromSubs(self,obj): + '''Make a wire from PathObj subelements''' + import Part + sl = [] + for sub in obj.PathSubs: + edgeNames = sub[1] + for n in edgeNames: + e = sub[0].Shape.getElement(n) + sl.append(e) + return Part.Wire(sl) + + def pathArray(self,shape,pathwire,count,xlate,align): + '''Distribute shapes along a path.''' + import Part + + placements = calculatePlacementsOnPath( + shape.Placement.Rotation, pathwire, count, xlate, align) + + base = [] + + for placement in placements: + ns = shape.copy() + ns.Placement = placement + + base.append(ns) + + return (Part.makeCompound(base)) + + +_PathArray = PathArray + + +def calculatePlacementsOnPath(shapeRotation, pathwire, count, xlate, align): + """Calculates the placements of a shape along a given path so that each copy will be distributed evenly""" + import Part + import DraftGeomUtils + + closedpath = DraftGeomUtils.isReallyClosed(pathwire) + normal = DraftGeomUtils.getNormal(pathwire) + path = Part.__sortEdges__(pathwire.Edges) + ends = [] + cdist = 0 + + for e in path: # find cumulative edge end distance + cdist += e.Length + ends.append(cdist) + + placements = [] + + # place the start shape + pt = path[0].Vertexes[0].Point + placements.append(calculatePlacement( + shapeRotation, path[0], 0, pt, xlate, align, normal)) + + # closed path doesn't need shape on last vertex + if not(closedpath): + # place the end shape + pt = path[-1].Vertexes[-1].Point + placements.append(calculatePlacement( + shapeRotation, path[-1], path[-1].Length, pt, xlate, align, normal)) + + if count < 3: + return placements + + # place the middle shapes + if closedpath: + stop = count + else: + stop = count - 1 + step = float(cdist) / stop + remains = 0 + travel = step + for i in range(1, stop): + # which edge in path should contain this shape? + # avoids problems with float math travel > ends[-1] + iend = len(ends) - 1 + + for j in range(0, len(ends)): + if travel <= ends[j]: + iend = j + break + + # place shape at proper spot on proper edge + remains = ends[iend] - travel + offset = path[iend].Length - remains + pt = path[iend].valueAt(getParameterFromV0(path[iend], offset)) + + placements.append(calculatePlacement( + shapeRotation, path[iend], offset, pt, xlate, align, normal)) + + travel += step + + return placements + + + +def calculatePlacement(globalRotation, edge, offset, RefPt, xlate, align, normal=None): + """Orient shape to tangent at parm offset along edge.""" + import functools + # http://en.wikipedia.org/wiki/Euler_angles + # start with null Placement point so translate goes to right place. + placement = App.Placement() + # preserve global orientation + placement.Rotation = globalRotation + + placement.move(RefPt + xlate) + + if not align: + return placement + + nullv = App.Vector(0, 0, 0) + + # get a local coord system (tangent, normal, binormal) at parameter offset (normally length) + t = edge.tangentAt(getParameterFromV0(edge, offset)) + t.normalize() + + try: + n = edge.normalAt(getParameterFromV0(edge, offset)) + n.normalize() + b = (t.cross(n)) + b.normalize() + # no normal defined here + except App.Base.FreeCADError: + n = nullv + b = nullv + App.Console.PrintMessage( + "Draft PathArray.orientShape - Cannot calculate Path normal.\n") + + priority = "ZXY" #the default. Doesn't seem to affect results. + newRot = App.Rotation(t, n, b, priority) + newGRot = newRot.multiply(globalRotation) + + placement.Rotation = newGRot + return placement + + + +def getParameterFromV0(edge, offset): + """return parameter at distance offset from edge.Vertexes[0] + sb method in Part.TopoShapeEdge???""" + + lpt = edge.valueAt(edge.getParameterByLength(0)) + vpt = edge.Vertexes[0].Point + + if not DraftVecUtils.equals(vpt, lpt): + # this edge is flipped + length = edge.Length - offset + else: + # this edge is right way around + length = offset + + return (edge.getParameterByLength(length)) diff --git a/src/Mod/Draft/draftviewproviders/view_array.py b/src/Mod/Draft/draftviewproviders/view_array.py new file mode 100644 index 0000000000..e23802925a --- /dev/null +++ b/src/Mod/Draft/draftviewproviders/view_array.py @@ -0,0 +1,75 @@ +# *************************************************************************** +# * (c) 2019 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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. * +# * * +# * FreeCAD 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 FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provides the view provider code for the Draft Array objects. +""" +## @package view_array +# \ingroup DRAFT +# \brief Provides the view provider code for the Draft Array objects. + +from draftviewproviders.view_base import ViewProviderDraft + + +class ViewProviderDraftArray(ViewProviderDraft): + """a view provider that displays a Array icon instead of a Draft icon""" + + def __init__(self,vobj): + super(ViewProviderDraftArray, self).__init__(vobj) + + def getIcon(self): + if hasattr(self.Object, "ArrayType"): + if self.Object.ArrayType == 'ortho': + return ":/icons/Draft_Array.svg" + elif self.Object.ArrayType == 'polar': + return ":/icons/Draft_PolarArray.svg" + elif self.Object.ArrayType == 'circular': + return ":/icons/Draft_CircularArray.svg" + elif hasattr(self.Object, "PointList"): + return ":/icons/Draft_PointArray.svg" + else: + return ":/icons/Draft_PathArray.svg" + + def resetColors(self, vobj): + colors = [] + if vobj.Object.Base: + if vobj.Object.Base.isDerivedFrom("Part::Feature"): + if len(vobj.Object.Base.ViewObject.DiffuseColor) > 1: + colors = vobj.Object.Base.ViewObject.DiffuseColor + else: + c = vobj.Object.Base.ViewObject.ShapeColor + c = (c[0],c[1],c[2],vobj.Object.Base.ViewObject.Transparency/100.0) + for f in vobj.Object.Base.Shape.Faces: + colors.append(c) + if colors: + n = 1 + if hasattr(vobj.Object,"ArrayType"): + if vobj.Object.ArrayType == "ortho": + n = vobj.Object.NumberX * vobj.Object.NumberY * vobj.Object.NumberZ + else: + n = vobj.Object.NumberPolar + elif hasattr(vobj.Object,"Count"): + n = vobj.Object.Count + colors = colors * n + vobj.DiffuseColor = colors + + +_ViewProviderDraftArray = ViewProviderDraftArray \ No newline at end of file