166 lines
6.8 KiB
Python
166 lines
6.8 KiB
Python
"""
|
|
Add material to support overhang or remove material at the overhang angle.
|
|
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
#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.
|
|
import __init__
|
|
|
|
from fabmetheus_utilities.geometry.creation import lineation
|
|
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
|
|
from fabmetheus_utilities.vector3 import Vector3
|
|
from fabmetheus_utilities import euclidean
|
|
|
|
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
|
|
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
|
|
__date__ = '$Date: 2008/02/05 $'
|
|
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
|
|
|
|
|
globalExecutionOrder = 60
|
|
|
|
|
|
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
|
|
"Get segment loop."
|
|
if len(loop) < 3:
|
|
return [loop]
|
|
derivation = SegmentDerivation(elementNode, prefix)
|
|
if derivation.path == getSegmentPathDefault():
|
|
return [loop]
|
|
path = getXNormalizedVector3Path(derivation.path)
|
|
if euclidean.getIsWiddershinsByVector3(loop):
|
|
path = path[: : -1]
|
|
for point in path:
|
|
point.x = 1.0 - point.x
|
|
if derivation.center == None:
|
|
point.y = - point.y
|
|
segmentLoop = []
|
|
startEnd = StartEnd(elementNode, len(loop), prefix)
|
|
for pointIndex in xrange(len(loop)):
|
|
if pointIndex >= startEnd.start and pointIndex < startEnd.end:
|
|
segmentLoop += getSegmentPath(derivation.center, loop, path, pointIndex)
|
|
else:
|
|
segmentLoop.append(loop[pointIndex])
|
|
return [euclidean.getLoopWithoutCloseSequentialPoints( close, segmentLoop)]
|
|
|
|
def getNewDerivation(elementNode, prefix, sideLength):
|
|
'Get new derivation.'
|
|
return SegmentDerivation(elementNode, prefix)
|
|
|
|
def getRadialPath(begin, center, end, path):
|
|
"Get radial path."
|
|
beginComplex = begin.dropAxis()
|
|
endComplex = end.dropAxis()
|
|
centerComplex = center.dropAxis()
|
|
beginMinusCenterComplex = beginComplex - centerComplex
|
|
endMinusCenterComplex = endComplex - centerComplex
|
|
beginMinusCenterComplexRadius = abs( beginMinusCenterComplex )
|
|
endMinusCenterComplexRadius = abs( endMinusCenterComplex )
|
|
if beginMinusCenterComplexRadius == 0.0 or endMinusCenterComplexRadius == 0.0:
|
|
return [ begin ]
|
|
beginMinusCenterComplex /= beginMinusCenterComplexRadius
|
|
endMinusCenterComplex /= endMinusCenterComplexRadius
|
|
angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCenterComplex, beginMinusCenterComplex )
|
|
radialPath = []
|
|
for point in path:
|
|
weightEnd = point.x
|
|
weightBegin = 1.0 - weightEnd
|
|
weightedRadius = beginMinusCenterComplexRadius * weightBegin + endMinusCenterComplexRadius * weightEnd * ( 1.0 + point.y )
|
|
radialComplex = weightedRadius * euclidean.getWiddershinsUnitPolar( angleDifference * point.x ) * beginMinusCenterComplex
|
|
polygonPoint = center + Vector3( radialComplex.real, radialComplex.imag, point.z )
|
|
radialPath.append( polygonPoint )
|
|
return radialPath
|
|
|
|
def getSegmentPath(center, loop, path, pointIndex):
|
|
"Get segment path."
|
|
centerBegin = loop[pointIndex]
|
|
centerEnd = loop[(pointIndex + 1) % len(loop)]
|
|
centerEndMinusBegin = centerEnd - centerBegin
|
|
if abs( centerEndMinusBegin ) <= 0.0:
|
|
return [ centerBegin ]
|
|
if center != None:
|
|
return getRadialPath(centerBegin, center, centerEnd, path)
|
|
begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
|
|
end = loop[(pointIndex + 2) % len(loop)]
|
|
return getWedgePath(begin, centerBegin, centerEnd, centerEndMinusBegin, end, path)
|
|
|
|
def getSegmentPathDefault():
|
|
"Get segment path default."
|
|
return [Vector3(), Vector3(0.0, 1.0)]
|
|
|
|
def getWedgePath( begin, centerBegin, centerEnd, centerEndMinusBegin, end, path ):
|
|
"Get segment path."
|
|
beginComplex = begin.dropAxis()
|
|
centerBeginComplex = centerBegin.dropAxis()
|
|
centerEndComplex = centerEnd.dropAxis()
|
|
endComplex = end.dropAxis()
|
|
wedgePath = []
|
|
centerBeginMinusBeginComplex = euclidean.getNormalized( centerBeginComplex - beginComplex )
|
|
centerEndMinusCenterBeginComplexOriginal = centerEndComplex - centerBeginComplex
|
|
centerEndMinusCenterBeginComplexLength = abs( centerEndMinusCenterBeginComplexOriginal )
|
|
if centerEndMinusCenterBeginComplexLength <= 0.0:
|
|
return [ centerBegin ]
|
|
centerEndMinusCenterBeginComplex = centerEndMinusCenterBeginComplexOriginal / centerEndMinusCenterBeginComplexLength
|
|
endMinusCenterEndComplex = euclidean.getNormalized( endComplex - centerEndComplex )
|
|
widdershinsBegin = getWiddershinsAverageByVector3( centerBeginMinusBeginComplex, centerEndMinusCenterBeginComplex )
|
|
widdershinsEnd = getWiddershinsAverageByVector3( centerEndMinusCenterBeginComplex, endMinusCenterEndComplex )
|
|
for point in path:
|
|
weightEnd = point.x
|
|
weightBegin = 1.0 - weightEnd
|
|
polygonPoint = centerBegin + centerEndMinusBegin * point.x
|
|
weightedWiddershins = widdershinsBegin * weightBegin + widdershinsEnd * weightEnd
|
|
polygonPoint += weightedWiddershins * point.y * centerEndMinusCenterBeginComplexLength
|
|
polygonPoint.z += point.z
|
|
wedgePath.append( polygonPoint )
|
|
return wedgePath
|
|
|
|
def getWiddershinsAverageByVector3( centerMinusBeginComplex, endMinusCenterComplex ):
|
|
"Get the normalized average of the widdershins vectors."
|
|
centerMinusBeginWiddershins = Vector3( - centerMinusBeginComplex.imag, centerMinusBeginComplex.real )
|
|
endMinusCenterWiddershins = Vector3( - endMinusCenterComplex.imag, endMinusCenterComplex.real )
|
|
return ( centerMinusBeginWiddershins + endMinusCenterWiddershins ).getNormalized()
|
|
|
|
def getXNormalizedVector3Path(path):
|
|
"Get path where the x ranges from 0 to 1."
|
|
if len(path) < 1:
|
|
return path
|
|
minimumX = path[0].x
|
|
for point in path[1 :]:
|
|
minimumX = min( minimumX, point.x )
|
|
for point in path:
|
|
point.x -= minimumX
|
|
maximumX = path[0].x
|
|
for point in path[1 :]:
|
|
maximumX = max( maximumX, point.x )
|
|
for point in path:
|
|
point.x /= maximumX
|
|
return path
|
|
|
|
def processElementNode(elementNode):
|
|
"Process the xml element."
|
|
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
|
|
|
|
|
|
class SegmentDerivation:
|
|
"Class to hold segment variables."
|
|
def __init__(self, elementNode, prefix):
|
|
'Set defaults.'
|
|
self.center = evaluate.getVector3ByPrefix(None, elementNode, prefix + 'center')
|
|
self.path = evaluate.getPathByPrefix(elementNode, getSegmentPathDefault(), prefix)
|
|
|
|
|
|
class StartEnd:
|
|
'Class to get a start through end range.'
|
|
def __init__(self, elementNode, modulo, prefix):
|
|
"Initialize."
|
|
self.start = evaluate.getEvaluatedInt(0, elementNode, prefix + 'start')
|
|
self.extent = evaluate.getEvaluatedInt(modulo - self.start, elementNode, prefix + 'extent')
|
|
self.end = evaluate.getEvaluatedInt(self.start + self.extent, elementNode, prefix + 'end')
|
|
self.revolutions = evaluate.getEvaluatedInt(1, elementNode, prefix + 'revolutions')
|
|
if self.revolutions > 1:
|
|
self.end += modulo * (self.revolutions - 1)
|
|
|
|
def __repr__(self):
|
|
"Get the string representation of this StartEnd."
|
|
return '%s, %s, %s' % (self.start, self.end, self.revolutions)
|