chiark / gitweb /
4defa0415f105e2ec212eadd58a2f602c2e83cab
[cura.git] / Cura / fabmetheus_utilities / geometry / creation / solid.py
1 """
2 Solid has functions for 3D shapes.
3
4 Solid has some of the same functions as lineation, however you can not define geometry by dictionary string in the target because there is no getGeometryOutputByArguments function.  You would have to define a shape by making the shape element.  Also, you can not define geometry by 'get<Creation Name>, because the target only gets element.  Instead you would have the shape element, and set the target in solid to that element.
5
6 """
7
8 from __future__ import absolute_import
9 #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module.
10 import __init__
11
12 from fabmetheus_utilities.geometry.creation import lineation
13 from fabmetheus_utilities.geometry.geometry_tools import path
14 from fabmetheus_utilities.geometry.geometry_utilities import boolean_geometry
15 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
16 from fabmetheus_utilities.geometry.geometry_utilities import matrix
17 from fabmetheus_utilities.geometry.solids import triangle_mesh
18 from fabmetheus_utilities.vector3 import Vector3
19 from fabmetheus_utilities import euclidean
20 import math
21
22
23 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
24 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
25 __date__ = '$Date: 2008/02/05 $'
26 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
27
28
29 def getGeometryOutputByFunction(elementNode, geometryFunction):
30         'Get geometry output by manipulationFunction.'
31         if elementNode.xmlObject == None:
32                 print('Warning, there is no object in getGeometryOutputByFunction in solid for:')
33                 print(elementNode)
34                 return None
35         geometryOutput = elementNode.xmlObject.getGeometryOutput()
36         if geometryOutput == None:
37                 print('Warning, there is no geometryOutput in getGeometryOutputByFunction in solid for:')
38                 print(elementNode)
39                 return None
40         return geometryFunction(elementNode, geometryOutput, '')
41
42 def getGeometryOutputByManipulation(elementNode, geometryOutput):
43         'Get geometryOutput manipulated by the plugins in the manipulation shapes & solids folders.'
44         xmlProcessor = elementNode.getXMLProcessor()
45         matchingPlugins = getSolidMatchingPlugins(elementNode)
46         matchingPlugins.sort(evaluate.compareExecutionOrderAscending)
47         for matchingPlugin in matchingPlugins:
48                 prefix = matchingPlugin.__name__.replace('_', '') + '.'
49                 geometryOutput = matchingPlugin.getManipulatedGeometryOutput(elementNode, geometryOutput, prefix)
50         return geometryOutput
51
52 def getLoopLayersSetCopy(elementNode, geometryOutput, importRadius, radius):
53         'Get the loop layers and set the copyShallow.'
54         halfLayerHeight = 0.5 * radius
55         copyShallow = elementNode.getCopyShallow()
56         processElementNodeByGeometry(copyShallow, geometryOutput)
57         targetMatrix = matrix.getBranchMatrixSetElementNode(elementNode)
58         matrix.setElementNodeDictionaryMatrix(copyShallow, targetMatrix)
59         transformedVertexes = copyShallow.xmlObject.getTransformedVertexes()
60         minimumZ = boolean_geometry.getMinimumZ(copyShallow.xmlObject)
61         if minimumZ == None:
62                 copyShallow.parentNode.xmlObject.archivableObjects.remove(copyShallow.xmlObject)
63                 return []
64         maximumZ = euclidean.getTopPath(transformedVertexes)
65         copyShallow.attributes['visible'] = True
66         copyShallowObjects = [copyShallow.xmlObject]
67         bottomLoopLayer = euclidean.LoopLayer(minimumZ)
68         z = minimumZ + 0.1 * radius
69         zoneArrangement = triangle_mesh.ZoneArrangement(radius, transformedVertexes)
70         bottomLoopLayer.loops = boolean_geometry.getEmptyZLoops(copyShallowObjects, importRadius, False, z, zoneArrangement)
71         loopLayers = [bottomLoopLayer]
72         z = minimumZ + halfLayerHeight
73         loopLayers += boolean_geometry.getLoopLayers(copyShallowObjects, importRadius, halfLayerHeight, maximumZ, False, z, zoneArrangement)
74         copyShallow.parentNode.xmlObject.archivableObjects.remove(copyShallow.xmlObject)
75         return loopLayers
76
77 def getLoopOrEmpty(loopIndex, loopLayers):
78         'Get the loop, or if the loopIndex is out of range, get an empty list.'
79         if loopIndex < 0 or loopIndex >= len(loopLayers):
80                 return []
81         return loopLayers[loopIndex].loops[0]
82
83 def getNewDerivation(elementNode):
84         'Get new derivation.'
85         return SolidDerivation(elementNode)
86
87 def getSolidMatchingPlugins(elementNode):
88         'Get solid plugins in the manipulation matrix, shapes & solids folders.'
89         xmlProcessor = elementNode.getXMLProcessor()
90         matchingPlugins = evaluate.getMatchingPlugins(elementNode, xmlProcessor.manipulationMatrixDictionary)
91         return matchingPlugins + evaluate.getMatchingPlugins(elementNode, xmlProcessor.manipulationShapeDictionary)
92
93 def processArchiveRemoveSolid(elementNode, geometryOutput):
94         'Process the target by the manipulationFunction.'
95         solidMatchingPlugins = getSolidMatchingPlugins(elementNode)
96         if len(solidMatchingPlugins) == 0:
97                 elementNode.parentNode.xmlObject.archivableObjects.append(elementNode.xmlObject)
98                 matrix.getBranchMatrixSetElementNode(elementNode)
99                 return
100         processElementNodeByGeometry(elementNode, getGeometryOutputByManipulation(elementNode, geometryOutput))
101
102 def processElementNode(elementNode):
103         'Process the xml element.'
104         processElementNodeByDerivation(None, elementNode)
105
106 def processElementNodeByDerivation(derivation, elementNode):
107         'Process the xml element by derivation.'
108         if derivation == None:
109                 derivation = SolidDerivation(elementNode)
110         elementAttributesCopy = elementNode.attributes.copy()
111         for target in derivation.targets:
112                 targetAttributesCopy = target.attributes.copy()
113                 target.attributes = elementAttributesCopy
114                 processTarget(target)
115                 target.attributes = targetAttributesCopy
116
117 def processElementNodeByFunction(elementNode, manipulationFunction):
118         'Process the xml element.'
119         if 'target' not in elementNode.attributes:
120                 print('Warning, there was no target in processElementNodeByFunction in solid for:')
121                 print(elementNode)
122                 return
123         target = evaluate.getEvaluatedLinkValue(elementNode, str(elementNode.attributes['target']).strip())
124         if target.__class__.__name__ == 'ElementNode':
125                 manipulationFunction(elementNode, target)
126                 return
127         path.convertElementNode(elementNode, target)
128         manipulationFunction(elementNode, elementNode)
129
130 def processElementNodeByFunctionPair(elementNode, geometryFunction, pathFunction):
131         'Process the xml element by the appropriate manipulationFunction.'
132         elementAttributesCopy = elementNode.attributes.copy()
133         targets = evaluate.getElementNodesByKey(elementNode, 'target')
134         for target in targets:
135                 targetAttributesCopy = target.attributes.copy()
136                 target.attributes = elementAttributesCopy
137                 processTargetByFunctionPair(geometryFunction, pathFunction, target)
138                 target.attributes = targetAttributesCopy
139
140 def processElementNodeByGeometry(elementNode, geometryOutput):
141         'Process the xml element by geometryOutput.'
142         if geometryOutput != None:
143                 elementNode.getXMLProcessor().convertElementNode(elementNode, geometryOutput)
144
145 def processTarget(target):
146         'Process the target.'
147         if target.xmlObject == None:
148                 print('Warning, there is no object in processElementNode in solid for:')
149                 print(target)
150                 return
151         geometryOutput = target.xmlObject.getGeometryOutput()
152         if geometryOutput == None:
153                 print('Warning, there is no geometryOutput in processElementNode in solid for:')
154                 print(target.xmlObject)
155                 return
156         geometryOutput = getGeometryOutputByManipulation(target, geometryOutput)
157         lineation.removeChildNodesFromElementObject(target)
158         target.getXMLProcessor().convertElementNode(target, geometryOutput)
159
160 def processTargetByFunctionPair(geometryFunction, pathFunction, target):
161         'Process the target by the manipulationFunction.'
162         if target.xmlObject == None:
163                 print('Warning, there is no object in processTargetByFunctions in solid for:')
164                 print(target)
165                 return
166         if len(target.xmlObject.getPaths()) > 0:
167                 lineation.processTargetByFunction(pathFunction, target)
168                 return
169         geometryOutput = getGeometryOutputByFunction(target, geometryFunction)
170         lineation.removeChildNodesFromElementObject(target)
171         target.getXMLProcessor().convertElementNode(target, geometryOutput)
172
173
174 class SolidDerivation:
175         'Class to hold solid variables.'
176         def __init__(self, elementNode):
177                 'Set defaults.'
178                 self.targets = evaluate.getElementNodesByKey(elementNode, 'target')