chiark / gitweb /
Add uppercase STL and HEX to file dialog filters for linux/MacOS
[cura.git] / Cura / fabmetheus_utilities / geometry / solids / cylinder.py
1 """
2 Boolean geometry cylinder.
3
4 """
5
6
7 from __future__ import absolute_import
8 #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.
9 import __init__
10
11 from fabmetheus_utilities.geometry.creation import lineation
12 from fabmetheus_utilities.geometry.creation import solid
13 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
14 from fabmetheus_utilities.geometry.geometry_utilities import matrix
15 from fabmetheus_utilities.geometry.solids import cube
16 from fabmetheus_utilities.geometry.solids import triangle_mesh
17 from fabmetheus_utilities.vector3 import Vector3
18 from fabmetheus_utilities import euclidean
19 import math
20
21 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
22 __credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
23 __date__ = '$Date: 2008/21/04 $'
24 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
25
26
27 def addCylinder(faces, inradius, sides, topOverBottom, vertexes):
28         'Add cylinder by inradius.'
29         polygonBottom = euclidean.getComplexPolygonByComplexRadius(complex(inradius.x, inradius.y), sides)
30         polygonTop = polygonBottom
31         if topOverBottom <= 0.0:
32                 polygonTop = [complex()]
33         elif topOverBottom != 1.0:
34                 polygonTop = euclidean.getComplexPathByMultiplier(topOverBottom, polygonTop)
35         bottomTopPolygon = [
36                 triangle_mesh.getAddIndexedLoop(polygonBottom, vertexes, -inradius.z),
37                 triangle_mesh.getAddIndexedLoop(polygonTop, vertexes, inradius.z)]
38         triangle_mesh.addPillarByLoops(faces, bottomTopPolygon)
39
40 def addCylinderOutputByEndStart(endZ, inradiusComplex, outputs, sides, start, topOverBottom=1.0):
41         'Add cylinder triangle mesh by endZ, inradius and start.'
42         inradius = Vector3(inradiusComplex.real, inradiusComplex.imag, 0.5 * abs(endZ - start.z))
43         cylinderOutput = getGeometryOutput(inradius, sides, topOverBottom)
44         vertexes = matrix.getVertexes(cylinderOutput)
45         if endZ < start.z:
46                 for vertex in vertexes:
47                         vertex.z = -vertex.z
48         translation = Vector3(start.x, start.y, inradius.z + min(start.z, endZ))
49         euclidean.translateVector3Path(vertexes, translation)
50         outputs.append(cylinderOutput)
51
52 def getGeometryOutput(inradius, sides, topOverBottom):
53         'Get cylinder triangle mesh by inradius.'
54         faces = []
55         vertexes = []
56         addCylinder(faces, inradius, sides, topOverBottom, vertexes)
57         return {'trianglemesh' : {'vertex' : vertexes, 'face' : faces}}
58
59 def getNewDerivation(elementNode):
60         'Get new derivation.'
61         return CylinderDerivation(elementNode)
62
63 def getTopOverBottom(angle, endZ, inradiusComplex, startZ):
64         'Get topOverBottom by angle in radians, endZ, inradius and start.'
65         return max(1.0 - abs(endZ - startZ) * math.tan(angle) / lineation.getRadiusAverage(inradiusComplex), 0.0)
66
67 def processElementNode(elementNode):
68         'Process the xml element.'
69         evaluate.processArchivable(Cylinder, elementNode)
70
71
72 class Cylinder( cube.Cube ):
73         'A cylinder object.'
74         def __init__(self):
75                 'Add empty lists.'
76                 cube.Cube.__init__(self)
77
78         def createShape(self):
79                 'Create the shape.'
80                 sides = evaluate.getSidesMinimumThreeBasedOnPrecision(self.elementNode, max(self.inradius.x, self.inradius.y))
81                 if self.elementNode.getCascadeBoolean(False, 'radiusAreal'):
82                         radiusArealizedMultiplier = euclidean.getRadiusArealizedMultiplier(sides)
83                         self.inradius.x *= radiusArealizedMultiplier
84                         self.inradius.y *= radiusArealizedMultiplier
85                 addCylinder(self.faces, self.inradius, sides, self.topOverBottom, self.vertexes)
86
87         def setToElementNode(self, elementNode):
88                 'Set to elementNode.'
89                 attributes = elementNode.attributes
90                 self.elementNode = elementNode
91                 derivation = CylinderDerivation(elementNode)
92                 self.inradius = derivation.inradius
93                 self.topOverBottom = derivation.topOverBottom
94                 if 'inradius' in attributes:
95                         del attributes['inradius']
96                 attributes['height'] = self.inradius.z + self.inradius.z
97                 attributes['radius.x'] = self.inradius.x
98                 attributes['radius.y'] = self.inradius.y
99                 attributes['topOverBottom'] = self.topOverBottom
100                 self.createShape()
101                 solid.processArchiveRemoveSolid(elementNode, self.getGeometryOutput())
102
103
104 class CylinderDerivation:
105         "Class to hold cylinder variables."
106         def __init__(self, elementNode):
107                 'Set defaults.'
108                 self.inradius = evaluate.getVector3ByPrefixes(elementNode, ['demisize', 'inradius', 'radius'], Vector3(1.0, 1.0, 1.0))
109                 self.inradius = evaluate.getVector3ByMultiplierPrefixes(elementNode, 2.0, ['diameter', 'size'], self.inradius)
110                 self.inradius.z = 0.5 * evaluate.getEvaluatedFloat(self.inradius.z + self.inradius.z, elementNode, 'height')
111                 self.topOverBottom = evaluate.getEvaluatedFloat(1.0, elementNode, 'topOverBottom')