chiark / gitweb /
ef96224fe98db85004ae4b4a494684328f0e2f0f
[cura.git] / Cura / fabmetheus_utilities / geometry / manipulation_paths / round.py
1 """
2 Add material to support overhang or remove material at the overhang angle.
3
4 """
5
6 from __future__ import absolute_import
7 #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.
8 import __init__
9
10 from fabmetheus_utilities.geometry.creation import lineation
11 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
12 from fabmetheus_utilities.vector3 import Vector3
13 from fabmetheus_utilities import euclidean
14 import math
15
16
17 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
18 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
19 __date__ = '$Date: 2008/02/05 $'
20 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
21
22
23 globalExecutionOrder = 40
24
25
26 def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
27         "Get round loop."
28         if len(loop) < 3:
29                 return [loop]
30         derivation = RoundDerivation(elementNode, prefix, sideLength)
31         if derivation.radius == 0.0:
32                 return loop
33         roundLoop = []
34         sidesPerRadian = 0.5 / math.pi * evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, sideLength)
35         for pointIndex in xrange(len(loop)):
36                 begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
37                 center = loop[pointIndex]
38                 end = loop[(pointIndex + 1) % len(loop)]
39                 roundLoop += getRoundPath(begin, center, close, end, derivation.radius, sidesPerRadian)
40         return [euclidean.getLoopWithoutCloseSequentialPoints(close, roundLoop)]
41
42 def getNewDerivation(elementNode, prefix, sideLength):
43         'Get new derivation.'
44         return RoundDerivation(elementNode, prefix, sideLength)
45
46 def getRoundPath( begin, center, close, end, radius, sidesPerRadian ):
47         "Get round path."
48         beginComplex = begin.dropAxis()
49         centerComplex = center.dropAxis()
50         endComplex = end.dropAxis()
51         beginComplexSegmentLength = abs( centerComplex - beginComplex )
52         endComplexSegmentLength = abs( centerComplex - endComplex )
53         minimumRadius = lineation.getMinimumRadius( beginComplexSegmentLength, endComplexSegmentLength, radius )
54         if minimumRadius <= close:
55                 return [ center ]
56         beginBevel = center + minimumRadius / beginComplexSegmentLength * ( begin - center )
57         endBevel = center + minimumRadius / endComplexSegmentLength * ( end - center )
58         beginBevelComplex = beginBevel.dropAxis()
59         endBevelComplex = endBevel.dropAxis()
60         midpointComplex = 0.5 * ( beginBevelComplex + endBevelComplex )
61         if radius < 0.0:
62                 centerComplex = midpointComplex + midpointComplex - centerComplex
63         midpointMinusCenterComplex = midpointComplex - centerComplex
64         midpointCenterLength = abs( midpointMinusCenterComplex )
65         midpointEndLength = abs( midpointComplex - endBevelComplex )
66         midpointCircleCenterLength = midpointEndLength * midpointEndLength / midpointCenterLength
67         circleRadius = math.sqrt( midpointCircleCenterLength * midpointCircleCenterLength + midpointEndLength * midpointEndLength )
68         circleCenterComplex = midpointComplex + midpointMinusCenterComplex * midpointCircleCenterLength / midpointCenterLength
69         circleCenter = Vector3( circleCenterComplex.real, circleCenterComplex.imag, center.z )
70         endMinusCircleCenterComplex = endBevelComplex - circleCenterComplex
71         beginMinusCircleCenter = beginBevel - circleCenter
72         beginMinusCircleCenterComplex = beginMinusCircleCenter.dropAxis()
73         angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCircleCenterComplex, beginMinusCircleCenterComplex )
74         steps = int( math.ceil( abs( angleDifference ) * sidesPerRadian ) )
75         stepPlaneAngle = euclidean.getWiddershinsUnitPolar( angleDifference / float( steps ) )
76         deltaZStep = ( end.z - begin.z ) / float( steps )
77         roundPath = [ beginBevel ]
78         for step in xrange( 1, steps ):
79                 beginMinusCircleCenterComplex = beginMinusCircleCenterComplex * stepPlaneAngle
80                 arcPointComplex = circleCenterComplex + beginMinusCircleCenterComplex
81                 arcPoint = Vector3( arcPointComplex.real, arcPointComplex.imag, begin.z + deltaZStep * step )
82                 roundPath.append( arcPoint )
83         return roundPath + [ endBevel ]
84
85 def processElementNode(elementNode):
86         "Process the xml element."
87         lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
88
89
90 class RoundDerivation:
91         "Class to hold round variables."
92         def __init__(self, elementNode, prefix, sideLength):
93                 'Set defaults.'
94                 self.radius = lineation.getFloatByPrefixSide(0.0, elementNode, prefix + 'radius', sideLength)