From 204f48c74e3a6f8a940aefea07f42e2a160d4171 Mon Sep 17 00:00:00 2001 From: Maxime Curioni Date: Tue, 30 Sep 2008 04:17:39 +0000 Subject: [PATCH] soc-2008-mxcurioni: sending files in release/scripts/freestyle folder --- .../freestyle/data/env_map/brown00.png | Bin 0 -> 22195 bytes .../scripts/freestyle/data/env_map/gray00.png | Bin 0 -> 18513 bytes .../scripts/freestyle/data/env_map/gray01.png | Bin 0 -> 9915 bytes .../scripts/freestyle/data/env_map/gray02.png | Bin 0 -> 7197 bytes .../scripts/freestyle/data/env_map/gray03.png | Bin 0 -> 16109 bytes .../style_modules/ChainingIterators.py | 739 ++++++++++ .../freestyle/style_modules/Functions0D.py | 81 ++ .../freestyle/style_modules/Functions1D.py | 45 + .../freestyle/style_modules/PredicatesB1D.py | 70 + .../freestyle/style_modules/PredicatesU0D.py | 103 ++ .../freestyle/style_modules/PredicatesU1D.py | 381 +++++ .../style_modules/anisotropic_diffusion.py | 75 + .../apriori_and_causal_density.py | 45 + .../style_modules/apriori_density.py | 43 + .../style_modules/backbone_stretcher.py | 36 + .../style_modules/blueprint_circles.py | 46 + .../style_modules/blueprint_ellipses.py | 46 + .../style_modules/blueprint_squares.py | 45 + .../freestyle/style_modules/cartoon.py | 42 + .../freestyle/style_modules/contour.py | 42 + .../freestyle/style_modules/curvature2d.py | 60 + .../style_modules/external_contour.py | 43 + .../style_modules/external_contour_sketchy.py | 48 + .../style_modules/external_contour_smooth.py | 44 + .../freestyle/style_modules/extra-lines.sml | 3 + .../freestyle/style_modules/freestyle_init.py | 459 ++++++ .../freestyle/style_modules/haloing.py | 50 + .../style_modules/ignore_small_occlusions.py | 41 + .../style_modules/invisible_lines.py | 42 + .../style_modules/japanese_bigbrush.py | 60 + .../style_modules/logical_operators.py | 36 + .../long_anisotropically_dense.py | 81 ++ .../multiple_parameterization.py | 51 + .../scripts/freestyle/style_modules/nature.py | 43 + .../freestyle/style_modules/near_lines.py | 44 + .../occluded_by_specific_object.py | 45 + .../freestyle/style_modules/polygonalize.py | 40 + .../scripts/freestyle/style_modules/qi0.py | 41 + .../style_modules/qi0_not_external_contour.py | 43 + .../scripts/freestyle/style_modules/qi1.py | 42 + .../scripts/freestyle/style_modules/qi2.py | 42 + .../style_modules/sequentialsplit_sketchy.py | 68 + .../freestyle/style_modules/shaders.py | 1288 +++++++++++++++++ .../sketchy_multiple_parameterization.py | 48 + .../style_modules/sketchy_topology_broken.py | 89 ++ .../sketchy_topology_preserved.py | 49 + .../split_at_highest_2d_curvatures.py | 41 + .../style_modules/split_at_tvertices.py | 42 + .../freestyle/style_modules/stroke_texture.py | 43 + .../freestyle/style_modules/suggestive.py | 43 + .../thickness_fof_depth_discontinuity.py | 62 + .../freestyle/style_modules/tipremover.py | 42 + .../style_modules/tvertex_remover.py | 42 + .../style_modules/uniformpruning_zsort.py | 40 + .../scripts/freestyle/style_modules/vector.py | 241 +++ 55 files changed, 5335 insertions(+) create mode 100755 release/scripts/freestyle/data/env_map/brown00.png create mode 100755 release/scripts/freestyle/data/env_map/gray00.png create mode 100755 release/scripts/freestyle/data/env_map/gray01.png create mode 100755 release/scripts/freestyle/data/env_map/gray02.png create mode 100755 release/scripts/freestyle/data/env_map/gray03.png create mode 100755 release/scripts/freestyle/style_modules/ChainingIterators.py create mode 100755 release/scripts/freestyle/style_modules/Functions0D.py create mode 100755 release/scripts/freestyle/style_modules/Functions1D.py create mode 100755 release/scripts/freestyle/style_modules/PredicatesB1D.py create mode 100755 release/scripts/freestyle/style_modules/PredicatesU0D.py create mode 100755 release/scripts/freestyle/style_modules/PredicatesU1D.py create mode 100755 release/scripts/freestyle/style_modules/anisotropic_diffusion.py create mode 100755 release/scripts/freestyle/style_modules/apriori_and_causal_density.py create mode 100755 release/scripts/freestyle/style_modules/apriori_density.py create mode 100755 release/scripts/freestyle/style_modules/backbone_stretcher.py create mode 100755 release/scripts/freestyle/style_modules/blueprint_circles.py create mode 100755 release/scripts/freestyle/style_modules/blueprint_ellipses.py create mode 100755 release/scripts/freestyle/style_modules/blueprint_squares.py create mode 100755 release/scripts/freestyle/style_modules/cartoon.py create mode 100755 release/scripts/freestyle/style_modules/contour.py create mode 100755 release/scripts/freestyle/style_modules/curvature2d.py create mode 100755 release/scripts/freestyle/style_modules/external_contour.py create mode 100755 release/scripts/freestyle/style_modules/external_contour_sketchy.py create mode 100755 release/scripts/freestyle/style_modules/external_contour_smooth.py create mode 100755 release/scripts/freestyle/style_modules/extra-lines.sml create mode 100644 release/scripts/freestyle/style_modules/freestyle_init.py create mode 100755 release/scripts/freestyle/style_modules/haloing.py create mode 100755 release/scripts/freestyle/style_modules/ignore_small_occlusions.py create mode 100755 release/scripts/freestyle/style_modules/invisible_lines.py create mode 100755 release/scripts/freestyle/style_modules/japanese_bigbrush.py create mode 100755 release/scripts/freestyle/style_modules/logical_operators.py create mode 100755 release/scripts/freestyle/style_modules/long_anisotropically_dense.py create mode 100755 release/scripts/freestyle/style_modules/multiple_parameterization.py create mode 100755 release/scripts/freestyle/style_modules/nature.py create mode 100755 release/scripts/freestyle/style_modules/near_lines.py create mode 100755 release/scripts/freestyle/style_modules/occluded_by_specific_object.py create mode 100755 release/scripts/freestyle/style_modules/polygonalize.py create mode 100755 release/scripts/freestyle/style_modules/qi0.py create mode 100755 release/scripts/freestyle/style_modules/qi0_not_external_contour.py create mode 100755 release/scripts/freestyle/style_modules/qi1.py create mode 100755 release/scripts/freestyle/style_modules/qi2.py create mode 100755 release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py create mode 100755 release/scripts/freestyle/style_modules/shaders.py create mode 100755 release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py create mode 100755 release/scripts/freestyle/style_modules/sketchy_topology_broken.py create mode 100755 release/scripts/freestyle/style_modules/sketchy_topology_preserved.py create mode 100755 release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py create mode 100755 release/scripts/freestyle/style_modules/split_at_tvertices.py create mode 100755 release/scripts/freestyle/style_modules/stroke_texture.py create mode 100755 release/scripts/freestyle/style_modules/suggestive.py create mode 100755 release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py create mode 100755 release/scripts/freestyle/style_modules/tipremover.py create mode 100755 release/scripts/freestyle/style_modules/tvertex_remover.py create mode 100755 release/scripts/freestyle/style_modules/uniformpruning_zsort.py create mode 100755 release/scripts/freestyle/style_modules/vector.py diff --git a/release/scripts/freestyle/data/env_map/brown00.png b/release/scripts/freestyle/data/env_map/brown00.png new file mode 100755 index 0000000000000000000000000000000000000000..855f06f4fb9a3ad79ded9b2358ef86eee2f84874 GIT binary patch literal 22195 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 literal 0 HcmV?d00001 diff --git a/release/scripts/freestyle/data/env_map/gray00.png b/release/scripts/freestyle/data/env_map/gray00.png new file mode 100755 index 0000000000000000000000000000000000000000..7c9b1a8149ea72831186d3d30b503e6da936fdea GIT binary patch literal 18513 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 literal 0 HcmV?d00001 diff --git a/release/scripts/freestyle/data/env_map/gray01.png b/release/scripts/freestyle/data/env_map/gray01.png new file mode 100755 index 0000000000000000000000000000000000000000..06542908e6bc8f44798845b08bda7d2b1b4682e8 GIT binary patch literal 9915 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 literal 0 HcmV?d00001 diff --git a/release/scripts/freestyle/data/env_map/gray02.png b/release/scripts/freestyle/data/env_map/gray02.png new file mode 100755 index 0000000000000000000000000000000000000000..0208f4920d9a9ba7e0ee5c91397cc6d0c9dacad5 GIT binary patch literal 7197 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 literal 0 HcmV?d00001 diff --git a/release/scripts/freestyle/data/env_map/gray03.png b/release/scripts/freestyle/data/env_map/gray03.png new file mode 100755 index 0000000000000000000000000000000000000000..aab9b957c210198bae6eeda62e2a89c19198a967 GIT binary patch literal 16109 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 self._percent * self._length): + winner = None + return winner + +## Chaining iterator that fills small occlusions +## size +## The max length of the occluded part +## expressed in pixels +class pyFillOcclusionsAbsoluteChainingIterator(ChainingIterator): + def __init__(self, length): + ChainingIterator.__init__(self, 0, 1,None,1) + self._length = float(length) + def getExactTypeName(self): + return "pySmallFillOcclusionsChainingIterator" + def init(self): + pass + def traverse(self, iter): + winner = None + winnerOrientation = 0 + #print self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond() + it = AdjacencyIterator(iter) + nextVertex = self.getVertex() + if(nextVertex.getNature() & Nature.T_VERTEX != 0): + tvertex = nextVertex.castToTVertex() + mateVE = tvertex.mate(self.getCurrentEdge()) + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getId() == mateVE.getId() ): + winner = ve + if(it.isIncoming() == 0): + winnerOrientation = 1 + else: + winnerOrientation = 0 + break + it.increment() + else: + ## case of NonTVertex + natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE] + for nat in natures: + if(self.getCurrentEdge().getNature() & nat != 0): + count=0 + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getNature() & nat != 0): + count = count+1 + winner = ve + if(it.isIncoming() == 0): + winnerOrientation = 1 + else: + winnerOrientation = 0 + it.increment() + if(count != 1): + winner = None + break + if(winner != None): + # check whether this edge was part of the selection + if(winner.getTimeStamp() != GetTimeStampCF()): + #print "---", winner.getId().getFirst(), winner.getId().getSecond() + # nw let's compute the length of this connex non selected part: + connexl = 0 + _cit = pyChainSilhouetteGenericIterator(0,0) + _cit.setBegin(winner) + _cit.setCurrentEdge(winner) + _cit.setOrientation(winnerOrientation) + _cit.init() + while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())): + ve = _cit.getObject() + #print "-------- --------", ve.getId().getFirst(), ve.getId().getSecond() + connexl = connexl + ve.getLength2D() + _cit.increment() + if(connexl > self._length): + winner = None + return winner + + +## Chaining iterator that fills small occlusions +## percent +## The max length of the occluded part +## expressed in % of the total chain length +class pyFillOcclusionsAbsoluteAndRelativeChainingIterator(ChainingIterator): + def __init__(self, percent, l): + ChainingIterator.__init__(self, 0, 1,None,1) + self._length = 0 + self._absLength = l + self._percent = float(percent) + def getExactTypeName(self): + return "pyFillOcclusionsChainingIterator" + def init(self): + # each time we're evaluating a chain length + # we try to do it once. Thus we reinit + # the chain length here: + self._length = 0 + def traverse(self, iter): + winner = None + winnerOrientation = 0 + print self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond() + it = AdjacencyIterator(iter) + nextVertex = self.getVertex() + if(nextVertex.getNature() & Nature.T_VERTEX != 0): + tvertex = nextVertex.castToTVertex() + mateVE = tvertex.mate(self.getCurrentEdge()) + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getId() == mateVE.getId() ): + winner = ve + if(it.isIncoming() == 0): + winnerOrientation = 1 + else: + winnerOrientation = 0 + break + it.increment() + else: + ## case of NonTVertex + natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE] + for nat in natures: + if(self.getCurrentEdge().getNature() & nat != 0): + count=0 + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getNature() & nat != 0): + count = count+1 + winner = ve + if(it.isIncoming() == 0): + winnerOrientation = 1 + else: + winnerOrientation = 0 + it.increment() + if(count != 1): + winner = None + break + if(winner != None): + # check whether this edge was part of the selection + if(winner.getTimeStamp() != GetTimeStampCF()): + #print "---", winner.getId().getFirst(), winner.getId().getSecond() + # if not, let's check whether it's short enough with + # respect to the chain made without staying in the selection + #------------------------------------------------------------ + # Did we compute the prospective chain length already ? + if(self._length == 0): + #if not, let's do it + _it = pyChainSilhouetteGenericIterator(0,0) + _it.setBegin(winner) + _it.setCurrentEdge(winner) + _it.setOrientation(winnerOrientation) + _it.init() + while(_it.isEnd() == 0): + ve = _it.getObject() + #print "--------", ve.getId().getFirst(), ve.getId().getSecond() + self._length = self._length + ve.getLength2D() + _it.increment() + if(_it.isBegin() != 0): + break; + _it.setBegin(winner) + _it.setCurrentEdge(winner) + _it.setOrientation(winnerOrientation) + if(_it.isBegin() == 0): + _it.decrement() + while ((_it.isEnd() == 0) and (_it.isBegin() == 0)): + ve = _it.getObject() + #print "--------", ve.getId().getFirst(), ve.getId().getSecond() + self._length = self._length + ve.getLength2D() + _it.decrement() + + # let's do the comparison: + # nw let's compute the length of this connex non selected part: + connexl = 0 + _cit = pyChainSilhouetteGenericIterator(0,0) + _cit.setBegin(winner) + _cit.setCurrentEdge(winner) + _cit.setOrientation(winnerOrientation) + _cit.init() + while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())): + ve = _cit.getObject() + #print "-------- --------", ve.getId().getFirst(), ve.getId().getSecond() + connexl = connexl + ve.getLength2D() + _cit.increment() + if((connexl > self._percent * self._length) or (connexl > self._absLength)): + winner = None + return winner + +## Chaining iterator that fills small occlusions without caring about the +## actual selection +## percent +## The max length of the occluded part +## expressed in % of the total chain length +class pyFillQi0AbsoluteAndRelativeChainingIterator(ChainingIterator): + def __init__(self, percent, l): + ChainingIterator.__init__(self, 0, 1,None,1) + self._length = 0 + self._absLength = l + self._percent = float(percent) + def getExactTypeName(self): + return "pyFillOcclusionsChainingIterator" + def init(self): + # each time we're evaluating a chain length + # we try to do it once. Thus we reinit + # the chain length here: + self._length = 0 + def traverse(self, iter): + winner = None + winnerOrientation = 0 + print self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond() + it = AdjacencyIterator(iter) + nextVertex = self.getVertex() + if(nextVertex.getNature() & Nature.T_VERTEX != 0): + tvertex = nextVertex.castToTVertex() + mateVE = tvertex.mate(self.getCurrentEdge()) + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getId() == mateVE.getId() ): + winner = ve + if(it.isIncoming() == 0): + winnerOrientation = 1 + else: + winnerOrientation = 0 + break + it.increment() + else: + ## case of NonTVertex + natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE] + for nat in natures: + if(self.getCurrentEdge().getNature() & nat != 0): + count=0 + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getNature() & nat != 0): + count = count+1 + winner = ve + if(it.isIncoming() == 0): + winnerOrientation = 1 + else: + winnerOrientation = 0 + it.increment() + if(count != 1): + winner = None + break + if(winner != None): + # check whether this edge was part of the selection + if(winner.qi() != 0): + #print "---", winner.getId().getFirst(), winner.getId().getSecond() + # if not, let's check whether it's short enough with + # respect to the chain made without staying in the selection + #------------------------------------------------------------ + # Did we compute the prospective chain length already ? + if(self._length == 0): + #if not, let's do it + _it = pyChainSilhouetteGenericIterator(0,0) + _it.setBegin(winner) + _it.setCurrentEdge(winner) + _it.setOrientation(winnerOrientation) + _it.init() + while(_it.isEnd() == 0): + ve = _it.getObject() + #print "--------", ve.getId().getFirst(), ve.getId().getSecond() + self._length = self._length + ve.getLength2D() + _it.increment() + if(_it.isBegin() != 0): + break; + _it.setBegin(winner) + _it.setCurrentEdge(winner) + _it.setOrientation(winnerOrientation) + if(_it.isBegin() == 0): + _it.decrement() + while ((_it.isEnd() == 0) and (_it.isBegin() == 0)): + ve = _it.getObject() + #print "--------", ve.getId().getFirst(), ve.getId().getSecond() + self._length = self._length + ve.getLength2D() + _it.decrement() + + # let's do the comparison: + # nw let's compute the length of this connex non selected part: + connexl = 0 + _cit = pyChainSilhouetteGenericIterator(0,0) + _cit.setBegin(winner) + _cit.setCurrentEdge(winner) + _cit.setOrientation(winnerOrientation) + _cit.init() + while((_cit.isEnd() == 0) and (_cit.getObject().qi() != 0)): + ve = _cit.getObject() + #print "-------- --------", ve.getId().getFirst(), ve.getId().getSecond() + connexl = connexl + ve.getLength2D() + _cit.increment() + if((connexl > self._percent * self._length) or (connexl > self._absLength)): + winner = None + return winner + + +## the natural chaining iterator +## It follows the edges of same nature on the same +## objects with preseance on silhouettes, then borders, +## then suggestive contours, then everything else. It doesn't chain the same ViewEdge twice +## You can specify whether to stay in the selection or not. +class pyNoIdChainSilhouetteIterator(ChainingIterator): + def __init__(self, stayInSelection=1): + ChainingIterator.__init__(self, stayInSelection, 1,None,1) + def getExactTypeName(self): + return "pyChainSilhouetteIterator" + def init(self): + pass + def traverse(self, iter): + winner = None + it = AdjacencyIterator(iter) + nextVertex = self.getVertex() + if(nextVertex.getNature() & Nature.T_VERTEX != 0): + tvertex = nextVertex.castToTVertex() + mateVE = tvertex.mate(self.getCurrentEdge()) + while(it.isEnd() == 0): + ve = it.getObject() + feB = self.getCurrentEdge().fedgeB() + feA = ve.fedgeA() + vB = feB.vertexB() + vA = feA.vertexA() + if vA.getId().getFirst() == vB.getId().getFirst(): + winner = ve + break + feA = self.getCurrentEdge().fedgeA() + feB = ve.fedgeB() + vB = feB.vertexB() + vA = feA.vertexA() + if vA.getId().getFirst() == vB.getId().getFirst(): + winner = ve + break + feA = self.getCurrentEdge().fedgeB() + feB = ve.fedgeB() + vB = feB.vertexB() + vA = feA.vertexB() + if vA.getId().getFirst() == vB.getId().getFirst(): + winner = ve + break + feA = self.getCurrentEdge().fedgeA() + feB = ve.fedgeA() + vB = feB.vertexA() + vA = feA.vertexA() + if vA.getId().getFirst() == vB.getId().getFirst(): + winner = ve + break + it.increment() + else: + ## case of NonTVertex + natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE] + for i in range(len(natures)): + currentNature = self.getCurrentEdge().getNature() + if(natures[i] & currentNature): + count=0 + while(it.isEnd() == 0): + visitNext = 0 + oNature = it.getObject().getNature() + if(oNature & natures[i] != 0): + if(natures[i] != oNature): + for j in range(i): + if(natures[j] & oNature != 0): + visitNext = 1 + break + if(visitNext != 0): + break + count = count+1 + winner = it.getObject() + it.increment() + if(count != 1): + winner = None + break + return winner + diff --git a/release/scripts/freestyle/style_modules/Functions0D.py b/release/scripts/freestyle/style_modules/Functions0D.py new file mode 100755 index 00000000000..f5ff106c340 --- /dev/null +++ b/release/scripts/freestyle/style_modules/Functions0D.py @@ -0,0 +1,81 @@ +from freestyle_init import * + + +class pyInverseCurvature2DAngleF0D(UnaryFunction0DDouble): + def getName(self): + return "InverseCurvature2DAngleF0D" + + def __call__(self, inter): + func = Curvature2DAngleF0D() + c = func(inter) + return (3.1415 - c) + +class pyCurvilinearLengthF0D(UnaryFunction0DDouble): + def getName(self): + return "CurvilinearLengthF0D" + + def __call__(self, inter): + i0d = inter.getObject() + s = i0d.getExactTypeName() + if (string.find(s, "CurvePoint") == -1): + print "CurvilinearLengthF0D: not implemented yet for %s" % (s) + return -1 + cp = castToCurvePoint(i0d) + return cp.t2d() + +## estimate anisotropy of density +class pyDensityAnisotropyF0D(UnaryFunction0DDouble): + def __init__(self,level): + UnaryFunction0DDouble.__init__(self) + self.IsoDensity = ReadCompleteViewMapPixelF0D(level) + self.d0Density = ReadSteerableViewMapPixelF0D(0, level) + self.d1Density = ReadSteerableViewMapPixelF0D(1, level) + self.d2Density = ReadSteerableViewMapPixelF0D(2, level) + self.d3Density = ReadSteerableViewMapPixelF0D(3, level) + def getName(self): + return "pyDensityAnisotropyF0D" + def __call__(self, inter): + c_iso = self.IsoDensity(inter) + c_0 = self.d0Density(inter) + c_1 = self.d1Density(inter) + c_2 = self.d2Density(inter) + c_3 = self.d3Density(inter) + cMax = max( max(c_0,c_1), max(c_2,c_3)) + cMin = min( min(c_0,c_1), min(c_2,c_3)) + if ( c_iso == 0 ): + v = 0 + else: + v = (cMax-cMin)/c_iso + return (v) + +## Returns the gradient vector for a pixel +## l +## the level at which one wants to compute the gradient +class pyViewMapGradientVectorF0D(UnaryFunction0DVec2f): + def __init__(self, l): + UnaryFunction0DVec2f.__init__(self) + self._l = l + self._step = pow(2,self._l) + def getName(self): + return "pyViewMapGradientVectorF0D" + def __call__(self, iter): + p = iter.getObject().getPoint2D() + gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y())) + gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y())) + return Vec2f(gx, gy) + +class pyViewMapGradientNormF0D(UnaryFunction0DDouble): + def __init__(self, l): + UnaryFunction0DDouble.__init__(self) + self._l = l + self._step = pow(2,self._l) + def getName(self): + return "pyViewMapGradientNormF0D" + def __call__(self, iter): + p = iter.getObject().getPoint2D() + gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y())) + gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y())) + grad = Vec2f(gx, gy) + return grad.norm() + + diff --git a/release/scripts/freestyle/style_modules/Functions1D.py b/release/scripts/freestyle/style_modules/Functions1D.py new file mode 100755 index 00000000000..308486bc6a7 --- /dev/null +++ b/release/scripts/freestyle/style_modules/Functions1D.py @@ -0,0 +1,45 @@ +from freestyle_init import * +from Functions0D import * +import string + +class pyGetInverseProjectedZF1D(UnaryFunction1DDouble): + def getName(self): + return "pyGetInverseProjectedZF1D" + + def __call__(self, inter): + func = GetProjectedZF1D() + z = func(inter) + return (1.0 - z) + +class pyGetSquareInverseProjectedZF1D(UnaryFunction1DDouble): + def getName(self): + return "pyGetInverseProjectedZF1D" + + def __call__(self, inter): + func = GetProjectedZF1D() + z = func(inter) + return (1.0 - z*z) + +class pyDensityAnisotropyF1D(UnaryFunction1DDouble): + def __init__(self,level, integrationType=IntegrationType.MEAN, sampling=2.0): + UnaryFunction1DDouble.__init__(self, integrationType) + self._func = pyDensityAnisotropyF0D(level) + self._integration = integrationType + self._sampling = sampling + def getName(self): + return "pyDensityAnisotropyF1D" + def __call__(self, inter): + v = integrateDouble(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration) + return v + +class pyViewMapGradientNormF1D(UnaryFunction1DDouble): + def __init__(self,l, integrationType, sampling=2.0): + UnaryFunction1DDouble.__init__(self, integrationType) + self._func = pyViewMapGradientNormF0D(l) + self._integration = integrationType + self._sampling = sampling + def getName(self): + return "pyViewMapGradientNormF1D" + def __call__(self, inter): + v = integrateDouble(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration) + return v diff --git a/release/scripts/freestyle/style_modules/PredicatesB1D.py b/release/scripts/freestyle/style_modules/PredicatesB1D.py new file mode 100755 index 00000000000..d4c1cace3fe --- /dev/null +++ b/release/scripts/freestyle/style_modules/PredicatesB1D.py @@ -0,0 +1,70 @@ +from freestyle_init import * +from Functions1D import * +from random import * + +class pyZBP1D(BinaryPredicate1D): + def getName(self): + return "pyZBP1D" + + def __call__(self, i1, i2): + func = GetZF1D() + return (func(i1) > func(i2)) + +class pyZDiscontinuityBP1D(BinaryPredicate1D): + def __init__(self, iType = IntegrationType.MEAN): + BinaryPredicate1D.__init__(self) + self._GetZDiscontinuity = ZDiscontinuityF1D(iType) + + def getName(self): + return "pyZDiscontinuityBP1D" + + def __call__(self, i1, i2): + return (self._GetZDiscontinuity(i1) > self._GetZDiscontinuity(i2)) + +class pyLengthBP1D(BinaryPredicate1D): + def getName(self): + return "LengthBP1D" + + def __call__(self, i1, i2): + return (i1.getLength2D() > i2.getLength2D()) + +class pySilhouetteFirstBP1D(BinaryPredicate1D): + def getName(self): + return "SilhouetteFirstBP1D" + + def __call__(self, inter1, inter2): + bpred = SameShapeIdBP1D() + if (bpred(inter1, inter2) != 1): + return 0 + if (inter1.getNature() & Nature.SILHOUETTE): + return (inter2.getNature() & Nature.SILHOUETTE) + return (inter1.getNature() == inter2.getNature()) + +class pyNatureBP1D(BinaryPredicate1D): + def getName(self): + return "NatureBP1D" + + def __call__(self, inter1, inter2): + return (inter1.getNature() & inter2.getNature()) + +class pyViewMapGradientNormBP1D(BinaryPredicate1D): + def __init__(self,l, sampling=2.0): + BinaryPredicate1D.__init__(self) + self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN) + def getName(self): + return "pyViewMapGradientNormBP1D" + def __call__(self, i1,i2): + print "compare gradient" + return (self._GetGradient(i1) > self._GetGradient(i2)) + +class pyShuffleBP1D(BinaryPredicate1D): + def __init__(self): + BinaryPredicate1D.__init__(self) + seed(1) + def getName(self): + return "pyNearAndContourFirstBP1D" + + def __call__(self, inter1, inter2): + r1 = uniform(0,1) + r2 = uniform(0,1) + return (r1 self._a) + +class pyUEqualsUP0D(UnaryPredicate0D): + def __init__(self,u, w): + UnaryPredicate0D.__init__(self) + self._u = u + self._w = w + + def getName(self): + return "UEqualsUP0D" + + def __call__(self, inter): + func = pyCurvilinearLengthF0D() + u = func(inter) + return ( ( u > (self._u-self._w) ) and ( u < (self._u+self._w) ) ) + +class pyVertexNatureUP0D(UnaryPredicate0D): + def __init__(self,nature): + UnaryPredicate0D.__init__(self) + self._nature = nature + + def getName(self): + return "pyVertexNatureUP0D" + + def __call__(self, inter): + v = inter.getObject() + nat = v.getNature() + if(nat & self._nature): + return 1; + return 0 + +## check whether an Interface0DIterator +## is a TVertex and is the one that is +## hidden (inferred from the context) +class pyBackTVertexUP0D(UnaryPredicate0D): + def __init__(self): + UnaryPredicate0D.__init__(self) + self._getQI = QuantitativeInvisibilityF0D() + def getName(self): + return "pyBackTVertexUP0D" + def __call__(self, iter): + v = iter.getObject() + nat = v.getNature() + if(nat & Nature.T_VERTEX == 0): + return 0 + next = iter + if(next.isEnd()): + return 0 + if(self._getQI(next) != 0): + return 1 + return 0 + +class pyParameterUP0DGoodOne(UnaryPredicate0D): + def __init__(self,pmin,pmax): + UnaryPredicate0D.__init__(self) + self._m = pmin + self._M = pmax + #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D() + + def getName(self): + return "pyCurvilinearAbscissaHigherThanUP0D" + + def __call__(self, inter): + #s = self.getCurvilinearAbscissa(inter) + u = inter.u() + #print u + return ((u>=self._m) and (u<=self._M)) + +class pyParameterUP0D(UnaryPredicate0D): + def __init__(self,pmin,pmax): + UnaryPredicate0D.__init__(self) + self._m = pmin + self._M = pmax + #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D() + + def getName(self): + return "pyCurvilinearAbscissaHigherThanUP0D" + + def __call__(self, inter): + func = Curvature2DAngleF0D() + c = func(inter) + b1 = (c>0.1) + #s = self.getCurvilinearAbscissa(inter) + u = inter.u() + #print u + b = ((u>=self._m) and (u<=self._M)) + return b and b1 + + diff --git a/release/scripts/freestyle/style_modules/PredicatesU1D.py b/release/scripts/freestyle/style_modules/PredicatesU1D.py new file mode 100755 index 00000000000..5d1b594a109 --- /dev/null +++ b/release/scripts/freestyle/style_modules/PredicatesU1D.py @@ -0,0 +1,381 @@ +from freestyle_init import * +from Functions1D import * + +count = 0 +class pyNFirstUP1D(UnaryPredicate1D): + def __init__(self, n): + UnaryPredicate1D.__init__(self) + self.__n = n + def __call__(self, inter): + global count + count = count + 1 + if count <= self.__n: + return 1 + return 0 + +class pyHigherLengthUP1D(UnaryPredicate1D): + def __init__(self,l): + UnaryPredicate1D.__init__(self) + self._l = l + + def getName(self): + return "HigherLengthUP1D" + + def __call__(self, inter): + return (inter.getLength2D() > self._l) + +class pyNatureUP1D(UnaryPredicate1D): + def __init__(self,nature): + UnaryPredicate1D.__init__(self) + self._nature = nature + self._getNature = CurveNatureF1D() + + def getName(self): + return "pyNatureUP1D" + + def __call__(self, inter): + if(self._getNature(inter) & self._nature): + return 1 + return 0 + +class pyHigherNumberOfTurnsUP1D(UnaryPredicate1D): + def __init__(self,n,a): + UnaryPredicate1D.__init__(self) + self._n = n + self._a = a + + def getName(self): + return "HigherNumberOfTurnsUP1D" + + def __call__(self, inter): + count = 0 + func = Curvature2DAngleF0D() + it = inter.verticesBegin() + while(it.isEnd() == 0): + if(func(it) > self._a): + count = count+1 + if(count > self._n): + return 1 + it.increment() + return 0 + +class pyDensityUP1D(UnaryPredicate1D): + def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0): + UnaryPredicate1D.__init__(self) + self._wsize = wsize + self._threshold = threshold + self._integration = integration + self._func = DensityF1D(self._wsize, self._integration, sampling) + + def getName(self): + return "pyDensityUP1D" + + def __call__(self, inter): + if(self._func(inter) < self._threshold): + return 1 + return 0 + +class pyLowSteerableViewMapDensityUP1D(UnaryPredicate1D): + def __init__(self,threshold, level,integration = IntegrationType.MEAN): + UnaryPredicate1D.__init__(self) + self._threshold = threshold + self._level = level + self._integration = integration + + def getName(self): + return "pyLowSteerableViewMapDensityUP1D" + + def __call__(self, inter): + func = GetSteerableViewMapDensityF1D(self._level, self._integration) + v = func(inter) + print v + if(v < self._threshold): + return 1 + return 0 + +class pyLowDirectionalViewMapDensityUP1D(UnaryPredicate1D): + def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN): + UnaryPredicate1D.__init__(self) + self._threshold = threshold + self._orientation = orientation + self._level = level + self._integration = integration + + def getName(self): + return "pyLowDirectionalViewMapDensityUP1D" + + def __call__(self, inter): + func = GetDirectionalViewMapDensityF1D(self._orientation, self._level, self._integration) + v = func(inter) + #print v + if(v < self._threshold): + return 1 + return 0 + +class pyHighSteerableViewMapDensityUP1D(UnaryPredicate1D): + def __init__(self,threshold, level,integration = IntegrationType.MEAN): + UnaryPredicate1D.__init__(self) + self._threshold = threshold + self._level = level + self._integration = integration + self._func = GetSteerableViewMapDensityF1D(self._level, self._integration) + def getName(self): + return "pyHighSteerableViewMapDensityUP1D" + + def __call__(self, inter): + + v = self._func(inter) + if(v > self._threshold): + return 1 + return 0 + +class pyHighDirectionalViewMapDensityUP1D(UnaryPredicate1D): + def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN, sampling=2.0): + UnaryPredicate1D.__init__(self) + self._threshold = threshold + self._orientation = orientation + self._level = level + self._integration = integration + self._sampling = sampling + def getName(self): + return "pyLowDirectionalViewMapDensityUP1D" + + def __call__(self, inter): + func = GetDirectionalViewMapDensityF1D(self._orientation, self._level, self._integration, self._sampling) + v = func(inter) + if(v > self._threshold): + return 1 + return 0 + +class pyHighViewMapDensityUP1D(UnaryPredicate1D): + def __init__(self,threshold, level,integration = IntegrationType.MEAN, sampling=2.0): + UnaryPredicate1D.__init__(self) + self._threshold = threshold + self._level = level + self._integration = integration + self._sampling = sampling + self._func = GetCompleteViewMapDensityF1D(self._level, self._integration, self._sampling) # 2.0 is the smpling + + def getName(self): + return "pyHighViewMapDensityUP1D" + + def __call__(self, inter): + #print "toto" + #print func.getName() + #print inter.getExactTypeName() + v= self._func(inter) + if(v > self._threshold): + return 1 + return 0 + +class pyDensityFunctorUP1D(UnaryPredicate1D): + def __init__(self,wsize,threshold, functor, funcmin=0.0, funcmax=1.0, integration = IntegrationType.MEAN): + UnaryPredicate1D.__init__(self) + self._wsize = wsize + self._threshold = float(threshold) + self._functor = functor + self._funcmin = float(funcmin) + self._funcmax = float(funcmax) + self._integration = integration + + def getName(self): + return "pyDensityFunctorUP1D" + + def __call__(self, inter): + func = DensityF1D(self._wsize, self._integration) + res = self._functor(inter) + k = (res-self._funcmin)/(self._funcmax-self._funcmin) + if(func(inter) < self._threshold*k): + return 1 + return 0 + +class pyZSmallerUP1D(UnaryPredicate1D): + def __init__(self,z, integration=IntegrationType.MEAN): + UnaryPredicate1D.__init__(self) + self._z = z + self._integration = integration + def getName(self): + return "pyZSmallerUP1D" + + def __call__(self, inter): + func = GetProjectedZF1D(self._integration) + if(func(inter) < self._z): + return 1 + return 0 + +class pyIsOccludedByUP1D(UnaryPredicate1D): + def __init__(self,id): + UnaryPredicate1D.__init__(self) + self._id = id + def getName(self): + return "pyIsOccludedByUP1D" + def __call__(self, inter): + func = GetShapeF1D() + shapes = func(inter) + for s in shapes: + if(s.getId() == self._id): + return 0 + it = inter.verticesBegin() + itlast = inter.verticesEnd() + itlast.decrement() + v = it.getObject() + vlast = itlast.getObject() + tvertex = v.castToTVertex() + if(tvertex != None): + #print "TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]" + eit = tvertex.edgesBegin() + while(eit.isEnd() == 0): + ve = eit.getObject().first + if(ve.shape_id() == self._id): + return 1 + #print "-------", ve.getId().getFirst(), "-", ve.getId().getSecond() + eit.increment() + tvertex = vlast.castToTVertex() + if(tvertex != None): + #print "TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]" + eit = tvertex.edgesBegin() + while(eit.isEnd() == 0): + ve = eit.getObject().first + if(ve.shape_id() == self._id): + return 1 + #print "-------", ve.getId().getFirst(), "-", ve.getId().getSecond() + eit.increment() + return 0 + +class pyIsInOccludersListUP1D(UnaryPredicate1D): + def __init__(self,id): + UnaryPredicate1D.__init__(self) + self._id = id + def getName(self): + return "pyIsInOccludersListUP1D" + def __call__(self, inter): + func = GetOccludersF1D() + occluders = func(inter) + for a in occluders: + if(a.getId() == self._id): + return 1 + return 0 + +class pyIsOccludedByItselfUP1D(UnaryPredicate1D): + def __init__(self): + UnaryPredicate1D.__init__(self) + self.__func1 = GetOccludersF1D() + self.__func2 = GetShapeF1D() + def getName(self): + return "pyIsOccludedByItselfUP1D" + def __call__(self, inter): + lst1 = self.__func1(inter) + lst2 = self.__func2(inter) + for vs1 in lst1: + for vs2 in lst2: + if vs1.getId() == vs2.getId(): + return 1 + return 0 + +class pyIsOccludedByIdListUP1D(UnaryPredicate1D): + def __init__(self, idlist): + UnaryPredicate1D.__init__(self) + self._idlist = idlist + self.__func1 = GetOccludersF1D() + def getName(self): + return "pyIsOccludedByIdListUP1D" + def __call__(self, inter): + lst1 = self.__func1(inter) + for vs1 in lst1: + for id in self._idlist: + if vs1.getId() == id: + return 1 + return 0 + +class pyShapeIdListUP1D(UnaryPredicate1D): + def __init__(self,idlist): + UnaryPredicate1D.__init__(self) + self._idlist = idlist + self._funcs = [] + for id in idlist : + self._funcs.append(ShapeUP1D(id.getFirst(), id.getSecond())) + + def getName(self): + return "pyShapeIdUP1D" + def __call__(self, inter): + for func in self._funcs : + if(func(inter) == 1) : + return 1 + return 0 + +## deprecated +class pyShapeIdUP1D(UnaryPredicate1D): + def __init__(self,id): + UnaryPredicate1D.__init__(self) + self._id = id + def getName(self): + return "pyShapeIdUP1D" + def __call__(self, inter): + func = GetShapeF1D() + shapes = func(inter) + for a in shapes: + if(a.getId() == self._id): + return 1 + return 0 + +class pyHighDensityAnisotropyUP1D(UnaryPredicate1D): + def __init__(self,threshold, level, sampling=2.0): + UnaryPredicate1D.__init__(self) + self._l = threshold + self.func = pyDensityAnisotropyF1D(level, IntegrationType.MEAN, sampling) + def getName(self): + return "pyHighDensityAnisotropyUP1D" + def __call__(self, inter): + return (self.func(inter) > self._l) + +class pyHighViewMapGradientNormUP1D(UnaryPredicate1D): + def __init__(self,threshold, l, sampling=2.0): + UnaryPredicate1D.__init__(self) + self._threshold = threshold + self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN) + def getName(self): + return "pyHighViewMapGradientNormUP1D" + def __call__(self, inter): + gn = self._GetGradient(inter) + #print gn + return (gn > self._threshold) + +class pyDensityVariableSigmaUP1D(UnaryPredicate1D): + def __init__(self,functor, sigmaMin,sigmaMax, lmin, lmax, tmin, tmax, integration = IntegrationType.MEAN, sampling=2.0): + UnaryPredicate1D.__init__(self) + self._functor = functor + self._sigmaMin = float(sigmaMin) + self._sigmaMax = float(sigmaMax) + self._lmin = float(lmin) + self._lmax = float(lmax) + self._tmin = tmin + self._tmax = tmax + self._integration = integration + self._sampling = sampling + + def getName(self): + return "pyDensityUP1D" + + def __call__(self, inter): + sigma = (self._sigmaMax-self._sigmaMin)/(self._lmax-self._lmin)*(self._functor(inter)-self._lmin) + self._sigmaMin + t = (self._tmax-self._tmin)/(self._lmax-self._lmin)*(self._functor(inter)-self._lmin) + self._tmin + if(sigma 4* c ): + if ( c < 1.5*self._threshold ): + return 1 + return 0 + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0))) +Operators.select(pyHigherLengthUP1D(40)) +## selects lines having a high anisotropic a priori density +Operators.select(pyHighDensityAnisotropyUP1D(0.3,4)) +Operators.sort(pyLengthBP1D()) +shaders_list = [ + SamplingShader(2.0), + ConstantThicknessShader(2), + ConstantColorShader(0.2,0.2,0.25,1), + ] +## uniform culling +Operators.create(pyDensityUP1D(3.0,2.0e-2, IntegrationType.MEAN, 0.1), shaders_list) + + diff --git a/release/scripts/freestyle/style_modules/multiple_parameterization.py b/release/scripts/freestyle/style_modules/multiple_parameterization.py new file mode 100755 index 00000000000..3f0409db5fa --- /dev/null +++ b/release/scripts/freestyle/style_modules/multiple_parameterization.py @@ -0,0 +1,51 @@ +# +# Filename : multiple_parameterization.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : The thickness and the color of the strokes vary continuously +# independently from occlusions although only +# visible lines are actually drawn. This is equivalent +# to assigning the thickness using a parameterization covering +# the complete silhouette (visible+invisible) and drawing +# the strokes using a second parameterization that only +# covers the visible portions. +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +## Chain following the same nature, but without the restriction +## of staying inside the selection (0). +Operators.bidirectionalChain(ChainSilhouetteIterator(0)) +shaders_list = [ + SamplingShader(20), + IncreasingThicknessShader(1.5, 30), + ConstantColorShader(0.0,0.0,0.0), + IncreasingColorShader(1,0,0,1,0,1,0,1), + TextureAssignerShader(-1), + pyHLRShader() ## this shader draws only visible portions + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/nature.py b/release/scripts/freestyle/style_modules/nature.py new file mode 100755 index 00000000000..b5481a8e519 --- /dev/null +++ b/release/scripts/freestyle/style_modules/nature.py @@ -0,0 +1,43 @@ +# +# Filename : nature.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Uses the NatureUP1D predicate to select the lines +# of a given type (among Nature.SILHOUETTE, Nature.CREASE, Nature.SUGGESTIVE_CONTOURS, +# Nature.BORDERS). +# The suggestive contours must have been enabled in the +# options dialog to appear in the View Map. +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesB1D import * +from shaders import * + +Operators.select(pyNatureUP1D(Nature.SILHOUETTE)) +Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D( pyNatureUP1D( Nature.SILHOUETTE) ) ) +shaders_list = [ + IncreasingThicknessShader(3, 10), + IncreasingColorShader(0.0,0.0,0.0, 1, 0.8,0,0,1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/near_lines.py b/release/scripts/freestyle/style_modules/near_lines.py new file mode 100755 index 00000000000..565bca1fe1f --- /dev/null +++ b/release/scripts/freestyle/style_modules/near_lines.py @@ -0,0 +1,44 @@ +# +# Filename : near_lines.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws the lines that are "closer" than a threshold +# (between 0 and 1) +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + + +from freestyle_init import * +from logical_operators import * +from PredicatesB1D import * +from PredicatesU1D import * +from shaders import * + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyZSmallerUP1D(0.5, IntegrationType.MEAN)) +Operators.select(upred) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) +shaders_list = [ + TextureAssignerShader(-1), + ConstantThicknessShader(5), + ConstantColorShader(0.0, 0.0, 0.0) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/occluded_by_specific_object.py b/release/scripts/freestyle/style_modules/occluded_by_specific_object.py new file mode 100755 index 00000000000..09ce39d5dd6 --- /dev/null +++ b/release/scripts/freestyle/style_modules/occluded_by_specific_object.py @@ -0,0 +1,45 @@ +# +# Filename : occluded_by_specific_object.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws only the lines that are occluded by a given object +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesU1D import * +from shaders import * + +## the id of the occluder (use SHIFT+click on the ViewMap to +## retrieve ids) +id = Id(3,0) +upred = AndUP1D(NotUP1D(QuantitativeInvisibilityUP1D(0)), +pyIsInOccludersListUP1D(id)) +Operators.select(upred) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) +shaders_list = [ + SamplingShader(5), + ConstantThicknessShader(3), + ConstantColorShader(0.3,0.3,0.3,1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/polygonalize.py b/release/scripts/freestyle/style_modules/polygonalize.py new file mode 100755 index 00000000000..4446c4c1dcc --- /dev/null +++ b/release/scripts/freestyle/style_modules/polygonalize.py @@ -0,0 +1,40 @@ +# +# Filename : polygonalize.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Make the strokes more "polygonal" +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + SamplingShader(2.0), + ConstantThicknessShader(3), + ConstantColorShader(0.0,0.0,0.0), + PolygonalizationShader(8) + ] +Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file diff --git a/release/scripts/freestyle/style_modules/qi0.py b/release/scripts/freestyle/style_modules/qi0.py new file mode 100755 index 00000000000..d35d23cb7c3 --- /dev/null +++ b/release/scripts/freestyle/style_modules/qi0.py @@ -0,0 +1,41 @@ +# +# Filename : qi0.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws the visible lines (chaining follows same nature lines) +# (most basic style module) +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + SamplingShader(5.0), + ConstantThicknessShader(4.0), + ConstantColorShader(0.0,0.0,0.0) + ] +Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file diff --git a/release/scripts/freestyle/style_modules/qi0_not_external_contour.py b/release/scripts/freestyle/style_modules/qi0_not_external_contour.py new file mode 100755 index 00000000000..eed41af32b4 --- /dev/null +++ b/release/scripts/freestyle/style_modules/qi0_not_external_contour.py @@ -0,0 +1,43 @@ +# +# Filename : qi0_not_external_contour.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws the visible lines (chaining follows same nature lines) +# that do not belong to the external contour of the scene +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) +Operators.select(upred) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) +shaders_list = [ + SamplingShader(4), + SpatialNoiseShader(4, 150, 2, True, True), + IncreasingThicknessShader(2, 5), + BackboneStretcherShader(20), + IncreasingColorShader(1,0,0,1,0,1,0,1), + TextureAssignerShader(4) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/qi1.py b/release/scripts/freestyle/style_modules/qi1.py new file mode 100755 index 00000000000..8d248376138 --- /dev/null +++ b/release/scripts/freestyle/style_modules/qi1.py @@ -0,0 +1,42 @@ +# +# Filename : qi1.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws lines hidden by one surface. +# *** Quantitative Invisibility must have been +# enabled in the options dialog to use this style module **** +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesB1D import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(1)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(1))) +shaders_list = [ + SamplingShader(5.0), + ConstantThicknessShader(3), + ConstantColorShader(0.5,0.5,0.5, 1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/qi2.py b/release/scripts/freestyle/style_modules/qi2.py new file mode 100755 index 00000000000..ba5e97b6982 --- /dev/null +++ b/release/scripts/freestyle/style_modules/qi2.py @@ -0,0 +1,42 @@ +# +# Filename : qi2.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws lines hidden by two surfaces. +# *** Quantitative Invisibility must have been +# enabled in the options dialog to use this style module **** +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesB1D import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(2)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(2))) +shaders_list = [ + SamplingShader(10), + ConstantThicknessShader(1.5), + ConstantColorShader(0.7,0.7,0.7, 1) + ] +Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file diff --git a/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py b/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py new file mode 100755 index 00000000000..53fa03103aa --- /dev/null +++ b/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py @@ -0,0 +1,68 @@ +# +# Filename : sequentialsplit_sketchy.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Use the sequential split with two different +# predicates to specify respectively the starting and +# the stopping extremities for strokes +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesU1D import * +from PredicatesU0D import * +from Functions0D import * + +## Predicate to tell whether a TVertex +## corresponds to a change from 0 to 1 or not. +class pyBackTVertexUP0D(UnaryPredicate0D): + def __init__(self): + UnaryPredicate0D.__init__(self) + self._getQI = QuantitativeInvisibilityF0D() + def getName(self): + return "pyBackTVertexUP0D" + def __call__(self, iter): + v = iter.getObject() + nat = v.getNature() + if(nat & Nature.T_VERTEX == 0): + return 0 + if(self._getQI(iter) != 0): + return 1 + return 0 + + +upred = QuantitativeInvisibilityUP1D(0) +Operators.select(upred) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) +## starting and stopping predicates: +start = pyVertexNatureUP0D(Nature.NON_T_VERTEX) +stop = pyBackTVertexUP0D() +Operators.sequentialSplit(start, stop, 10) +shaders_list = [ + SpatialNoiseShader(7, 120, 2, True, True), + IncreasingThicknessShader(5, 8), + ConstantColorShader(0.2, 0.2, 0.2, 1), + TextureAssignerShader(4) + ] +Operators.create(TrueUP1D(), shaders_list) + diff --git a/release/scripts/freestyle/style_modules/shaders.py b/release/scripts/freestyle/style_modules/shaders.py new file mode 100755 index 00000000000..610e1d2a943 --- /dev/null +++ b/release/scripts/freestyle/style_modules/shaders.py @@ -0,0 +1,1288 @@ +from freestyle_init import * +from PredicatesU0D import * +from PredicatesB1D import * +from PredicatesU1D import * +from logical_operators import * +from ChainingIterators import * +from random import * +from math import * +from vector import * + +## thickness modifiers +###################### + +class pyDepthDiscontinuityThicknessShader(StrokeShader): + def __init__(self, min, max): + StrokeShader.__init__(self) + self.__min = float(min) + self.__max = float(max) + self.__func = ZDiscontinuityF0D() + def getName(self): + return "pyDepthDiscontinuityThicknessShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + z_min=0.0 + z_max=1.0 + a = (self.__max - self.__min)/(z_max-z_min) + b = (self.__min*z_max-self.__max*z_min)/(z_max-z_min) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + z = self.__func(it.castToInterface0DIterator()) + thickness = a*z+b + it.getObject().attribute().setThickness(thickness, thickness) + it.increment() + +class pyConstantThicknessShader(StrokeShader): + def __init__(self, thickness): + StrokeShader.__init__(self) + self._thickness = thickness + + def getName(self): + return "pyConstantThicknessShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + t = self._thickness/2.0 + att.setThickness(t, t) + it.increment() + +class pyFXSThicknessShader(StrokeShader): + def __init__(self, thickness): + StrokeShader.__init__(self) + self._thickness = thickness + + def getName(self): + return "pyFXSThicknessShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + t = self._thickness/2.0 + att.setThickness(t, t) + it.increment() + +class pyFXSVaryingThicknessWithDensityShader(StrokeShader): + def __init__(self, wsize, threshold_min, threshold_max, thicknessMin, thicknessMax): + StrokeShader.__init__(self) + self.wsize= wsize + self.threshold_min= threshold_min + self.threshold_max= threshold_max + self._thicknessMin = thicknessMin + self._thicknessMax = thicknessMax + + def getName(self): + return "pyVaryingThicknessWithDensityShader" + def shade(self, stroke): + n = stroke.strokeVerticesSize() + i = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + func = DensityF0D(self.wsize) + while it.isEnd() == 0: + att = it.getObject().attribute() + toto = it.castToInterface0DIterator() + c= func(toto) + if (c < self.threshold_min ): + c = self.threshold_min + if (c > self.threshold_max ): + c = self.threshold_max +## t = (c - self.threshold_min)/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin + t = (self.threshold_max - c )/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin + att.setThickness(t/2.0, t/2.0) + i = i+1 + it.increment() +class pyIncreasingThicknessShader(StrokeShader): + def __init__(self, thicknessMin, thicknessMax): + StrokeShader.__init__(self) + self._thicknessMin = thicknessMin + self._thicknessMax = thicknessMax + + def getName(self): + return "pyIncreasingThicknessShader" + def shade(self, stroke): + n = stroke.strokeVerticesSize() + i = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + c = float(i)/float(n) + if(i < float(n)/2.0): + t = (1.0 - c)*self._thicknessMin + c * self._thicknessMax + else: + t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin + att.setThickness(t/2.0, t/2.0) + i = i+1 + it.increment() + +class pyConstrainedIncreasingThicknessShader(StrokeShader): + def __init__(self, thicknessMin, thicknessMax, ratio): + StrokeShader.__init__(self) + self._thicknessMin = thicknessMin + self._thicknessMax = thicknessMax + self._ratio = ratio + + def getName(self): + return "pyConstrainedIncreasingThicknessShader" + def shade(self, stroke): + slength = stroke.getLength2D() + tmp = self._ratio*slength + maxT = 0.0 + if(tmp < self._thicknessMax): + maxT = tmp + else: + maxT = self._thicknessMax + n = stroke.strokeVerticesSize() + i = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + c = float(i)/float(n) + if(i < float(n)/2.0): + t = (1.0 - c)*self._thicknessMin + c * maxT + else: + t = (1.0 - c)*maxT + c * self._thicknessMin + att.setThickness(t/2.0, t/2.0) + if(i == n-1): + att.setThickness(self._thicknessMin/2.0, self._thicknessMin/2.0) + i = i+1 + it.increment() + +class pyDecreasingThicknessShader(StrokeShader): + def __init__(self, thicknessMax, thicknessMin): + StrokeShader.__init__(self) + self._thicknessMin = thicknessMin + self._thicknessMax = thicknessMax + + def getName(self): + return "pyDecreasingThicknessShader" + def shade(self, stroke): + l = stroke.getLength2D() + tMax = self._thicknessMax + if(self._thicknessMax > 0.33*l): + tMax = 0.33*l + tMin = self._thicknessMin + if(self._thicknessMin > 0.1*l): + tMin = 0.1*l + n = stroke.strokeVerticesSize() + i = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + c = float(i)/float(n) + t = (1.0 - c)*tMax +c*tMin + att.setThickness(t/2.0, t/2.0) + i = i+1 + it.increment() + +def smoothC( a, exp ): + c = pow(float(a),exp)*pow(2.0,exp) + return c + +class pyNonLinearVaryingThicknessShader(StrokeShader): + def __init__(self, thicknessExtremity, thicknessMiddle, exponent): + StrokeShader.__init__(self) + self._thicknessMin = thicknessMiddle + self._thicknessMax = thicknessExtremity + self._exponent = exponent + + def getName(self): + return "pyNonLinearVaryingThicknessShader" + def shade(self, stroke): + n = stroke.strokeVerticesSize() + i = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + if(i < float(n)/2.0): + c = float(i)/float(n) + else: + c = float(n-i)/float(n) + c = smoothC(c, self._exponent) + t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin + att.setThickness(t/2.0, t/2.0) + i = i+1 + it.increment() + +## Spherical linear interpolation (cos) +class pySLERPThicknessShader(StrokeShader): + def __init__(self, thicknessMin, thicknessMax, omega=1.2): + StrokeShader.__init__(self) + self._thicknessMin = thicknessMin + self._thicknessMax = thicknessMax + self._omega = omega + + def getName(self): + return "pySLERPThicknessShader" + def shade(self, stroke): + slength = stroke.getLength2D() + tmp = 0.33*slength + maxT = self._thicknessMax + if(tmp < self._thicknessMax): + maxT = tmp + + n = stroke.strokeVerticesSize() + i = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + c = float(i)/float(n) + if(i < float(n)/2.0): + t = sin((1-c)*self._omega)/sinh(self._omega)*self._thicknessMin + sin(c*self._omega)/sinh(self._omega) * maxT + else: + t = sin((1-c)*self._omega)/sinh(self._omega)*maxT + sin(c*self._omega)/sinh(self._omega) * self._thicknessMin + att.setThickness(t/2.0, t/2.0) + i = i+1 + it.increment() + +class pyTVertexThickenerShader(StrokeShader): ## FIXME + def __init__(self, a=1.5, n=3): + StrokeShader.__init__(self) + self._a = a + self._n = n + + def getName(self): + return "pyTVertexThickenerShader" + + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX) + while it.isEnd() == 0: + if(predTVertex(it) == 1): + it2 = StrokeVertexIterator(it) + it2.increment() + if not(it.isBegin() or it2.isEnd()): + it.increment() + continue + n = self._n + a = self._a + if(it.isBegin()): + it3 = StrokeVertexIterator(it) + count = 0 + while (it3.isEnd() == 0 and count < n): + att = it3.getObject().attribute() + tr = att.getThicknessR(); + tl = att.getThicknessL(); + r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1 + #r = (1.0-a)/float(n-1)*count + a + att.setThickness(r*tr, r*tl) + it3.increment() + count = count + 1 + if(it2.isEnd()): + it4 = StrokeVertexIterator(it) + count = 0 + while (it4.isBegin() == 0 and count < n): + att = it4.getObject().attribute() + tr = att.getThicknessR(); + tl = att.getThicknessL(); + r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1 + #r = (1.0-a)/float(n-1)*count + a + att.setThickness(r*tr, r*tl) + it4.decrement() + count = count + 1 + if ((it4.isBegin() == 1)): + att = it4.getObject().attribute() + tr = att.getThicknessR(); + tl = att.getThicknessL(); + r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1 + #r = (1.0-a)/float(n-1)*count + a + att.setThickness(r*tr, r*tl) + it.increment() + +class pyImportance2DThicknessShader(StrokeShader): + def __init__(self, x, y, w, kmin, kmax): + StrokeShader.__init__(self) + self._x = x + self._y = y + self._w = float(w) + self._kmin = float(kmin) + self._kmax = float(kmax) + + def getName(self): + return "pyImportanceThicknessShader" + def shade(self, stroke): + origin = Vec2(self._x, self._y) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + p = Vec2(v.getProjectedX(), v.getProjectedY()) + d = (p-origin).length() + if(d>self._w): + k = self._kmin + else: + k = (self._kmax*(self._w-d) + self._kmin*d)/self._w + att = v.attribute() + tr = att.getThicknessR() + tl = att.getThicknessL() + att.setThickness(k*tr/2.0, k*tl/2.0) + it.increment() + +class pyImportance3DThicknessShader(StrokeShader): + def __init__(self, x, y, z, w, kmin, kmax): + StrokeShader.__init__(self) + self._x = x + self._y = y + self._z = z + self._w = float(w) + self._kmin = float(kmin) + self._kmax = float(kmax) + + def getName(self): + return "pyImportance3DThicknessShader" + def shade(self, stroke): + origin = Vec3(self._x, self._y, self._z) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + p = Vec3(v.getX(), v.getY(), v.getZ()) + d = (p-origin).length() + if(d>self._w): + k = self._kmin + else: + k = (self._kmax*(self._w-d) + self._kmin*d)/self._w + att = v.attribute() + tr = att.getThicknessR() + tl = att.getThicknessL() + att.setThickness(k*tr/2.0, k*tl/2.0) + it.increment() + +class pyZDependingThicknessShader(StrokeShader): + def __init__(self, min, max): + StrokeShader.__init__(self) + self.__min = min + self.__max = max + self.__func = GetProjectedZF0D() + def getName(self): + return "pyZDependingThicknessShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + z_min = 1 + z_max = 0 + while it.isEnd() == 0: + z = self.__func(it.castToInterface0DIterator()) + if z < z_min: + z_min = z + elif z > z_max: + z_max = z + it.increment() + z_diff = 1 / (z_max - z_min) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + z = (self.__func(it.castToInterface0DIterator()) - z_min) * z_diff + thickness = (1 - z) * self.__max + z * self.__min + it.getObject().attribute().setThickness(thickness, thickness) + it.increment() + + +## color modifiers +################## + +class pyConstantColorShader(StrokeShader): + def __init__(self,r,g,b, a = 1): + StrokeShader.__init__(self) + self._r = r + self._g = g + self._b = b + self._a = a + def getName(self): + return "pyConstantColorShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + att.setColor(self._r, self._g, self._b) + att.setAlpha(self._a) + it.increment() + +#c1->c2 +class pyIncreasingColorShader(StrokeShader): + def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2): + StrokeShader.__init__(self) + self._c1 = [r1,g1,b1,a1] + self._c2 = [r2,g2,b2,a2] + def getName(self): + return "pyIncreasingColorShader" + def shade(self, stroke): + n = stroke.strokeVerticesSize() - 1 + inc = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + c = float(inc)/float(n) + + att.setColor( (1-c)*self._c1[0] + c*self._c2[0], + (1-c)*self._c1[1] + c*self._c2[1], + (1-c)*self._c1[2] + c*self._c2[2],) + att.setAlpha((1-c)*self._c1[3] + c*self._c2[3],) + inc = inc+1 + it.increment() + +# c1->c2->c1 +class pyInterpolateColorShader(StrokeShader): + def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2): + StrokeShader.__init__(self) + self._c1 = [r1,g1,b1,a1] + self._c2 = [r2,g2,b2,a2] + def getName(self): + return "pyInterpolateColorShader" + def shade(self, stroke): + n = stroke.strokeVerticesSize() - 1 + inc = 0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + u = float(inc)/float(n) + c = 1-2*(fabs(u-0.5)) + att.setColor( (1-c)*self._c1[0] + c*self._c2[0], + (1-c)*self._c1[1] + c*self._c2[1], + (1-c)*self._c1[2] + c*self._c2[2],) + att.setAlpha((1-c)*self._c1[3] + c*self._c2[3],) + inc = inc+1 + it.increment() + +class pyMaterialColorShader(StrokeShader): + def __init__(self, threshold=50): + StrokeShader.__init__(self) + self._threshold = threshold + + def getName(self): + return "pyMaterialColorShader" + + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + func = MaterialF0D() + xn = 0.312713 + yn = 0.329016 + Yn = 1.0 + un = 4.* xn/ ( -2.*xn + 12.*yn + 3. ) + vn= 9.* yn/ ( -2.*xn + 12.*yn +3. ) + while it.isEnd() == 0: + toto = it.castToInterface0DIterator() + mat = func(toto) + + r = mat.diffuseR() + g = mat.diffuseG() + b = mat.diffuseB() + + X = 0.412453*r + 0.35758 *g + 0.180423*b + Y = 0.212671*r + 0.71516 *g + 0.072169*b + Z = 0.019334*r + 0.119193*g + 0.950227*b + + if((X == 0) and (Y == 0) and (Z == 0)): + X = 0.01 + Y = 0.01 + Z = 0.01 + u = 4.*X / (X + 15.*Y + 3.*Z) + v = 9.*Y / (X + 15.*Y + 3.*Z) + + L= 116. * math.pow((Y/Yn),(1./3.)) -16 + U = 13. * L * (u - un) + V = 13. * L * (v - vn) + + if (L > self._threshold): + L = L/1.3 + U = U+10 + else: + L = L +2.5*(100-L)/5. + U = U/3.0 + V = V/3.0 + u = U / (13. * L) + un + v = V / (13. * L) + vn + + Y = Yn * math.pow( ((L+16.)/116.), 3.) + X = -9. * Y * u / ((u - 4.)* v - u * v) + Z = (9. * Y - 15*v*Y - v*X) /( 3. * v) + + r = 3.240479 * X - 1.53715 * Y - 0.498535 * Z + g = -0.969256 * X + 1.875991 * Y + 0.041556 * Z + b = 0.055648 * X - 0.204043 * Y + 1.057311 * Z + + att = it.getObject().attribute() + att.setColor(r, g, b) + it.increment() + +class pyRandomColorShader(StrokeShader): + def getName(self): + return "pyRandomColorShader" + def __init__(self, s=1): + StrokeShader.__init__(self) + seed(s) + def shade(self, stroke): + ## pick a random color + c0 = float(uniform(15,75))/100.0 + c1 = float(uniform(15,75))/100.0 + c2 = float(uniform(15,75))/100.0 + print c0, c1, c2 + it = stroke.strokeVerticesBegin() + while(it.isEnd() == 0): + it.getObject().attribute().setColor(c0,c1,c2) + it.increment() + +class py2DCurvatureColorShader(StrokeShader): + def getName(self): + return "py2DCurvatureColorShader" + + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + func = Curvature2DAngleF0D() + while it.isEnd() == 0: + toto = it.castToInterface0DIterator() + sv = it.getObject() + att = sv.attribute() + c = func(toto) + if (c<0): + print "negative 2D curvature" + color = 10.0 * c/3.1415 + print color + att.setColor(color,color,color); + it.increment() + +class pyTimeColorShader(StrokeShader): + def __init__(self, step=0.01): + StrokeShader.__init__(self) + self._t = 0 + self._step = step + def shade(self, stroke): + c = self._t*1.0 + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + att = it.getObject().attribute() + att.setColor(c,c,c) + it.increment() + self._t = self._t+self._step + +## geometry modifiers + +class pySamplingShader(StrokeShader): + def __init__(self, sampling): + StrokeShader.__init__(self) + self._sampling = sampling + def getName(self): + return "pySamplingShader" + def shade(self, stroke): + stroke.Resample(float(self._sampling)) + +class pyBackboneStretcherShader(StrokeShader): + def __init__(self, l): + StrokeShader.__init__(self) + self._l = l + def getName(self): + return "pyBackboneStretcherShader" + def shade(self, stroke): + it0 = stroke.strokeVerticesBegin() + it1 = StrokeVertexIterator(it0) + it1.increment() + itn = stroke.strokeVerticesEnd() + itn.decrement() + itn_1 = StrokeVertexIterator(itn) + itn_1.decrement() + v0 = it0.getObject() + v1 = it1.getObject() + vn_1 = itn_1.getObject() + vn = itn.getObject() + p0 = Vec2f(v0.getProjectedX(), v0.getProjectedY()) + pn = Vec2f(vn.getProjectedX(), vn.getProjectedY()) + p1 = Vec2f(v1.getProjectedX(), v1.getProjectedY()) + pn_1 = Vec2f(vn_1.getProjectedX(), vn_1.getProjectedY()) + d1 = p0-p1 + d1 = d1/d1.norm() + dn = pn-pn_1 + dn = dn/dn.norm() + newFirst = p0+d1*float(self._l) + newLast = pn+dn*float(self._l) + v0.setPoint(newFirst) + vn.setPoint(newLast) + +class pyLengthDependingBackboneStretcherShader(StrokeShader): + def __init__(self, l): + StrokeShader.__init__(self) + self._l = l + def getName(self): + return "pyBackboneStretcherShader" + def shade(self, stroke): + l = stroke.getLength2D() + stretch = self._l*l + it0 = stroke.strokeVerticesBegin() + it1 = StrokeVertexIterator(it0) + it1.increment() + itn = stroke.strokeVerticesEnd() + itn.decrement() + itn_1 = StrokeVertexIterator(itn) + itn_1.decrement() + v0 = it0.getObject() + v1 = it1.getObject() + vn_1 = itn_1.getObject() + vn = itn.getObject() + p0 = Vec2f(v0.getProjectedX(), v0.getProjectedY()) + pn = Vec2f(vn.getProjectedX(), vn.getProjectedY()) + p1 = Vec2f(v1.getProjectedX(), v1.getProjectedY()) + pn_1 = Vec2f(vn_1.getProjectedX(), vn_1.getProjectedY()) + d1 = p0-p1 + d1 = d1/d1.norm() + dn = pn-pn_1 + dn = dn/dn.norm() + newFirst = p0+d1*float(stretch) + newLast = pn+dn*float(stretch) + v0.setPoint(newFirst) + vn.setPoint(newLast) + + +## Shader to replace a stroke by its corresponding tangent +class pyGuidingLineShader(StrokeShader): + def getName(self): + return "pyGuidingLineShader" + ## shading method + def shade(self, stroke): + it = stroke.strokeVerticesBegin() ## get the first vertex + itlast = stroke.strokeVerticesEnd() ## + itlast.decrement() ## get the last one + t = itlast.getObject().getPoint() - it.getObject().getPoint() ## tangent direction + itmiddle = StrokeVertexIterator(it) ## + while(itmiddle.getObject().u()<0.5): ## look for the stroke middle vertex + itmiddle.increment() ## + it = StrokeVertexIterator(itmiddle) + it.increment() + while(it.isEnd() == 0): ## position all the vertices along the tangent for the right part + it.getObject().setPoint(itmiddle.getObject().getPoint() \ + +t*(it.getObject().u()-itmiddle.getObject().u())) + it.increment() + it = StrokeVertexIterator(itmiddle) + it.decrement() + while(it.isBegin() == 0): ## position all the vertices along the tangent for the left part + it.getObject().setPoint(itmiddle.getObject().getPoint() \ + -t*(itmiddle.getObject().u()-it.getObject().u())) + it.decrement() + it.getObject().setPoint(itmiddle.getObject().getPoint()-t*(itmiddle.getObject().u())) ## first vertex + + +class pyBackboneStretcherNoCuspShader(StrokeShader): + def __init__(self, l): + StrokeShader.__init__(self) + self._l = l + def getName(self): + return "pyBackboneStretcherNoCuspShader" + def shade(self, stroke): + it0 = stroke.strokeVerticesBegin() + it1 = StrokeVertexIterator(it0) + it1.increment() + itn = stroke.strokeVerticesEnd() + itn.decrement() + itn_1 = StrokeVertexIterator(itn) + itn_1.decrement() + v0 = it0.getObject() + v1 = it1.getObject() + if((v0.getNature() & Nature.CUSP == 0) and (v1.getNature() & Nature.CUSP == 0)): + p0 = v0.getPoint() + p1 = v1.getPoint() + d1 = p0-p1 + d1 = d1/d1.norm() + newFirst = p0+d1*float(self._l) + v0.setPoint(newFirst) + vn_1 = itn_1.getObject() + vn = itn.getObject() + if((vn.getNature() & Nature.CUSP == 0) and (vn_1.getNature() & Nature.CUSP == 0)): + pn = vn.getPoint() + pn_1 = vn_1.getPoint() + dn = pn-pn_1 + dn = dn/dn.norm() + newLast = pn+dn*float(self._l) + vn.setPoint(newLast) + +normalInfo=Normal2DF0D() +curvatureInfo=Curvature2DAngleF0D() + +def edgestopping(x, sigma): + return exp(- x*x/(2*sigma*sigma)) + +class pyDiffusion2Shader(StrokeShader): + def __init__(self, lambda1, nbIter): + StrokeShader.__init__(self) + self._lambda = lambda1 + self._nbIter = nbIter + self._normalInfo = Normal2DF0D() + self._curvatureInfo = Curvature2DAngleF0D() + def getName(self): + return "pyDiffusionShader" + def shade(self, stroke): + for i in range (1, self._nbIter): + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v=it.getObject() + p1 = v.getPoint() + p2 = self._normalInfo(it.castToInterface0DIterator())*self._lambda*self._curvatureInfo(it.castToInterface0DIterator()) + v.setPoint(p1+p2) + it.increment() + +class pyTipRemoverShader(StrokeShader): + def __init__(self, l): + StrokeShader.__init__(self) + self._l = l + def getName(self): + return "pyTipRemoverShader" + def shade(self, stroke): + originalSize = stroke.strokeVerticesSize() + if(originalSize<4): + return + verticesToRemove = [] + oldAttributes = [] + it = stroke.strokeVerticesBegin() + while(it.isEnd() == 0): + v = it.getObject() + if((v.curvilinearAbscissa() < self._l) or (v.strokeLength()-v.curvilinearAbscissa() < self._l)): + verticesToRemove.append(v) + oldAttributes.append(StrokeAttribute(v.attribute())) + it.increment() + if(originalSize-len(verticesToRemove) < 2): + return + for sv in verticesToRemove: + stroke.RemoveVertex(sv) + stroke.Resample(originalSize) + if(stroke.strokeVerticesSize() != originalSize): + print "pyTipRemover: Warning: resampling problem" + it = stroke.strokeVerticesBegin() + for a in oldAttributes: + if(it.isEnd() == 1): + break + v = it.getObject() + v.setAttribute(a) + it.increment() + +class pyTVertexRemoverShader(StrokeShader): + def getName(self): + return "pyTVertexRemoverShader" + def shade(self, stroke): + if(stroke.strokeVerticesSize() <= 3 ): + return + predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX) + it = stroke.strokeVerticesBegin() + itlast = stroke.strokeVerticesEnd() + itlast.decrement() + if(predTVertex(it) == 1): + stroke.RemoveVertex(it.getObject()) + if(predTVertex(itlast) == 1): + stroke.RemoveVertex(itlast.getObject()) + +class pyExtremitiesOrientationShader(StrokeShader): + def __init__(self, x1,y1,x2=0,y2=0): + StrokeShader.__init__(self) + self._v1 = Vec2(x1,y1) + self._v2 = Vec2(x2,y2) + def getName(self): + return "pyExtremitiesOrientationShader" + def shade(self, stroke): + print self._v1.x(),self._v1.y() + stroke.setBeginningOrientation(self._v1.x(),self._v1.y()) + stroke.setEndingOrientation(self._v2.x(),self._v2.y()) + +class pyHLRShader(StrokeShader): + def getName(self): + return "pyHLRShader" + def shade(self, stroke): + originalSize = stroke.strokeVerticesSize() + if(originalSize<4): + return + it = stroke.strokeVerticesBegin() + invisible = 0 + it2 = StrokeVertexIterator(it) + it2.increment() + fe = getFEdge(it.getObject(), it2.getObject()) + if(fe.qi() != 0): + invisible = 1 + while(it2.isEnd() == 0): + v = it.getObject() + vnext = it2.getObject() + if(v.getNature() & Nature.VIEW_VERTEX): + #if(v.getNature() & Nature.T_VERTEX): + fe = getFEdge(v,vnext) + qi = fe.qi() + if(qi != 0): + invisible = 1 + else: + invisible = 0 + if(invisible == 1): + v.attribute().setVisible(0) + it.increment() + it2.increment() + +class pyTVertexOrientationShader(StrokeShader): + def __init__(self): + StrokeShader.__init__(self) + self._Get2dDirection = Orientation2DF1D() + def getName(self): + return "pyTVertexOrientationShader" + ## finds the TVertex orientation from the TVertex and + ## the previous or next edge + def findOrientation(self, tv, ve): + mateVE = tv.mate(ve) + if((ve.qi() != 0) or (mateVE.qi() != 0)): + ait = AdjacencyIterator(tv,1,0) + winner = None + incoming = 1 + while(ait.isEnd() == 0): + ave = ait.getObject() + if((ave.getId() != ve.getId()) and (ave.getId() != mateVE.getId())): + winner = ait.getObject() + if(ait.isIncoming() == 0): + incoming = 0 + break + ait.increment() + if(winner != None): + if(incoming != 0): + direction = self._Get2dDirection(winner.fedgeB()) + else: + direction = self._Get2dDirection(winner.fedgeA()) + return direction + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + it2 = StrokeVertexIterator(it) + it2.increment() + ## case where the first vertex is a TVertex + v = it.getObject() + if(v.getNature() & Nature.T_VERTEX): + tv = v.castToTVertex() + ve = getFEdge(v, it2.getObject()).viewedge() + if(tv != None): + dir = self.findOrientation(tv, ve) + #print dir.x(), dir.y() + v.attribute().setAttributeVec2f("orientation", dir) + while(it2.isEnd() == 0): + vprevious = it.getObject() + v = it2.getObject() + if(v.getNature() & Nature.T_VERTEX): + tv = v.castToTVertex() + ve = getFEdge(vprevious, v).viewedge() + if(tv != None): + dir = self.findOrientation(tv, ve) + #print dir.x(), dir.y() + v.attribute().setAttributeVec2f("orientation", dir) + it.increment() + it2.increment() + ## case where the last vertex is a TVertex + v = it.getObject() + if(v.getNature() & Nature.T_VERTEX): + itPrevious = StrokeVertexIterator(it) + itPrevious.decrement() + tv = v.castToTVertex() + ve = getFEdge(itPrevious.getObject(), v).viewedge() + if(tv != None): + dir = self.findOrientation(tv, ve) + #print dir.x(), dir.y() + v.attribute().setAttributeVec2f("orientation", dir) + +class pySinusDisplacementShader(StrokeShader): + def __init__(self, f, a): + StrokeShader.__init__(self) + self._f = f + self._a = a + self._getNormal = Normal2DF0D() + + def getName(self): + return "pySinusDisplacementShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + #print self._getNormal.getName() + n = self._getNormal(it.castToInterface0DIterator()) + p = v.getPoint() + u = v.u() + a = self._a*(1-2*(fabs(u-0.5))) + n = n*a*cos(self._f*u*6.28) + #print n.x(), n.y() + v.setPoint(p+n) + #v.setPoint(v.getPoint()+n*a*cos(f*v.u())) + it.increment() + +class pyPerlinNoise1DShader(StrokeShader): + def __init__(self, freq = 10, amp = 10, oct = 4): + StrokeShader.__init__(self) + self.__noise = FrsNoise() + self.__freq = freq + self.__amp = amp + self.__oct = oct + def getName(self): + return "pyPerlinNoise1DShader" + def shade(self, stroke): + i = randint(0, 50) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + nres = self.__noise.turbulence1(i, self.__freq, self.__amp, self.__oct) + v.setPoint(v.getProjectedX() + nres, v.getProjectedY() + nres) + i = i+1 + it.increment() + +class pyPerlinNoise2DShader(StrokeShader): + def __init__(self, freq = 10, amp = 10, oct = 4): + StrokeShader.__init__(self) + self.__noise = FrsNoise() + self.__freq = freq + self.__amp = amp + self.__oct = oct + def getName(self): + return "pyPerlinNoise2DShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + vec = Vec2f(v.getProjectedX(), v.getProjectedY()) + nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct) + v.setPoint(v.getProjectedX() + nres, v.getProjectedY() + nres) + it.increment() + +class pyBluePrintCirclesShader(StrokeShader): + def __init__(self, turns = 1): + StrokeShader.__init__(self) + self.__turns = turns + def getName(self): + return "pyBluePrintCirclesShader" + def shade(self, stroke): + p_min = Vec2f(10000, 10000) + p_max = Vec2f(0, 0) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + p = it.getObject().getPoint() + if (p.x() < p_min.x()): + p_min.setX(p.x()) + if (p.x() > p_max.x()): + p_max.setX(p.x()) + if (p.y() < p_min.y()): + p_min.setY(p.y()) + if (p.y() > p_max.y()): + p_max.setY(p.y()) + it.increment() + stroke.Resample(32 * self.__turns) + sv_nb = stroke.strokeVerticesSize() +# print "min :", p_min.x(), p_min.y() # DEBUG +# print "mean :", p_sum.x(), p_sum.y() # DEBUG +# print "max :", p_max.x(), p_max.y() # DEBUG +# print "----------------------" # DEBUG +####################################################### + sv_nb = sv_nb / self.__turns + center = (p_min + p_max) / 2 + radius = (center.x() - p_min.x() + center.y() - p_min.y()) / 2 + p_new = Vec2f() +####################################################### + it = stroke.strokeVerticesBegin() + for j in range(self.__turns): + radius = radius + randint(-3, 3) + center_x = center.x() + randint(-5, 5) + center_y = center.y() + randint(-5, 5) + center.setX(center_x) + center.setY(center_y) + i = 0 + while i < sv_nb: + p_new.setX(center.x() + radius * cos(2 * pi * float(i) / float(sv_nb - 1))) + p_new.setY(center.y() + radius * sin(2 * pi * float(i) / float(sv_nb - 1))) + it.getObject().setPoint(p_new.x(), p_new.y()) + i = i + 1 + it.increment() + while it.isEnd() == 0: + stroke.RemoveVertex(it.getObject()) + it.increment() + + +class pyBluePrintEllipsesShader(StrokeShader): + def __init__(self, turns = 1): + StrokeShader.__init__(self) + self.__turns = turns + def getName(self): + return "pyBluePrintEllipsesShader" + def shade(self, stroke): + p_min = Vec2f(10000, 10000) + p_max = Vec2f(0, 0) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + p = it.getObject().getPoint() + if (p.x() < p_min.x()): + p_min.setX(p.x()) + if (p.x() > p_max.x()): + p_max.setX(p.x()) + if (p.y() < p_min.y()): + p_min.setY(p.y()) + if (p.y() > p_max.y()): + p_max.setY(p.y()) + it.increment() + stroke.Resample(32 * self.__turns) + sv_nb = stroke.strokeVerticesSize() +# print "min :", p_min.x(), p_min.y() # DEBUG +# print "mean :", p_sum.x(), p_sum.y() # DEBUG +# print "max :", p_max.x(), p_max.y() # DEBUG +# print "----------------------" # DEBUG +####################################################### + sv_nb = sv_nb / self.__turns + center = (p_min + p_max) / 2 + radius_x = center.x() - p_min.x() + radius_y = center.y() - p_min.y() + p_new = Vec2f() +####################################################### + it = stroke.strokeVerticesBegin() + for j in range(self.__turns): + radius_x = radius_x + randint(-3, 3) + radius_y = radius_y + randint(-3, 3) + center_x = center.x() + randint(-5, 5) + center_y = center.y() + randint(-5, 5) + center.setX(center_x) + center.setY(center_y) + i = 0 + while i < sv_nb: + p_new.setX(center.x() + radius_x * cos(2 * pi * float(i) / float(sv_nb - 1))) + p_new.setY(center.y() + radius_y * sin(2 * pi * float(i) / float(sv_nb - 1))) + it.getObject().setPoint(p_new.x(), p_new.y()) + i = i + 1 + it.increment() + while it.isEnd() == 0: + stroke.RemoveVertex(it.getObject()) + it.increment() + + +class pyBluePrintSquaresShader(StrokeShader): + def __init__(self, turns = 1, bb_len = 10): + StrokeShader.__init__(self) + self.__turns = turns + self.__bb_len = bb_len + def getName(self): + return "pyBluePrintSquaresShader" + def shade(self, stroke): + p_min = Vec2f(10000, 10000) + p_max = Vec2f(0, 0) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + p = it.getObject().getPoint() + if (p.x() < p_min.x()): + p_min.setX(p.x()) + if (p.x() > p_max.x()): + p_max.setX(p.x()) + if (p.y() < p_min.y()): + p_min.setY(p.y()) + if (p.y() > p_max.y()): + p_max.setY(p.y()) + it.increment() + stroke.Resample(32 * self.__turns) + sv_nb = stroke.strokeVerticesSize() +####################################################### + sv_nb = sv_nb / self.__turns + first = sv_nb / 4 + second = 2 * first + third = 3 * first + fourth = sv_nb + vec_first = Vec2f(p_max.x() - p_min.x() + 2 * self.__bb_len, 0) + vec_second = Vec2f(0, p_max.y() - p_min.y() + 2 * self.__bb_len) + vec_third = vec_first * -1 + vec_fourth = vec_second * -1 + p_first = Vec2f(p_min.x() - self.__bb_len, p_min.y()) + p_second = Vec2f(p_max.x(), p_min.y() - self.__bb_len) + p_third = Vec2f(p_max.x() + self.__bb_len, p_max.y()) + p_fourth = Vec2f(p_min.x(), p_max.y() + self.__bb_len) +####################################################### + it = stroke.strokeVerticesBegin() + visible = 1 + for j in range(self.__turns): + i = 0 + while i < sv_nb: + if i < first: + p_new = p_first + vec_first * float(i)/float(first - 1) + if i == first - 1: + visible = 0 + elif i < second: + p_new = p_second + vec_second * float(i - first)/float(second - first - 1) + if i == second - 1: + visible = 0 + elif i < third: + p_new = p_third + vec_third * float(i - second)/float(third - second - 1) + if i == third - 1: + visible = 0 + else: + p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1) + if i == fourth - 1: + visible = 0 + it.getObject().setPoint(p_new.x(), p_new.y()) + it.getObject().attribute().setVisible(visible) + if visible == 0: + visible = 1 + i = i + 1 + it.increment() + while it.isEnd() == 0: + stroke.RemoveVertex(it.getObject()) + it.increment() + + +class pyBluePrintDirectedSquaresShader(StrokeShader): + def __init__(self, turns = 1, bb_len = 10, mult = 1): + StrokeShader.__init__(self) + self.__mult = mult + self.__turns = turns + self.__bb_len = 1 + float(bb_len) / 100 + def getName(self): + return "pyBluePrintDirectedSquaresShader" + def shade(self, stroke): + stroke.Resample(32 * self.__turns) + p_mean = Vec2f(0, 0) + p_min = Vec2f(10000, 10000) + p_max = Vec2f(0, 0) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + p = it.getObject().getPoint() + p_mean = p_mean + p +## if (p.x() < p_min.x()): +## p_min.setX(p.x()) +## if (p.x() > p_max.x()): +## p_max.setX(p.x()) +## if (p.y() < p_min.y()): +## p_min.setY(p.y()) +## if (p.y() > p_max.y()): +## p_max.setY(p.y()) + it.increment() + sv_nb = stroke.strokeVerticesSize() + p_mean = p_mean / sv_nb + p_var_xx = 0 + p_var_yy = 0 + p_var_xy = 0 + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + p = it.getObject().getPoint() + p_var_xx = p_var_xx + pow(p.x() - p_mean.x(), 2) + p_var_yy = p_var_yy + pow(p.y() - p_mean.y(), 2) + p_var_xy = p_var_xy + (p.x() - p_mean.x()) * (p.y() - p_mean.y()) + it.increment() + p_var_xx = p_var_xx / sv_nb + p_var_yy = p_var_yy / sv_nb + p_var_xy = p_var_xy / sv_nb +## print p_var_xx, p_var_yy, p_var_xy + trace = p_var_xx + p_var_yy + det = p_var_xx * p_var_yy - p_var_xy * p_var_xy + sqrt_coeff = sqrt(trace * trace - 4 * det) + lambda1 = (trace + sqrt_coeff) / 2 + lambda2 = (trace - sqrt_coeff) / 2 +## print lambda1, lambda2 + theta = atan(2 * p_var_xy / (p_var_xx - p_var_yy)) / 2 +## print theta + if p_var_yy > p_var_xx: + e1 = Vec2f(cos(theta + pi / 2), sin(theta + pi / 2)) * sqrt(lambda1) * self.__mult + e2 = Vec2f(cos(theta + pi), sin(theta + pi)) * sqrt(lambda2) * self.__mult + else: + e1 = Vec2f(cos(theta), sin(theta)) * sqrt(lambda1) * self.__mult + e2 = Vec2f(cos(theta + pi / 2), sin(theta + pi / 2)) * sqrt(lambda2) * self.__mult +####################################################### + sv_nb = sv_nb / self.__turns + first = sv_nb / 4 + second = 2 * first + third = 3 * first + fourth = sv_nb + bb_len1 = self.__bb_len + bb_len2 = 1 + (bb_len1 - 1) * sqrt(lambda1 / lambda2) + p_first = p_mean - e1 - e2 * bb_len2 + p_second = p_mean - e1 * bb_len1 + e2 + p_third = p_mean + e1 + e2 * bb_len2 + p_fourth = p_mean + e1 * bb_len1 - e2 + vec_first = e2 * bb_len2 * 2 + vec_second = e1 * bb_len1 * 2 + vec_third = vec_first * -1 + vec_fourth = vec_second * -1 +####################################################### + it = stroke.strokeVerticesBegin() + visible = 1 + for j in range(self.__turns): + i = 0 + while i < sv_nb: + if i < first: + p_new = p_first + vec_first * float(i)/float(first - 1) + if i == first - 1: + visible = 0 + elif i < second: + p_new = p_second + vec_second * float(i - first)/float(second - first - 1) + if i == second - 1: + visible = 0 + elif i < third: + p_new = p_third + vec_third * float(i - second)/float(third - second - 1) + if i == third - 1: + visible = 0 + else: + p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1) + if i == fourth - 1: + visible = 0 + it.getObject().setPoint(p_new.x(), p_new.y()) + it.getObject().attribute().setVisible(visible) + if visible == 0: + visible = 1 + i = i + 1 + it.increment() + while it.isEnd() == 0: + stroke.RemoveVertex(it.getObject()) + it.increment() + +class pyModulateAlphaShader(StrokeShader): + def __init__(self, min = 0, max = 1): + StrokeShader.__init__(self) + self.__min = min + self.__max = max + def getName(self): + return "pyModulateAlphaShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + alpha = it.getObject().attribute().getAlpha() + p = it.getObject().getPoint() + alpha = alpha * p.y() / 400 + if alpha < self.__min: + alpha = self.__min + elif alpha > self.__max: + alpha = self.__max + it.getObject().attribute().setAlpha(alpha) + it.increment() + + +## various +class pyDummyShader(StrokeShader): + def getName(self): + return "pyDummyShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + it_end = stroke.strokeVerticesEnd() + while it.isEnd() == 0: + toto = it.castToInterface0DIterator() + att = it.getObject().attribute() + att.setColor(0.3, 0.4, 0.4) + att.setThickness(0, 5) + it.increment() + +class pyDebugShader(StrokeShader): + def getName(self): + return "pyDebugShader" + + def shade(self, stroke): + fe = GetSelectedFEdgeCF() + id1=fe.vertexA().getId() + id2=fe.vertexB().getId() + #print id1.getFirst(), id1.getSecond() + #print id2.getFirst(), id2.getSecond() + it = stroke.strokeVerticesBegin() + found = 0 + foundfirst = 0 + foundsecond = 0 + while it.isEnd() == 0: + cp = it.getObject() + if((cp.A().getId() == id1) or (cp.B().getId() == id1)): + foundfirst = 1 + if((cp.A().getId() == id2) or (cp.B().getId() == id2)): + foundsecond = 1 + if((foundfirst != 0) and (foundsecond != 0)): + found = 1 + break + it.increment() + if(found != 0): + print "The selected Stroke id is: ", stroke.getId().getFirst(), stroke.getId().getSecond() + diff --git a/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py b/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py new file mode 100755 index 00000000000..163c891fa90 --- /dev/null +++ b/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py @@ -0,0 +1,48 @@ +# +# Filename : sketchy_multiple_parameterization.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Builds sketchy strokes whose topology relies on a +# parameterization that covers the complete lines (visible+invisible) +# whereas only the visible portions are actually drawn +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + + +Operators.select(QuantitativeInvisibilityUP1D(0)) +## 0: don't restrict to selection +Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(3,0)) +shaders_list = [ + SamplingShader(2), + SpatialNoiseShader(15, 120, 2, 1, 1), + IncreasingThicknessShader(5, 30), + SmoothingShader(100, 0.05, 0, 0.2, 0, 0, 0, 1), + IncreasingColorShader(0,0.2,0,1,0.2,0.7,0.2,1), + TextureAssignerShader(6), + pyHLRShader() + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/sketchy_topology_broken.py b/release/scripts/freestyle/style_modules/sketchy_topology_broken.py new file mode 100755 index 00000000000..5c151cfe837 --- /dev/null +++ b/release/scripts/freestyle/style_modules/sketchy_topology_broken.py @@ -0,0 +1,89 @@ +# +# Filename : sketchy_topology_broken.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : The topology of the strokes is, first, built +# independantly from the 3D topology of objects, +# and, second, so as to chain several times the same ViewEdge. +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + +## Backbone stretcher that leaves cusps intact to avoid cracks +class pyBackboneStretcherNoCuspShader(StrokeShader): + def __init__(self, l): + StrokeShader.__init__(self) + self._l = l + def getName(self): + return "pyBackboneStretcherNoCuspShader" + def shade(self, stroke): + it0 = stroke.strokeVerticesBegin() + it1 = StrokeVertexIterator(it0) + it1.increment() + itn = stroke.strokeVerticesEnd() + itn.decrement() + itn_1 = StrokeVertexIterator(itn) + itn_1.decrement() + v0 = it0.getObject() + v1 = it1.getObject() + if((v0.getNature() & Nature.CUSP == 0) and (v1.getNature() & Nature.CUSP == 0)): + p0 = v0.getPoint() + p1 = v1.getPoint() + d1 = p0-p1 + d1 = d1/d1.norm() + newFirst = p0+d1*float(self._l) + v0.setPoint(newFirst) + else: + print "got a v0 cusp" + vn_1 = itn_1.getObject() + vn = itn.getObject() + if((vn.getNature() & Nature.CUSP == 0) and (vn_1.getNature() & Nature.CUSP == 0)): + pn = vn.getPoint() + pn_1 = vn_1.getPoint() + dn = pn-pn_1 + dn = dn/dn.norm() + newLast = pn+dn*float(self._l) + vn.setPoint(newLast) + else: + print "got a vn cusp" + + +Operators.select(QuantitativeInvisibilityUP1D(0)) +## Chain 3 times each ViewEdge indpendantly from the +## initial objects topology +Operators.bidirectionalChain(pySketchyChainingIterator(3)) +shaders_list = [ + SamplingShader(4), + SpatialNoiseShader(6, 120, 2, 1, 1), + IncreasingThicknessShader(4, 10), + SmoothingShader(100, 0.1, 0, 0.2, 0, 0, 0, 1), + pyBackboneStretcherNoCuspShader(20), + #ConstantColorShader(0.0,0.0,0.0) + IncreasingColorShader(0.2,0.2,0.2,1,0.5,0.5,0.5,1), + #IncreasingColorShader(1,0,0,1,0,1,0,1), + TextureAssignerShader(4) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py b/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py new file mode 100755 index 00000000000..85e11af38b9 --- /dev/null +++ b/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py @@ -0,0 +1,49 @@ +# +# Filename : sketchy_topology_preserved.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : The topology of the strokes is built +# so as to chain several times the same ViewEdge. +# The topology of the objects is preserved +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from PredicatesU1D import * +from shaders import * + +upred = QuantitativeInvisibilityUP1D(0) +Operators.select(upred) +Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(3,1)) +shaders_list = [ + SamplingShader(4), + SpatialNoiseShader(20, 220, 2, 1, 1), + IncreasingThicknessShader(4, 8), + SmoothingShader(300, 0.05, 0, 0.2, 0, 0, 0, 0.5), + ConstantColorShader(0.6,0.2,0.0), + TextureAssignerShader(4), + ] + +Operators.create(TrueUP1D(), shaders_list) + diff --git a/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py b/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py new file mode 100755 index 00000000000..52cc10a9c60 --- /dev/null +++ b/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py @@ -0,0 +1,41 @@ +# +# Filename : split_at_highest_2d_curvature.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws the visible lines (chaining follows same nature lines) +# (most basic style module) +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesU0D import * +from PredicatesU1D import * +from Functions0D import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +func = pyInverseCurvature2DAngleF0D() +Operators.recursiveSplit(func, pyParameterUP0D(0.4,0.6), NotUP1D(pyHigherLengthUP1D(100)), 2) +shaders_list = [ConstantThicknessShader(10), IncreasingColorShader(1,0,0,1,0,1,0,1), TextureAssignerShader(3)] +Operators.create(TrueUP1D(), shaders_list) + diff --git a/release/scripts/freestyle/style_modules/split_at_tvertices.py b/release/scripts/freestyle/style_modules/split_at_tvertices.py new file mode 100755 index 00000000000..78f781dd290 --- /dev/null +++ b/release/scripts/freestyle/style_modules/split_at_tvertices.py @@ -0,0 +1,42 @@ +# +# Filename : split_at_tvertices.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws strokes that starts and stops at Tvertices (visible or not) +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesU1D import * +from PredicatesU0D import * +from Functions0D import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +start = pyVertexNatureUP0D(Nature.T_VERTEX) +## use the same predicate to decide where to start and where to stop +## the strokes: +Operators.sequentialSplit(start, start, 10) +shaders_list = [ConstantThicknessShader(5), IncreasingColorShader(1,0,0,1,0,1,0,1), TextureAssignerShader(3)] +Operators.create(TrueUP1D(), shaders_list) + diff --git a/release/scripts/freestyle/style_modules/stroke_texture.py b/release/scripts/freestyle/style_modules/stroke_texture.py new file mode 100755 index 00000000000..afebbe30a90 --- /dev/null +++ b/release/scripts/freestyle/style_modules/stroke_texture.py @@ -0,0 +1,43 @@ +# +# Filename : stroke_texture.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws textured strokes (illustrate the StrokeTextureShader shader) +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesB1D import * +from shaders import * +from ChainingIterators import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + SamplingShader(3), + BezierCurveShader(4), + StrokeTextureShader("washbrushAlpha.bmp", Stroke.DRY_MEDIUM, 1), + ConstantThicknessShader(40), + ConstantColorShader(0,0,0,1), + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/suggestive.py b/release/scripts/freestyle/style_modules/suggestive.py new file mode 100755 index 00000000000..39d8515ed6c --- /dev/null +++ b/release/scripts/freestyle/style_modules/suggestive.py @@ -0,0 +1,43 @@ +# +# Filename : suggestive.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws the suggestive contours. +# ***** The suggestive contours must be enabled +# in the options dialog ***** +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from PredicatesB1D import * +from PredicatesU1D import * +from shaders import * + +upred = AndUP1D(pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR), QuantitativeInvisibilityUP1D(0)) +Operators.select(upred) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) +shaders_list = [ + IncreasingThicknessShader(1, 3), + ConstantColorShader(0.2,0.2,0.2, 1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py b/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py new file mode 100755 index 00000000000..21f6c7bdf35 --- /dev/null +++ b/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py @@ -0,0 +1,62 @@ +# +# Filename : thickness_fof_depth_discontinuity.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Assigns to strokes a thickness that depends on the depth discontinuity +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + +class pyDepthDiscontinuityThicknessShader(StrokeShader): + def __init__(self, min, max): + StrokeShader.__init__(self) + self.__min = float(min) + self.__max = float(max) + self.__func = ZDiscontinuityF0D() + def getName(self): + return "pyDepthDiscontinuityThicknessShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + z_min=0.0 + z_max=1.0 + a = (self.__max - self.__min)/(z_max-z_min) + b = (self.__min*z_max-self.__max*z_min)/(z_max-z_min) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + z = self.__func(it.castToInterface0DIterator()) + thickness = a*z+b + it.getObject().attribute().setThickness(thickness, thickness) + it.increment() + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + SamplingShader(1), + ConstantThicknessShader(3), + ConstantColorShader(0.0,0.0,0.0), + pyDepthDiscontinuityThicknessShader(0.8, 6) + ] +Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file diff --git a/release/scripts/freestyle/style_modules/tipremover.py b/release/scripts/freestyle/style_modules/tipremover.py new file mode 100755 index 00000000000..3e495b7d332 --- /dev/null +++ b/release/scripts/freestyle/style_modules/tipremover.py @@ -0,0 +1,42 @@ +# +# Filename : tipremover.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Removes strokes extremities +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + SamplingShader(5), + ConstantThicknessShader(3), + ConstantColorShader(0,0,0), + TipRemoverShader(20) + ] +Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file diff --git a/release/scripts/freestyle/style_modules/tvertex_remover.py b/release/scripts/freestyle/style_modules/tvertex_remover.py new file mode 100755 index 00000000000..c328f4c98ec --- /dev/null +++ b/release/scripts/freestyle/style_modules/tvertex_remover.py @@ -0,0 +1,42 @@ +# +# Filename : tvertex_remover.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Removes TVertices +# +############################################################################# +# +# Copyright (C) : Please refer to the COPYRIGHT file distributed +# with this source distribution. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################# + + +from freestyle_init import * +from logical_operators import * +from PredicatesB1D import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + IncreasingThicknessShader(3, 5), + ConstantColorShader(0.2,0.2,0.2, 1), + SamplingShader(10.0), + pyTVertexRemoverShader() + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/uniformpruning_zsort.py b/release/scripts/freestyle/style_modules/uniformpruning_zsort.py new file mode 100755 index 00000000000..4b1a8bef9df --- /dev/null +++ b/release/scripts/freestyle/style_modules/uniformpruning_zsort.py @@ -0,0 +1,40 @@ +from freestyle_init import * +from logical_operators import * +from PredicatesU1D import * +from PredicatesU0D import * +from PredicatesB1D import * +from Functions0D import * +from Functions1D import * +from shaders import * + +class pyDensityUP1D(UnaryPredicate1D): + def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0): + UnaryPredicate1D.__init__(self) + self._wsize = wsize + self._threshold = threshold + self._integration = integration + self._func = DensityF1D(self._wsize, self._integration, sampling) + + def getName(self): + return "pyDensityUP1D" + + def __call__(self, inter): + d = self._func(inter) + print "For Chain ", inter.getId().getFirst(), inter.getId().getSecond(), "density is ", d + if(d < self._threshold): + return 1 + return 0 + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator()) +#Operators.sequentialSplit(pyVertexNatureUP0D(Nature.VIEW_VERTEX), 2) +Operators.sort(pyZBP1D()) +shaders_list = [ + StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0), + ConstantThicknessShader(3), + SamplingShader(5.0), + ConstantColorShader(0,0,0,1) + ] +Operators.create(pyDensityUP1D(2,0.05, IntegrationType.MEAN,4), shaders_list) +#Operators.create(pyDensityFunctorUP1D(8,0.03, pyGetInverseProjectedZF1D(), 0,1, IntegrationType.MEAN), shaders_list) + diff --git a/release/scripts/freestyle/style_modules/vector.py b/release/scripts/freestyle/style_modules/vector.py new file mode 100755 index 00000000000..039f262546b --- /dev/null +++ b/release/scripts/freestyle/style_modules/vector.py @@ -0,0 +1,241 @@ +# This module defines 3d geometrical vectors with the standard +# operations on them. +# +# Written by: Konrad Hinsen +# Last revision: 1996-1-26 +# + +"""This module defines three-dimensional geometrical vectors. Vectors support +the usual mathematical operations (v1, v2: vectors, s: scalar): + v1+v2 addition + v1-v2 subtraction + v1*v2 scalar product + s*v1 multiplication with a scalar + v1/s division by a scalar + v1.cross(v2) cross product + v1.length() length + v1.normal() normal vector in direction of v1 + v1.angle(v2) angle between two vectors + v1.x(), v1[0] first element + v1.y(), v1[1] second element + v1.z(), v1[2] third element + +The module offers the following items for export: + Vec3D(x,y,z) the constructor for vectors + isVector(x) a type check function + ex, ey, ez unit vectors along the x-, y-, and z-axes (predefined constants) + +Note: vector elements can be any kind of numbers on which the operations +addition, subtraction, multiplication, division, comparison, sqrt, and acos +are defined. Integer elements are treated as floating point elements. +""" + +import math, types + +class Vec3: + + isVec3 = 1 + + def __init__(self, x=0., y=0., z=0.): + self.data = [x,y,z] + + def __repr__(self): + return 'Vec3(%s,%s,%s)' % (`self.data[0]`,\ + `self.data[1]`,`self.data[2]`) + + def __str__(self): + return `self.data` + + def __add__(self, other): + return Vec3(self.data[0]+other.data[0],\ + self.data[1]+other.data[1],self.data[2]+other.data[2]) + __radd__ = __add__ + + def __neg__(self): + return Vec3(-self.data[0], -self.data[1], -self.data[2]) + + def __sub__(self, other): + return Vec3(self.data[0]-other.data[0],\ + self.data[1]-other.data[1],self.data[2]-other.data[2]) + + def __rsub__(self, other): + return Vec3(other.data[0]-self.data[0],\ + other.data[1]-self.data[1],other.data[2]-self.data[2]) + + def __mul__(self, other): + if isVec3(other): + return reduce(lambda a,b: a+b, + map(lambda a,b: a*b, self.data, other.data)) + else: + return Vec3(self.data[0]*other, self.data[1]*other, + self.data[2]*other) + + def __rmul__(self, other): + if isVec3(other): + return reduce(lambda a,b: a+b, + map(lambda a,b: a*b, self.data, other.data)) + else: + return Vec3(other*self.data[0], other*self.data[1], + other*self.data[2]) + + def __div__(self, other): + if isVec3(other): + raise TypeError, "Can't divide by a vector" + else: + return Vec3(_div(self.data[0],other), _div(self.data[1],other), + _div(self.data[2],other)) + + def __rdiv__(self, other): + raise TypeError, "Can't divide by a vector" + + def __cmp__(self, other): + return cmp(self.data[0],other.data[0]) \ + or cmp(self.data[1],other.data[1]) \ + or cmp(self.data[2],other.data[2]) + + def __getitem__(self, index): + return self.data[index] + + def x(self): + return self.data[0] + def y(self): + return self.data[1] + def z(self): + return self.data[2] + + def length(self): + return math.sqrt(self*self) + + def normal(self): + len = self.length() + if len == 0: + raise ZeroDivisionError, "Can't normalize a zero-length vector" + return self/len + + def cross(self, other): + if not isVec3(other): + raise TypeError, "Cross product with non-vector" + return Vec3(self.data[1]*other.data[2]-self.data[2]*other.data[1], + self.data[2]*other.data[0]-self.data[0]*other.data[2], + self.data[0]*other.data[1]-self.data[1]*other.data[0]) + + def angle(self, other): + if not isVec3(other): + raise TypeError, "Angle between vector and non-vector" + cosa = (self*other)/(self.length()*other.length()) + cosa = max(-1.,min(1.,cosa)) + return math.acos(cosa) + + +class Vec2: + + isVec2 = 1 + + def __init__(self, x=0., y=0.): + self.data = [x,y] + + def __repr__(self): + return 'Vec2(%s,%s,%s)' % (`self.data[0]`,\ + `self.data[1]`) + + def __str__(self): + return `self.data` + + def __add__(self, other): + return Vec2(self.data[0]+other.data[0],\ + self.data[1]+other.data[1]) + __radd__ = __add__ + + def __neg__(self): + return Vec2(-self.data[0], -self.data[1]) + + def __sub__(self, other): + return Vec2(self.data[0]-other.data[0],\ + self.data[1]-other.data[1]) + + def __rsub__(self, other): + return Vec2(other.data[0]-self.data[0],\ + other.data[1]-self.data[1]) + + def __mul__(self, other): + if isVec2(other): + return reduce(lambda a,b: a+b, + map(lambda a,b: a*b, self.data, other.data)) + else: + return Vec2(self.data[0]*other, self.data[1]*other) + + def __rmul__(self, other): + if isVec2(other): + return reduce(lambda a,b: a+b, + map(lambda a,b: a*b, self.data, other.data)) + else: + return Vec2(other*self.data[0], other*self.data[1]) + + def __div__(self, other): + if isVec2(other): + raise TypeError, "Can't divide by a vector" + else: + return Vec2(_div(self.data[0],other), _div(self.data[1],other)) + + def __rdiv__(self, other): + raise TypeError, "Can't divide by a vector" + + def __cmp__(self, other): + return cmp(self.data[0],other.data[0]) \ + or cmp(self.data[1],other.data[1]) + + def __getitem__(self, index): + return self.data[index] + + def x(self): + return self.data[0] + def y(self): + return self.data[1] + + def length(self): + return math.sqrt(self*self) + + def normal(self): + len = self.length() + if len == 0: + raise ZeroDivisionError, "Can't normalize a zero-length vector" + return self/len + + #def cross(self, other): +# if not isVec2(other): +# raise TypeError, "Cross product with non-vector" +# return Vec2(self.data[1]*other.data[2]-self.data[2]*other.data[1], +# self.data[2]*other.data[0]-self.data[0]*other.data[2], +# self.data[0]*other.data[1]-self.data[1]*other.data[0]) + + def angle(self, other): + if not isVec2(other): + raise TypeError, "Angle between vector and non-vector" + cosa = (self*other)/(self.length()*other.length()) + cosa = max(-1.,min(1.,cosa)) + return math.acos(cosa) + + + +# Type check + +def isVec3(x): + return hasattr(x,'isVec3') + +def isVec2(x): + return hasattr(x,'isVec2') + +# "Correct" division for arbitrary number types + +def _div(a,b): + if type(a) == types.IntType and type(b) == types.IntType: + return float(a)/float(b) + else: + return a/b + + +# Some useful constants + +ex = Vec3(1.,0.,0.) +ey = Vec3(0.,1.,0.) +ez = Vec3(0.,0.,1.)