def creator(env):
sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
- incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
+ incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', '#/source/blender/freestyle', env['BF_OPENGL_INC']]
defs = []
"mathutils",
"mathutils.geometry",
"mathutils.noise",
+ "Freestyle",
]
# ------
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
MethodDescriptorType = type(dict.get)
GetSetDescriptorType = type(int.real)
+StaticMethodType = type(staticmethod(lambda: None))
from types import MemberDescriptorType
_BPY_STRUCT_FAKE = "bpy_struct"
if type(descr) == GetSetDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
+ for key, descr in descr_items:
+ if type(descr) == StaticMethodType:
+ descr = getattr(value, key)
+ write_indented_lines(" ", fw, descr.__doc__ or "Undocumented", False)
+ fw("\n")
+
fw("\n\n")
file.close()
# mathutils
"mathutils", "mathutils.geometry", "mathutils.noise",
# misc
- "bgl", "blf", "gpu", "aud", "bpy_extras",
+ "Freestyle", "bgl", "blf", "gpu", "aud", "bpy_extras",
# bmesh, submodules are in own page
"bmesh",
)
"mathutils" : "Math Types & Utilities",
"mathutils.geometry": "Geometry Utilities",
"mathutils.noise" : "Noise Utilities",
+ "Freestyle" : "Freestyle Data Types & Operators",
}
for mod_name, mod_descr in importable_modules.items():
if mod_name not in EXCLUDE_MODULES:
+++ /dev/null
-#!/bin/sh
-BF_DIST_BIN=`dirname "$0"`
-BF_PROGRAM="blender" # BF_PROGRAM=`basename "$0"`-bin
-exitcode=0
-
-LD_LIBRARY_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH}
-
-if [ -n "$LD_LIBRARYN32_PATH" ]; then
- LD_LIBRARYN32_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN32_PATH}
-fi
-if [ -n "$LD_LIBRARYN64_PATH" ]; then
- LD_LIBRARYN64_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN64_PATH}
-fi
-if [ -n "$LD_LIBRARY_PATH_64" ]; then
- LD_LIBRARY_PATH_64=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH_64}
-fi
-
-# Workaround for half-transparent windows when compiz is enabled
-XLIB_SKIP_ARGB_VISUALS=1
-
-export LD_LIBRARY_PATH LD_LIBRARYN32_PATH LD_LIBRARYN64_PATH LD_LIBRARY_PATH_64 LD_PRELOAD XLIB_SKIP_ARGB_VISUALS
-
-"$BF_DIST_BIN/$BF_PROGRAM" ${1+"$@"}
-exitcode=$?
-exit $exitcode
--- /dev/null
+#
+# 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
+
--- /dev/null
+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
+
+
--- /dev/null
+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
--- /dev/null
+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)
--- /dev/null
+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
+
+
--- /dev/null
+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
--- /dev/null
+#
+# 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)
+
+
+
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+1suggestive.py
+1ridges.py
+1nor_suggestive_or_ridges.py
--- /dev/null
+from Freestyle import *
+from mathutils import Vector
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
+
+
--- /dev/null
+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
--- /dev/null
+#
+# 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)
+
+
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+# ##### 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())