<commit_before># ***************************************************************************
# *   Copyright (c) 2009, 2010 <NAME> <<EMAIL>>        *
# *   Copyright (c) 2009, 2010 <NAME> <<EMAIL>>                   *
# *   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.

import FreeCAD as App
import DraftVecUtils

from draftutils.utils import get_param
from draftutils.messages import _msg, _wrn
from draftutils.translate import _tr, translate

from draftobjects.draftlink import DraftLink

class PathArray(DraftLink):
    """The Draft Path Array object - distributes copies of an object along a path.
    Original mode is the historic "Align" for old (v0.18) documents.  It is not 
    really the Fernat alignment. Uses the normal parameter from getNormal (or the
    default) as a constant - it does not calculate curve normal.
    X is curve tangent, Y is normal parameter, Z is (X x Y)

    Tangent mode is similar to Original, but includes a pre-rotation (in execute) to 
    align the Base object's X to the TangentVector, then X follows curve tangent, 
    normal input parameter is the Z component.

    If the ForceVertical option is applied, the normal parameter from getNormal is 
    ignored, and X is curve tangent, Z is VerticalVector, Y is (X x Z)

    Frenet mode orients the copies to a coordinate system along the path.
    X is tangent to curve, Y is curve normal, Z is curve binormal. 
    if normal can not be computed (ex a straight line), the default is used."""
    
    def __init__(self, obj):
        super(PathArray, self).__init__(obj, "PathArray")

    #For PathLinkArray, DraftLink.attach creates the link to the Base object.
    def attach(self,obj):
        self.setProperties(obj)
        super(PathArray, self).attach(obj) 

    def setProperties(self,obj):
        if not obj:
            return
        if hasattr(obj, "PropertiesList"):
            pl = obj.PropertiesList
        else:
            pl = []

        if not "Base" in pl:
            _tip = _tr("The base object that must be duplicated")
            obj.addProperty("App::PropertyLinkGlobal", "Base", "Objects",  _tip)

        if not "PathObj" in pl:
            _tip = _tr("The path object along which to distribute objects")
            obj.addProperty("App::PropertyLinkGlobal", "PathObj", "Objects", _tip)

        if not "PathSubs" in pl:
            _tip = _tr("Selected subobjects (edges) of PathObj")
            obj.addProperty("App::PropertyLinkSubListGlobal", "PathSubs", "Objects", _tip)
            obj.PathSubs = []
            
        if not "Count" in pl:
            _tip = _tr("Number of copies")
            obj.addProperty("App::PropertyInteger", "Count", "Parameters", _tip)
            obj.Count = 2

