diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-12-30 18:26:31 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2014-01-28 18:34:00 +0400 |
commit | e84732858590eccf3eeea3be3178b95d652f4131 (patch) | |
tree | ef5ace8081c49d533765aa6ad629e17f54b0bbd0 /release | |
parent | 8ab3cf1db009f10279eb87af0d0c6f3b1cf10ad8 (diff) |
Patch set by Folkert Vries (flokkievids) with respect to T37565-patch-v1.zip (F32402).
Applied with minor modifications.
Diffstat (limited to 'release')
7 files changed, 403 insertions, 272 deletions
diff --git a/release/scripts/freestyle/modules/freestyle/__init__.py b/release/scripts/freestyle/modules/freestyle/__init__.py index 1fe5a2f520b..dc98a2660ad 100644 --- a/release/scripts/freestyle/modules/freestyle/__init__.py +++ b/release/scripts/freestyle/modules/freestyle/__init__.py @@ -16,6 +16,10 @@ # # ##### END GPL LICENSE BLOCK ##### +""" +Top-level module containing all Freestyle stylization constructs +""" + # module members from _freestyle import Operators from . import chainingiterators, functions, predicates, shaders, types, utils diff --git a/release/scripts/freestyle/modules/freestyle/chainingiterators.py b/release/scripts/freestyle/modules/freestyle/chainingiterators.py index 07ce14495cc..aad82d16bd2 100644 --- a/release/scripts/freestyle/modules/freestyle/chainingiterators.py +++ b/release/scripts/freestyle/modules/freestyle/chainingiterators.py @@ -16,13 +16,20 @@ # # ##### END GPL LICENSE BLOCK ##### +""" +Chaining iterators used for the chaining operation to construct long +strokes by concatenating feature edges according to selected chaining +rules. Also intended to be a collection of examples for defining +chaining iterators in Python +""" + # module members from _freestyle import ( ChainPredicateIterator, ChainSilhouetteIterator, ) -# modules for implementing chaining iterators +# constructs for predicate definition in Python from freestyle.types import ( AdjacencyIterator, ChainingIterator, @@ -33,14 +40,18 @@ from freestyle.predicates import ( ExternalContourUP1D, ) from freestyle.utils import ContextFunctions as CF + import bpy -## 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): + """Natural chaining iterator + + Follows the edges of the same nature following the topology of + objects, with decreasing priority for silhouettes, then borders, + then suggestive contours, then all other edge types. A ViewEdge + is only chained once. + """ def __init__(self, stayInSelection=True): ChainingIterator.__init__(self, stayInSelection, True, None, True) def init(self): @@ -83,14 +94,20 @@ class pyChainSilhouetteIterator(ChainingIterator): 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): + """Natural chaining iterator + + Follows the edges of the same nature following the topology of + objects, with decreasing priority for silhouettes, then borders, + then suggestive contours, then all other edge types. + + :arg stayInSelection: True if it is allowed to go out of the selection + :type stayInSelection: bool + :arg stayInUnvisited: May the same ViewEdge be chained twice + :type stayInUnvisited: bool + """ + def __init__(self, stayInSelection=True, stayInUnvisited=True): ChainingIterator.__init__(self, stayInSelection, stayInUnvisited, None, True) def init(self): @@ -137,7 +154,10 @@ class pyChainSilhouetteGenericIterator(ChainingIterator): break return winner + class pyExternalContourChainingIterator(ChainingIterator): + """Chains by external contour""" + def __init__(self): ChainingIterator.__init__(self, False, True, None, True) self._isExternalContour = ExternalContourUP1D() @@ -153,10 +173,11 @@ class pyExternalContourChainingIterator(ChainingIterator): while not it.is_end: ave = it.object if self._isExternalContour(ave): - return 1 + return True it.increment() - print("pyExternlContourChainingIterator : didn't find next edge") - return 0 + if bpy.app.debug_freestyle: + print("pyExternalContourChainingIterator : didn't find next edge") + return False def traverse(self, iter): winner = None it = AdjacencyIterator(iter) @@ -181,9 +202,18 @@ class pyExternalContourChainingIterator(ChainingIterator): it.increment() return winner -## the natural chaining iterator -## with a sketchy multiple touch + class pySketchyChainSilhouetteIterator(ChainingIterator): + """Natural chaining iterator with a sketchy multiple touch + + Chains the same ViewEdge multiple times to achieve a sketchy effect. + + :arg rounds: Number of times every Viewedge is chained. + :type rounds: int + :arg stayInSelection: if False, edges outside of the selection can be chained. + :type stayInSelection: bool + """ + def __init__(self, nRounds=3,stayInSelection=True): ChainingIterator.__init__(self, stayInSelection, False, None, True) self._timeStamp = CF.get_time_stamp()+nRounds @@ -237,10 +267,12 @@ class pySketchyChainSilhouetteIterator(ChainingIterator): 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): + """Chaining iterator designed for sketchy style + + It chaines the same ViewEdge several times in order to produce + multiple strokes per ViewEdge. + """ def __init__(self, nRounds=3, stayInSelection=True): ChainingIterator.__init__(self, stayInSelection, False, None, True) self._timeStamp = CF.get_time_stamp()+nRounds @@ -272,23 +304,27 @@ class pySketchyChainingIterator(ChainingIterator): 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): + """Chaining iterator that fills small occlusions + + :arg percent: The maximul length of the occluded part, expressed + in a percentage of the total chain length. + :type percent: float + """ + def __init__(self, percent): ChainingIterator.__init__(self, False, True, None, True) self._length = 0 self._percent = float(percent) def init(self): - # each time we're evaluating a chain length - # we try to do it once. Thus we reinit - # the chain length here: + # A chain's length should preferably be evaluated only once. + # Therefore, the chain length is reset here. self._length = 0 def traverse(self, iter): winner = None + winnerOrientation = False + winnerOrientation = 0 #print(self.current_edge.id.first, self.current_edge.id.second) it = AdjacencyIterator(iter) tvertex = self.next_vertex @@ -298,10 +334,7 @@ class pyFillOcclusionsRelativeChainingIterator(ChainingIterator): ve = it.object if ve.id == mateVE.id: winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming break it.increment() else: @@ -315,10 +348,7 @@ class pyFillOcclusionsRelativeChainingIterator(ChainingIterator): if (ve.nature & nat) != 0: count = count+1 winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming it.increment() if count != 1: winner = None @@ -359,6 +389,7 @@ class pyFillOcclusionsRelativeChainingIterator(ChainingIterator): # let's do the comparison: # nw let's compute the length of this connex non selected part: connexl = 0 + _cit = pyChainSilhouetteGenericIterator(False, False) _cit.begin = winner _cit.current_edge = winner @@ -373,11 +404,13 @@ class pyFillOcclusionsRelativeChainingIterator(ChainingIterator): winner = None return winner -## Chaining iterator that fills small occlusions -## size -## The max length of the occluded part -## expressed in pixels + class pyFillOcclusionsAbsoluteChainingIterator(ChainingIterator): + """Chaining iterator that fills small occlusions + + :arg size: The maximum length of the occluded part in pixels. + :type size: int + """ def __init__(self, length): ChainingIterator.__init__(self, False, True, None, True) self._length = float(length) @@ -395,10 +428,7 @@ class pyFillOcclusionsAbsoluteChainingIterator(ChainingIterator): ve = it.object if ve.id == mateVE.id: winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming break it.increment() else: @@ -412,10 +442,7 @@ class pyFillOcclusionsAbsoluteChainingIterator(ChainingIterator): if (ve.nature & nat) != 0: count = count+1 winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming it.increment() if count != 1: winner = None @@ -441,11 +468,14 @@ class pyFillOcclusionsAbsoluteChainingIterator(ChainingIterator): 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): + """Chaining iterator that fills small occlusions regardless of the + selection + + :arg percent: The maximul length of the occluded part as a + percentage of the total chain length. + :type percent: float + """ def __init__(self, percent, l): ChainingIterator.__init__(self, False, True, None, True) self._length = 0 @@ -468,10 +498,7 @@ class pyFillOcclusionsAbsoluteAndRelativeChainingIterator(ChainingIterator): ve = it.object if ve.id == mateVE.id: winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming break it.increment() else: @@ -485,10 +512,7 @@ class pyFillOcclusionsAbsoluteAndRelativeChainingIterator(ChainingIterator): if (ve.nature & nat) != 0: count = count+1 winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming it.increment() if count != 1: winner = None @@ -543,25 +567,28 @@ class pyFillOcclusionsAbsoluteAndRelativeChainingIterator(ChainingIterator): 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): + """Chaining iterator that fills small occlusions regardless of the + selection + + :arg percent: The maximul length of the occluded part as a + percentage of the total chain length. + :type percent: float + """ def __init__(self, percent, l): ChainingIterator.__init__(self, False, True, None, True) self._length = 0 self._absLength = l self._percent = float(percent) def init(self): - # each time we're evaluating a chain length - # we try to do it once. Thus we reinit - # the chain length here: + # A chain's length should preverably be evaluated only once. + # Therefore, the chain length is reset here. self._length = 0 def traverse(self, iter): winner = None winnerOrientation = False + #print(self.current_edge.id.first, self.current_edge.id.second) it = AdjacencyIterator(iter) tvertex = self.next_vertex @@ -571,10 +598,7 @@ class pyFillQi0AbsoluteAndRelativeChainingIterator(ChainingIterator): ve = it.object if ve.id == mateVE.id: winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming break it.increment() else: @@ -588,10 +612,7 @@ class pyFillQi0AbsoluteAndRelativeChainingIterator(ChainingIterator): if (ve.nature & nat) != 0: count = count+1 winner = ve - if not it.is_incoming: - winnerOrientation = True - else: - winnerOrientation = False + winnerOrientation = not it.is_incoming it.increment() if count != 1: winner = None @@ -647,12 +668,18 @@ class pyFillQi0AbsoluteAndRelativeChainingIterator(ChainingIterator): 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): + """Natural chaining iterator + + Follows the edges of the same nature following the topology of + objects, with decreasing priority for silhouettes, then borders, + then suggestive contours, then all other edge types. It won't + chain the same ViewEdge twice. + + :arg stayInSelection: True if it is allowed to go out of the selection + :type stayInSelection: bool + """ + def __init__(self, stayInSelection=True): ChainingIterator.__init__(self, stayInSelection, True, None, True) def init(self): diff --git a/release/scripts/freestyle/modules/freestyle/functions.py b/release/scripts/freestyle/modules/freestyle/functions.py index 3c67c843a77..686dce6615f 100644 --- a/release/scripts/freestyle/modules/freestyle/functions.py +++ b/release/scripts/freestyle/modules/freestyle/functions.py @@ -16,6 +16,12 @@ # # ##### END GPL LICENSE BLOCK ##### +""" +Functions operating on vertices (0D elements) and polylines (1D +elements). Also intended to be a collection of examples for predicate +definition in Python +""" + # module members from _freestyle import ( ChainingTimeStampF1D, @@ -71,7 +77,7 @@ from _freestyle import ( ZDiscontinuityF1D, ) -# modules for implementing functions +# constructs for function definition in Python from freestyle.types import ( CurvePoint, IntegrationType, @@ -82,15 +88,17 @@ from freestyle.types import ( ) from freestyle.utils import ContextFunctions as CF from freestyle.utils import integrate -import math -import mathutils + +from mathutils import Vector ## Functions for 0D elements (vertices) ####################################### class CurveMaterialF0D(UnaryFunction0DMaterial): - # A replacement of the built-in MaterialF0D for stroke creation. - # MaterialF0D does not work with Curves and Strokes. + """ + A replacement of the built-in MaterialF0D for stroke creation. + MaterialF0D does not work with Curves and Strokes. + """ def __call__(self, inter): cp = inter.object assert(isinstance(cp, CurvePoint)) @@ -110,8 +118,8 @@ class pyCurvilinearLengthF0D(UnaryFunction0DDouble): assert(isinstance(cp, CurvePoint)) return cp.t2d -## estimate anisotropy of density class pyDensityAnisotropyF0D(UnaryFunction0DDouble): + """Estimates the anisotropy of density""" def __init__(self,level): UnaryFunction0DDouble.__init__(self) self.IsoDensity = ReadCompleteViewMapPixelF0D(level) @@ -133,34 +141,36 @@ class pyDensityAnisotropyF0D(UnaryFunction0DDouble): 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): + """Returns the gradient vector for a pixel + + :arg level: the level at which to compute the gradient + :type level: int + """ + def __init__(self, level): UnaryFunction0DVec2f.__init__(self) - self._l = l - self._step = math.pow(2,self._l) + self._l = level + self._step = pow(2, self._l) def __call__(self, iter): p = iter.object.point_2d gx = CF.read_complete_view_map_pixel(self._l, int(p.x+self._step), int(p.y)) - \ CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y)) gy = CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y+self._step)) - \ CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y)) - return mathutils.Vector([gx, gy]) + return Vector((gx, gy)) class pyViewMapGradientNormF0D(UnaryFunction0DDouble): def __init__(self, l): UnaryFunction0DDouble.__init__(self) self._l = l - self._step = math.pow(2,self._l) + self._step = pow(2,self._l) def __call__(self, iter): p = iter.object.point_2d gx = CF.read_complete_view_map_pixel(self._l, int(p.x+self._step), int(p.y)) - \ CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y)) gy = CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y+self._step)) - \ CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y)) - grad = mathutils.Vector([gx, gy]) + grad = Vector((gx, gy)) return grad.length ## Functions for 1D elements (curves) diff --git a/release/scripts/freestyle/modules/freestyle/predicates.py b/release/scripts/freestyle/modules/freestyle/predicates.py index 236ff6c46b9..ab702f1c290 100644 --- a/release/scripts/freestyle/modules/freestyle/predicates.py +++ b/release/scripts/freestyle/modules/freestyle/predicates.py @@ -16,6 +16,12 @@ # # ##### END GPL LICENSE BLOCK ##### +""" +Predicates operating on vertices (0D elements) and polylines (1D +elements). Also intended to be a collection of examples for predicate +definition in Python +""" + # module members from _freestyle import ( ContourUP1D, @@ -37,7 +43,7 @@ from _freestyle import ( WithinImageBoundaryUP1D, ) -# modules for implementing predicates +# constructs for predicate definition in Python from freestyle.types import ( BinaryPredicate1D, IntegrationType, @@ -66,6 +72,7 @@ from freestyle.functions import ( ) import random + ## Unary predicates for 0D elements (vertices) ############################################## @@ -105,23 +112,20 @@ class pyBackTVertexUP0D(UnaryPredicate0D): self._getQI = QuantitativeInvisibilityF0D() def __call__(self, iter): if (iter.object.nature & Nature.T_VERTEX) == 0: - return 0 + return False if iter.is_end: - return 0 + return False if self._getQI(iter) != 0: - return 1 - return 0 + return True + return False class pyParameterUP0DGoodOne(UnaryPredicate0D): def __init__(self,pmin,pmax): UnaryPredicate0D.__init__(self) self._m = pmin self._M = pmax - #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D() def __call__(self, inter): - #s = self.getCurvilinearAbscissa(inter) u = inter.u - #print(u) return ((u>=self._m) and (u<=self._M)) class pyParameterUP0D(UnaryPredicate0D): @@ -129,14 +133,11 @@ class pyParameterUP0D(UnaryPredicate0D): UnaryPredicate0D.__init__(self) self._m = pmin self._M = pmax - #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D() 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 @@ -174,8 +175,8 @@ class pyNFirstUP1D(UnaryPredicate1D): def __call__(self, inter): self.__count = self.__count + 1 if self.__count <= self.__n: - return 1 - return 0 + return True + return False class pyHigherLengthUP1D(UnaryPredicate1D): def __init__(self,l): @@ -191,8 +192,8 @@ class pyNatureUP1D(UnaryPredicate1D): self._getNature = CurveNatureF1D() def __call__(self, inter): if(self._getNature(inter) & self._nature): - return 1 - return 0 + return True + return False class pyHigherNumberOfTurnsUP1D(UnaryPredicate1D): def __init__(self,n,a): @@ -207,9 +208,9 @@ class pyHigherNumberOfTurnsUP1D(UnaryPredicate1D): if func(it) > self._a: count = count+1 if count > self._n: - return 1 + return True it.increment() - return 0 + return False class pyDensityUP1D(UnaryPredicate1D): def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0): @@ -219,9 +220,7 @@ class pyDensityUP1D(UnaryPredicate1D): self._integration = integration self._func = DensityF1D(self._wsize, self._integration, sampling) def __call__(self, inter): - if self._func(inter) < self._threshold: - return 1 - return 0 + return (self._func(inter) < self._threshold) class pyLowSteerableViewMapDensityUP1D(UnaryPredicate1D): def __init__(self,threshold, level,integration = IntegrationType.MEAN): @@ -231,11 +230,7 @@ class pyLowSteerableViewMapDensityUP1D(UnaryPredicate1D): self._integration = integration def __call__(self, inter): func = GetSteerableViewMapDensityF1D(self._level, self._integration) - v = func(inter) - #print(v) - if v < self._threshold: - return 1 - return 0 + return (func(inter) < self._threshold) class pyLowDirectionalViewMapDensityUP1D(UnaryPredicate1D): def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN): @@ -246,11 +241,7 @@ class pyLowDirectionalViewMapDensityUP1D(UnaryPredicate1D): self._integration = integration 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 + return (func(inter) < self._threshold) class pyHighSteerableViewMapDensityUP1D(UnaryPredicate1D): def __init__(self,threshold, level,integration = IntegrationType.MEAN): @@ -260,10 +251,7 @@ class pyHighSteerableViewMapDensityUP1D(UnaryPredicate1D): self._integration = integration self._func = GetSteerableViewMapDensityF1D(self._level, self._integration) def __call__(self, inter): - v = self._func(inter) - if v > self._threshold: - return 1 - return 0 + return (self._func(inter) > self._threshold) class pyHighDirectionalViewMapDensityUP1D(UnaryPredicate1D): def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN, sampling=2.0): @@ -275,10 +263,7 @@ class pyHighDirectionalViewMapDensityUP1D(UnaryPredicate1D): self._sampling = sampling 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 + return (func(inter) > self._threshold) class pyHighViewMapDensityUP1D(UnaryPredicate1D): def __init__(self,threshold, level,integration = IntegrationType.MEAN, sampling=2.0): @@ -289,13 +274,7 @@ class pyHighViewMapDensityUP1D(UnaryPredicate1D): self._sampling = sampling self._func = GetCompleteViewMapDensityF1D(self._level, self._integration, self._sampling) # 2.0 is the smpling def __call__(self, inter): - #print("toto") - #print(func.name) - #print(inter.name) - v= self._func(inter) - if v > self._threshold: - return 1 - return 0 + return (self._func(inter) > self._threshold) class pyDensityFunctorUP1D(UnaryPredicate1D): def __init__(self,wsize,threshold, functor, funcmin=0.0, funcmax=1.0, integration = IntegrationType.MEAN): @@ -310,9 +289,8 @@ class pyDensityFunctorUP1D(UnaryPredicate1D): 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 + return (func(inter) < (self._threshold * k)) + class pyZSmallerUP1D(UnaryPredicate1D): def __init__(self,z, integration=IntegrationType.MEAN): @@ -321,9 +299,7 @@ class pyZSmallerUP1D(UnaryPredicate1D): self._integration = integration def __call__(self, inter): func = GetProjectedZF1D(self._integration) - if func(inter) < self._z: - return 1 - return 0 + return (func(inter) < self._z) class pyIsOccludedByUP1D(UnaryPredicate1D): def __init__(self,id): @@ -334,7 +310,7 @@ class pyIsOccludedByUP1D(UnaryPredicate1D): shapes = func(inter) for s in shapes: if(s.id == self._id): - return 0 + return False it = inter.vertices_begin() itlast = inter.vertices_end() itlast.decrement() @@ -347,7 +323,7 @@ class pyIsOccludedByUP1D(UnaryPredicate1D): while not eit.is_end: ve, incoming = eit.object if ve.id == self._id: - return 1 + return True #print("-------", ve.id.first, "-", ve.id.second) eit.increment() tvertex = vlast.viewvertex @@ -357,10 +333,10 @@ class pyIsOccludedByUP1D(UnaryPredicate1D): while not eit.is_end: ve, incoming = eit.object if ve.id == self._id: - return 1 + return True #print("-------", ve.id.first, "-", ve.id.second) eit.increment() - return 0 + return False class pyIsInOccludersListUP1D(UnaryPredicate1D): def __init__(self,id): @@ -371,8 +347,8 @@ class pyIsInOccludersListUP1D(UnaryPredicate1D): occluders = func(inter) for a in occluders: if a.id == self._id: - return 1 - return 0 + return True + return False class pyIsOccludedByItselfUP1D(UnaryPredicate1D): def __init__(self): @@ -385,8 +361,8 @@ class pyIsOccludedByItselfUP1D(UnaryPredicate1D): for vs1 in lst1: for vs2 in lst2: if vs1.id == vs2.id: - return 1 - return 0 + return True + return False class pyIsOccludedByIdListUP1D(UnaryPredicate1D): def __init__(self, idlist): @@ -398,8 +374,8 @@ class pyIsOccludedByIdListUP1D(UnaryPredicate1D): for vs1 in lst1: for _id in self._idlist: if vs1.id == _id: - return 1 - return 0 + return True + return False class pyShapeIdListUP1D(UnaryPredicate1D): def __init__(self,idlist): @@ -409,10 +385,10 @@ class pyShapeIdListUP1D(UnaryPredicate1D): for _id in idlist : self._funcs.append(ShapeUP1D(_id.first, _id.second)) def __call__(self, inter): - for func in self._funcs : + for func in self._funcs: if func(inter) == 1: - return 1 - return 0 + return True + return False ## deprecated class pyShapeIdUP1D(UnaryPredicate1D): @@ -424,8 +400,8 @@ class pyShapeIdUP1D(UnaryPredicate1D): shapes = func(inter) for a in shapes: if a.id == self._id: - return 1 - return 0 + return True + return False class pyHighDensityAnisotropyUP1D(UnaryPredicate1D): def __init__(self,threshold, level, sampling=2.0): @@ -460,13 +436,9 @@ class pyDensityVariableSigmaUP1D(UnaryPredicate1D): 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 + sigma = max(sigma, self._sigmaMin) self._func = DensityF1D(sigma, self._integration, self._sampling) - d = self._func(inter) - if d < t: - return 1 - return 0 + return (self._func(inter) < t) class pyClosedCurveUP1D(UnaryPredicate1D): def __call__(self, inter): @@ -478,8 +450,8 @@ class pyClosedCurveUP1D(UnaryPredicate1D): #print(v.id.first, v.id.second) #print(vlast.id.first, vlast.id.second) if v.id == vlast.id: - return 1 - return 0 + return True + return False ## Binary predicates for 1D elements (curves) ############################################# @@ -504,7 +476,7 @@ class pySilhouetteFirstBP1D(BinaryPredicate1D): def __call__(self, inter1, inter2): bpred = SameShapeIdBP1D() if (bpred(inter1, inter2) != 1): - return 0 + return False if (inter1.nature & Nature.SILHOUETTE): return (inter2.nature & Nature.SILHOUETTE) != 0 return (inter1.nature == inter2.nature) diff --git a/release/scripts/freestyle/modules/freestyle/shaders.py b/release/scripts/freestyle/modules/freestyle/shaders.py index edac96278a9..fb621b2a844 100644 --- a/release/scripts/freestyle/modules/freestyle/shaders.py +++ b/release/scripts/freestyle/modules/freestyle/shaders.py @@ -21,6 +21,11 @@ # Date : 11/08/2005 # Purpose : Stroke shaders to be used for creation of stylized strokes +""" +Stroke shaders used for creation of stylized strokes. Also intended +to be a collection of examples for shader definition in Python +""" + # module members from _freestyle import ( BackboneStretcherShader, @@ -47,7 +52,7 @@ from _freestyle import ( streamShader, ) -# modules for implementing shaders +# constructs for shader definition in Python from freestyle.types import ( Interface0DIterator, Nature, @@ -69,14 +74,20 @@ from freestyle.predicates import ( pyVertexNatureUP0D, ) from freestyle.utils import ContextFunctions as CF -import math -import mathutils -import random + +from math import atan, cos, pi, pow, sin, sinh, sqrt +from mathutils import Vector +from random import randint + ## thickness modifiers ###################### class pyDepthDiscontinuityThicknessShader(StrokeShader): + """ + Assigns a thickness to the stroke based on the stroke's distance + to the camera (Z-value) + """ def __init__(self, min, max): StrokeShader.__init__(self) self.__min = float(min) @@ -95,6 +106,9 @@ class pyDepthDiscontinuityThicknessShader(StrokeShader): it.increment() class pyConstantThicknessShader(StrokeShader): + """ + Assigns a constant thickness along the stroke + """ def __init__(self, thickness): StrokeShader.__init__(self) self._thickness = thickness @@ -106,6 +120,9 @@ class pyConstantThicknessShader(StrokeShader): it.increment() class pyFXSVaryingThicknessWithDensityShader(StrokeShader): + """ + Assings thickness to a stroke based on the density of the diffuse map + """ def __init__(self, wsize, threshold_min, threshold_max, thicknessMin, thicknessMax): StrokeShader.__init__(self) self.wsize= wsize @@ -131,6 +148,9 @@ class pyFXSVaryingThicknessWithDensityShader(StrokeShader): it.increment() class pyIncreasingThicknessShader(StrokeShader): + """ + Increasingly thickens the stroke + """ def __init__(self, thicknessMin, thicknessMax): StrokeShader.__init__(self) self._thicknessMin = thicknessMin @@ -150,6 +170,10 @@ class pyIncreasingThicknessShader(StrokeShader): it.increment() class pyConstrainedIncreasingThicknessShader(StrokeShader): + """ + Increasingly thickens the stroke, constrained by a ratio of the + stroke's length + """ def __init__(self, thicknessMin, thicknessMax, ratio): StrokeShader.__init__(self) self._thicknessMin = thicknessMin @@ -180,6 +204,9 @@ class pyConstrainedIncreasingThicknessShader(StrokeShader): it.increment() class pyDecreasingThicknessShader(StrokeShader): + """ + Inverse of pyIncreasingThicknessShader, decreasingly thickens the stroke + """ def __init__(self, thicknessMin, thicknessMax): StrokeShader.__init__(self) self._thicknessMin = thicknessMin @@ -203,6 +230,9 @@ class pyDecreasingThicknessShader(StrokeShader): it.increment() class pyNonLinearVaryingThicknessShader(StrokeShader): + """ + Assigns thickness to a stroke based on an exponential function + """ def __init__(self, thicknessExtremity, thicknessMiddle, exponent): StrokeShader.__init__(self) self._thicknessMin = thicknessMiddle @@ -223,10 +253,12 @@ class pyNonLinearVaryingThicknessShader(StrokeShader): i = i+1 it.increment() def smoothC(self, a, exp): - return math.pow(float(a), exp) * math.pow(2.0, exp) + return pow(float(a), exp) * pow(2.0, exp) -## Spherical linear interpolation (cos) class pySLERPThicknessShader(StrokeShader): + """ + Assigns thickness to a stroke based on spherical linear interpolation + """ def __init__(self, thicknessMin, thicknessMax, omega=1.2): StrokeShader.__init__(self) self._thicknessMin = thicknessMin @@ -244,14 +276,17 @@ class pySLERPThicknessShader(StrokeShader): while not it.is_end: c = float(i)/float(n) if i < float(n)/2.0: - t = math.sin((1-c)*self._omega)/math.sinh(self._omega)*self._thicknessMin + math.sin(c*self._omega)/math.sinh(self._omega) * maxT + t = sin((1-c)*self._omega)/sinh(self._omega)*self._thicknessMin + sin(c*self._omega)/sinh(self._omega) * maxT else: - t = math.sin((1-c)*self._omega)/math.sinh(self._omega)*maxT + math.sin(c*self._omega)/math.sinh(self._omega) * self._thicknessMin + t = sin((1-c)*self._omega)/sinh(self._omega)*maxT + sin(c*self._omega)/sinh(self._omega) * self._thicknessMin it.object.attribute.thickness = (t/2.0, t/2.0) i = i+1 it.increment() class pyTVertexThickenerShader(StrokeShader): ## FIXME + """ + Thickens TVertices (visual intersections between two edges) + """ def __init__(self, a=1.5, n=3): StrokeShader.__init__(self) self._a = a @@ -299,6 +334,11 @@ class pyTVertexThickenerShader(StrokeShader): ## FIXME it.increment() class pyImportance2DThicknessShader(StrokeShader): + """ + Assigns thickness based on distance to a given point in 2D space. + the thickness is inverted, so the vertices closest to the + specified point have the lowest thickness + """ def __init__(self, x, y, w, kmin, kmax): StrokeShader.__init__(self) self._x = x @@ -307,12 +347,11 @@ class pyImportance2DThicknessShader(StrokeShader): self._kmin = float(kmin) self._kmax = float(kmax) def shade(self, stroke): - origin = mathutils.Vector([self._x, self._y]) + origin = Vector((self._x, self._y)) it = stroke.stroke_vertices_begin() while not it.is_end: v = it.object - p = mathutils.Vector([v.projected_x, v.projected_y]) - d = (p-origin).length + d = (v.point_2d - self._origin).length if d > self._w: k = self._kmin else: @@ -323,6 +362,9 @@ class pyImportance2DThicknessShader(StrokeShader): it.increment() class pyImportance3DThicknessShader(StrokeShader): + """ + Assigns thickness based on distance to a given point in 3D space + """ def __init__(self, x, y, z, w, kmin, kmax): StrokeShader.__init__(self) self._x = x @@ -332,7 +374,7 @@ class pyImportance3DThicknessShader(StrokeShader): self._kmin = float(kmin) self._kmax = float(kmax) def shade(self, stroke): - origin = mathutils.Vector([self._x, self._y, self._z]) + origin = Vector((self._x, self._y, self._z)) it = stroke.stroke_vertices_begin() while not it.is_end: v = it.object @@ -348,6 +390,10 @@ class pyImportance3DThicknessShader(StrokeShader): it.increment() class pyZDependingThicknessShader(StrokeShader): + """ + Assigns thickness based on an object's local Z depth (point + closest to camera is 1, point furthest from camera is zero) + """ def __init__(self, min, max): StrokeShader.__init__(self) self.__min = min @@ -377,6 +423,9 @@ class pyZDependingThicknessShader(StrokeShader): ################## class pyConstantColorShader(StrokeShader): + """ + Assigns a constant color to the stroke + """ def __init__(self,r,g,b, a = 1): StrokeShader.__init__(self) self._r = r @@ -391,8 +440,11 @@ class pyConstantColorShader(StrokeShader): att.alpha = self._a it.increment() -#c1->c2 + class pyIncreasingColorShader(StrokeShader): + """ + Fades from one color to another along the stroke + """ def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2): StrokeShader.__init__(self) self._c1 = [r1,g1,b1,a1] @@ -412,8 +464,11 @@ class pyIncreasingColorShader(StrokeShader): inc = inc+1 it.increment() -# c1->c2->c1 + class pyInterpolateColorShader(StrokeShader): + """ + Fades from one color to another and back + """ def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2): StrokeShader.__init__(self) self._c1 = [r1,g1,b1,a1] @@ -425,7 +480,7 @@ class pyInterpolateColorShader(StrokeShader): while not it.is_end: att = it.object.attribute u = float(inc)/float(n) - c = 1-2*(math.fabs(u-0.5)) + c = 1 - 2 * abs(u - 0.5) att.color = ((1-c)*self._c1[0] + c*self._c2[0], (1-c)*self._c1[1] + c*self._c2[1], (1-c)*self._c1[2] + c*self._c2[2]) @@ -434,6 +489,9 @@ class pyInterpolateColorShader(StrokeShader): it.increment() class pyMaterialColorShader(StrokeShader): + """ + Assigns the color of the underlying material to the stroke + """ def __init__(self, threshold=50): StrokeShader.__init__(self) self._threshold = threshold @@ -443,8 +501,8 @@ class pyMaterialColorShader(StrokeShader): xn = 0.312713 yn = 0.329016 Yn = 1.0 - un = 4.* xn/ ( -2.*xn + 12.*yn + 3. ) - vn= 9.* yn/ ( -2.*xn + 12.*yn +3. ) + un = 4.* xn / (-2.*xn + 12.*yn + 3.) + vn= 9.* yn / (-2.*xn + 12.*yn +3.) while not it.is_end: mat = func(Interface0DIterator(it)) @@ -456,14 +514,14 @@ class pyMaterialColorShader(StrokeShader): Y = 0.212671*r + 0.71516 *g + 0.072169*b Z = 0.019334*r + 0.119193*g + 0.950227*b - if X == 0 and Y == 0 and Z == 0: + if (X, Y, Z) == (0, 0, 0): X = 0.01 Y = 0.01 Z = 0.01 u = 4.*X / (X + 15.*Y + 3.*Z) v = 9.*Y / (X + 15.*Y + 3.*Z) - L= 116. * math.pow((Y/Yn),(1./3.)) -16 + L= 116. * pow((Y/Yn),(1./3.)) -16 U = 13. * L * (u - un) V = 13. * L * (v - vn) @@ -477,7 +535,7 @@ class pyMaterialColorShader(StrokeShader): u = U / (13. * L) + un v = V / (13. * L) + vn - Y = Yn * math.pow( ((L+16.)/116.), 3.) + Y = Yn * pow(((L+16.)/116.), 3.) X = -9. * Y * u / ((u - 4.)* v - u * v) Z = (9. * Y - 15*v*Y - v*X) /( 3. * v) @@ -493,6 +551,9 @@ class pyMaterialColorShader(StrokeShader): it.increment() class pyRandomColorShader(StrokeShader): + """ + Assigns a color to the stroke based on given seed + """ def __init__(self, s=1): StrokeShader.__init__(self) random.seed(s) @@ -508,6 +569,10 @@ class pyRandomColorShader(StrokeShader): it.increment() class py2DCurvatureColorShader(StrokeShader): + """ + Assigns a color (greyscale) to the stroke based on the curvature. + A higher curvature will yield a brighter color + """ def shade(self, stroke): it = stroke.stroke_vertices_begin() func = Curvature2DAngleF0D() @@ -520,21 +585,25 @@ class py2DCurvatureColorShader(StrokeShader): it.increment() class pyTimeColorShader(StrokeShader): + """ + Assigns a greyscale value that increases for every vertex. + The brightness will increase along the stroke + """ def __init__(self, step=0.01): StrokeShader.__init__(self) - self._t = 0 self._step = step def shade(self, stroke): - c = self._t*1.0 - it = stroke.stroke_vertices_begin() - while not it.is_end: - it.object.attribute.color = (c,c,c) - it.increment() - self._t = self._t+self._step + for i, svert in enumerate(iter(stroke)): + c = i * self._step + svert.attribute.color = (c,c,c) ## geometry modifiers class pySamplingShader(StrokeShader): + """ + Resamples the stroke, which gives the stroke the ammount of + vertices specified + """ def __init__(self, sampling): StrokeShader.__init__(self) self._sampling = sampling @@ -543,6 +612,9 @@ class pySamplingShader(StrokeShader): stroke.update_length() class pyBackboneStretcherShader(StrokeShader): + """ + Stretches the stroke's backbone by a given length (in pixels) + """ def __init__(self, l): StrokeShader.__init__(self) self._l = l @@ -558,14 +630,12 @@ class pyBackboneStretcherShader(StrokeShader): v1 = it1.object vn_1 = itn_1.object vn = itn.object - p0 = mathutils.Vector([v0.projected_x, v0.projected_y]) - pn = mathutils.Vector([vn.projected_x, vn.projected_y]) - p1 = mathutils.Vector([v1.projected_x, v1.projected_y]) - pn_1 = mathutils.Vector([vn_1.projected_x, vn_1.projected_y]) - d1 = p0-p1 - d1.normalize() - dn = pn-pn_1 - dn.normalize() + p0 = v0.point_2d + pn = vn.point_2d + p1 = v1.point_2d + pn_1 = vn_1.point_2d + d1 = (p0 - p1).normalized() + dn = (pn - pn_1).normalized() newFirst = p0+d1*float(self._l) newLast = pn+dn*float(self._l) v0.point = newFirst @@ -573,6 +643,9 @@ class pyBackboneStretcherShader(StrokeShader): stroke.update_length() class pyLengthDependingBackboneStretcherShader(StrokeShader): + """ + Stretches the stroke's backbone proportional to the stroke's length + """ def __init__(self, l): StrokeShader.__init__(self) self._l = l @@ -590,14 +663,12 @@ class pyLengthDependingBackboneStretcherShader(StrokeShader): v1 = it1.object vn_1 = itn_1.object vn = itn.object - p0 = mathutils.Vector([v0.projected_x, v0.projected_y]) - pn = mathutils.Vector([vn.projected_x, vn.projected_y]) - p1 = mathutils.Vector([v1.projected_x, v1.projected_y]) - pn_1 = mathutils.Vector([vn_1.projected_x, vn_1.projected_y]) - d1 = p0-p1 - d1.normalize() - dn = pn-pn_1 - dn.normalize() + p0 = v0.point_2d + pn = vn.point_2d + p1 = v1.point_2d + pn_1 = vn_1.point_2d + d1 = (p0 - p1).normalized() + dn = (pn - pn_1).normalized() newFirst = p0+d1*float(stretch) newLast = pn+dn*float(stretch) v0.point = newFirst @@ -605,8 +676,11 @@ class pyLengthDependingBackboneStretcherShader(StrokeShader): stroke.update_length() -## Shader to replace a stroke by its corresponding tangent + class pyGuidingLineShader(StrokeShader): + """ + Replaces the stroke by its corresponding tangent + """ def shade(self, stroke): it = stroke.stroke_vertices_begin() ## get the first vertex itlast = stroke.stroke_vertices_end() ## @@ -630,6 +704,9 @@ class pyGuidingLineShader(StrokeShader): class pyBackboneStretcherNoCuspShader(StrokeShader): + """ + Stretches the stroke's backbone, excluding cusp vertices (end junctions) + """ def __init__(self, l): StrokeShader.__init__(self) self._l = l @@ -644,28 +721,24 @@ class pyBackboneStretcherNoCuspShader(StrokeShader): v0 = it0.object v1 = it1.object if (v0.nature & Nature.CUSP) == 0 and (v1.nature & Nature.CUSP) == 0: - p0 = v0.point - p1 = v1.point - d1 = p0-p1 - d1.normalize() + d1 = (v0.point - v1.point).normalized() newFirst = p0+d1*float(self._l) v0.point = newFirst vn_1 = itn_1.object vn = itn.object if (vn.nature & Nature.CUSP) == 0 and (vn_1.nature & Nature.CUSP) == 0: - pn = vn.point - pn_1 = vn_1.point - dn = pn-pn_1 - dn.normalize() - newLast = pn+dn*float(self._l) + dn = (vn.point - vn_1.point).normalized() + newLast = vn.point + dn * float(self._l) vn.point = newLast stroke.update_length() class pyDiffusion2Shader(StrokeShader): - """This shader iteratively adds an offset to the position of each - stroke vertex in the direction perpendicular to the stroke direction - at the point. The offset is scaled by the 2D curvature (i.e., how - quickly the stroke curve is) at the point.""" + """ + Iteratively adds an offset to the position of each stroke vertex + in the direction perpendicular to the stroke direction at the + point. The offset is scaled by the 2D curvature (i.e. how quickly + the stroke curve is) at the point. + """ def __init__(self, lambda1, nbIter): StrokeShader.__init__(self) self._lambda = lambda1 @@ -684,6 +757,9 @@ class pyDiffusion2Shader(StrokeShader): stroke.update_length() class pyTipRemoverShader(StrokeShader): + """ + Removes the tips of the stroke + """ def __init__(self, l): StrokeShader.__init__(self) self._l = l @@ -717,6 +793,9 @@ class pyTipRemoverShader(StrokeShader): stroke.update_length() class pyTVertexRemoverShader(StrokeShader): + """ + Removes t-vertices from the stroke + """ def shade(self, stroke): if stroke.stroke_vertices_size() <= 3: return @@ -733,14 +812,18 @@ class pyTVertexRemoverShader(StrokeShader): #class pyExtremitiesOrientationShader(StrokeShader): # def __init__(self, x1,y1,x2=0,y2=0): # StrokeShader.__init__(self) -# self._v1 = mathutils.Vector([x1,y1]) -# self._v2 = mathutils.Vector([x2,y2]) +# self._v1 = Vector((x1,y1)) +# self._v2 = Vector((x2,y2)) # def shade(self, stroke): # #print(self._v1.x,self._v1.y) # stroke.setBeginningOrientation(self._v1.x,self._v1.y) # stroke.setEndingOrientation(self._v2.x,self._v2.y) class pyHLRShader(StrokeShader): + """ + Controlls visibility based upon the quantative invisibility (QI) + based on hidden line removal (HLR) + """ def shade(self, stroke): originalSize = stroke.stroke_vertices_size() if originalSize < 4: @@ -770,6 +853,7 @@ class pyHLRShader(StrokeShader): def get_fedge(self, it1, it2): return it1.get_fedge(it2) +# broken and a mess class pyTVertexOrientationShader(StrokeShader): def __init__(self): StrokeShader.__init__(self) @@ -846,6 +930,9 @@ class pyTVertexOrientationShader(StrokeShader): return it1.get_fedge(it2) class pySinusDisplacementShader(StrokeShader): + """ + Displaces the stroke in the shape of a sine wave + """ def __init__(self, f, a): StrokeShader.__init__(self) self._f = f @@ -859,15 +946,20 @@ class pySinusDisplacementShader(StrokeShader): n = self._getNormal(Interface0DIterator(it)) p = v.point u = v.u - a = self._a*(1-2*(math.fabs(u-0.5))) - n = n*a*math.cos(self._f*u*6.28) + a = self._a*(1-2*(abs(u-0.5))) + n = n*a*cos(self._f*u*6.28) #print(n.x, n.y) v.point = p+n - #v.point = v.point+n*a*math.cos(f*v.u) + #v.point = v.point+n*a*cos(f*v.u) it.increment() stroke.update_length() class pyPerlinNoise1DShader(StrokeShader): + """ + Displaces the stroke using the curvilinear abscissa. This means + that lines with the same length and sampling interval will be + identically distorded + """ def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1): StrokeShader.__init__(self) self.__noise = Noise(seed) @@ -885,6 +977,13 @@ class pyPerlinNoise1DShader(StrokeShader): stroke.update_length() class pyPerlinNoise2DShader(StrokeShader): + """ + Displaces the stroke using the strokes coordinates. This means + that in a scene no strokes will be distorded identically + + More information on the noise shaders can be found at + freestyleintegration.wordpress.com/2011/09/25/development-updates-on-september-25/ + """ def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1): StrokeShader.__init__(self) self.__noise = Noise(seed) @@ -895,13 +994,15 @@ class pyPerlinNoise2DShader(StrokeShader): it = stroke.stroke_vertices_begin() while not it.is_end: v = it.object - vec = mathutils.Vector([v.projected_x, v.projected_y]) - nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct) + nres = self.__noise.turbulence2(v.point_2d, self.__freq, self.__amp, self.__oct) v.point = (v.projected_x + nres, v.projected_y + nres) it.increment() stroke.update_length() class pyBluePrintCirclesShader(StrokeShader): + """ + Draws the silhouette of the object as a circle + """ def __init__(self, turns = 1, random_radius = 3, random_center = 5): StrokeShader.__init__(self) self.__turns = turns @@ -934,7 +1035,7 @@ class pyBluePrintCirclesShader(StrokeShader): sv_nb = sv_nb // self.__turns center = (p_min + p_max) / 2 radius = (center.x - p_min.x + center.y - p_min.y) / 2 - p_new = mathutils.Vector([0, 0]) + p_new = Vector((0,0)) ####################################################### R = self.__random_radius C = self.__random_center @@ -943,14 +1044,14 @@ class pyBluePrintCirclesShader(StrokeShader): for j in range(self.__turns): prev_radius = radius prev_center = center - radius = radius + random.randint(-R, R) - center = center + mathutils.Vector([random.randint(-C, C), random.randint(-C, C)]) + radius = radius + randint(-R, R) + center = center + Vector((randint(-C, C), randint(-C, C))) while i < sv_nb and not it.is_end: t = float(i) / float(sv_nb - 1) r = prev_radius + (radius - prev_radius) * t c = prev_center + (center - prev_center) * t - p_new.x = c.x + r * math.cos(2 * math.pi * t) - p_new.y = c.y + r * math.sin(2 * math.pi * t) + p_new.x = c.x + r * cos(2 * pi * t) + p_new.y = c.y + r * sin(2 * pi * t) it.object.point = p_new i = i + 1 it.increment() @@ -964,6 +1065,9 @@ class pyBluePrintCirclesShader(StrokeShader): stroke.update_length() class pyBluePrintEllipsesShader(StrokeShader): + """ + Draws the silhouette of the object as an ellips + """ def __init__(self, turns = 1, random_radius = 3, random_center = 5): StrokeShader.__init__(self) self.__turns = turns @@ -991,7 +1095,7 @@ class pyBluePrintEllipsesShader(StrokeShader): sv_nb = sv_nb // self.__turns center = (p_min + p_max) / 2 radius = center - p_min - p_new = mathutils.Vector([0, 0]) + p_new = Vecor((0,0)) ####################################################### R = self.__random_radius C = self.__random_center @@ -1000,14 +1104,14 @@ class pyBluePrintEllipsesShader(StrokeShader): for j in range(self.__turns): prev_radius = radius prev_center = center - radius = radius + mathutils.Vector([random.randint(-R, R), random.randint(-R, R)]) - center = center + mathutils.Vector([random.randint(-C, C), random.randint(-C, C)]) + radius = radius + Vector((randint(-R, R), randint(-R, R))) + center = center + Vector((randint(-C, C), randint(-C, C))) while i < sv_nb and not it.is_end: t = float(i) / float(sv_nb - 1) r = prev_radius + (radius - prev_radius) * t c = prev_center + (center - prev_center) * t - p_new.x = c.x + r.x * math.cos(2 * math.pi * t) - p_new.y = c.y + r.y * math.sin(2 * math.pi * t) + p_new.x = c.x + r.x * cos(2 * pi * t) + p_new.y = c.y + r.y * sin(2 * pi * t) it.object.point = p_new i = i + 1 it.increment() @@ -1022,6 +1126,9 @@ class pyBluePrintEllipsesShader(StrokeShader): class pyBluePrintSquaresShader(StrokeShader): + """ + Draws the silhouette of the object as a square + """ def __init__(self, turns = 1, bb_len = 10, bb_rand = 0): StrokeShader.__init__(self) self.__turns = turns @@ -1052,28 +1159,28 @@ class pyBluePrintSquaresShader(StrokeShader): second = 2 * first third = 3 * first fourth = sv_nb - p_first = mathutils.Vector([p_min.x - self.__bb_len, p_min.y]) - p_first_end = mathutils.Vector([p_max.x + self.__bb_len, p_min.y]) - p_second = mathutils.Vector([p_max.x, p_min.y - self.__bb_len]) - p_second_end = mathutils.Vector([p_max.x, p_max.y + self.__bb_len]) - p_third = mathutils.Vector([p_max.x + self.__bb_len, p_max.y]) - p_third_end = mathutils.Vector([p_min.x - self.__bb_len, p_max.y]) - p_fourth = mathutils.Vector([p_min.x, p_max.y + self.__bb_len]) - p_fourth_end = mathutils.Vector([p_min.x, p_min.y - self.__bb_len]) + p_first = Vector((p_min.x - self.__bb_len, p_min.y)) + p_first_end = Vector((p_max.x + self.__bb_len, p_min.y)) + p_second = Vector((p_max.x, p_min.y - self.__bb_len)) + p_second_end = Vector((p_max.x, p_max.y + self.__bb_len)) + p_third = Vector((p_max.x + self.__bb_len, p_max.y)) + p_third_end = Vector((p_min.x - self.__bb_len, p_max.y)) + p_fourth = Vector((p_min.x, p_max.y + self.__bb_len)) + p_fourth_end = Vector((p_min.x, p_min.y - self.__bb_len)) ####################################################### R = self.__bb_rand r = self.__bb_rand // 2 it = stroke.stroke_vertices_begin() visible = True for j in range(self.__turns): - p_first = p_first + mathutils.Vector([random.randint(-R, R), random.randint(-r, r)]) - p_first_end = p_first_end + mathutils.Vector([random.randint(-R, R), random.randint(-r, r)]) - p_second = p_second + mathutils.Vector([random.randint(-r, r), random.randint(-R, R)]) - p_second_end = p_second_end + mathutils.Vector([random.randint(-r, r), random.randint(-R, R)]) - p_third = p_third + mathutils.Vector([random.randint(-R, R), random.randint(-r, r)]) - p_third_end = p_third_end + mathutils.Vector([random.randint(-R, R), random.randint(-r, r)]) - p_fourth = p_fourth + mathutils.Vector([random.randint(-r, r), random.randint(-R, R)]) - p_fourth_end = p_fourth_end + mathutils.Vector([random.randint(-r, r), random.randint(-R, R)]) + p_first = p_first + Vector((randint(-R, R), randint(-r, r))) + p_first_end = p_first_end + Vector((randint(-R, R), randint(-r, r))) + p_second = p_second + Vector((randint(-r, r), randint(-R, R))) + p_second_end = p_second_end + Vector((randint(-r, r), randint(-R, R))) + p_third = p_third + Vector((randint(-R, R), randint(-r, r))) + p_third_end = p_third_end + Vector((randint(-R, R), randint(-r, r))) + p_fourth = p_fourth + Vector((randint(-r, r), randint(-R, R))) + p_fourth_end = p_fourth_end + Vector((randint(-r, r), randint(-R, R))) vec_first = p_first_end - p_first vec_second = p_second_end - p_second vec_third = p_third_end - p_third @@ -1116,7 +1223,7 @@ class pyBluePrintSquaresShader(StrokeShader): stroke.remove_vertex(sv) stroke.update_length() - +# needs a docstring class pyBluePrintDirectedSquaresShader(StrokeShader): def __init__(self, turns = 1, bb_len = 10, mult = 1): StrokeShader.__init__(self) @@ -1125,7 +1232,7 @@ class pyBluePrintDirectedSquaresShader(StrokeShader): self.__bb_len = 1 + float(bb_len) / 100 def shade(self, stroke): stroke.resample(32 * self.__turns) - p_mean = mathutils.Vector([0, 0]) + p_mean = Vector((0, 0)) it = stroke.stroke_vertices_begin() while not it.is_end: p = it.object.point @@ -1139,8 +1246,8 @@ class pyBluePrintDirectedSquaresShader(StrokeShader): it = stroke.stroke_vertices_begin() while not it.is_end: p = it.object.point - p_var_xx = p_var_xx + math.pow(p.x - p_mean.x, 2) - p_var_yy = p_var_yy + math.pow(p.y - p_mean.y, 2) + p_var_xx = p_var_xx + pow(p.x - p_mean.x, 2) + p_var_yy = p_var_yy + pow(p.y - p_mean.y, 2) p_var_xy = p_var_xy + (p.x - p_mean.x) * (p.y - p_mean.y) it.increment() p_var_xx = p_var_xx / sv_nb @@ -1149,18 +1256,18 @@ class pyBluePrintDirectedSquaresShader(StrokeShader): ## print(p_var_xx, p_var_yy, p_var_xy) trace = p_var_xx + p_var_yy det = p_var_xx * p_var_yy - p_var_xy * p_var_xy - sqrt_coeff = math.sqrt(trace * trace - 4 * det) + sqrt_coeff = sqrt(trace * trace - 4 * det) lambda1 = (trace + sqrt_coeff) / 2 lambda2 = (trace - sqrt_coeff) / 2 ## print(lambda1, lambda2) - theta = math.atan(2 * p_var_xy / (p_var_xx - p_var_yy)) / 2 + theta = atan(2 * p_var_xy / (p_var_xx - p_var_yy)) / 2 ## print(theta) if p_var_yy > p_var_xx: - e1 = mathutils.Vector([math.cos(theta + math.pi / 2), math.sin(theta + math.pi / 2)]) * math.sqrt(lambda1) * self.__mult - e2 = mathutils.Vector([math.cos(theta + math.pi), math.sin(theta + math.pi)]) * math.sqrt(lambda2) * self.__mult + e1 = Vector((cos(theta + pi / 2), sin(theta + pi / 2))) * sqrt(lambda1) * self.__mult + e2 = Vector((cos(theta + pi), sin(theta + pi))) * sqrt(lambda2) * self.__mult else: - e1 = mathutils.Vector([math.cos(theta), math.sin(theta)]) * math.sqrt(lambda1) * self.__mult - e2 = mathutils.Vector([math.cos(theta + math.pi / 2), math.sin(theta + math.pi / 2)]) * math.sqrt(lambda2) * self.__mult + e1 = Vector((cos(theta), sin(theta))) * sqrt(lambda1) * self.__mult + e2 = Vector((cos(theta + pi / 2), sin(theta + pi / 2))) * sqrt(lambda2) * self.__mult ####################################################### sv_nb = sv_nb // self.__turns first = sv_nb // 4 @@ -1168,7 +1275,7 @@ class pyBluePrintDirectedSquaresShader(StrokeShader): third = 3 * first fourth = sv_nb bb_len1 = self.__bb_len - bb_len2 = 1 + (bb_len1 - 1) * math.sqrt(lambda1 / lambda2) + bb_len2 = 1 + (bb_len1 - 1) * sqrt(lambda1 / lambda2) p_first = p_mean - e1 - e2 * bb_len2 p_second = p_mean - e1 * bb_len1 + e2 p_third = p_mean + e1 + e2 * bb_len2 @@ -1214,6 +1321,9 @@ class pyBluePrintDirectedSquaresShader(StrokeShader): stroke.update_length() class pyModulateAlphaShader(StrokeShader): + """ + Limits the stroke's alpha between a min and max value + """ def __init__(self, min = 0, max = 1): StrokeShader.__init__(self) self.__min = min diff --git a/release/scripts/freestyle/modules/freestyle/types.py b/release/scripts/freestyle/modules/freestyle/types.py index d7f7078e1aa..8fdacf14c23 100644 --- a/release/scripts/freestyle/modules/freestyle/types.py +++ b/release/scripts/freestyle/modules/freestyle/types.py @@ -16,6 +16,10 @@ # # ##### END GPL LICENSE BLOCK ##### +""" +Submodule containing all Freestyle types +""" + # module members from _freestyle import ( AdjacencyIterator, diff --git a/release/scripts/freestyle/modules/freestyle/utils.py b/release/scripts/freestyle/modules/freestyle/utils.py index af9cc109ae1..6d2c9da8146 100644 --- a/release/scripts/freestyle/modules/freestyle/utils.py +++ b/release/scripts/freestyle/modules/freestyle/utils.py @@ -16,6 +16,10 @@ # # ##### END GPL LICENSE BLOCK ##### +""" +Helper functions used for Freestyle style module writing +""" + # module members from _freestyle import ( ContextFunctions, |