diff options
Diffstat (limited to 'release/scripts/freestyle')
55 files changed, 6012 insertions, 0 deletions
diff --git a/release/scripts/freestyle/data/env_map/brown00.png b/release/scripts/freestyle/data/env_map/brown00.png Binary files differnew file mode 100644 index 00000000000..855f06f4fb9 --- /dev/null +++ b/release/scripts/freestyle/data/env_map/brown00.png diff --git a/release/scripts/freestyle/data/env_map/gray00.png b/release/scripts/freestyle/data/env_map/gray00.png Binary files differnew file mode 100644 index 00000000000..7c9b1a8149e --- /dev/null +++ b/release/scripts/freestyle/data/env_map/gray00.png diff --git a/release/scripts/freestyle/data/env_map/gray01.png b/release/scripts/freestyle/data/env_map/gray01.png Binary files differnew file mode 100644 index 00000000000..06542908e6b --- /dev/null +++ b/release/scripts/freestyle/data/env_map/gray01.png diff --git a/release/scripts/freestyle/data/env_map/gray02.png b/release/scripts/freestyle/data/env_map/gray02.png Binary files differnew file mode 100644 index 00000000000..0208f4920d9 --- /dev/null +++ b/release/scripts/freestyle/data/env_map/gray02.png diff --git a/release/scripts/freestyle/data/env_map/gray03.png b/release/scripts/freestyle/data/env_map/gray03.png Binary files differnew file mode 100644 index 00000000000..aab9b957c21 --- /dev/null +++ b/release/scripts/freestyle/data/env_map/gray03.png diff --git a/release/scripts/freestyle/style_modules/ChainingIterators.py b/release/scripts/freestyle/style_modules/ChainingIterators.py new file mode 100644 index 00000000000..f2d953ddc14 --- /dev/null +++ b/release/scripts/freestyle/style_modules/ChainingIterators.py @@ -0,0 +1,731 @@ +# +# Filename : ChainingIterators.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Chaining Iterators to be used with chaining operators +# +############################################################################# +# +# 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 * + +## the natural chaining iterator +## It follows the edges of same nature following the topology of +## 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 pyChainSilhouetteIterator(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) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + mateVE = tvertex.mate(self.getCurrentEdge()) + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getId() == mateVE.getId() ): + 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 + +## 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. +## You can specify whether to chain iterate over edges that were +## already visited or not. +class pyChainSilhouetteGenericIterator(ChainingIterator): + def __init__(self, stayInSelection=1, stayInUnvisited=1): + ChainingIterator.__init__(self, stayInSelection, stayInUnvisited,None,1) + def getExactTypeName(self): + return "pyChainSilhouetteGenericIterator" + def init(self): + pass + def traverse(self, iter): + winner = None + it = AdjacencyIterator(iter) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + mateVE = tvertex.mate(self.getCurrentEdge()) + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getId() == mateVE.getId() ): + 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() + ve = it.getObject() + if(ve.getId() == self.getCurrentEdge().getId()): + it.increment() + continue + 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 = ve + it.increment() + if(count != 1): + winner = None + break + return winner + +class pyExternalContourChainingIterator(ChainingIterator): + def __init__(self): + ChainingIterator.__init__(self, 0, 1,None,1) + self._isExternalContour = ExternalContourUP1D() + + def getExactTypeName(self): + return "pyExternalContourIterator" + + def init(self): + self._nEdges = 0 + self._isInSelection = 1 + + def checkViewEdge(self, ve, orientation): + if(orientation != 0): + vertex = ve.B() + else: + vertex = ve.A() + it = AdjacencyIterator(vertex,1,1) + while(it.isEnd() == 0): + ave = it.getObject() + if(self._isExternalContour(ave)): + return 1 + it.increment() + print("pyExternlContourChainingIterator : didn't find next edge") + return 0 + def traverse(self, iter): + winner = None + it = AdjacencyIterator(iter) + while(it.isEnd() == 0): + ve = it.getObject() + if(self._isExternalContour(ve)): + if (ve.getTimeStamp() == GetTimeStampCF()): + winner = ve + it.increment() + + self._nEdges = self._nEdges+1 + if(winner == None): + orient = 1 + it = AdjacencyIterator(iter) + while(it.isEnd() == 0): + ve = it.getObject() + if(it.isIncoming() != 0): + orient = 0 + good = self.checkViewEdge(ve,orient) + if(good != 0): + winner = ve + it.increment() + return winner + +## the natural chaining iterator +## with a sketchy multiple touch +class pySketchyChainSilhouetteIterator(ChainingIterator): + def __init__(self, nRounds=3,stayInSelection=1): + ChainingIterator.__init__(self, stayInSelection, 0,None,1) + self._timeStamp = GetTimeStampCF()+nRounds + self._nRounds = nRounds + def getExactTypeName(self): + return "pySketchyChainSilhouetteIterator" + def init(self): + self._timeStamp = GetTimeStampCF()+self._nRounds + def traverse(self, iter): + winner = None + it = AdjacencyIterator(iter) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + mateVE = tvertex.mate(self.getCurrentEdge()) + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getId() == mateVE.getId() ): + 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() + ve = it.getObject() + if(ve.getId() == self.getCurrentEdge().getId()): + it.increment() + continue + 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 = ve + it.increment() + if(count != 1): + winner = None + break + if(winner == None): + winner = self.getCurrentEdge() + if(winner.getChainingTimeStamp() == self._timeStamp): + winner = None + return winner + + +# Chaining iterator designed for sketchy style. +# can chain several times the same ViewEdge +# in order to produce multiple strokes per ViewEdge. +class pySketchyChainingIterator(ChainingIterator): + def __init__(self, nRounds=3, stayInSelection=1): + ChainingIterator.__init__(self, stayInSelection, 0,None,1) + self._timeStamp = GetTimeStampCF()+nRounds + self._nRounds = nRounds + def getExactTypeName(self): + return "pySketchyChainingIterator" + + def init(self): + self._timeStamp = GetTimeStampCF()+self._nRounds + + def traverse(self, iter): + winner = None + it = AdjacencyIterator(iter) + while(it.isEnd() == 0): + ve = it.getObject() + if(ve.getId() == self.getCurrentEdge().getId()): + it.increment() + continue + winner = ve + it.increment() + if(winner == None): + winner = self.getCurrentEdge() + if(winner.getChainingTimeStamp() == self._timeStamp): + return 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 pyFillOcclusionsRelativeChainingIterator(ChainingIterator): + def __init__(self, percent): + ChainingIterator.__init__(self, 0, 1,None,1) + self._length = 0 + 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) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + 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): + 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) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + 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) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + 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) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + 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) + tvertex = self.getVertex() + if type(tvertex) is TVertex: + 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 100644 index 00000000000..38dd4b770a6 --- /dev/null +++ b/release/scripts/freestyle/style_modules/Functions0D.py @@ -0,0 +1,92 @@ +from freestyle_init import * + +class CurveMaterialF0D(UnaryFunction0DMaterial): + # A replacement of the built-in MaterialF0D for stroke creation. + # MaterialF0D does not work with Curves and Strokes. + def getName(self): + return "CurveMaterialF0D" + def __call__(self, inter): + cp = inter.getObject() + assert(isinstance(cp, CurvePoint)) + fe = cp.A().getFEdge(cp.B()) + assert(fe is not None) + return fe.material() if fe.isSmooth() else fe.bMaterial() + +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) + 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 Vector([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 = Vector([gx, gy]) + return grad.length + + diff --git a/release/scripts/freestyle/style_modules/Functions1D.py b/release/scripts/freestyle/style_modules/Functions1D.py new file mode 100644 index 00000000000..aaf115356cb --- /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 = integrate(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 = integrate(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 100644 index 00000000000..3b7d21039df --- /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<r2) diff --git a/release/scripts/freestyle/style_modules/PredicatesU0D.py b/release/scripts/freestyle/style_modules/PredicatesU0D.py new file mode 100644 index 00000000000..162254f17ed --- /dev/null +++ b/release/scripts/freestyle/style_modules/PredicatesU0D.py @@ -0,0 +1,103 @@ +from freestyle_init import * +from Functions0D import * + +class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D): + def __init__(self,a): + UnaryPredicate0D.__init__(self) + self._a = a + + def getName(self): + return "HigherCurvature2DAngleUP0D" + + def __call__(self, inter): + func = Curvature2DAngleF0D() + a = func(inter) + return ( a > 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 100644 index 00000000000..3529ca8b4e3 --- /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.viewvertex() + if type(tvertex) is TVertex: + print("TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]") + eit = tvertex.edgesBegin() + while(eit.isEnd() == 0): + ve, incoming = eit.getObject() + if(ve.getId() == self._id): + return 1 + print("-------", ve.getId().getFirst(), "-", ve.getId().getSecond()) + eit.increment() + tvertex = vlast.viewvertex() + if type(tvertex) is TVertex: + print("TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]") + eit = tvertex.edgesBegin() + while(eit.isEnd() == 0): + ve, incoming = eit.getObject() + if(ve.getId() == 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<self._sigmaMin): + sigma = self._sigmaMin + self._func = DensityF1D(sigma, self._integration, self._sampling) + d = self._func(inter) + if(d<t): + return 1 + return 0 + +class pyClosedCurveUP1D(UnaryPredicate1D): + def __call__(self, inter): + it = inter.verticesBegin() + itlast = inter.verticesEnd() + itlast.decrement() + vlast = itlast.getObject() + v = it.getObject() + print(v.getId().getFirst(), v.getId().getSecond()) + print(vlast.getId().getFirst(), vlast.getId().getSecond()) + if(v.getId() == vlast.getId()): + return 1 + return 0 diff --git a/release/scripts/freestyle/style_modules/anisotropic_diffusion.py b/release/scripts/freestyle/style_modules/anisotropic_diffusion.py new file mode 100644 index 00000000000..7e7ebf647bd --- /dev/null +++ b/release/scripts/freestyle/style_modules/anisotropic_diffusion.py @@ -0,0 +1,74 @@ +# +# Filename : anisotropic_diffusion.py +# Author : Fredo Durand +# Date : 12/08/2004 +# Purpose : Smoothes lines using an anisotropic diffusion scheme +# +############################################################################# +# +# 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 PredicatesU0D import * +from math import * + +## thickness modifiers + +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 + 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 = normalInfo(it.castToInterface0DIterator())*self._lambda*curvatureInfo(it.castToInterface0DIterator()) + v.setPoint(p1+p2) + it.increment() + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) +Operators.select( upred ) +bpred = TrueBP1D(); +Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred) ) +shaders_list = [ + ConstantThicknessShader(4), + StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0), + SamplingShader(2), + pyDiffusion2Shader(-0.03, 30), + IncreasingColorShader(1.0,0.0,0.0,1, 0, 1, 0, 1) + ] +Operators.create(TrueUP1D(), shaders_list) + + + diff --git a/release/scripts/freestyle/style_modules/apriori_and_causal_density.py b/release/scripts/freestyle/style_modules/apriori_and_causal_density.py new file mode 100644 index 00000000000..7cdd4b2fd66 --- /dev/null +++ b/release/scripts/freestyle/style_modules/apriori_and_causal_density.py @@ -0,0 +1,45 @@ +# +# Filename : apriori_and_causal_density.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Selects the lines with high a priori density and +# subjects them to the causal density so as to avoid +# cluttering +# +############################################################################# +# +# 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), pyHighViewMapDensityUP1D(0.3, IntegrationType.LAST)) +Operators.select(upred) +bpred = TrueBP1D() +Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + ConstantThicknessShader(2), + ConstantColorShader(0.0, 0.0, 0.0,1) + ] +Operators.create(pyDensityUP1D(1,0.1, IntegrationType.MEAN), shaders_list) diff --git a/release/scripts/freestyle/style_modules/apriori_density.py b/release/scripts/freestyle/style_modules/apriori_density.py new file mode 100644 index 00000000000..5ff6c58e77f --- /dev/null +++ b/release/scripts/freestyle/style_modules/apriori_density.py @@ -0,0 +1,43 @@ +# +# Filename : apriori_density.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws lines having a high a priori density +# +############################################################################# +# +# 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 * + +Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.1,5))) +bpred = TrueBP1D() +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.0007,5)) +Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + ConstantThicknessShader(2), + ConstantColorShader(0.0, 0.0, 0.0,1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/backbone_stretcher.py b/release/scripts/freestyle/style_modules/backbone_stretcher.py new file mode 100644 index 00000000000..8a6b9d71a66 --- /dev/null +++ b/release/scripts/freestyle/style_modules/backbone_stretcher.py @@ -0,0 +1,36 @@ +# +# Filename : backbone_stretcher.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Stretches the geometry of visible lines +# +############################################################################# +# +# 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 = [TextureAssignerShader(4), ConstantColorShader(0.5, 0.5, 0.5), BackboneStretcherShader(20)] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/blueprint_circles.py b/release/scripts/freestyle/style_modules/blueprint_circles.py new file mode 100644 index 00000000000..7f3a7564cfe --- /dev/null +++ b/release/scripts/freestyle/style_modules/blueprint_circles.py @@ -0,0 +1,46 @@ +# +# Filename : blueprint_circles.py +# Author : Emmanuel Turquin +# Date : 04/08/2005 +# Purpose : Produces a blueprint using circular contour 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 PredicatesB1D import * +from PredicatesU1D import * +from shaders import * + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D()) +bpred = SameShapeIdBP1D() +Operators.select(upred) +Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred)) +Operators.select(pyHigherLengthUP1D(200)) +shaders_list = [ + ConstantThicknessShader(5), + pyBluePrintCirclesShader(3), + pyPerlinNoise1DShader(0.1, 15, 8), + TextureAssignerShader(4), + IncreasingColorShader(0.8, 0.8, 0.3, 0.4, 0.3, 0.3, 0.3, 0.1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/blueprint_ellipses.py b/release/scripts/freestyle/style_modules/blueprint_ellipses.py new file mode 100644 index 00000000000..a5cfe4ec30b --- /dev/null +++ b/release/scripts/freestyle/style_modules/blueprint_ellipses.py @@ -0,0 +1,46 @@ +# +# Filename : blueprint_ellipses.py +# Author : Emmanuel Turquin +# Date : 04/08/2005 +# Purpose : Produces a blueprint using elliptic contour 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 PredicatesB1D import * +from PredicatesU1D import * +from shaders import * + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D()) +bpred = SameShapeIdBP1D() +Operators.select(upred) +Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred)) +Operators.select(pyHigherLengthUP1D(200)) +shaders_list = [ + ConstantThicknessShader(5), + pyBluePrintEllipsesShader(3), + pyPerlinNoise1DShader(0.1, 10, 8), + TextureAssignerShader(4), + IncreasingColorShader(0.6, 0.3, 0.3, 0.7, 0.3, 0.3, 0.3, 0.1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/blueprint_squares.py b/release/scripts/freestyle/style_modules/blueprint_squares.py new file mode 100644 index 00000000000..7798acc7d47 --- /dev/null +++ b/release/scripts/freestyle/style_modules/blueprint_squares.py @@ -0,0 +1,45 @@ +# Filename : blueprint_squares.py +# Author : Emmanuel Turquin +# Date : 04/08/2005 +# Purpose : Produces a blueprint using square contour 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 PredicatesB1D import * +from PredicatesU1D import * +from shaders import * + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D()) +bpred = SameShapeIdBP1D() +Operators.select(upred) +Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred)) +Operators.select(pyHigherLengthUP1D(200)) +shaders_list = [ + ConstantThicknessShader(8), + pyBluePrintSquaresShader(2, 20), + pyPerlinNoise1DShader(0.07, 10, 8), + TextureAssignerShader(4), + IncreasingColorShader(0.6, 0.3, 0.3, 0.7, 0.6, 0.3, 0.3, 0.3), + ConstantThicknessShader(4) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/cartoon.py b/release/scripts/freestyle/style_modules/cartoon.py new file mode 100644 index 00000000000..6ace7e0585a --- /dev/null +++ b/release/scripts/freestyle/style_modules/cartoon.py @@ -0,0 +1,42 @@ +# +# Filename : cartoon.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws colored lines. The color is automatically +# infered from each object's material in a cartoon-like +# fashion. +# +############################################################################# +# +# 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 = [ + BezierCurveShader(3), + ConstantThicknessShader(4), + pyMaterialColorShader(0.8) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/contour.py b/release/scripts/freestyle/style_modules/contour.py new file mode 100644 index 00000000000..c4b3a0f0827 --- /dev/null +++ b/release/scripts/freestyle/style_modules/contour.py @@ -0,0 +1,42 @@ +# +# Filename : contour.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws each object's visible contour +# +############################################################################# +# +# 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 * + +Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D() ) ) +bpred = SameShapeIdBP1D(); +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D()) +Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + ConstantThicknessShader(5.0), + IncreasingColorShader(0.8,0,0,1,0.1,0,0,1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/curvature2d.py b/release/scripts/freestyle/style_modules/curvature2d.py new file mode 100644 index 00000000000..fc2bcab4946 --- /dev/null +++ b/release/scripts/freestyle/style_modules/curvature2d.py @@ -0,0 +1,60 @@ +# +# Filename : curvature2d.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : The stroke points are colored in gray levels and depending +# on the 2d curvature value +# +############################################################################# +# +# 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 * + +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: + it0D = it.castToInterface0DIterator() + sv = it.getObject() + att = sv.attribute() + c = func(it0D) + if (c<0): + print("negative 2D curvature") + color = 10.0 * c/3.1415 + att.setColor(color,color,color); + it.increment() + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0))) +shaders_list = [ + StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0), + ConstantThicknessShader(5), + py2DCurvatureColorShader() + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/external_contour.py b/release/scripts/freestyle/style_modules/external_contour.py new file mode 100644 index 00000000000..2a39b79a410 --- /dev/null +++ b/release/scripts/freestyle/style_modules/external_contour.py @@ -0,0 +1,43 @@ +# +# Filename : external_contour.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws 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 * +from PredicatesB1D import * +from PredicatesU1D import * +from ChainingIterators import * +from shaders import * + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) +Operators.select(upred ) +bpred = TrueBP1D(); +Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred)) +shaders_list = [ + ConstantThicknessShader(3), + ConstantColorShader(0.0, 0.0, 0.0,1) + ] +Operators.create(TrueUP1D(), shaders_list)
\ No newline at end of file diff --git a/release/scripts/freestyle/style_modules/external_contour_sketchy.py b/release/scripts/freestyle/style_modules/external_contour_sketchy.py new file mode 100644 index 00000000000..8a4c570b279 --- /dev/null +++ b/release/scripts/freestyle/style_modules/external_contour_sketchy.py @@ -0,0 +1,48 @@ +# +# Filename : external_contour_sketchy.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws the external contour of the scene using a sketchy +# chaining iterator (in particular each ViewEdge can be drawn +# several times +# +############################################################################# +# +# 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 * + + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) +Operators.select(upred) +Operators.bidirectionalChain(pySketchyChainingIterator(), NotUP1D(upred)) +shaders_list = [ + SamplingShader(4), + SpatialNoiseShader(10, 150, 2, 1, 1), + IncreasingThicknessShader(4, 10), + SmoothingShader(400, 0.1, 0, 0.2, 0, 0, 0, 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/external_contour_smooth.py b/release/scripts/freestyle/style_modules/external_contour_smooth.py new file mode 100644 index 00000000000..201dc271388 --- /dev/null +++ b/release/scripts/freestyle/style_modules/external_contour_smooth.py @@ -0,0 +1,44 @@ +# +# Filename : external_contour_smooth.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws a smooth external contour +# +############################################################################# +# +# 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 * +from ChainingIterators import * + +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) +Operators.select(upred) +bpred = TrueBP1D(); +Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred)) +shaders_list = [ + SamplingShader(2), + IncreasingThicknessShader(4,20), + IncreasingColorShader(1.0, 0.0, 0.5,1, 0.5,1, 0.3, 1), + SmoothingShader(100, 0.05, 0, 0.2, 0, 0, 0, 1) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/extra-lines.sml b/release/scripts/freestyle/style_modules/extra-lines.sml new file mode 100644 index 00000000000..c63cd40945d --- /dev/null +++ b/release/scripts/freestyle/style_modules/extra-lines.sml @@ -0,0 +1,3 @@ +1suggestive.py +1ridges.py +1nor_suggestive_or_ridges.py diff --git a/release/scripts/freestyle/style_modules/freestyle_init.py b/release/scripts/freestyle/style_modules/freestyle_init.py new file mode 100644 index 00000000000..9eb8b2d6340 --- /dev/null +++ b/release/scripts/freestyle/style_modules/freestyle_init.py @@ -0,0 +1,2 @@ +from Freestyle import * +from mathutils import Vector diff --git a/release/scripts/freestyle/style_modules/haloing.py b/release/scripts/freestyle/style_modules/haloing.py new file mode 100644 index 00000000000..afa46173d54 --- /dev/null +++ b/release/scripts/freestyle/style_modules/haloing.py @@ -0,0 +1,50 @@ +# +# Filename : haloing.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : This style module selects the lines that +# are connected (in the image) to a specific +# object and trims them in order to produce +# a haloing effect around the target shape +# +############################################################################# +# +# 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 PredicatesB1D import * +from shaders import * + +# id corresponds to the id of the target object +# (accessed by SHIFT+click) +id = Id(3,0) +upred = AndUP1D(QuantitativeInvisibilityUP1D(0) , pyIsOccludedByUP1D(id)) +Operators.select(upred) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) +shaders_list = [ + IncreasingThicknessShader(3, 5), + IncreasingColorShader(1,0,0, 1,0,1,0,1), + SamplingShader(1.0), + pyTVertexRemoverShader(), + TipRemoverShader(3.0) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/ignore_small_occlusions.py b/release/scripts/freestyle/style_modules/ignore_small_occlusions.py new file mode 100644 index 00000000000..ff6efa89ade --- /dev/null +++ b/release/scripts/freestyle/style_modules/ignore_small_occlusions.py @@ -0,0 +1,41 @@ +# +# Filename : ignore_small_oclusions.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : The strokes are drawn through small occlusions +# +############################################################################# +# +# 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(pyFillOcclusionsChainingIterator(0.1)) +Operators.bidirectionalChain(pyFillOcclusionsAbsoluteChainingIterator(12)) +shaders_list = [ + SamplingShader(5.0), + ConstantThicknessShader(3), + ConstantColorShader(0.0,0.0,0.0), + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/invisible_lines.py b/release/scripts/freestyle/style_modules/invisible_lines.py new file mode 100644 index 00000000000..ea509463bfd --- /dev/null +++ b/release/scripts/freestyle/style_modules/invisible_lines.py @@ -0,0 +1,42 @@ +# +# Filename : invisible_lines.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Draws all lines whose Quantitative Invisibility +# is different from 0 +# +############################################################################# +# +# 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 * + +upred = NotUP1D(QuantitativeInvisibilityUP1D(0)) +Operators.select(upred) +Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) +shaders_list = [ + SamplingShader(5.0), + ConstantThicknessShader(3.0), + ConstantColorShader(0.7,0.7,0.7) + ] +Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/freestyle/style_modules/japanese_bigbrush.py b/release/scripts/freestyle/style_modules/japanese_bigbrush.py new file mode 100644 index 00000000000..7f109598aaa --- /dev/null +++ b/release/scripts/freestyle/style_modules/japanese_bigbrush.py @@ -0,0 +1,60 @@ +# +# Filename : japanese_bigbrush.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Simulates a big brush fr oriental painting +# +############################################################################# +# +# 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 PredicatesB1D import * +from Functions0D import * +from shaders import * + +Operators.select(QuantitativeInvisibilityUP1D(0)) +Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0))) +## Splits strokes at points of highest 2D curavture +## when there are too many abrupt turns in it +func = pyInverseCurvature2DAngleF0D() +Operators.recursiveSplit(func, pyParameterUP0D(0.2,0.8), NotUP1D(pyHigherNumberOfTurnsUP1D(3, 0.5)), 2) +## Keeps only long enough strokes +Operators.select(pyHigherLengthUP1D(100)) +## Sorts so as to draw the longest strokes first +## (this will be done using the causal density) +Operators.sort(pyLengthBP1D()) +shaders_list = [ + pySamplingShader(10), + BezierCurveShader(30), + SamplingShader(50), + ConstantThicknessShader(10), + pyNonLinearVaryingThicknessShader(4,25, 0.6), + TextureAssignerShader(6), + ConstantColorShader(0.2, 0.2, 0.2,1.0), + TipRemoverShader(10) + ] + +## Use the causal density to avoid cluttering +Operators.create(pyDensityUP1D(8,0.4, IntegrationType.MEAN), shaders_list) + + diff --git a/release/scripts/freestyle/style_modules/logical_operators.py b/release/scripts/freestyle/style_modules/logical_operators.py new file mode 100644 index 00000000000..0ecf6623697 --- /dev/null +++ b/release/scripts/freestyle/style_modules/logical_operators.py @@ -0,0 +1,36 @@ +from freestyle_init import * + +class AndUP1D(UnaryPredicate1D): + def __init__(self, pred1, pred2): + UnaryPredicate1D.__init__(self) + self.__pred1 = pred1 + self.__pred2 = pred2 + + def getName(self): + return "AndUP1D" + + def __call__(self, inter): + return self.__pred1(inter) and self.__pred2(inter) + +class OrUP1D(UnaryPredicate1D): + def __init__(self, pred1, pred2): + UnaryPredicate1D.__init__(self) + self.__pred1 = pred1 + self.__pred2 = pred2 + + def getName(self): + return "OrUP1D" + + def __call__(self, inter): + return self.__pred1(inter) or self.__pred2(inter) + +class NotUP1D(UnaryPredicate1D): + def __init__(self, pred): + UnaryPredicate1D.__init__(self) + self.__pred = pred + + def getName(self): + return "NotUP1D" + + def __call__(self, inter): + return self.__pred(inter) == 0 diff --git a/release/scripts/freestyle/style_modules/long_anisotropically_dense.py b/release/scripts/freestyle/style_modules/long_anisotropically_dense.py new file mode 100644 index 00000000000..155ee489680 --- /dev/null +++ b/release/scripts/freestyle/style_modules/long_anisotropically_dense.py @@ -0,0 +1,81 @@ +# +# Filename : long_anisotropically_dense.py +# Author : Stephane Grabli +# Date : 04/08/2005 +# Purpose : Selects the lines that are long and have a high anisotropic +# a priori density and uses causal density +# to draw without cluttering. Ideally, half of the +# selected lines are culled using the causal density. +# +# ********************* WARNING ************************************* +# ******** The Directional a priori density maps must ****** +# ******** have been computed prior to using 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 PredicatesU1D import * +from PredicatesU0D import * +from PredicatesB1D import * +from Functions0D import * +from Functions1D import * +from shaders import * + +## custom density predicate +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) + self._func2 = DensityF1D(self._wsize, IntegrationType.MAX, sampling) + + def getName(self): + return "pyDensityUP1D" + + def __call__(self, inter): + c = self._func(inter) + m = self._func2(inter) + if(c < self._threshold): + return 1 + if( m > 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 100644 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 100644 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 100644 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 100644 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/parameter_editor.py b/release/scripts/freestyle/style_modules/parameter_editor.py new file mode 100644 index 00000000000..76ca49adaa6 --- /dev/null +++ b/release/scripts/freestyle/style_modules/parameter_editor.py @@ -0,0 +1,1317 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +import Freestyle +import math +import mathutils +import time + +from freestyle_init import * +from logical_operators import * +from ChainingIterators import * +from shaders import * + +class ColorRampModifier(StrokeShader): + def __init__(self, blend, influence, ramp): + StrokeShader.__init__(self) + self.__blend = blend + self.__influence = influence + self.__ramp = ramp + def evaluate(self, t): + col = Freestyle.evaluateColorRamp(self.__ramp, t) + col = col.xyz # omit alpha + return col + def blend_ramp(self, a, b): + return Freestyle.blendRamp(self.__blend, a, self.__influence, b) + +class ScalarBlendModifier(StrokeShader): + def __init__(self, blend, influence): + StrokeShader.__init__(self) + self.__blend = blend + self.__influence = influence + def blend(self, v1, v2): + fac = self.__influence + facm = 1.0 - fac + if self.__blend == "MIX": + v1 = facm * v1 + fac * v2 + elif self.__blend == "ADD": + v1 += fac * v2 + elif self.__blend == "MULTIPLY": + v1 *= facm + fac * v2; + elif self.__blend == "SUBTRACT": + v1 -= fac * v2 + elif self.__blend == "DIVIDE": + if v2 != 0.0: + v1 = facm * v1 + fac * v1 / v2 + elif self.__blend == "DIFFERENCE": + v1 = facm * v1 + fac * abs(v1 - v2) + elif self.__blend == "MININUM": + tmp = fac * v1 + if v1 > tmp: + v1 = tmp + elif self.__blend == "MAXIMUM": + tmp = fac * v1 + if v1 < tmp: + v1 = tmp + else: + raise ValueError("unknown curve blend type: " + self.__blend) + return v1 + +class CurveMappingModifier(ScalarBlendModifier): + def __init__(self, blend, influence, mapping, invert, curve): + ScalarBlendModifier.__init__(self, blend, influence) + assert mapping in ("LINEAR", "CURVE") + self.__mapping = getattr(self, mapping) + self.__invert = invert + self.__curve = curve + def LINEAR(self, t): + if self.__invert: + return 1.0 - t + return t + def CURVE(self, t): + return Freestyle.evaluateCurveMappingF(self.__curve, 0, t) + def evaluate(self, t): + return self.__mapping(t) + +class ThicknessModifierMixIn: + def __init__(self): + scene = Freestyle.getCurrentScene() + self.__persp_camera = (scene.camera.data.type == "PERSP") + def set_thickness(self, sv, outer, inner): + fe = sv.A().getFEdge(sv.B()) + nature = fe.getNature() + if (nature & Nature.BORDER): + if self.__persp_camera: + point = -sv.getPoint3D() + point.normalize() + dir = point.dot(fe.normalB()) + else: + dir = fe.normalB().z + if dir < 0.0: # the back side is visible + outer, inner = inner, outer + elif (nature & Nature.SILHOUETTE): + if fe.isSmooth(): # TODO more tests needed + outer, inner = inner, outer + else: + outer = inner = (outer + inner) / 2 + sv.attribute().setThickness(outer, inner) + +class ThicknessBlenderMixIn(ThicknessModifierMixIn): + def __init__(self, position, ratio): + ThicknessModifierMixIn.__init__(self) + self.__position = position + self.__ratio = ratio + def blend_thickness(self, outer, inner, v): + if self.__position == "CENTER": + outer = self.blend(outer, v / 2) + inner = self.blend(inner, v / 2) + elif self.__position == "INSIDE": + outer = self.blend(outer, 0) + inner = self.blend(inner, v) + elif self.__position == "OUTSIDE": + outer = self.blend(outer, v) + inner = self.blend(inner, 0) + elif self.__position == "RELATIVE": + outer = self.blend(outer, v * self.__ratio) + inner = self.blend(inner, v * (1 - self.__ratio)) + else: + raise ValueError("unknown thickness position: " + self.__position) + return outer, inner + +class BaseColorShader(ConstantColorShader): + def getName(self): + return "BaseColorShader" + +class BaseThicknessShader(StrokeShader, ThicknessModifierMixIn): + def __init__(self, thickness, position, ratio): + StrokeShader.__init__(self) + ThicknessModifierMixIn.__init__(self) + if position == "CENTER": + self.__outer = thickness / 2 + self.__inner = thickness / 2 + elif position == "INSIDE": + self.__outer = 0 + self.__inner = thickness + elif position == "OUTSIDE": + self.__outer = thickness + self.__inner = 0 + elif position == "RELATIVE": + self.__outer = thickness * ratio + self.__inner = thickness * (1 - ratio) + else: + raise ValueError("unknown thickness position: " + self.position) + def getName(self): + return "BaseThicknessShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + sv = it.getObject() + self.set_thickness(sv, self.__outer, self.__inner) + it.increment() + +# Along Stroke modifiers + +def iter_t2d_along_stroke(stroke): + total = stroke.getLength2D() + distance = 0.0 + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + p = it.getObject().getPoint() + if not it.isBegin(): + distance += (prev - p).length + prev = p + t = min(distance / total, 1.0) + yield it, t + it.increment() + +class ColorAlongStrokeShader(ColorRampModifier): + def getName(self): + return "ColorAlongStrokeShader" + def shade(self, stroke): + for it, t in iter_t2d_along_stroke(stroke): + attr = it.getObject().attribute() + a = attr.getColorRGB() + b = self.evaluate(t) + c = self.blend_ramp(a, b) + attr.setColor(c) + +class AlphaAlongStrokeShader(CurveMappingModifier): + def getName(self): + return "AlphaAlongStrokeShader" + def shade(self, stroke): + for it, t in iter_t2d_along_stroke(stroke): + attr = it.getObject().attribute() + a = attr.getAlpha() + b = self.evaluate(t) + c = self.blend(a, b) + attr.setAlpha(c) + +class ThicknessAlongStrokeShader(ThicknessBlenderMixIn, CurveMappingModifier): + def __init__(self, thickness_position, thickness_ratio, + blend, influence, mapping, invert, curve, value_min, value_max): + ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio) + CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) + self.__value_min = value_min + self.__value_max = value_max + def getName(self): + return "ThicknessAlongStrokeShader" + def shade(self, stroke): + for it, t in iter_t2d_along_stroke(stroke): + sv = it.getObject() + a = sv.attribute().getThicknessRL() + b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min) + c = self.blend_thickness(a[0], a[1], b) + self.set_thickness(sv, c[0], c[1]) + +# Distance from Camera modifiers + +def iter_distance_from_camera(stroke, range_min, range_max): + normfac = range_max - range_min # normalization factor + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + p = it.getObject().getPoint3D() # in the camera coordinate + distance = p.length + if distance < range_min: + t = 0.0 + elif distance > range_max: + t = 1.0 + else: + t = (distance - range_min) / normfac + yield it, t + it.increment() + +class ColorDistanceFromCameraShader(ColorRampModifier): + def __init__(self, blend, influence, ramp, range_min, range_max): + ColorRampModifier.__init__(self, blend, influence, ramp) + self.__range_min = range_min + self.__range_max = range_max + def getName(self): + return "ColorDistanceFromCameraShader" + def shade(self, stroke): + for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max): + attr = it.getObject().attribute() + a = attr.getColorRGB() + b = self.evaluate(t) + c = self.blend_ramp(a, b) + attr.setColor(c) + +class AlphaDistanceFromCameraShader(CurveMappingModifier): + def __init__(self, blend, influence, mapping, invert, curve, range_min, range_max): + CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) + self.__range_min = range_min + self.__range_max = range_max + def getName(self): + return "AlphaDistanceFromCameraShader" + def shade(self, stroke): + for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max): + attr = it.getObject().attribute() + a = attr.getAlpha() + b = self.evaluate(t) + c = self.blend(a, b) + attr.setAlpha(c) + +class ThicknessDistanceFromCameraShader(ThicknessBlenderMixIn, CurveMappingModifier): + def __init__(self, thickness_position, thickness_ratio, + blend, influence, mapping, invert, curve, range_min, range_max, value_min, value_max): + ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio) + CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) + self.__range_min = range_min + self.__range_max = range_max + self.__value_min = value_min + self.__value_max = value_max + def getName(self): + return "ThicknessDistanceFromCameraShader" + def shade(self, stroke): + for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max): + sv = it.getObject() + a = sv.attribute().getThicknessRL() + b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min) + c = self.blend_thickness(a[0], a[1], b) + self.set_thickness(sv, c[0], c[1]) + +# Distance from Object modifiers + +def iter_distance_from_object(stroke, object, range_min, range_max): + scene = Freestyle.getCurrentScene() + mv = scene.camera.matrix_world.copy() # model-view matrix + mv.invert() + loc = mv * object.location # loc in the camera coordinate + normfac = range_max - range_min # normalization factor + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + p = it.getObject().getPoint3D() # in the camera coordinate + distance = (p - loc).length + if distance < range_min: + t = 0.0 + elif distance > range_max: + t = 1.0 + else: + t = (distance - range_min) / normfac + yield it, t + it.increment() + +class ColorDistanceFromObjectShader(ColorRampModifier): + def __init__(self, blend, influence, ramp, target, range_min, range_max): + ColorRampModifier.__init__(self, blend, influence, ramp) + self.__target = target + self.__range_min = range_min + self.__range_max = range_max + def getName(self): + return "ColorDistanceFromObjectShader" + def shade(self, stroke): + if self.__target is None: + return + for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max): + attr = it.getObject().attribute() + a = attr.getColorRGB() + b = self.evaluate(t) + c = self.blend_ramp(a, b) + attr.setColor(c) + +class AlphaDistanceFromObjectShader(CurveMappingModifier): + def __init__(self, blend, influence, mapping, invert, curve, target, range_min, range_max): + CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) + self.__target = target + self.__range_min = range_min + self.__range_max = range_max + def getName(self): + return "AlphaDistanceFromObjectShader" + def shade(self, stroke): + if self.__target is None: + return + for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max): + attr = it.getObject().attribute() + a = attr.getAlpha() + b = self.evaluate(t) + c = self.blend(a, b) + attr.setAlpha(c) + +class ThicknessDistanceFromObjectShader(ThicknessBlenderMixIn, CurveMappingModifier): + def __init__(self, thickness_position, thickness_ratio, + blend, influence, mapping, invert, curve, target, range_min, range_max, value_min, value_max): + ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio) + CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) + self.__target = target + self.__range_min = range_min + self.__range_max = range_max + self.__value_min = value_min + self.__value_max = value_max + def getName(self): + return "ThicknessDistanceFromObjectShader" + def shade(self, stroke): + if self.__target is None: + return + for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max): + sv = it.getObject() + a = sv.attribute().getThicknessRL() + b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min) + c = self.blend_thickness(a[0], a[1], b) + self.set_thickness(sv, c[0], c[1]) + +# Material modifiers + +def iter_material_color(stroke, material_attr): + func = CurveMaterialF0D() + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + material = func(it.castToInterface0DIterator()) + if material_attr == "DIFF": + color = (material.diffuseR(), + material.diffuseG(), + material.diffuseB()) + elif material_attr == "SPEC": + color = (material.specularR(), + material.specularG(), + material.specularB()) + else: + raise ValueError("unexpected material attribute: " + material_attr) + yield it, color + it.increment() + +def iter_material_value(stroke, material_attr): + func = CurveMaterialF0D() + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + material = func(it.castToInterface0DIterator()) + if material_attr == "DIFF": + r = material.diffuseR() + g = material.diffuseG() + b = material.diffuseB() + t = 0.35 * r + 0.45 * r + 0.2 * b + elif material_attr == "DIFF_R": + t = material.diffuseR() + elif material_attr == "DIFF_G": + t = material.diffuseG() + elif material_attr == "DIFF_B": + t = material.diffuseB() + elif material_attr == "SPEC": + r = material.specularR() + g = material.specularG() + b = material.specularB() + t = 0.35 * r + 0.45 * r + 0.2 * b + elif material_attr == "SPEC_R": + t = material.specularR() + elif material_attr == "SPEC_G": + t = material.specularG() + elif material_attr == "SPEC_B": + t = material.specularB() + elif material_attr == "SPEC_HARDNESS": + t = material.shininess() + elif material_attr == "ALPHA": + t = material.diffuseA() + else: + raise ValueError("unexpected material attribute: " + material_attr) + yield it, t + it.increment() + +class ColorMaterialShader(ColorRampModifier): + def __init__(self, blend, influence, ramp, material_attr, use_ramp): + ColorRampModifier.__init__(self, blend, influence, ramp) + self.__material_attr = material_attr + self.__use_ramp = use_ramp + def getName(self): + return "ColorMaterialShader" + def shade(self, stroke): + if self.__material_attr in ["DIFF", "SPEC"] and not self.__use_ramp: + for it, b in iter_material_color(stroke, self.__material_attr): + attr = it.getObject().attribute() + a = attr.getColorRGB() + c = self.blend_ramp(a, b) + attr.setColor(c) + else: + for it, t in iter_material_value(stroke, self.__material_attr): + attr = it.getObject().attribute() + a = attr.getColorRGB() + b = self.evaluate(t) + c = self.blend_ramp(a, b) + attr.setColor(c) + +class AlphaMaterialShader(CurveMappingModifier): + def __init__(self, blend, influence, mapping, invert, curve, material_attr): + CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) + self.__material_attr = material_attr + def getName(self): + return "AlphaMaterialShader" + def shade(self, stroke): + for it, t in iter_material_value(stroke, self.__material_attr): + attr = it.getObject().attribute() + a = attr.getAlpha() + b = self.evaluate(t) + c = self.blend(a, b) + attr.setAlpha(c) + +class ThicknessMaterialShader(ThicknessBlenderMixIn, CurveMappingModifier): + def __init__(self, thickness_position, thickness_ratio, + blend, influence, mapping, invert, curve, material_attr, value_min, value_max): + ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio) + CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) + self.__material_attr = material_attr + self.__value_min = value_min + self.__value_max = value_max + def getName(self): + return "ThicknessMaterialShader" + def shade(self, stroke): + for it, t in iter_material_value(stroke, self.__material_attr): + sv = it.getObject() + a = sv.attribute().getThicknessRL() + b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min) + c = self.blend_thickness(a[0], a[1], b) + self.set_thickness(sv, c[0], c[1]) + +# Calligraphic thickness modifier + +class CalligraphicThicknessShader(ThicknessBlenderMixIn, ScalarBlendModifier): + def __init__(self, thickness_position, thickness_ratio, + blend, influence, orientation, min_thickness, max_thickness): + ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio) + ScalarBlendModifier.__init__(self, blend, influence) + self.__orientation = mathutils.Vector((math.cos(orientation), math.sin(orientation))) + self.__min_thickness = min_thickness + self.__max_thickness = max_thickness + def shade(self, stroke): + func = VertexOrientation2DF0D() + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + dir = func(it.castToInterface0DIterator()) + orthDir = mathutils.Vector((-dir.y, dir.x)) + orthDir.normalize() + fac = abs(orthDir * self.__orientation) + sv = it.getObject() + a = sv.attribute().getThicknessRL() + b = self.__min_thickness + fac * (self.__max_thickness - self.__min_thickness) + b = max(b, 0.0) + c = self.blend_thickness(a[0], a[1], b) + self.set_thickness(sv, c[0], c[1]) + it.increment() + +# Geometry modifiers + +def iter_distance_along_stroke(stroke): + distance = 0.0 + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + p = it.getObject().getPoint() + if not it.isBegin(): + distance += (prev - p).length + prev = p + yield it, distance + it.increment() + +class SinusDisplacementShader(StrokeShader): + def __init__(self, wavelength, amplitude, phase): + StrokeShader.__init__(self) + self._wavelength = wavelength + self._amplitude = amplitude + self._phase = phase / wavelength * 2 * math.pi + self._getNormal = Normal2DF0D() + def getName(self): + return "SinusDisplacementShader" + def shade(self, stroke): + for it, distance in iter_distance_along_stroke(stroke): + v = it.getObject() + n = self._getNormal(it.castToInterface0DIterator()) + p = v.getPoint() + u = v.u() + n = n * self._amplitude * math.cos(distance / self._wavelength * 2 * math.pi + self._phase) + v.setPoint(p + n) + stroke.UpdateLength() + +class PerlinNoise1DShader(StrokeShader): + def __init__(self, freq = 10, amp = 10, oct = 4, angle = math.radians(45), seed = -1): + StrokeShader.__init__(self) + self.__noise = Noise(seed) + self.__freq = freq + self.__amp = amp + self.__oct = oct + self.__dir = Vector([cos(angle), sin(angle)]) + def getName(self): + return "PerlinNoise1DShader" + def shade(self, stroke): + length = stroke.getLength2D() + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + v = it.getObject() + nres = self.__noise.turbulence1(length * v.u(), self.__freq, self.__amp, self.__oct) + v.setPoint(v.getPoint() + nres * self.__dir) + it.increment() + stroke.UpdateLength() + +class PerlinNoise2DShader(StrokeShader): + def __init__(self, freq = 10, amp = 10, oct = 4, angle = math.radians(45), seed = -1): + StrokeShader.__init__(self) + self.__noise = Noise(seed) + self.__freq = freq + self.__amp = amp + self.__oct = oct + self.__dir = Vector([cos(angle), sin(angle)]) + def getName(self): + return "PerlinNoise2DShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + v = it.getObject() + vec = Vector([v.getProjectedX(), v.getProjectedY()]) + nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct) + v.setPoint(v.getPoint() + nres * self.__dir) + it.increment() + stroke.UpdateLength() + +class Offset2DShader(StrokeShader): + def __init__(self, start, end, x, y): + StrokeShader.__init__(self) + self.__start = start + self.__end = end + self.__xy = Vector([x, y]) + self.__getNormal = Normal2DF0D() + def getName(self): + return "Offset2DShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + v = it.getObject() + u = v.u() + a = self.__start + u * (self.__end - self.__start) + n = self.__getNormal(it.castToInterface0DIterator()) + n = n * a + p = v.getPoint() + v.setPoint(p + n + self.__xy) + it.increment() + stroke.UpdateLength() + +class Transform2DShader(StrokeShader): + def __init__(self, pivot, scale_x, scale_y, angle, pivot_u, pivot_x, pivot_y): + StrokeShader.__init__(self) + self.__pivot = pivot + self.__scale_x = scale_x + self.__scale_y = scale_y + self.__angle = angle + self.__pivot_u = pivot_u + self.__pivot_x = pivot_x + self.__pivot_y = pivot_y + def getName(self): + return "Transform2DShader" + def shade(self, stroke): + # determine the pivot of scaling and rotation operations + if self.__pivot == "START": + it = stroke.strokeVerticesBegin() + pivot = it.getObject().getPoint() + elif self.__pivot == "END": + it = stroke.strokeVerticesEnd() + it.decrement() + pivot = it.getObject().getPoint() + elif self.__pivot == "PARAM": + p = None + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + prev = p + v = it.getObject() + p = v.getPoint() + u = v.u() + if self.__pivot_u < u: + break + it.increment() + if prev is None: + pivot = p + else: + delta = u - self.__pivot_u + pivot = p + delta * (prev - p) + elif self.__pivot == "CENTER": + pivot = Vector([0.0, 0.0]) + n = 0 + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + p = it.getObject().getPoint() + pivot = pivot + p + n = n + 1 + it.increment() + pivot.x = pivot.x / n + pivot.y = pivot.y / n + elif self.__pivot == "ABSOLUTE": + pivot = Vector([self.__pivot_x, self.__pivot_y]) + # apply scaling and rotation operations + cos_theta = math.cos(self.__angle) + sin_theta = math.sin(self.__angle) + it = stroke.strokeVerticesBegin() + while not it.isEnd(): + v = it.getObject() + p = v.getPoint() + p = p - pivot + x = p.x * self.__scale_x + y = p.y * self.__scale_y + p.x = x * cos_theta - y * sin_theta + p.y = x * sin_theta + y * cos_theta + v.setPoint(p + pivot) + it.increment() + stroke.UpdateLength() + +# Predicates and helper functions + +class QuantitativeInvisibilityRangeUP1D(UnaryPredicate1D): + def __init__(self, qi_start, qi_end): + UnaryPredicate1D.__init__(self) + self.__getQI = QuantitativeInvisibilityF1D() + self.__qi_start = qi_start + self.__qi_end = qi_end + def getName(self): + return "QuantitativeInvisibilityRangeUP1D" + def __call__(self, inter): + qi = self.__getQI(inter) + return self.__qi_start <= qi <= self.__qi_end + +def join_unary_predicates(upred_list, bpred): + if not upred_list: + return None + upred = upred_list[0] + for p in upred_list[1:]: + upred = bpred(upred, p) + return upred + +class ObjectNamesUP1D(UnaryPredicate1D): + def __init__(self, names, negative): + UnaryPredicate1D.__init__(self) + self._names = names + self._negative = negative + def getName(self): + return "ObjectNamesUP1D" + def __call__(self, viewEdge): + found = viewEdge.viewShape().getName() in self._names + if self._negative: + return not found + return found + +# Stroke caps + +def iter_stroke_vertices(stroke): + it = stroke.strokeVerticesBegin() + prev_p = None + while not it.isEnd(): + sv = it.getObject() + p = sv.getPoint() + if prev_p is None or (prev_p - p).length > 1e-6: + yield sv + prev_p = p + it.increment() + +class RoundCapShader(StrokeShader): + def round_cap_thickness(self, x): + x = max(0.0, min(x, 1.0)) + return math.sqrt(1.0 - (x ** 2)) + def shade(self, stroke): + # save the location and attribute of stroke vertices + buffer = [] + for sv in iter_stroke_vertices(stroke): + buffer.append((sv.getPoint(), sv.attribute())) + nverts = len(buffer) + if nverts < 2: + return + # calculate the number of additional vertices to form caps + R, L = stroke[0].attribute().getThicknessRL() + caplen_beg = (R + L) / 2.0 + nverts_beg = max(5, int(R + L)) + R, L = stroke[-1].attribute().getThicknessRL() + caplen_end = (R + L) / 2.0 + nverts_end = max(5, int(R + L)) + # adjust the total number of stroke vertices + stroke.Resample(nverts + nverts_beg + nverts_end) + # restore the location and attribute of the original vertices + for i in range(nverts): + p, attr = buffer[i] + stroke[nverts_beg + i].setPoint(p) + stroke[nverts_beg + i].setAttribute(attr) + # reshape the cap at the beginning of the stroke + q, attr = buffer[1] + p, attr = buffer[0] + d = p - q + d = d / d.length * caplen_beg + n = 1.0 / nverts_beg + R, L = attr.getThicknessRL() + for i in range(nverts_beg): + t = (nverts_beg - i) * n + stroke[i].setPoint(p + d * t) + r = self.round_cap_thickness((nverts_beg - i + 1) * n) + stroke[i].setAttribute(attr) + stroke[i].attribute().setThickness(R * r, L * r) + # reshape the cap at the end of the stroke + q, attr = buffer[-2] + p, attr = buffer[-1] + d = p - q + d = d / d.length * caplen_end + n = 1.0 / nverts_end + R, L = attr.getThicknessRL() + for i in range(nverts_end): + t = (nverts_end - i) * n + stroke[-i-1].setPoint(p + d * t) + r = self.round_cap_thickness((nverts_end - i + 1) * n) + stroke[-i-1].setAttribute(attr) + stroke[-i-1].attribute().setThickness(R * r, L * r) + # update the curvilinear 2D length of each vertex + stroke.UpdateLength() + +class SquareCapShader(StrokeShader): + def shade(self, stroke): + # save the location and attribute of stroke vertices + buffer = [] + for sv in iter_stroke_vertices(stroke): + buffer.append((sv.getPoint(), sv.attribute())) + nverts = len(buffer) + if nverts < 2: + return + # calculate the number of additional vertices to form caps + R, L = stroke[0].attribute().getThicknessRL() + caplen_beg = (R + L) / 2.0 + nverts_beg = 1 + R, L = stroke[-1].attribute().getThicknessRL() + caplen_end = (R + L) / 2.0 + nverts_end = 1 + # adjust the total number of stroke vertices + stroke.Resample(nverts + nverts_beg + nverts_end) + # restore the location and attribute of the original vertices + for i in range(nverts): + p, attr = buffer[i] + stroke[nverts_beg + i].setPoint(p) + stroke[nverts_beg + i].setAttribute(attr) + # reshape the cap at the beginning of the stroke + q, attr = buffer[1] + p, attr = buffer[0] + d = p - q + stroke[0].setPoint(p + d / d.length * caplen_beg) + stroke[0].setAttribute(attr) + # reshape the cap at the end of the stroke + q, attr = buffer[-2] + p, attr = buffer[-1] + d = p - q + stroke[-1].setPoint(p + d / d.length * caplen_beg) + stroke[-1].setAttribute(attr) + # update the curvilinear 2D length of each vertex + stroke.UpdateLength() + +# Split by dashed line pattern + +class SplitPatternStartingUP0D(UnaryPredicate0D): + def __init__(self, controller): + UnaryPredicate0D.__init__(self) + self._controller = controller + def __call__(self, inter): + return self._controller.start() + +class SplitPatternStoppingUP0D(UnaryPredicate0D): + def __init__(self, controller): + UnaryPredicate0D.__init__(self) + self._controller = controller + def __call__(self, inter): + return self._controller.stop() + +class SplitPatternController: + def __init__(self, pattern, sampling): + self.sampling = float(sampling) + k = len(pattern) // 2 + n = k * 2 + self.start_pos = [pattern[i] + pattern[i+1] for i in range(0, n, 2)] + self.stop_pos = [pattern[i] for i in range(0, n, 2)] + self.init() + def init(self): + self.start_len = 0.0 + self.start_idx = 0 + self.stop_len = self.sampling + self.stop_idx = 0 + def start(self): + self.start_len += self.sampling + if abs(self.start_len - self.start_pos[self.start_idx]) < self.sampling / 2.0: + self.start_len = 0.0 + self.start_idx = (self.start_idx + 1) % len(self.start_pos) + return True + return False + def stop(self): + if self.start_len > 0.0: + self.init() + self.stop_len += self.sampling + if abs(self.stop_len - self.stop_pos[self.stop_idx]) < self.sampling / 2.0: + self.stop_len = self.sampling + self.stop_idx = (self.stop_idx + 1) % len(self.stop_pos) + return True + return False + +# Dashed line + +class DashedLineShader(StrokeShader): + def __init__(self, pattern): + StrokeShader.__init__(self) + self._pattern = pattern + def getName(self): + return "DashedLineShader" + def shade(self, stroke): + index = 0 # pattern index + start = 0.0 # 2D curvilinear length + visible = True + sampling = 1.0 + it = stroke.strokeVerticesBegin(sampling) + while not it.isEnd(): + pos = it.t() + # The extra 'sampling' term is added below, because the + # visibility attribute of the i-th vertex refers to the + # visibility of the stroke segment between the i-th and + # (i+1)-th vertices. + if pos - start + sampling > self._pattern[index]: + start = pos + index += 1 + if index == len(self._pattern): + index = 0 + visible = not visible + it.getObject().attribute().setVisible(visible) + it.increment() + +# predicates for chaining + +class AngleLargerThanBP1D(BinaryPredicate1D): + def __init__(self, angle): + BinaryPredicate1D.__init__(self) + self._angle = angle + def getName(self): + return "AngleLargerThanBP1D" + def __call__(self, i1, i2): + fe1a = i1.fedgeA() + fe1b = i1.fedgeB() + fe2a = i2.fedgeA() + fe2b = i2.fedgeB() + sv1a = fe1a.vertexA().getPoint2D() + sv1b = fe1b.vertexB().getPoint2D() + sv2a = fe2a.vertexA().getPoint2D() + sv2b = fe2b.vertexB().getPoint2D() + if (sv1a - sv2a).length < 1e-6: + dir1 = sv1a - sv1b + dir2 = sv2b - sv2a + elif (sv1b - sv2b).length < 1e-6: + dir1 = sv1b - sv1a + dir2 = sv2a - sv2b + elif (sv1a - sv2b).length < 1e-6: + dir1 = sv1a - sv1b + dir2 = sv2a - sv2b + elif (sv1b - sv2a).length < 1e-6: + dir1 = sv1b - sv1a + dir2 = sv2b - sv2a + else: + return False + denom = dir1.length * dir2.length + if denom < 1e-6: + return False + x = (dir1 * dir2) / denom + return math.acos(min(max(x, -1.0), 1.0)) > self._angle + +class AndBP1D(BinaryPredicate1D): + def __init__(self, pred1, pred2): + BinaryPredicate1D.__init__(self) + self.__pred1 = pred1 + self.__pred2 = pred2 + def getName(self): + return "AndBP1D" + def __call__(self, i1, i2): + return self.__pred1(i1, i2) and self.__pred2(i1, i2) + +# predicates for selection + +class LengthThresholdUP1D(UnaryPredicate1D): + def __init__(self, min_length=None, max_length=None): + UnaryPredicate1D.__init__(self) + self._min_length = min_length + self._max_length = max_length + def getName(self): + return "LengthThresholdUP1D" + def __call__(self, inter): + length = inter.getLength2D() + if self._min_length is not None and length < self._min_length: + return False + if self._max_length is not None and length > self._max_length: + return False + return True + +class FaceMarkBothUP1D(UnaryPredicate1D): + def __call__(self, inter): # ViewEdge + fe = inter.fedgeA() + while fe is not None: + if fe.isSmooth(): + if fe.faceMark(): + return True + else: + if fe.aFaceMark() and fe.bFaceMark(): + return True + fe = fe.nextEdge() + return False + +class FaceMarkOneUP1D(UnaryPredicate1D): + def __call__(self, inter): # ViewEdge + fe = inter.fedgeA() + while fe is not None: + if fe.isSmooth(): + if fe.faceMark(): + return True + else: + if fe.aFaceMark() or fe.bFaceMark(): + return True + fe = fe.nextEdge() + return False + +# predicates for splitting + +class MaterialBoundaryUP0D(UnaryPredicate0D): + def getName(self): + return "MaterialBoundaryUP0D" + def __call__(self, it): + if it.isBegin(): + return False + it_prev = Interface0DIterator(it) + it_prev.decrement() + v = it.getObject() + it.increment() + if it.isEnd(): + return False + fe = v.getFEdge(it_prev.getObject()) + idx1 = fe.materialIndex() if fe.isSmooth() else fe.bMaterialIndex() + fe = v.getFEdge(it.getObject()) + idx2 = fe.materialIndex() if fe.isSmooth() else fe.bMaterialIndex() + return idx1 != idx2 + +class Curvature2DAngleThresholdUP0D(UnaryPredicate0D): + def __init__(self, min_angle=None, max_angle=None): + UnaryPredicate0D.__init__(self) + self._min_angle = min_angle + self._max_angle = max_angle + self._func = Curvature2DAngleF0D() + def getName(self): + return "Curvature2DAngleThresholdUP0D" + def __call__(self, inter): + angle = math.pi - self._func(inter) + if self._min_angle is not None and angle < self._min_angle: + return True + if self._max_angle is not None and angle > self._max_angle: + return True + return False + +class Length2DThresholdUP0D(UnaryPredicate0D): + def __init__(self, length_limit): + UnaryPredicate0D.__init__(self) + self._length_limit = length_limit + self._t = 0.0 + def getName(self): + return "Length2DThresholdUP0D" + def __call__(self, inter): + t = inter.t() # curvilinear abscissa + if t < self._t: + self._t = 0.0 + return False + if t - self._t < self._length_limit: + return False + self._t = t + return True + +# Seed for random number generation + +class Seed: + def __init__(self): + self.t_max = 2 ** 15 + self.t = int(time.time()) % self.t_max + def get(self, seed): + if seed < 0: + self.t = (self.t + 1) % self.t_max + return self.t + return seed + +_seed = Seed() + +# main function for parameter processing + +def process(layer_name, lineset_name): + scene = Freestyle.getCurrentScene() + layer = scene.render.layers[layer_name] + lineset = layer.freestyle_settings.linesets[lineset_name] + linestyle = lineset.linestyle + + selection_criteria = [] + # prepare selection criteria by visibility + if lineset.select_by_visibility: + if lineset.visibility == "VISIBLE": + selection_criteria.append( + QuantitativeInvisibilityUP1D(0)) + elif lineset.visibility == "HIDDEN": + selection_criteria.append( + NotUP1D(QuantitativeInvisibilityUP1D(0))) + elif lineset.visibility == "RANGE": + selection_criteria.append( + QuantitativeInvisibilityRangeUP1D(lineset.qi_start, lineset.qi_end)) + # prepare selection criteria by edge types + if lineset.select_by_edge_types: + edge_type_criteria = [] + if lineset.select_silhouette: + upred = pyNatureUP1D(Nature.SILHOUETTE) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_silhouette else upred) + if lineset.select_border: + upred = pyNatureUP1D(Nature.BORDER) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_border else upred) + if lineset.select_crease: + upred = pyNatureUP1D(Nature.CREASE) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_crease else upred) + if lineset.select_ridge_valley: + upred = pyNatureUP1D(Nature.RIDGE) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_ridge_valley else upred) + if lineset.select_suggestive_contour: + upred = pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_suggestive_contour else upred) + if lineset.select_material_boundary: + upred = pyNatureUP1D(Nature.MATERIAL_BOUNDARY) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_material_boundary else upred) + if lineset.select_edge_mark: + upred = pyNatureUP1D(Nature.EDGE_MARK) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_edge_mark else upred) + if lineset.select_contour: + upred = ContourUP1D() + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_contour else upred) + if lineset.select_external_contour: + upred = ExternalContourUP1D() + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_external_contour else upred) + if lineset.edge_type_combination == "OR": + upred = join_unary_predicates(edge_type_criteria, OrUP1D) + else: + upred = join_unary_predicates(edge_type_criteria, AndUP1D) + if upred is not None: + if lineset.edge_type_negation == "EXCLUSIVE": + upred = NotUP1D(upred) + selection_criteria.append(upred) + # prepare selection criteria by face marks + if lineset.select_by_face_marks: + if lineset.face_mark_condition == "BOTH": + upred = FaceMarkBothUP1D() + else: + upred = FaceMarkOneUP1D() + if lineset.face_mark_negation == "EXCLUSIVE": + upred = NotUP1D(upred) + selection_criteria.append(upred) + # prepare selection criteria by group of objects + if lineset.select_by_group: + if lineset.group is not None: + names = dict((ob.name, True) for ob in lineset.group.objects) + upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE') + selection_criteria.append(upred) + # prepare selection criteria by image border + if lineset.select_by_image_border: + w = scene.render.resolution_x + h = scene.render.resolution_y + if scene.render.use_border: + xmin = scene.render.border_min_x * w + xmax = scene.render.border_max_x * w + ymin = scene.render.border_min_y * h + ymax = scene.render.border_max_y * h + else: + xmin, xmax = 0.0, float(w) + ymin, ymax = 0.0, float(h) + upred = WithinImageBoundaryUP1D(xmin, ymin, xmax, ymax) + selection_criteria.append(upred) + # select feature edges + upred = join_unary_predicates(selection_criteria, AndUP1D) + if upred is None: + upred = TrueUP1D() + Operators.select(upred) + # join feature edges to form chains + if linestyle.use_chaining: + if linestyle.chaining == "PLAIN": + if linestyle.same_object: + Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred)) + else: + Operators.bidirectionalChain(ChainPredicateIterator(upred, TrueBP1D()), NotUP1D(upred)) + elif linestyle.chaining == "SKETCHY": + if linestyle.same_object: + Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(linestyle.rounds)) + else: + Operators.bidirectionalChain(pySketchyChainingIterator(linestyle.rounds)) + else: + Operators.chain(ChainPredicateIterator(FalseUP1D(), FalseBP1D()), NotUP1D(upred)) + # split chains + if linestyle.material_boundary: + Operators.sequentialSplit(MaterialBoundaryUP0D()) + if linestyle.use_min_angle or linestyle.use_max_angle: + min_angle = linestyle.min_angle if linestyle.use_min_angle else None + max_angle = linestyle.max_angle if linestyle.use_max_angle else None + Operators.sequentialSplit(Curvature2DAngleThresholdUP0D(min_angle, max_angle)) + if linestyle.use_split_length: + Operators.sequentialSplit(Length2DThresholdUP0D(linestyle.split_length), 1.0) + if linestyle.use_split_pattern: + pattern = [] + if linestyle.split_dash1 > 0 and linestyle.split_gap1 > 0: + pattern.append(linestyle.split_dash1) + pattern.append(linestyle.split_gap1) + if linestyle.split_dash2 > 0 and linestyle.split_gap2 > 0: + pattern.append(linestyle.split_dash2) + pattern.append(linestyle.split_gap2) + if linestyle.split_dash3 > 0 and linestyle.split_gap3 > 0: + pattern.append(linestyle.split_dash3) + pattern.append(linestyle.split_gap3) + if len(pattern) > 0: + sampling = 1.0 + controller = SplitPatternController(pattern, sampling) + Operators.sequentialSplit(SplitPatternStartingUP0D(controller), + SplitPatternStoppingUP0D(controller), + sampling) + # select chains + if linestyle.use_min_length or linestyle.use_max_length: + min_length = linestyle.min_length if linestyle.use_min_length else None + max_length = linestyle.max_length if linestyle.use_max_length else None + Operators.select(LengthThresholdUP1D(min_length, max_length)) + # prepare a list of stroke shaders + shaders_list = [] + for m in linestyle.geometry_modifiers: + if not m.use: + continue + if m.type == "SAMPLING": + shaders_list.append(SamplingShader( + m.sampling)) + elif m.type == "BEZIER_CURVE": + shaders_list.append(BezierCurveShader( + m.error)) + elif m.type == "SINUS_DISPLACEMENT": + shaders_list.append(SinusDisplacementShader( + m.wavelength, m.amplitude, m.phase)) + elif m.type == "SPATIAL_NOISE": + shaders_list.append(SpatialNoiseShader( + m.amplitude, m.scale, m.octaves, m.smooth, m.pure_random)) + elif m.type == "PERLIN_NOISE_1D": + shaders_list.append(PerlinNoise1DShader( + m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed))) + elif m.type == "PERLIN_NOISE_2D": + shaders_list.append(PerlinNoise2DShader( + m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed))) + elif m.type == "BACKBONE_STRETCHER": + shaders_list.append(BackboneStretcherShader( + m.backbone_length)) + elif m.type == "TIP_REMOVER": + shaders_list.append(TipRemoverShader( + m.tip_length)) + elif m.type == "POLYGONIZATION": + shaders_list.append(PolygonalizationShader( + m.error)) + elif m.type == "GUIDING_LINES": + shaders_list.append(GuidingLinesShader( + m.offset)) + elif m.type == "BLUEPRINT": + if m.shape == "CIRCLES": + shaders_list.append(pyBluePrintCirclesShader( + m.rounds, m.random_radius, m.random_center)) + elif m.shape == "ELLIPSES": + shaders_list.append(pyBluePrintEllipsesShader( + m.rounds, m.random_radius, m.random_center)) + elif m.shape == "SQUARES": + shaders_list.append(pyBluePrintSquaresShader( + m.rounds, m.backbone_length, m.random_backbone)) + elif m.type == "2D_OFFSET": + shaders_list.append(Offset2DShader( + m.start, m.end, m.x, m.y)) + elif m.type == "2D_TRANSFORM": + shaders_list.append(Transform2DShader( + m.pivot, m.scale_x, m.scale_y, m.angle, m.pivot_u, m.pivot_x, m.pivot_y)) + color = linestyle.color + if (not linestyle.use_chaining) or (linestyle.chaining == "PLAIN" and linestyle.same_object): + thickness_position = linestyle.thickness_position + else: + thickness_position = "CENTER" + import bpy + if bpy.app.debug_freestyle: + print("Warning: Thickness position options are applied when chaining is disabled") + print(" or the Plain chaining is used with the Same Object option enabled.") + shaders_list.append(BaseColorShader(color.r, color.g, color.b, linestyle.alpha)) + shaders_list.append(BaseThicknessShader(linestyle.thickness, thickness_position, + linestyle.thickness_ratio)) + for m in linestyle.color_modifiers: + if not m.use: + continue + if m.type == "ALONG_STROKE": + shaders_list.append(ColorAlongStrokeShader( + m.blend, m.influence, m.color_ramp)) + elif m.type == "DISTANCE_FROM_CAMERA": + shaders_list.append(ColorDistanceFromCameraShader( + m.blend, m.influence, m.color_ramp, + m.range_min, m.range_max)) + elif m.type == "DISTANCE_FROM_OBJECT": + shaders_list.append(ColorDistanceFromObjectShader( + m.blend, m.influence, m.color_ramp, m.target, + m.range_min, m.range_max)) + elif m.type == "MATERIAL": + shaders_list.append(ColorMaterialShader( + m.blend, m.influence, m.color_ramp, m.material_attr, + m.use_ramp)) + for m in linestyle.alpha_modifiers: + if not m.use: + continue + if m.type == "ALONG_STROKE": + shaders_list.append(AlphaAlongStrokeShader( + m.blend, m.influence, m.mapping, m.invert, m.curve)) + elif m.type == "DISTANCE_FROM_CAMERA": + shaders_list.append(AlphaDistanceFromCameraShader( + m.blend, m.influence, m.mapping, m.invert, m.curve, + m.range_min, m.range_max)) + elif m.type == "DISTANCE_FROM_OBJECT": + shaders_list.append(AlphaDistanceFromObjectShader( + m.blend, m.influence, m.mapping, m.invert, m.curve, m.target, + m.range_min, m.range_max)) + elif m.type == "MATERIAL": + shaders_list.append(AlphaMaterialShader( + m.blend, m.influence, m.mapping, m.invert, m.curve, + m.material_attr)) + for m in linestyle.thickness_modifiers: + if not m.use: + continue + if m.type == "ALONG_STROKE": + shaders_list.append(ThicknessAlongStrokeShader( + thickness_position, linestyle.thickness_ratio, + m.blend, m.influence, m.mapping, m.invert, m.curve, + m.value_min, m.value_max)) + elif m.type == "DISTANCE_FROM_CAMERA": + shaders_list.append(ThicknessDistanceFromCameraShader( + thickness_position, linestyle.thickness_ratio, + m.blend, m.influence, m.mapping, m.invert, m.curve, + m.range_min, m.range_max, m.value_min, m.value_max)) + elif m.type == "DISTANCE_FROM_OBJECT": + shaders_list.append(ThicknessDistanceFromObjectShader( + thickness_position, linestyle.thickness_ratio, + m.blend, m.influence, m.mapping, m.invert, m.curve, m.target, + m.range_min, m.range_max, m.value_min, m.value_max)) + elif m.type == "MATERIAL": + shaders_list.append(ThicknessMaterialShader( + thickness_position, linestyle.thickness_ratio, + m.blend, m.influence, m.mapping, m.invert, m.curve, + m.material_attr, m.value_min, m.value_max)) + elif m.type == "CALLIGRAPHY": + shaders_list.append(CalligraphicThicknessShader( + thickness_position, linestyle.thickness_ratio, + m.blend, m.influence, + m.orientation, m.min_thickness, m.max_thickness)) + if linestyle.caps == "ROUND": + shaders_list.append(RoundCapShader()) + elif linestyle.caps == "SQUARE": + shaders_list.append(SquareCapShader()) + if linestyle.use_dashed_line: + pattern = [] + if linestyle.dash1 > 0 and linestyle.gap1 > 0: + pattern.append(linestyle.dash1) + pattern.append(linestyle.gap1) + if linestyle.dash2 > 0 and linestyle.gap2 > 0: + pattern.append(linestyle.dash2) + pattern.append(linestyle.gap2) + if linestyle.dash3 > 0 and linestyle.gap3 > 0: + pattern.append(linestyle.dash3) + pattern.append(linestyle.gap3) + if len(pattern) > 0: + shaders_list.append(DashedLineShader(pattern)) + # create strokes using the shaders list + 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 index 00000000000..f05042f8332 --- /dev/null +++ b/release/scripts/freestyle/style_modules/shaders.py @@ -0,0 +1,1344 @@ +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 * + +## 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 = Vector([self._x, self._y]) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + p = Vector([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 = Vector([self._x, self._y, self._z]) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + p = Vector([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 + if 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. * 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 * 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 + + r = max(0,r) + g = max(0,g) + b = max(0,b) + + 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)) + stroke.UpdateLength() + +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 = Vector([v0.getProjectedX(), v0.getProjectedY()]) + pn = Vector([vn.getProjectedX(), vn.getProjectedY()]) + p1 = Vector([v1.getProjectedX(), v1.getProjectedY()]) + pn_1 = Vector([vn_1.getProjectedX(), vn_1.getProjectedY()]) + d1 = p0-p1 + d1.normalize() + dn = pn-pn_1 + dn.normalize() + newFirst = p0+d1*float(self._l) + newLast = pn+dn*float(self._l) + v0.setPoint(newFirst) + vn.setPoint(newLast) + stroke.UpdateLength() + +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 = Vector([v0.getProjectedX(), v0.getProjectedY()]) + pn = Vector([vn.getProjectedX(), vn.getProjectedY()]) + p1 = Vector([v1.getProjectedX(), v1.getProjectedY()]) + pn_1 = Vector([vn_1.getProjectedX(), vn_1.getProjectedY()]) + d1 = p0-p1 + d1.normalize() + dn = pn-pn_1 + dn.normalize() + newFirst = p0+d1*float(stretch) + newLast = pn+dn*float(stretch) + v0.setPoint(newFirst) + vn.setPoint(newLast) + stroke.UpdateLength() + + +## 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 + stroke.UpdateLength() + + +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.normalize() + 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.normalize() + newLast = pn+dn*float(self._l) + vn.setPoint(newLast) + stroke.UpdateLength() + +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() + stroke.UpdateLength() + +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() + stroke.UpdateLength() + +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()) + stroke.UpdateLength() + +class pyExtremitiesOrientationShader(StrokeShader): + def __init__(self, x1,y1,x2=0,y2=0): + StrokeShader.__init__(self) + self._v1 = Vector([x1,y1]) + self._v2 = Vector([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) + +def getFEdge(it1, it2): + return it1.getFEdge(it2) + +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.viewedge().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.viewedge().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() + stroke.UpdateLength() + +class pyPerlinNoise1DShader(StrokeShader): + def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1): + StrokeShader.__init__(self) + self.__noise = Noise(seed) + self.__freq = freq + self.__amp = amp + self.__oct = oct + def getName(self): + return "pyPerlinNoise1DShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + v = it.getObject() + i = v.getProjectedX() + v.getProjectedY() + nres = self.__noise.turbulence1(i, self.__freq, self.__amp, self.__oct) + v.setPoint(v.getProjectedX() + nres, v.getProjectedY() + nres) + it.increment() + stroke.UpdateLength() + +class pyPerlinNoise2DShader(StrokeShader): + def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1): + StrokeShader.__init__(self) + self.__noise = Noise(seed) + 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 = Vector([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() + stroke.UpdateLength() + +class pyBluePrintCirclesShader(StrokeShader): + def __init__(self, turns = 1, random_radius = 3, random_center = 5): + StrokeShader.__init__(self) + self.__turns = turns + self.__random_center = random_center + self.__random_radius = random_radius + def getName(self): + return "pyBluePrintCirclesShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + if it.isEnd(): + return + p_min = it.getObject().getPoint() + p_max = it.getObject().getPoint() + while it.isEnd() == 0: + p = it.getObject().getPoint() + if (p.x < p_min.x): + p_min.x = p.x + if (p.x > p_max.x): + p_max.x = p.x + if (p.y < p_min.y): + p_min.y = p.y + if (p.y > p_max.y): + p_max.y = 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 = Vector([0, 0]) +####################################################### + R = self.__random_radius + C = self.__random_center + i = 0 + it = stroke.strokeVerticesBegin() + for j in range(self.__turns): + prev_radius = radius + prev_center = center + radius = radius + randint(-R, R) + center = center + Vector([randint(-C, C), randint(-C, C)]) + while i < sv_nb and it.isEnd() == 0: + t = float(i) / float(sv_nb - 1) + r = prev_radius + (radius - prev_radius) * t + c = prev_center + (center - prev_center) * t + p_new.x = c.x + r * cos(2 * pi * t) + p_new.y = c.y + r * sin(2 * pi * t) + it.getObject().setPoint(p_new) + i = i + 1 + it.increment() + i = 1 + verticesToRemove = [] + while it.isEnd() == 0: + verticesToRemove.append(it.getObject()) + it.increment() + for sv in verticesToRemove: + stroke.RemoveVertex(sv) + stroke.UpdateLength() + +class pyBluePrintEllipsesShader(StrokeShader): + def __init__(self, turns = 1, random_radius = 3, random_center = 5): + StrokeShader.__init__(self) + self.__turns = turns + self.__random_center = random_center + self.__random_radius = random_radius + def getName(self): + return "pyBluePrintEllipsesShader" + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + if it.isEnd(): + return + p_min = it.getObject().getPoint() + p_max = it.getObject().getPoint() + while it.isEnd() == 0: + p = it.getObject().getPoint() + if (p.x < p_min.x): + p_min.x = p.x + if (p.x > p_max.x): + p_max.x = p.x + if (p.y < p_min.y): + p_min.y = p.y + if (p.y > p_max.y): + p_max.y = p.y + it.increment() + stroke.Resample(32 * self.__turns) + sv_nb = stroke.strokeVerticesSize() + sv_nb = sv_nb // self.__turns + center = (p_min + p_max) / 2 + radius = center - p_min + p_new = Vector([0, 0]) +####################################################### + R = self.__random_radius + C = self.__random_center + i = 0 + it = stroke.strokeVerticesBegin() + for j in range(self.__turns): + prev_radius = radius + prev_center = center + radius = radius + Vector([randint(-R, R), randint(-R, R)]) + center = center + Vector([randint(-C, C), randint(-C, C)]) + while i < sv_nb and it.isEnd() == 0: + t = float(i) / float(sv_nb - 1) + r = prev_radius + (radius - prev_radius) * t + c = prev_center + (center - prev_center) * t + p_new.x = c.x + r.x * cos(2 * pi * t) + p_new.y = c.y + r.y * sin(2 * pi * t) + it.getObject().setPoint(p_new) + i = i + 1 + it.increment() + i = 1 + verticesToRemove = [] + while it.isEnd() == 0: + verticesToRemove.append(it.getObject()) + it.increment() + for sv in verticesToRemove: + stroke.RemoveVertex(sv) + stroke.UpdateLength() + + +class pyBluePrintSquaresShader(StrokeShader): + def __init__(self, turns = 1, bb_len = 10, bb_rand = 0): + StrokeShader.__init__(self) + self.__turns = turns + self.__bb_len = bb_len + self.__bb_rand = bb_rand + + def getName(self): + return "pyBluePrintSquaresShader" + + def shade(self, stroke): + it = stroke.strokeVerticesBegin() + if it.isEnd(): + return + p_min = it.getObject().getPoint() + p_max = it.getObject().getPoint() + while it.isEnd() == 0: + p = it.getObject().getPoint() + if (p.x < p_min.x): + p_min.x = p.x + if (p.x > p_max.x): + p_max.x = p.x + if (p.y < p_min.y): + p_min.y = p.y + if (p.y > p_max.y): + p_max.y = 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 + p_first = Vector([p_min.x - self.__bb_len, p_min.y]) + p_first_end = Vector([p_max.x + self.__bb_len, p_min.y]) + p_second = Vector([p_max.x, p_min.y - self.__bb_len]) + p_second_end = Vector([p_max.x, p_max.y + self.__bb_len]) + p_third = Vector([p_max.x + self.__bb_len, p_max.y]) + p_third_end = Vector([p_min.x - self.__bb_len, p_max.y]) + p_fourth = Vector([p_min.x, p_max.y + self.__bb_len]) + p_fourth_end = Vector([p_min.x, p_min.y - self.__bb_len]) +####################################################### + R = self.__bb_rand + r = self.__bb_rand // 2 + it = stroke.strokeVerticesBegin() + visible = 1 + for j in range(self.__turns): + p_first = p_first + Vector([randint(-R, R), randint(-r, r)]) + p_first_end = p_first_end + Vector([randint(-R, R), randint(-r, r)]) + p_second = p_second + Vector([randint(-r, r), randint(-R, R)]) + p_second_end = p_second_end + Vector([randint(-r, r), randint(-R, R)]) + p_third = p_third + Vector([randint(-R, R), randint(-r, r)]) + p_third_end = p_third_end + Vector([randint(-R, R), randint(-r, r)]) + p_fourth = p_fourth + Vector([randint(-r, r), randint(-R, R)]) + p_fourth_end = p_fourth_end + Vector([randint(-r, r), randint(-R, R)]) + vec_first = p_first_end - p_first + vec_second = p_second_end - p_second + vec_third = p_third_end - p_third + vec_fourth = p_fourth_end - p_fourth + i = 0 + while i < sv_nb and it.isEnd() == 0: + 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 + if it.getObject() == None: + i = i + 1 + it.increment() + if visible == 0: + visible = 1 + continue + it.getObject().setPoint(p_new) + it.getObject().attribute().setVisible(visible) + if visible == 0: + visible = 1 + i = i + 1 + it.increment() + verticesToRemove = [] + while it.isEnd() == 0: + verticesToRemove.append(it.getObject()) + it.increment() + for sv in verticesToRemove: + stroke.RemoveVertex(sv) + stroke.UpdateLength() + + +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 = Vector([0, 0]) + it = stroke.strokeVerticesBegin() + while it.isEnd() == 0: + p = it.getObject().getPoint() + p_mean = p_mean + p + 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 = Vector([cos(theta + pi / 2), sin(theta + pi / 2)]) * sqrt(lambda1) * self.__mult + e2 = Vector([cos(theta + pi), sin(theta + pi)]) * sqrt(lambda2) * self.__mult + else: + e1 = Vector([cos(theta), sin(theta)]) * sqrt(lambda1) * self.__mult + e2 = Vector([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) + it.getObject().attribute().setVisible(visible) + if visible == 0: + visible = 1 + i = i + 1 + it.increment() + verticesToRemove = [] + while it.isEnd() == 0: + verticesToRemove.append(it.getObject()) + it.increment() + for sv in verticesToRemove: + stroke.RemoveVertex(sv) + stroke.UpdateLength() + +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 100644 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 100644 index 00000000000..9ec0cffcfec --- /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.normalize() + 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.normalize() + 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 index 00000000000..50a2f6423fd --- /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) + |