# copy alignment properties
        if not "Align" in pl:
            _tip = _tr("Orient the copies along path")
            obj.addProperty("App::PropertyBool", "Align", "Alignment", _tip)
            obj.Align = False
            
        if not "AlignMode" in pl:
            _tip = _tr("How to orient copies on path")
            obj.addProperty("App::PropertyEnumeration","AlignMode","Alignment", _tip)
            obj.AlignMode = ['Original','Frenet','Tangent']
            obj.AlignMode = 'Original'
            
        if not "Xlate" in pl:
            _tip = _tr("Optional translation vector")
            obj.addProperty("App::PropertyVectorDistance","Xlate","Alignment", _tip)
            obj.Xlate = App.Vector(0,0,0)
            
        if not "TangentVector" in pl:
            _tip = _tr("Alignment vector for Tangent mode")
            obj.addProperty("App::PropertyVector","TangentVector","Alignment", _tip)
            obj.TangentVector = App.Vector(1,0,0)

        if not "ForceVertical" in pl:
            _tip = _tr("Force Original/Tangent modes to use VerticalVector as Z")
            obj.addProperty("App::PropertyBool","ForceVertical","Alignment", _tip)
            obj.ForceVertical = False

        if not "VerticalVector" in pl:
            _tip = _tr("ForceVertical direction")
            obj.addProperty("App::PropertyVector","VerticalVector","Alignment", _tip)
            obj.VerticalVector = App.Vector(0,0,1)

        if self.use_link:
            _tip = _tr("Show array element as children object")
            obj.addProperty("App::PropertyBool","ExpandArray", "Parameters", _tip)
            obj.ExpandArray = False
            obj.setPropertyStatus('Shape','Transient')

    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                  #placement of whole pathArray
            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.execute: path " + obj.PathObj.Name + " has no edges\n")
                return
            if (hasattr(obj, "TangentVector")) and (obj.AlignMode == "Tangent") and (obj.Align):
                basePlacement = obj.Base.Shape.Placement
                baseRotation = basePlacement.Rotation
                stdX = App.Vector(1.0, 0.0, 0.0)                          #default TangentVector
                if (not DraftVecUtils.equals(stdX, obj.TangentVector)):
                    preRotation = App.Rotation(stdX, obj.TangentVector)   #make rotation from X to TangentVector
                    netRotation = baseRotation.multiply(preRotation)
                else:
                    netRotation = baseRotation
                base = calculatePlacementsOnPath(
                        netRotation,w,obj.Count,obj.Xlate,obj.Align, obj.AlignMode, 
                            obj.ForceVertical, obj.VerticalVector)
            else:
                base = calculatePlacementsOnPath(
                        obj.Base.Shape.Placement.Rotation,w,obj.Count,obj.Xlate,obj.Align, obj.AlignMode,
                            obj.ForceVertical, obj.VerticalVector)
            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 onDocumentRestored(self, obj):
        self.setProperties(obj)

        self.migrate_attributes(obj)
        if self.use_link:
            self.linkSetup(obj)
        else:
            obj.setPropertyStatus('Shape','-Transient')
        if obj.Shape.isNull():
            if getattr(obj,'PlacementList',None):
                self.buildShape(obj,obj.Placement,obj.PlacementList)
            else:
                self.execute(obj)

_PathArray = PathArray
<commit_msg>Draft: small fix for older PathArray objects<commit_after># ***************************************************************************
# *   Copyright (c) 2009, 2010 <NAME> <<EMAIL>>        *
# *   Copyright (c) 2009, 2010 <NAME> <<EMAIL>>                   *
# *   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.

import FreeCAD as App
import DraftVecUtils

from draftutils.utils import get_param
from draftutils.messages import _msg, _wrn
from draftutils.translate import _tr, translate

from draftobjects.draftlink import DraftLink

class PathArray(DraftLink):
    """The Draft Path Array object - distributes copies of an object along a path.
    Original mode is the historic "Align" for old (v0.18) documents.  It is not 
    really the Fernat alignment. Uses the normal parameter from getNormal (or the
    default) as a constant - it does not calculate curve normal.
    X is curve tangent, Y is normal parameter, Z is (X x Y)

    Tangent mode is similar to Original, but includes a pre-rotation (in execute) to 
    align the Base object's X to the TangentVector, then X follows curve tangent, 
    normal input parameter is the Z component.

    If the ForceVertical option is applied, the normal parameter from getNormal is 
    ignored, and X is curve tangent, Z is VerticalVector, Y is (X x Z)

    Frenet mode orients the copies to a coordinate system along the path.
    X is tangent to curve, Y is curve normal, Z is curve binormal. 
    if normal can not be computed (ex a straight line), the default is used."""
    
    def __init__(self, obj):
        super(PathArray, self).__init__(obj, "PathArray")

    #For PathLinkArray, DraftLink.attach creates the link to the Base object.
    def attach(self,obj):
        self.setProperties(obj)
        super(PathArray, self).attach(obj) 

    def setProperties(self,obj):
        if not obj:
            return
        if hasattr(obj, "PropertiesList"):
            pl = obj.PropertiesList
        else:
            pl = []

        if not "Base" in pl:
            _tip = _tr("The base object that must be duplicated")
            obj.addProperty("App::PropertyLinkGlobal", "Base", "Objects",  _tip)

        if not "PathObj" in pl:
            _tip = _tr("The path object along which to distribute objects")
            obj.addProperty("App::PropertyLinkGlobal", "PathObj", "Objects", _tip)

        if not "PathSubs" in pl:
            _tip = _tr("Selected subobjects (edges) of PathObj")
            obj.addProperty("App::PropertyLinkSubListGlobal", "PathSubs", "Objects", _tip)
            obj.PathSubs = []
            
        if not "Count" in pl:
            _tip = _tr("Number of copies")
            obj.addProperty("App::PropertyInteger", "Count", "Parameters", _tip)
            obj.Count = 2

