Reorganized the Freestyle Python API in a hierarchical package structure.
Both C- and Python-coded API components were rearranged into logical groups. New Python modules are packaged as follows: freestyle - Top-level package freestyle.types - Classes for core data structues (e.g., view map) freestyle.chainingiterators - Pre-defined chaining iterators freestyle.functions - Pre-defined 0D and 1D functions freestyle.predicates - Pre-defined 0D and 1D predicates freestyle.shaders - Pre-defined stroke shaders freestyle.utils - Utility functions The Python modules are installed in scripts/freestyle/modules. Pre-defined styles are installed in scripts/freestyle/styles. To-do: update styles according to the new Freestyle API package structure.
This commit is contained in:
21
release/scripts/freestyle/modules/freestyle/__init__.py
Normal file
21
release/scripts/freestyle/modules/freestyle/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# module members
|
||||
from _freestyle import Operators
|
||||
from . import chainingiterators, functions, predicates, types, utils
|
716
release/scripts/freestyle/modules/freestyle/chainingiterators.py
Normal file
716
release/scripts/freestyle/modules/freestyle/chainingiterators.py
Normal file
@@ -0,0 +1,716 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# module members
|
||||
from _freestyle import (
|
||||
ChainPredicateIterator,
|
||||
ChainSilhouetteIterator,
|
||||
)
|
||||
|
||||
# modules for implementing chaining iterators
|
||||
from freestyle.types import (
|
||||
AdjacencyIterator,
|
||||
ChainingIterator,
|
||||
)
|
||||
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):
|
||||
def __init__(self, stayInSelection=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, True, None, True)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
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.object
|
||||
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=True, stayInUnvisited=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, stayInUnvisited, None, True)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
ve = it.object
|
||||
if ve.id == self.current_edge.id:
|
||||
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, False, True, None, True)
|
||||
self._isExternalContour = ExternalContourUP1D()
|
||||
def init(self):
|
||||
self._nEdges = 0
|
||||
self._isInSelection = 1
|
||||
def checkViewEdge(self, ve, orientation):
|
||||
if orientation != 0:
|
||||
vertex = ve.second_svertex()
|
||||
else:
|
||||
vertex = ve.first_svertex()
|
||||
it = AdjacencyIterator(vertex,1,1)
|
||||
while not it.is_end:
|
||||
ave = it.object
|
||||
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 not it.is_end:
|
||||
ve = it.object
|
||||
if self._isExternalContour(ve):
|
||||
if ve.time_stamp == CF.get_time_stamp():
|
||||
winner = ve
|
||||
it.increment()
|
||||
|
||||
self._nEdges = self._nEdges+1
|
||||
if winner is None:
|
||||
orient = 1
|
||||
it = AdjacencyIterator(iter)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if it.is_incoming:
|
||||
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=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, False, None, True)
|
||||
self._timeStamp = CF.get_time_stamp()+nRounds
|
||||
self._nRounds = nRounds
|
||||
def init(self):
|
||||
self._timeStamp = CF.get_time_stamp()+self._nRounds
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
ve = it.object
|
||||
if ve.id == self.current_edge.id:
|
||||
it.increment()
|
||||
continue
|
||||
if (oNature & natures[i]) != 0:
|
||||
if (natures[i] != oNature) != 0:
|
||||
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 is None:
|
||||
winner = self.current_edge
|
||||
if winner.chaining_time_stamp == 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=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, False, None, True)
|
||||
self._timeStamp = CF.get_time_stamp()+nRounds
|
||||
self._nRounds = nRounds
|
||||
def init(self):
|
||||
self._timeStamp = CF.get_time_stamp()+self._nRounds
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
found = False
|
||||
it = AdjacencyIterator(iter)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == self.current_edge.id:
|
||||
found = True
|
||||
it.increment()
|
||||
continue
|
||||
winner = ve
|
||||
it.increment()
|
||||
if not found:
|
||||
# This is a fatal error condition: self.current_edge must be found
|
||||
# among the edges seen by the AdjacencyIterator [bug #35695].
|
||||
if bpy.app.debug_freestyle:
|
||||
print('pySketchyChainingIterator: current edge not found')
|
||||
return None
|
||||
if winner is None:
|
||||
winner = self.current_edge
|
||||
if winner.chaining_time_stamp == 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, 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:
|
||||
self._length = 0
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.time_stamp != CF.get_time_stamp():
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# 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.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
_it.init()
|
||||
while not _it.is_end:
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_it.increment()
|
||||
if _it.is_begin:
|
||||
break;
|
||||
_it.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
if not _it.is_begin:
|
||||
_it.decrement()
|
||||
while (not _it.is_end) and (not _it.is_begin):
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_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.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while _cit.is_end == 0 and _cit.object.time_stamp != CF.get_time_stamp():
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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, False, True, None, True)
|
||||
self._length = float(length)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.time_stamp != CF.get_time_stamp():
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# nw let's compute the length of this connex non selected part:
|
||||
connexl = 0
|
||||
_cit = pyChainSilhouetteGenericIterator(0,0)
|
||||
_cit.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while _cit.is_end == 0 and _cit.object.time_stamp != CF.get_time_stamp():
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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, 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:
|
||||
self._length = 0
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.time_stamp != CF.get_time_stamp():
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# 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.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
_it.init()
|
||||
while not _it.is_end:
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_it.increment()
|
||||
if _it.is_begin:
|
||||
break;
|
||||
_it.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
if not _it.is_begin:
|
||||
_it.decrement()
|
||||
while (not _it.is_end) and (not _it.is_begin):
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_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.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while _cit.is_end == 0 and _cit.object.time_stamp != CF.get_time_stamp():
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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, 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:
|
||||
self._length = 0
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.qi != 0:
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# 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.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
_it.init()
|
||||
while not _it.is_end:
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_it.increment()
|
||||
if _it.is_begin:
|
||||
break;
|
||||
_it.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
if not _it.is_begin:
|
||||
_it.decrement()
|
||||
while (not _it.is_end) and (not _it.is_begin):
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_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.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while not _cit.is_end and _cit.object.qi != 0:
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, True, None, True)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
feB = self.current_edge.last_fedge
|
||||
feA = ve.first_fedge
|
||||
vB = feB.second_svertex
|
||||
vA = feA.first_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
winner = ve
|
||||
break
|
||||
feA = self.current_edge.first_fedge
|
||||
feB = ve.last_fedge
|
||||
vB = feB.second_svertex
|
||||
vA = feA.first_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
winner = ve
|
||||
break
|
||||
feA = self.current_edge.last_fedge
|
||||
feB = ve.last_fedge
|
||||
vB = feB.second_svertex
|
||||
vA = feA.second_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
winner = ve
|
||||
break
|
||||
feA = self.current_edge.first_fedge
|
||||
feB = ve.first_fedge
|
||||
vB = feB.first_svertex
|
||||
vA = feA.first_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
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.object
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
return winner
|
197
release/scripts/freestyle/modules/freestyle/functions.py
Normal file
197
release/scripts/freestyle/modules/freestyle/functions.py
Normal file
@@ -0,0 +1,197 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# module members
|
||||
from _freestyle import (
|
||||
ChainingTimeStampF1D,
|
||||
Curvature2DAngleF0D,
|
||||
Curvature2DAngleF1D,
|
||||
CurveNatureF0D,
|
||||
CurveNatureF1D,
|
||||
DensityF0D,
|
||||
DensityF1D,
|
||||
GetCompleteViewMapDensityF1D,
|
||||
GetCurvilinearAbscissaF0D,
|
||||
GetDirectionalViewMapDensityF1D,
|
||||
GetOccludeeF0D,
|
||||
GetOccludeeF1D,
|
||||
GetOccludersF0D,
|
||||
GetOccludersF1D,
|
||||
GetParameterF0D,
|
||||
GetProjectedXF0D,
|
||||
GetProjectedXF1D,
|
||||
GetProjectedYF0D,
|
||||
GetProjectedYF1D,
|
||||
GetProjectedZF0D,
|
||||
GetProjectedZF1D,
|
||||
GetShapeF0D,
|
||||
GetShapeF1D,
|
||||
GetSteerableViewMapDensityF1D,
|
||||
GetViewMapGradientNormF0D,
|
||||
GetViewMapGradientNormF1D,
|
||||
GetXF0D,
|
||||
GetXF1D,
|
||||
GetYF0D,
|
||||
GetYF1D,
|
||||
GetZF0D,
|
||||
GetZF1D,
|
||||
IncrementChainingTimeStampF1D,
|
||||
LocalAverageDepthF0D,
|
||||
LocalAverageDepthF1D,
|
||||
MaterialF0D,
|
||||
Normal2DF0D,
|
||||
Normal2DF1D,
|
||||
Orientation2DF1D,
|
||||
Orientation3DF1D,
|
||||
QuantitativeInvisibilityF0D,
|
||||
QuantitativeInvisibilityF1D,
|
||||
ReadCompleteViewMapPixelF0D,
|
||||
ReadMapPixelF0D,
|
||||
ReadSteerableViewMapPixelF0D,
|
||||
ShapeIdF0D,
|
||||
TimeStampF1D,
|
||||
VertexOrientation2DF0D,
|
||||
VertexOrientation3DF0D,
|
||||
ZDiscontinuityF0D,
|
||||
ZDiscontinuityF1D,
|
||||
)
|
||||
|
||||
# modules for implementing functions
|
||||
from freestyle.types import (
|
||||
IntegrationType,
|
||||
UnaryFunction0DDouble,
|
||||
UnaryFunction0DMaterial,
|
||||
UnaryFunction0DVec2f,
|
||||
UnaryFunction1DDouble,
|
||||
)
|
||||
from freestyle.utils import ContextFunctions as CF
|
||||
import math
|
||||
import mathutils
|
||||
|
||||
## 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.
|
||||
def __call__(self, inter):
|
||||
cp = inter.object
|
||||
assert(isinstance(cp, CurvePoint))
|
||||
fe = cp.first_svertex.get_fedge(cp.second_svertex)
|
||||
assert(fe is not None)
|
||||
return fe.material if fe.is_smooth else fe.material_left
|
||||
|
||||
class pyInverseCurvature2DAngleF0D(UnaryFunction0DDouble):
|
||||
def __call__(self, inter):
|
||||
func = Curvature2DAngleF0D()
|
||||
c = func(inter)
|
||||
return (3.1415 - c)
|
||||
|
||||
class pyCurvilinearLengthF0D(UnaryFunction0DDouble):
|
||||
def __call__(self, inter):
|
||||
cp = inter.object
|
||||
assert(isinstance(cp, CurvePoint))
|
||||
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 __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 = math.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])
|
||||
|
||||
class pyViewMapGradientNormF0D(UnaryFunction0DDouble):
|
||||
def __init__(self, l):
|
||||
UnaryFunction0DDouble.__init__(self)
|
||||
self._l = l
|
||||
self._step = math.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])
|
||||
return grad.length
|
||||
|
||||
## Functions for 1D elements (curves)
|
||||
#####################################
|
||||
|
||||
class pyGetInverseProjectedZF1D(UnaryFunction1DDouble):
|
||||
def __call__(self, inter):
|
||||
func = GetProjectedZF1D()
|
||||
z = func(inter)
|
||||
return (1.0 - z)
|
||||
|
||||
class pyGetSquareInverseProjectedZF1D(UnaryFunction1DDouble):
|
||||
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 __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 __call__(self, inter):
|
||||
v = integrate(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration)
|
||||
return v
|
516
release/scripts/freestyle/modules/freestyle/predicates.py
Normal file
516
release/scripts/freestyle/modules/freestyle/predicates.py
Normal file
@@ -0,0 +1,516 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# module members
|
||||
from _freestyle import (
|
||||
ContourUP1D,
|
||||
DensityLowerThanUP1D,
|
||||
EqualToChainingTimeStampUP1D,
|
||||
EqualToTimeStampUP1D,
|
||||
ExternalContourUP1D,
|
||||
FalseBP1D,
|
||||
FalseUP0D,
|
||||
FalseUP1D,
|
||||
Length2DBP1D,
|
||||
QuantitativeInvisibilityUP1D,
|
||||
SameShapeIdBP1D,
|
||||
ShapeUP1D,
|
||||
TrueBP1D,
|
||||
TrueUP0D,
|
||||
TrueUP1D,
|
||||
ViewMapGradientNormBP1D,
|
||||
WithinImageBoundaryUP1D,
|
||||
)
|
||||
|
||||
# modules for implementing predicates
|
||||
from freestyle.types import (
|
||||
IntegrationType,
|
||||
BinaryPredicate1D,
|
||||
UnaryPredicate0D,
|
||||
UnaryPredicate1D,
|
||||
)
|
||||
from freestyle.functions import (
|
||||
pyCurvilinearLengthF0D,
|
||||
pyDensityAnisotropyF1D,
|
||||
pyViewMapGradientNormF1D,
|
||||
)
|
||||
import random
|
||||
|
||||
## Unary predicates for 0D elements (vertices)
|
||||
##############################################
|
||||
|
||||
class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D):
|
||||
def __init__(self,a):
|
||||
UnaryPredicate0D.__init__(self)
|
||||
self._a = a
|
||||
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 __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 __call__(self, inter):
|
||||
v = inter.object
|
||||
return (v.nature & self._nature) != 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 __call__(self, iter):
|
||||
if (iter.object.nature & Nature.T_VERTEX) == 0:
|
||||
return 0
|
||||
if iter.is_end:
|
||||
return 0
|
||||
if self._getQI(iter) != 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 __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 __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
|
||||
|
||||
## Unary predicates for 1D elements (curves)
|
||||
############################################
|
||||
|
||||
class AndUP1D(UnaryPredicate1D):
|
||||
def __init__(self, pred1, pred2):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self.__pred1 = pred1
|
||||
self.__pred2 = pred2
|
||||
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 __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 __call__(self, inter):
|
||||
return not self.__pred(inter)
|
||||
|
||||
class pyNFirstUP1D(UnaryPredicate1D):
|
||||
def __init__(self, n):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self.__n = n
|
||||
self.__count = 0
|
||||
def __call__(self, inter):
|
||||
self.__count = self.__count + 1
|
||||
if self.__count <= self.__n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class pyHigherLengthUP1D(UnaryPredicate1D):
|
||||
def __init__(self,l):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._l = l
|
||||
def __call__(self, inter):
|
||||
return (inter.length_2d > self._l)
|
||||
|
||||
class pyNatureUP1D(UnaryPredicate1D):
|
||||
def __init__(self,nature):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._nature = nature
|
||||
self._getNature = CurveNatureF1D()
|
||||
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 __call__(self, inter):
|
||||
count = 0
|
||||
func = Curvature2DAngleF0D()
|
||||
it = inter.vertices_begin()
|
||||
while not it.is_end:
|
||||
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 __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 __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 __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 __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 __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 __call__(self, inter):
|
||||
#print("toto")
|
||||
#print(func.name)
|
||||
#print(inter.name)
|
||||
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 __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 __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 __call__(self, inter):
|
||||
func = GetShapeF1D()
|
||||
shapes = func(inter)
|
||||
for s in shapes:
|
||||
if(s.id == self._id):
|
||||
return 0
|
||||
it = inter.vertices_begin()
|
||||
itlast = inter.vertices_end()
|
||||
itlast.decrement()
|
||||
v = it.object
|
||||
vlast = itlast.object
|
||||
tvertex = v.viewvertex
|
||||
if type(tvertex) is TVertex:
|
||||
#print("TVertex: [ ", tvertex.id.first, ",", tvertex.id.second," ]")
|
||||
eit = tvertex.edges_begin()
|
||||
while not eit.is_end:
|
||||
ve, incoming = eit.object
|
||||
if ve.id == self._id:
|
||||
return 1
|
||||
#print("-------", ve.id.first, "-", ve.id.second)
|
||||
eit.increment()
|
||||
tvertex = vlast.viewvertex
|
||||
if type(tvertex) is TVertex:
|
||||
#print("TVertex: [ ", tvertex.id.first, ",", tvertex.id.second," ]")
|
||||
eit = tvertex.edges_begin()
|
||||
while not eit.is_end:
|
||||
ve, incoming = eit.object
|
||||
if ve.id == self._id:
|
||||
return 1
|
||||
#print("-------", ve.id.first, "-", ve.id.second)
|
||||
eit.increment()
|
||||
return 0
|
||||
|
||||
class pyIsInOccludersListUP1D(UnaryPredicate1D):
|
||||
def __init__(self,id):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._id = id
|
||||
def __call__(self, inter):
|
||||
func = GetOccludersF1D()
|
||||
occluders = func(inter)
|
||||
for a in occluders:
|
||||
if a.id == self._id:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class pyIsOccludedByItselfUP1D(UnaryPredicate1D):
|
||||
def __init__(self):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self.__func1 = GetOccludersF1D()
|
||||
self.__func2 = GetShapeF1D()
|
||||
def __call__(self, inter):
|
||||
lst1 = self.__func1(inter)
|
||||
lst2 = self.__func2(inter)
|
||||
for vs1 in lst1:
|
||||
for vs2 in lst2:
|
||||
if vs1.id == vs2.id:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class pyIsOccludedByIdListUP1D(UnaryPredicate1D):
|
||||
def __init__(self, idlist):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._idlist = idlist
|
||||
self.__func1 = GetOccludersF1D()
|
||||
def __call__(self, inter):
|
||||
lst1 = self.__func1(inter)
|
||||
for vs1 in lst1:
|
||||
for _id in self._idlist:
|
||||
if vs1.id == _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.first, _id.second))
|
||||
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 __call__(self, inter):
|
||||
func = GetShapeF1D()
|
||||
shapes = func(inter)
|
||||
for a in shapes:
|
||||
if a.id == 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 __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 __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 __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.vertices_begin()
|
||||
itlast = inter.vertices_end()
|
||||
itlast.decrement()
|
||||
vlast = itlast.object
|
||||
v = it.object
|
||||
#print(v.id.first, v.id.second)
|
||||
#print(vlast.id.first, vlast.id.second)
|
||||
if v.id == vlast.id:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
## Binary predicates for 1D elements (curves)
|
||||
#############################################
|
||||
|
||||
class pyZBP1D(BinaryPredicate1D):
|
||||
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 __call__(self, i1, i2):
|
||||
return (self._GetZDiscontinuity(i1) > self._GetZDiscontinuity(i2))
|
||||
|
||||
class pyLengthBP1D(BinaryPredicate1D):
|
||||
def __call__(self, i1, i2):
|
||||
return (i1.length_2d > i2.length_2d)
|
||||
|
||||
class pySilhouetteFirstBP1D(BinaryPredicate1D):
|
||||
def __call__(self, inter1, inter2):
|
||||
bpred = SameShapeIdBP1D()
|
||||
if (bpred(inter1, inter2) != 1):
|
||||
return 0
|
||||
if (inter1.nature & Nature.SILHOUETTE):
|
||||
return (inter2.nature & Nature.SILHOUETTE) != 0
|
||||
return (inter1.nature == inter2.nature)
|
||||
|
||||
class pyNatureBP1D(BinaryPredicate1D):
|
||||
def __call__(self, inter1, inter2):
|
||||
return (inter1.nature & inter2.nature)
|
||||
|
||||
class pyViewMapGradientNormBP1D(BinaryPredicate1D):
|
||||
def __init__(self,l, sampling=2.0):
|
||||
BinaryPredicate1D.__init__(self)
|
||||
self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN)
|
||||
def __call__(self, i1,i2):
|
||||
#print("compare gradient")
|
||||
return (self._GetGradient(i1) > self._GetGradient(i2))
|
||||
|
||||
class pyShuffleBP1D(BinaryPredicate1D):
|
||||
def __init__(self):
|
||||
BinaryPredicate1D.__init__(self)
|
||||
random.seed(1)
|
||||
def __call__(self, inter1, inter2):
|
||||
r1 = random.uniform(0,1)
|
||||
r2 = random.uniform(0,1)
|
||||
return (r1<r2)
|
1249
release/scripts/freestyle/modules/freestyle/shaders.py
Normal file
1249
release/scripts/freestyle/modules/freestyle/shaders.py
Normal file
File diff suppressed because it is too large
Load Diff
81
release/scripts/freestyle/modules/freestyle/types.py
Normal file
81
release/scripts/freestyle/modules/freestyle/types.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# module members
|
||||
from _freestyle import (
|
||||
AdjacencyIterator,
|
||||
BBox,
|
||||
BinaryPredicate0D,
|
||||
BinaryPredicate1D,
|
||||
Chain,
|
||||
ChainingIterator,
|
||||
Curve,
|
||||
CurvePoint,
|
||||
CurvePointIterator,
|
||||
FEdge,
|
||||
FEdgeSharp,
|
||||
FEdgeSmooth,
|
||||
Id,
|
||||
IntegrationType,
|
||||
Interface0D,
|
||||
Interface0DIterator,
|
||||
Interface1D,
|
||||
Iterator,
|
||||
Material,
|
||||
MediumType,
|
||||
Nature,
|
||||
Noise,
|
||||
NonTVertex,
|
||||
SShape,
|
||||
SVertex,
|
||||
SVertexIterator,
|
||||
Stroke,
|
||||
StrokeShader,
|
||||
StrokeAttribute,
|
||||
StrokeVertex,
|
||||
StrokeVertexIterator,
|
||||
TVertex,
|
||||
UnaryFunction0D,
|
||||
UnaryFunction0DDouble,
|
||||
UnaryFunction0DEdgeNature,
|
||||
UnaryFunction0DFloat,
|
||||
UnaryFunction0DId,
|
||||
UnaryFunction0DMaterial,
|
||||
UnaryFunction0DUnsigned,
|
||||
UnaryFunction0DVec2f,
|
||||
UnaryFunction0DVec3f,
|
||||
UnaryFunction0DVectorViewShape,
|
||||
UnaryFunction0DViewShape,
|
||||
UnaryFunction1D,
|
||||
UnaryFunction1DDouble,
|
||||
UnaryFunction1DEdgeNature,
|
||||
UnaryFunction1DFloat,
|
||||
UnaryFunction1DUnsigned,
|
||||
UnaryFunction1DVec2f,
|
||||
UnaryFunction1DVec3f,
|
||||
UnaryFunction1DVectorViewShape,
|
||||
UnaryFunction1DVoid,
|
||||
UnaryPredicate0D,
|
||||
UnaryPredicate1D,
|
||||
ViewEdge,
|
||||
ViewEdgeIterator,
|
||||
ViewMap,
|
||||
ViewShape,
|
||||
ViewVertex,
|
||||
orientedViewEdgeIterator,
|
||||
)
|
24
release/scripts/freestyle/modules/freestyle/utils.py
Normal file
24
release/scripts/freestyle/modules/freestyle/utils.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# module members
|
||||
from _freestyle import (
|
||||
ContextFunctions,
|
||||
getCurrentScene,
|
||||
integrate,
|
||||
)
|
@@ -26,6 +26,8 @@ import math
|
||||
import mathutils
|
||||
import time
|
||||
|
||||
from _freestyle import blendRamp, evaluateColorRamp, evaluateCurveMappingF
|
||||
|
||||
from ChainingIterators import pySketchyChainSilhouetteIterator, pySketchyChainingIterator
|
||||
from freestyle import BackboneStretcherShader, BezierCurveShader, BinaryPredicate1D, ChainPredicateIterator, \
|
||||
ChainSilhouetteIterator, ConstantColorShader, ContourUP1D, Curvature2DAngleF0D, ExternalContourUP1D, \
|
@@ -1,713 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# Filename : ChainingIterators.py
|
||||
# Author : Stephane Grabli
|
||||
# Date : 04/08/2005
|
||||
# Purpose : Chaining Iterators to be used with chaining operators
|
||||
|
||||
from freestyle import AdjacencyIterator, ChainingIterator, ExternalContourUP1D, Nature, TVertex
|
||||
from freestyle 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):
|
||||
def __init__(self, stayInSelection=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, True, None, True)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
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.object
|
||||
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=True, stayInUnvisited=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, stayInUnvisited, None, True)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
ve = it.object
|
||||
if ve.id == self.current_edge.id:
|
||||
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, False, True, None, True)
|
||||
self._isExternalContour = ExternalContourUP1D()
|
||||
def init(self):
|
||||
self._nEdges = 0
|
||||
self._isInSelection = 1
|
||||
def checkViewEdge(self, ve, orientation):
|
||||
if orientation != 0:
|
||||
vertex = ve.second_svertex()
|
||||
else:
|
||||
vertex = ve.first_svertex()
|
||||
it = AdjacencyIterator(vertex,1,1)
|
||||
while not it.is_end:
|
||||
ave = it.object
|
||||
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 not it.is_end:
|
||||
ve = it.object
|
||||
if self._isExternalContour(ve):
|
||||
if ve.time_stamp == CF.get_time_stamp():
|
||||
winner = ve
|
||||
it.increment()
|
||||
|
||||
self._nEdges = self._nEdges+1
|
||||
if winner is None:
|
||||
orient = 1
|
||||
it = AdjacencyIterator(iter)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if it.is_incoming:
|
||||
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=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, False, None, True)
|
||||
self._timeStamp = CF.get_time_stamp()+nRounds
|
||||
self._nRounds = nRounds
|
||||
def init(self):
|
||||
self._timeStamp = CF.get_time_stamp()+self._nRounds
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
ve = it.object
|
||||
if ve.id == self.current_edge.id:
|
||||
it.increment()
|
||||
continue
|
||||
if (oNature & natures[i]) != 0:
|
||||
if (natures[i] != oNature) != 0:
|
||||
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 is None:
|
||||
winner = self.current_edge
|
||||
if winner.chaining_time_stamp == 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=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, False, None, True)
|
||||
self._timeStamp = CF.get_time_stamp()+nRounds
|
||||
self._nRounds = nRounds
|
||||
def init(self):
|
||||
self._timeStamp = CF.get_time_stamp()+self._nRounds
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
found = False
|
||||
it = AdjacencyIterator(iter)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == self.current_edge.id:
|
||||
found = True
|
||||
it.increment()
|
||||
continue
|
||||
winner = ve
|
||||
it.increment()
|
||||
if not found:
|
||||
# This is a fatal error condition: self.current_edge must be found
|
||||
# among the edges seen by the AdjacencyIterator [bug #35695].
|
||||
if bpy.app.debug_freestyle:
|
||||
print('pySketchyChainingIterator: current edge not found')
|
||||
return None
|
||||
if winner is None:
|
||||
winner = self.current_edge
|
||||
if winner.chaining_time_stamp == 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, 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:
|
||||
self._length = 0
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.time_stamp != CF.get_time_stamp():
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# 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.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
_it.init()
|
||||
while not _it.is_end:
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_it.increment()
|
||||
if _it.is_begin:
|
||||
break;
|
||||
_it.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
if not _it.is_begin:
|
||||
_it.decrement()
|
||||
while (not _it.is_end) and (not _it.is_begin):
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_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.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while _cit.is_end == 0 and _cit.object.time_stamp != CF.get_time_stamp():
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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, False, True, None, True)
|
||||
self._length = float(length)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.time_stamp != CF.get_time_stamp():
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# nw let's compute the length of this connex non selected part:
|
||||
connexl = 0
|
||||
_cit = pyChainSilhouetteGenericIterator(0,0)
|
||||
_cit.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while _cit.is_end == 0 and _cit.object.time_stamp != CF.get_time_stamp():
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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, 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:
|
||||
self._length = 0
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.time_stamp != CF.get_time_stamp():
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# 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.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
_it.init()
|
||||
while not _it.is_end:
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_it.increment()
|
||||
if _it.is_begin:
|
||||
break;
|
||||
_it.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
if not _it.is_begin:
|
||||
_it.decrement()
|
||||
while (not _it.is_end) and (not _it.is_begin):
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_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.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while _cit.is_end == 0 and _cit.object.time_stamp != CF.get_time_stamp():
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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, 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:
|
||||
self._length = 0
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
winnerOrientation = 0
|
||||
#print(self.current_edge.id.first, self.current_edge.id.second)
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if ve.id == mateVE.id:
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
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.current_edge.nature & nat) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
if (ve.nature & nat) != 0:
|
||||
count = count+1
|
||||
winner = ve
|
||||
if not it.is_incoming:
|
||||
winnerOrientation = 1
|
||||
else:
|
||||
winnerOrientation = 0
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
if winner is not None:
|
||||
# check whether this edge was part of the selection
|
||||
if winner.qi != 0:
|
||||
#print("---", winner.id.first, winner.id.second)
|
||||
# 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.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
_it.init()
|
||||
while not _it.is_end:
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_it.increment()
|
||||
if _it.is_begin:
|
||||
break;
|
||||
_it.begin = winner
|
||||
_it.current_edge = winner
|
||||
_it.orientation = winnerOrientation
|
||||
if not _it.is_begin:
|
||||
_it.decrement()
|
||||
while (not _it.is_end) and (not _it.is_begin):
|
||||
ve = _it.object
|
||||
#print("--------", ve.id.first, ve.id.second)
|
||||
self._length = self._length + ve.length_2d
|
||||
_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.begin = winner
|
||||
_cit.current_edge = winner
|
||||
_cit.orientation = winnerOrientation
|
||||
_cit.init()
|
||||
while not _cit.is_end and _cit.object.qi != 0:
|
||||
ve = _cit.object
|
||||
#print("-------- --------", ve.id.first, ve.id.second)
|
||||
connexl = connexl + ve.length_2d
|
||||
_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=True):
|
||||
ChainingIterator.__init__(self, stayInSelection, True, None, True)
|
||||
def init(self):
|
||||
pass
|
||||
def traverse(self, iter):
|
||||
winner = None
|
||||
it = AdjacencyIterator(iter)
|
||||
tvertex = self.next_vertex
|
||||
if type(tvertex) is TVertex:
|
||||
mateVE = tvertex.get_mate(self.current_edge)
|
||||
while not it.is_end:
|
||||
ve = it.object
|
||||
feB = self.current_edge.last_fedge
|
||||
feA = ve.first_fedge
|
||||
vB = feB.second_svertex
|
||||
vA = feA.first_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
winner = ve
|
||||
break
|
||||
feA = self.current_edge.first_fedge
|
||||
feB = ve.last_fedge
|
||||
vB = feB.second_svertex
|
||||
vA = feA.first_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
winner = ve
|
||||
break
|
||||
feA = self.current_edge.last_fedge
|
||||
feB = ve.last_fedge
|
||||
vB = feB.second_svertex
|
||||
vA = feA.second_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
winner = ve
|
||||
break
|
||||
feA = self.current_edge.first_fedge
|
||||
feB = ve.first_fedge
|
||||
vB = feB.first_svertex
|
||||
vA = feA.first_svertex
|
||||
if vA.id.first == vB.id.first:
|
||||
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.current_edge.nature
|
||||
if (natures[i] & currentNature) != 0:
|
||||
count=0
|
||||
while not it.is_end:
|
||||
visitNext = 0
|
||||
oNature = it.object.nature
|
||||
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.object
|
||||
it.increment()
|
||||
if count != 1:
|
||||
winner = None
|
||||
break
|
||||
return winner
|
||||
|
@@ -1,105 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# Filename : Functions0D.py
|
||||
# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin
|
||||
# Date : 30/06/2005
|
||||
# Purpose : Functions (functors) to be used for 0D elements
|
||||
|
||||
from freestyle import Curvature2DAngleF0D, CurvePoint, ReadCompleteViewMapPixelF0D, \
|
||||
ReadSteerableViewMapPixelF0D, UnaryFunction0DDouble, UnaryFunction0DMaterial, \
|
||||
UnaryFunction0DVec2f
|
||||
from freestyle import ContextFunctions as CF
|
||||
|
||||
import math
|
||||
import mathutils
|
||||
|
||||
class CurveMaterialF0D(UnaryFunction0DMaterial):
|
||||
# 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))
|
||||
fe = cp.first_svertex.get_fedge(cp.second_svertex)
|
||||
assert(fe is not None)
|
||||
return fe.material if fe.is_smooth else fe.material_left
|
||||
|
||||
class pyInverseCurvature2DAngleF0D(UnaryFunction0DDouble):
|
||||
def __call__(self, inter):
|
||||
func = Curvature2DAngleF0D()
|
||||
c = func(inter)
|
||||
return (3.1415 - c)
|
||||
|
||||
class pyCurvilinearLengthF0D(UnaryFunction0DDouble):
|
||||
def __call__(self, inter):
|
||||
cp = inter.object
|
||||
assert(isinstance(cp, CurvePoint))
|
||||
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 __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 = math.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])
|
||||
|
||||
class pyViewMapGradientNormF0D(UnaryFunction0DDouble):
|
||||
def __init__(self, l):
|
||||
UnaryFunction0DDouble.__init__(self)
|
||||
self._l = l
|
||||
self._step = math.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])
|
||||
return grad.length
|
@@ -1,58 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# Filename : Functions1D.py
|
||||
# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin
|
||||
# Date : 08/04/2005
|
||||
# Purpose : Functions (functors) to be used for 1D elements
|
||||
|
||||
from freestyle import GetProjectedZF1D, IntegrationType, UnaryFunction1DDouble, integrate
|
||||
from Functions0D import pyDensityAnisotropyF0D, pyViewMapGradientNormF0D
|
||||
import string
|
||||
|
||||
class pyGetInverseProjectedZF1D(UnaryFunction1DDouble):
|
||||
def __call__(self, inter):
|
||||
func = GetProjectedZF1D()
|
||||
z = func(inter)
|
||||
return (1.0 - z)
|
||||
|
||||
class pyGetSquareInverseProjectedZF1D(UnaryFunction1DDouble):
|
||||
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 __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 __call__(self, inter):
|
||||
v = integrate(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration)
|
||||
return v
|
@@ -1,73 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# Filename : PredicatesB1D.py
|
||||
# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin
|
||||
# Date : 08/04/2005
|
||||
# Purpose : Binary predicates (functors) to be used for 1D elements
|
||||
|
||||
from freestyle import BinaryPredicate1D, GetZF1D, IntegrationType, Nature, SameShapeIdBP1D, ZDiscontinuityF1D
|
||||
from Functions1D import pyViewMapGradientNormF1D
|
||||
|
||||
import random
|
||||
|
||||
class pyZBP1D(BinaryPredicate1D):
|
||||
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 __call__(self, i1, i2):
|
||||
return (self._GetZDiscontinuity(i1) > self._GetZDiscontinuity(i2))
|
||||
|
||||
class pyLengthBP1D(BinaryPredicate1D):
|
||||
def __call__(self, i1, i2):
|
||||
return (i1.length_2d > i2.length_2d)
|
||||
|
||||
class pySilhouetteFirstBP1D(BinaryPredicate1D):
|
||||
def __call__(self, inter1, inter2):
|
||||
bpred = SameShapeIdBP1D()
|
||||
if (bpred(inter1, inter2) != 1):
|
||||
return 0
|
||||
if (inter1.nature & Nature.SILHOUETTE):
|
||||
return (inter2.nature & Nature.SILHOUETTE) != 0
|
||||
return (inter1.nature == inter2.nature)
|
||||
|
||||
class pyNatureBP1D(BinaryPredicate1D):
|
||||
def __call__(self, inter1, inter2):
|
||||
return (inter1.nature & inter2.nature)
|
||||
|
||||
class pyViewMapGradientNormBP1D(BinaryPredicate1D):
|
||||
def __init__(self,l, sampling=2.0):
|
||||
BinaryPredicate1D.__init__(self)
|
||||
self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN)
|
||||
def __call__(self, i1,i2):
|
||||
#print("compare gradient")
|
||||
return (self._GetGradient(i1) > self._GetGradient(i2))
|
||||
|
||||
class pyShuffleBP1D(BinaryPredicate1D):
|
||||
def __init__(self):
|
||||
BinaryPredicate1D.__init__(self)
|
||||
random.seed(1)
|
||||
def __call__(self, inter1, inter2):
|
||||
r1 = random.uniform(0,1)
|
||||
r2 = random.uniform(0,1)
|
||||
return (r1<r2)
|
@@ -1,96 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# Filename : PredicatesU0D.py
|
||||
# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin
|
||||
# Date : 08/04/2005
|
||||
# Purpose : Unary predicates (functors) to be used for 0D elements
|
||||
|
||||
from freestyle import Curvature2DAngleF0D, Nature, QuantitativeInvisibilityF0D, UnaryPredicate0D
|
||||
from Functions0D import pyCurvilinearLengthF0D
|
||||
|
||||
class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D):
|
||||
def __init__(self,a):
|
||||
UnaryPredicate0D.__init__(self)
|
||||
self._a = a
|
||||
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 __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 __call__(self, inter):
|
||||
v = inter.object
|
||||
return (v.nature & self._nature) != 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 __call__(self, iter):
|
||||
if (iter.object.nature & Nature.T_VERTEX) == 0:
|
||||
return 0
|
||||
if iter.is_end:
|
||||
return 0
|
||||
if self._getQI(iter) != 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 __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 __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
|
@@ -1,342 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# Filename : PredicatesU1D.py
|
||||
# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin
|
||||
# Date : 08/04/2005
|
||||
# Purpose : Unary predicates (functors) to be used for 1D elements
|
||||
|
||||
from freestyle import Curvature2DAngleF0D, CurveNatureF1D, DensityF1D, GetCompleteViewMapDensityF1D, \
|
||||
GetDirectionalViewMapDensityF1D, GetOccludersF1D, GetProjectedZF1D, GetShapeF1D, GetSteerableViewMapDensityF1D, \
|
||||
IntegrationType, ShapeUP1D, TVertex, UnaryPredicate1D
|
||||
from Functions1D import pyDensityAnisotropyF1D, pyViewMapGradientNormF1D
|
||||
|
||||
class pyNFirstUP1D(UnaryPredicate1D):
|
||||
def __init__(self, n):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self.__n = n
|
||||
self.__count = 0
|
||||
def __call__(self, inter):
|
||||
self.__count = self.__count + 1
|
||||
if self.__count <= self.__n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class pyHigherLengthUP1D(UnaryPredicate1D):
|
||||
def __init__(self,l):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._l = l
|
||||
def __call__(self, inter):
|
||||
return (inter.length_2d > self._l)
|
||||
|
||||
class pyNatureUP1D(UnaryPredicate1D):
|
||||
def __init__(self,nature):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._nature = nature
|
||||
self._getNature = CurveNatureF1D()
|
||||
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 __call__(self, inter):
|
||||
count = 0
|
||||
func = Curvature2DAngleF0D()
|
||||
it = inter.vertices_begin()
|
||||
while not it.is_end:
|
||||
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 __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 __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 __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 __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 __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 __call__(self, inter):
|
||||
#print("toto")
|
||||
#print(func.name)
|
||||
#print(inter.name)
|
||||
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 __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 __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 __call__(self, inter):
|
||||
func = GetShapeF1D()
|
||||
shapes = func(inter)
|
||||
for s in shapes:
|
||||
if(s.id == self._id):
|
||||
return 0
|
||||
it = inter.vertices_begin()
|
||||
itlast = inter.vertices_end()
|
||||
itlast.decrement()
|
||||
v = it.object
|
||||
vlast = itlast.object
|
||||
tvertex = v.viewvertex
|
||||
if type(tvertex) is TVertex:
|
||||
#print("TVertex: [ ", tvertex.id.first, ",", tvertex.id.second," ]")
|
||||
eit = tvertex.edges_begin()
|
||||
while not eit.is_end:
|
||||
ve, incoming = eit.object
|
||||
if ve.id == self._id:
|
||||
return 1
|
||||
#print("-------", ve.id.first, "-", ve.id.second)
|
||||
eit.increment()
|
||||
tvertex = vlast.viewvertex
|
||||
if type(tvertex) is TVertex:
|
||||
#print("TVertex: [ ", tvertex.id.first, ",", tvertex.id.second," ]")
|
||||
eit = tvertex.edges_begin()
|
||||
while not eit.is_end:
|
||||
ve, incoming = eit.object
|
||||
if ve.id == self._id:
|
||||
return 1
|
||||
#print("-------", ve.id.first, "-", ve.id.second)
|
||||
eit.increment()
|
||||
return 0
|
||||
|
||||
class pyIsInOccludersListUP1D(UnaryPredicate1D):
|
||||
def __init__(self,id):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._id = id
|
||||
def __call__(self, inter):
|
||||
func = GetOccludersF1D()
|
||||
occluders = func(inter)
|
||||
for a in occluders:
|
||||
if a.id == self._id:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class pyIsOccludedByItselfUP1D(UnaryPredicate1D):
|
||||
def __init__(self):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self.__func1 = GetOccludersF1D()
|
||||
self.__func2 = GetShapeF1D()
|
||||
def __call__(self, inter):
|
||||
lst1 = self.__func1(inter)
|
||||
lst2 = self.__func2(inter)
|
||||
for vs1 in lst1:
|
||||
for vs2 in lst2:
|
||||
if vs1.id == vs2.id:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class pyIsOccludedByIdListUP1D(UnaryPredicate1D):
|
||||
def __init__(self, idlist):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._idlist = idlist
|
||||
self.__func1 = GetOccludersF1D()
|
||||
def __call__(self, inter):
|
||||
lst1 = self.__func1(inter)
|
||||
for vs1 in lst1:
|
||||
for _id in self._idlist:
|
||||
if vs1.id == _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.first, _id.second))
|
||||
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 __call__(self, inter):
|
||||
func = GetShapeF1D()
|
||||
shapes = func(inter)
|
||||
for a in shapes:
|
||||
if a.id == 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 __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 __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 __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.vertices_begin()
|
||||
itlast = inter.vertices_end()
|
||||
itlast.decrement()
|
||||
vlast = itlast.object
|
||||
v = it.object
|
||||
#print(v.id.first, v.id.second)
|
||||
#print(vlast.id.first, vlast.id.second)
|
||||
if v.id == vlast.id:
|
||||
return 1
|
||||
return 0
|
@@ -1,47 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# Filename : logical_operators.py
|
||||
# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin
|
||||
# Date : 08/04/2005
|
||||
# Purpose : Logical unary predicates (functors) for 1D elements
|
||||
|
||||
from freestyle import UnaryPredicate1D
|
||||
|
||||
class AndUP1D(UnaryPredicate1D):
|
||||
def __init__(self, pred1, pred2):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self.__pred1 = pred1
|
||||
self.__pred2 = pred2
|
||||
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 __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 __call__(self, inter):
|
||||
return not self.__pred(inter)
|
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ void Path::setRootDir(const string& iRootDir)
|
||||
string(DIR_SEP.c_str()) + "variation_patterns" + string(DIR_SEP.c_str());
|
||||
_BrushesPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "textures" +
|
||||
string(DIR_SEP.c_str()) + "brushes" + string(DIR_SEP.c_str());
|
||||
_PythonPath = _ProjectDir + string(DIR_SEP.c_str()) + "style_modules" + string(DIR_SEP.c_str());
|
||||
_PythonPath = _ProjectDir + string(DIR_SEP.c_str()) + "modules" + string(DIR_SEP.c_str());
|
||||
if (getenv("PYTHONPATH")) {
|
||||
_PythonPath += string(PATH_SEP.c_str()) + string(getenv("PYTHONPATH"));
|
||||
}
|
||||
|
@@ -469,7 +469,7 @@ static PyMethodDef module_functions[] = {
|
||||
|
||||
static PyModuleDef module_definition = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"freestyle",
|
||||
"_freestyle",
|
||||
module_docstring,
|
||||
-1,
|
||||
module_functions
|
||||
|
Reference in New Issue
Block a user