# copy alignment properties
        if not "Align" in pl:
            _tip = _tr("Orient the copies along path")
            obj.addProperty("App::PropertyBool", "Align", "Alignment", _tip)
            obj.Align = False
            
        if not "AlignMode" in pl:
            _tip = _tr("How to orient copies on path")
            obj.addProperty("App::PropertyEnumeration","AlignMode","Alignment", _tip)
            obj.AlignMode = ['Original','Frenet','Tangent']
            obj.AlignMode = 'Original'
            
        if not "Xlate" in pl:
            _tip = _tr("Optional translation vector")
            obj.addProperty("App::PropertyVectorDistance","Xlate","Alignment", _tip)
            obj.Xlate = App.Vector(0,0,0)
            
        if not "TangentVector" in pl:
            _tip = _tr("Alignment vector for Tangent mode")
            obj.addProperty("App::PropertyVector","TangentVector","Alignment", _tip)
            obj.TangentVector = App.Vector(1,0,0)

        if not "ForceVertical" in pl:
            _tip = _tr("Force Original/Tangent modes to use VerticalVector as Z")
            obj.addProperty("App::PropertyBool","ForceVertical","Alignment", _tip)
            obj.ForceVertical = False

        if not "VerticalVector" in pl:
            _tip = _tr("ForceVertical direction")
            obj.addProperty("App::PropertyVector","VerticalVector","Alignment", _tip)
            obj.VerticalVector = App.Vector(0,0,1)

        if self.use_link and "ExpandArray" not in pl:
            _tip = _tr("Show array element as children object")
            obj.addProperty("App::PropertyBool","ExpandArray", "Parameters", _tip)
            obj.ExpandArray = False
            obj.setPropertyStatus('Shape','Transient')

    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                  #placement of whole pathArray
            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.execute: path " + obj.PathObj.Name + " has no edges\n")
                return
            if (hasattr(obj, "TangentVector")) and (obj.AlignMode == "Tangent") and (obj.Align):
                basePlacement = obj.Base.Shape.Placement
                baseRotation = basePlacement.Rotation
                stdX = App.Vector(1.0, 0.0, 0.0)                          #default TangentVector
                if (not DraftVecUtils.equals(stdX, obj.TangentVector)):
                    preRotation = App.Rotation(stdX, obj.TangentVector)   #make rotation from X to TangentVector
                    netRotation = baseRotation.multiply(preRotation)
                else:
                    netRotation = baseRotation
                base = calculatePlacementsOnPath(
                        netRotation,w,obj.Count,obj.Xlate,obj.Align, obj.AlignMode, 
                            obj.ForceVertical, obj.VerticalVector)
            else:
                base = calculatePlacementsOnPath(
                        obj.Base.Shape.Placement.Rotation,w,obj.Count,obj.Xlate,obj.Align, obj.AlignMode,
                            obj.ForceVertical, obj.VerticalVector)
            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 onDocumentRestored(self, obj):
        self.migrate_attributes(obj)
        self.setProperties(obj)

        if self.use_link:
            self.linkSetup(obj)
        else:
            obj.setPropertyStatus('Shape','-Transient')
        if obj.Shape.isNull():
            if getattr(obj,'PlacementList',None):
                self.buildShape(obj,obj.Placement,obj.PlacementList)
            else:
                self.execute(obj)

_PathArray = PathArray

{'fraction_non_alphanumeric': 0.10640231778674089, 'fraction_numerical': 0.006476168834857694, 'mean_word_length': 1.9261968085106382, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2635717', 'n_tokens_mistral': 4701, 'n_tokens_neox': 4459, 'n_words': 1427}