blender/release/scripts/freestyle/style_modules/shaders.py
Tamito Kajiyama 731d08d497 Freestyle Python API improvements - part 3.
Major API updates were made to address code review comments.
This revision mostly focuses on Python wrappers of C++ 0D and 1D elements (i.e.,
Interface0D and Interface1D, as well as their subclasses).

* Most getter/setter methods were reimplemented as attributes using PyGetSetDef.
Vector attributes are now implemented based on mathutils callbacks.  Boolean
attributes now only accept boolean values.

* The __getitem__ method was removed and the Sequence protocol was used instead.

* The naming of methods and attributes was fixed to follow the naming conventions
of the Blender Python API (i.e., lower case + underscores for methods and attributes,
and CamelCase for classes).  Some naming inconsistency within the Freestyle Python
API was also addressed.

* The Freestyle API had a number of method names including prefix/suffix "A" and
"B", and their meanings were inconsistent (i.e., referring to different things
depending on the classes).  The names with these two letters were replaced with
more straightforward names.  Also some attribute names were changed so as to indicate
the type of the value (e.g., FEdge.next_fedge instead of FEdge.next_edge) in line
with other names explicitly indicating what the value is (e.g., SVertex.viewvertex).

* In addition, some code clean-up was done in both C++ and Python.

Notes:

In summary, the following irregular naming changes were made through this revision
(those resulting from regular changes of naming conventions are not listed):

- CurvePoint: {A,B} --> {first,second}_svertex
- FEdge: vertex{A,B} --> {first,second}_svertex
- FEdge: {next,previous}Edge --> {next,previous}_fedge
- FEdgeSharp: normal{A,B} --> normal_{right,left}
- FEdgeSharp: {a,b}FaceMark --> face_mark_{right,left}
- FEdgeSharp: {a,b}Material --> material_{right,left}
- FEdgeSharp: {a,b}MaterialIndex --> material_index_{right,left}
- FrsCurve: empty --> is_empty
- FrsCurve: nSegments --> segments_size
- TVertex: mate() --> get_mate()
- ViewEdge: fedge{A,B} --> {first,last}_fedge
- ViewEdge: setaShape, aShape --> occlude
- ViewEdge: {A,B} --> {first,last}_viewvertex
- ViewMap: getScene3dBBox --> scene_bbox
2013-02-14 23:48:34 +00:00

1299 lines
38 KiB
Python

from freestyle_init import *
from PredicatesU0D import *
from PredicatesB1D import *
from PredicatesU1D import *
from logical_operators import *
from ChainingIterators import *
from random import *
from math import *
## thickness modifiers
######################
class pyDepthDiscontinuityThicknessShader(StrokeShader):
def __init__(self, min, max):
StrokeShader.__init__(self)
self.__min = float(min)
self.__max = float(max)
self.__func = ZDiscontinuityF0D()
def getName(self):
return "pyDepthDiscontinuityThicknessShader"
def shade(self, stroke):
z_min=0.0
z_max=1.0
a = (self.__max - self.__min)/(z_max-z_min)
b = (self.__min*z_max-self.__max*z_min)/(z_max-z_min)
it = stroke.stroke_vertices_begin()
while not it.isEnd():
z = self.__func(it.castToInterface0DIterator())
thickness = a*z+b
it.getObject().attribute.thickness = (thickness, thickness)
it.increment()
class pyConstantThicknessShader(StrokeShader):
def __init__(self, thickness):
StrokeShader.__init__(self)
self._thickness = thickness
def getName(self):
return "pyConstantThicknessShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
t = self._thickness/2.0
it.getObject().attribute.thickness = (t, t)
it.increment()
class pyFXSThicknessShader(StrokeShader):
def __init__(self, thickness):
StrokeShader.__init__(self)
self._thickness = thickness
def getName(self):
return "pyFXSThicknessShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
t = self._thickness/2.0
it.getObject().attribute.thickness = (t, t)
it.increment()
class pyFXSVaryingThicknessWithDensityShader(StrokeShader):
def __init__(self, wsize, threshold_min, threshold_max, thicknessMin, thicknessMax):
StrokeShader.__init__(self)
self.wsize= wsize
self.threshold_min= threshold_min
self.threshold_max= threshold_max
self._thicknessMin = thicknessMin
self._thicknessMax = thicknessMax
def getName(self):
return "pyVaryingThicknessWithDensityShader"
def shade(self, stroke):
n = stroke.stroke_vertices_size()
i = 0
it = stroke.stroke_vertices_begin()
func = DensityF0D(self.wsize)
while not it.isEnd():
toto = it.castToInterface0DIterator()
c= func(toto)
if c < self.threshold_min:
c = self.threshold_min
if c > self.threshold_max:
c = self.threshold_max
## t = (c - self.threshold_min)/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin
t = (self.threshold_max - c )/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin
it.getObject().attribute.thickness = (t/2.0, t/2.0)
i = i+1
it.increment()
class pyIncreasingThicknessShader(StrokeShader):
def __init__(self, thicknessMin, thicknessMax):
StrokeShader.__init__(self)
self._thicknessMin = thicknessMin
self._thicknessMax = thicknessMax
def getName(self):
return "pyIncreasingThicknessShader"
def shade(self, stroke):
n = stroke.stroke_vertices_size()
i = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
c = float(i)/float(n)
if i < float(n)/2.0:
t = (1.0 - c)*self._thicknessMin + c * self._thicknessMax
else:
t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin
it.getObject().attribute.thickness = (t/2.0, t/2.0)
i = i+1
it.increment()
class pyConstrainedIncreasingThicknessShader(StrokeShader):
def __init__(self, thicknessMin, thicknessMax, ratio):
StrokeShader.__init__(self)
self._thicknessMin = thicknessMin
self._thicknessMax = thicknessMax
self._ratio = ratio
def getName(self):
return "pyConstrainedIncreasingThicknessShader"
def shade(self, stroke):
slength = stroke.length_2d
tmp = self._ratio*slength
maxT = 0.0
if tmp < self._thicknessMax:
maxT = tmp
else:
maxT = self._thicknessMax
n = stroke.stroke_vertices_size()
i = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
att = it.getObject().attribute
c = float(i)/float(n)
if i < float(n)/2.0:
t = (1.0 - c)*self._thicknessMin + c * maxT
else:
t = (1.0 - c)*maxT + c * self._thicknessMin
att.thickness = (t/2.0, t/2.0)
if i == n-1:
att.thickness = (self._thicknessMin/2.0, self._thicknessMin/2.0)
i = i+1
it.increment()
class pyDecreasingThicknessShader(StrokeShader):
def __init__(self, thicknessMax, thicknessMin):
StrokeShader.__init__(self)
self._thicknessMin = thicknessMin
self._thicknessMax = thicknessMax
def getName(self):
return "pyDecreasingThicknessShader"
def shade(self, stroke):
l = stroke.length_2d
tMax = self._thicknessMax
if self._thicknessMax > 0.33*l:
tMax = 0.33*l
tMin = self._thicknessMin
if self._thicknessMin > 0.1*l:
tMin = 0.1*l
n = stroke.stroke_vertices_size()
i = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
c = float(i)/float(n)
t = (1.0 - c)*tMax +c*tMin
it.getObject().attribute.thickness = (t/2.0, t/2.0)
i = i+1
it.increment()
def smoothC(a, exp):
c = pow(float(a),exp)*pow(2.0,exp)
return c
class pyNonLinearVaryingThicknessShader(StrokeShader):
def __init__(self, thicknessExtremity, thicknessMiddle, exponent):
StrokeShader.__init__(self)
self._thicknessMin = thicknessMiddle
self._thicknessMax = thicknessExtremity
self._exponent = exponent
def getName(self):
return "pyNonLinearVaryingThicknessShader"
def shade(self, stroke):
n = stroke.stroke_vertices_size()
i = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
if i < float(n)/2.0:
c = float(i)/float(n)
else:
c = float(n-i)/float(n)
c = smoothC(c, self._exponent)
t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin
it.getObject().attribute.thickness = (t/2.0, t/2.0)
i = i+1
it.increment()
## Spherical linear interpolation (cos)
class pySLERPThicknessShader(StrokeShader):
def __init__(self, thicknessMin, thicknessMax, omega=1.2):
StrokeShader.__init__(self)
self._thicknessMin = thicknessMin
self._thicknessMax = thicknessMax
self._omega = omega
def getName(self):
return "pySLERPThicknessShader"
def shade(self, stroke):
slength = stroke.length_2d
tmp = 0.33*slength
maxT = self._thicknessMax
if tmp < self._thicknessMax:
maxT = tmp
n = stroke.stroke_vertices_size()
i = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
c = float(i)/float(n)
if i < float(n)/2.0:
t = sin((1-c)*self._omega)/sinh(self._omega)*self._thicknessMin + sin(c*self._omega)/sinh(self._omega) * maxT
else:
t = sin((1-c)*self._omega)/sinh(self._omega)*maxT + sin(c*self._omega)/sinh(self._omega) * self._thicknessMin
it.getObject().attribute.thickness = (t/2.0, t/2.0)
i = i+1
it.increment()
class pyTVertexThickenerShader(StrokeShader): ## FIXME
def __init__(self, a=1.5, n=3):
StrokeShader.__init__(self)
self._a = a
self._n = n
def getName(self):
return "pyTVertexThickenerShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX)
while not it.isEnd():
if predTVertex(it) == 1:
it2 = StrokeVertexIterator(it)
it2.increment()
if not (it.isBegin() or it2.isEnd()):
it.increment()
continue
n = self._n
a = self._a
if it.isBegin():
it3 = StrokeVertexIterator(it)
count = 0
while (not it3.isEnd()) and count < n:
att = it3.getObject().attribute
(tr, tl) = att.thickness
r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
#r = (1.0-a)/float(n-1)*count + a
att.thickness = (r*tr, r*tl)
it3.increment()
count = count + 1
if it2.isEnd():
it4 = StrokeVertexIterator(it)
count = 0
while (not it4.isBegin()) and count < n:
att = it4.getObject().attribute
(tr, tl) = att.thickness
r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
#r = (1.0-a)/float(n-1)*count + a
att.thickness = (r*tr, r*tl)
it4.decrement()
count = count + 1
if it4.isBegin():
att = it4.getObject().attribute
(tr, tl) = att.thickness
r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
#r = (1.0-a)/float(n-1)*count + a
att.thickness = (r*tr, r*tl)
it.increment()
class pyImportance2DThicknessShader(StrokeShader):
def __init__(self, x, y, w, kmin, kmax):
StrokeShader.__init__(self)
self._x = x
self._y = y
self._w = float(w)
self._kmin = float(kmin)
self._kmax = float(kmax)
def getName(self):
return "pyImportanceThicknessShader"
def shade(self, stroke):
origin = Vector([self._x, self._y])
it = stroke.stroke_vertices_begin()
while not it.isEnd():
v = it.getObject()
p = Vector([v.projected_x, v.projected_y])
d = (p-origin).length
if d > self._w:
k = self._kmin
else:
k = (self._kmax*(self._w-d) + self._kmin*d)/self._w
att = v.attribute
(tr, tl) = att.thickness
att.thickness = (k*tr/2.0, k*tl/2.0)
it.increment()
class pyImportance3DThicknessShader(StrokeShader):
def __init__(self, x, y, z, w, kmin, kmax):
StrokeShader.__init__(self)
self._x = x
self._y = y
self._z = z
self._w = float(w)
self._kmin = float(kmin)
self._kmax = float(kmax)
def getName(self):
return "pyImportance3DThicknessShader"
def shade(self, stroke):
origin = Vector([self._x, self._y, self._z])
it = stroke.stroke_vertices_begin()
while not it.isEnd():
v = it.getObject()
p = v.point_3d
d = (p-origin).length
if d > self._w:
k = self._kmin
else:
k = (self._kmax*(self._w-d) + self._kmin*d)/self._w
att = v.attribute
(tr, tl) = att.thickness
att.thickness = (k*tr/2.0, k*tl/2.0)
it.increment()
class pyZDependingThicknessShader(StrokeShader):
def __init__(self, min, max):
StrokeShader.__init__(self)
self.__min = min
self.__max = max
self.__func = GetProjectedZF0D()
def getName(self):
return "pyZDependingThicknessShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
z_min = 1
z_max = 0
while not it.isEnd():
z = self.__func(it.castToInterface0DIterator())
if z < z_min:
z_min = z
if z > z_max:
z_max = z
it.increment()
z_diff = 1 / (z_max - z_min)
it = stroke.stroke_vertices_begin()
while not it.isEnd():
z = (self.__func(it.castToInterface0DIterator()) - z_min) * z_diff
thickness = (1 - z) * self.__max + z * self.__min
it.getObject().attribute.thickness = (thickness, thickness)
it.increment()
## color modifiers
##################
class pyConstantColorShader(StrokeShader):
def __init__(self,r,g,b, a = 1):
StrokeShader.__init__(self)
self._r = r
self._g = g
self._b = b
self._a = a
def getName(self):
return "pyConstantColorShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
att = it.getObject().attribute
att.color = (self._r, self._g, self._b)
att.alpha = self._a
it.increment()
#c1->c2
class pyIncreasingColorShader(StrokeShader):
def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2):
StrokeShader.__init__(self)
self._c1 = [r1,g1,b1,a1]
self._c2 = [r2,g2,b2,a2]
def getName(self):
return "pyIncreasingColorShader"
def shade(self, stroke):
n = stroke.stroke_vertices_size() - 1
inc = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
att = it.getObject().attribute
c = float(inc)/float(n)
att.color = ((1-c)*self._c1[0] + c*self._c2[0],
(1-c)*self._c1[1] + c*self._c2[1],
(1-c)*self._c1[2] + c*self._c2[2])
att.alpha = (1-c)*self._c1[3] + c*self._c2[3]
inc = inc+1
it.increment()
# c1->c2->c1
class pyInterpolateColorShader(StrokeShader):
def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2):
StrokeShader.__init__(self)
self._c1 = [r1,g1,b1,a1]
self._c2 = [r2,g2,b2,a2]
def getName(self):
return "pyInterpolateColorShader"
def shade(self, stroke):
n = stroke.stroke_vertices_size() - 1
inc = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
att = it.getObject().attribute
u = float(inc)/float(n)
c = 1-2*(fabs(u-0.5))
att.color = ((1-c)*self._c1[0] + c*self._c2[0],
(1-c)*self._c1[1] + c*self._c2[1],
(1-c)*self._c1[2] + c*self._c2[2])
att.alpha = (1-c)*self._c1[3] + c*self._c2[3]
inc = inc+1
it.increment()
class pyMaterialColorShader(StrokeShader):
def __init__(self, threshold=50):
StrokeShader.__init__(self)
self._threshold = threshold
def getName(self):
return "pyMaterialColorShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
func = MaterialF0D()
xn = 0.312713
yn = 0.329016
Yn = 1.0
un = 4.* xn/ ( -2.*xn + 12.*yn + 3. )
vn= 9.* yn/ ( -2.*xn + 12.*yn +3. )
while not it.isEnd():
toto = it.castToInterface0DIterator()
mat = func(toto)
r = mat.diffuse[0]
g = mat.diffuse[1]
b = mat.diffuse[2]
X = 0.412453*r + 0.35758 *g + 0.180423*b
Y = 0.212671*r + 0.71516 *g + 0.072169*b
Z = 0.019334*r + 0.119193*g + 0.950227*b
if X == 0 and Y == 0 and Z == 0:
X = 0.01
Y = 0.01
Z = 0.01
u = 4.*X / (X + 15.*Y + 3.*Z)
v = 9.*Y / (X + 15.*Y + 3.*Z)
L= 116. * pow((Y/Yn),(1./3.)) -16
U = 13. * L * (u - un)
V = 13. * L * (v - vn)
if L > self._threshold:
L = L/1.3
U = U+10
else:
L = L +2.5*(100-L)/5.
U = U/3.0
V = V/3.0
u = U / (13. * L) + un
v = V / (13. * L) + vn
Y = Yn * pow( ((L+16.)/116.), 3.)
X = -9. * Y * u / ((u - 4.)* v - u * v)
Z = (9. * Y - 15*v*Y - v*X) /( 3. * v)
r = 3.240479 * X - 1.53715 * Y - 0.498535 * Z
g = -0.969256 * X + 1.875991 * Y + 0.041556 * Z
b = 0.055648 * X - 0.204043 * Y + 1.057311 * Z
r = max(0,r)
g = max(0,g)
b = max(0,b)
it.getObject().attribute.color = (r, g, b)
it.increment()
class pyRandomColorShader(StrokeShader):
def __init__(self, s=1):
StrokeShader.__init__(self)
seed(s)
def getName(self):
return "pyRandomColorShader"
def shade(self, stroke):
## pick a random color
c0 = float(uniform(15,75))/100.0
c1 = float(uniform(15,75))/100.0
c2 = float(uniform(15,75))/100.0
print(c0, c1, c2)
it = stroke.stroke_vertices_begin()
while not it.isEnd():
it.getObject().attribute.color = (c0,c1,c2)
it.increment()
class py2DCurvatureColorShader(StrokeShader):
def getName(self):
return "py2DCurvatureColorShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
func = Curvature2DAngleF0D()
while not it.isEnd():
c = func(it.castToInterface0DIterator())
if c < 0:
print("negative 2D curvature")
color = 10.0 * c/3.1415
it.getObject().attribute.color = (color, color, color)
it.increment()
class pyTimeColorShader(StrokeShader):
def __init__(self, step=0.01):
StrokeShader.__init__(self)
self._t = 0
self._step = step
def shade(self, stroke):
c = self._t*1.0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
it.getObject().attribute.color = (c,c,c)
it.increment()
self._t = self._t+self._step
## geometry modifiers
class pySamplingShader(StrokeShader):
def __init__(self, sampling):
StrokeShader.__init__(self)
self._sampling = sampling
def getName(self):
return "pySamplingShader"
def shade(self, stroke):
stroke.resample(float(self._sampling))
stroke.update_length()
class pyBackboneStretcherShader(StrokeShader):
def __init__(self, l):
StrokeShader.__init__(self)
self._l = l
def getName(self):
return "pyBackboneStretcherShader"
def shade(self, stroke):
it0 = stroke.stroke_vertices_begin()
it1 = StrokeVertexIterator(it0)
it1.increment()
itn = stroke.stroke_vertices_end()
itn.decrement()
itn_1 = StrokeVertexIterator(itn)
itn_1.decrement()
v0 = it0.getObject()
v1 = it1.getObject()
vn_1 = itn_1.getObject()
vn = itn.getObject()
p0 = Vector([v0.projected_x, v0.projected_y])
pn = Vector([vn.projected_x, vn.projected_y])
p1 = Vector([v1.projected_x, v1.projected_y])
pn_1 = Vector([vn_1.projected_x, vn_1.projected_y])
d1 = p0-p1
d1.normalize()
dn = pn-pn_1
dn.normalize()
newFirst = p0+d1*float(self._l)
newLast = pn+dn*float(self._l)
v0.point = newFirst
vn.point = newLast
stroke.update_length()
class pyLengthDependingBackboneStretcherShader(StrokeShader):
def __init__(self, l):
StrokeShader.__init__(self)
self._l = l
def getName(self):
return "pyBackboneStretcherShader"
def shade(self, stroke):
l = stroke.length_2d
stretch = self._l*l
it0 = stroke.stroke_vertices_begin()
it1 = StrokeVertexIterator(it0)
it1.increment()
itn = stroke.stroke_vertices_end()
itn.decrement()
itn_1 = StrokeVertexIterator(itn)
itn_1.decrement()
v0 = it0.getObject()
v1 = it1.getObject()
vn_1 = itn_1.getObject()
vn = itn.getObject()
p0 = Vector([v0.projected_x, v0.projected_y])
pn = Vector([vn.projected_x, vn.projected_y])
p1 = Vector([v1.projected_x, v1.projected_y])
pn_1 = Vector([vn_1.projected_x, vn_1.projected_y])
d1 = p0-p1
d1.normalize()
dn = pn-pn_1
dn.normalize()
newFirst = p0+d1*float(stretch)
newLast = pn+dn*float(stretch)
v0.point = newFirst
vn.point = newLast
stroke.update_length()
## Shader to replace a stroke by its corresponding tangent
class pyGuidingLineShader(StrokeShader):
def getName(self):
return "pyGuidingLineShader"
## shading method
def shade(self, stroke):
it = stroke.stroke_vertices_begin() ## get the first vertex
itlast = stroke.stroke_vertices_end() ##
itlast.decrement() ## get the last one
t = itlast.getObject().point - it.getObject().point ## tangent direction
itmiddle = StrokeVertexIterator(it) ##
while itmiddle.getObject().u < 0.5: ## look for the stroke middle vertex
itmiddle.increment() ##
it = StrokeVertexIterator(itmiddle)
it.increment()
while not it.isEnd(): ## position all the vertices along the tangent for the right part
it.getObject().point = itmiddle.getObject().point \
+t*(it.getObject().u-itmiddle.getObject().u)
it.increment()
it = StrokeVertexIterator(itmiddle)
it.decrement()
while not it.isBegin(): ## position all the vertices along the tangent for the left part
it.getObject().point = itmiddle.getObject().point \
-t*(itmiddle.getObject().u-it.getObject().u)
it.decrement()
it.getObject().point = itmiddle.getObject().point-t*itmiddle.getObject().u ## first vertex
stroke.update_length()
class pyBackboneStretcherNoCuspShader(StrokeShader):
def __init__(self, l):
StrokeShader.__init__(self)
self._l = l
def getName(self):
return "pyBackboneStretcherNoCuspShader"
def shade(self, stroke):
it0 = stroke.stroke_vertices_begin()
it1 = StrokeVertexIterator(it0)
it1.increment()
itn = stroke.stroke_vertices_end()
itn.decrement()
itn_1 = StrokeVertexIterator(itn)
itn_1.decrement()
v0 = it0.getObject()
v1 = it1.getObject()
if (v0.nature & Nature.CUSP) == 0 and (v1.nature & Nature.CUSP) == 0:
p0 = v0.point
p1 = v1.point
d1 = p0-p1
d1.normalize()
newFirst = p0+d1*float(self._l)
v0.point = newFirst
vn_1 = itn_1.getObject()
vn = itn.getObject()
if (vn.nature & Nature.CUSP) == 0 and (vn_1.nature & Nature.CUSP) == 0:
pn = vn.point
pn_1 = vn_1.point
dn = pn-pn_1
dn.normalize()
newLast = pn+dn*float(self._l)
vn.point = newLast
stroke.update_length()
class pyDiffusion2Shader(StrokeShader):
"""This shader iteratively adds an offset to the position of each
stroke vertex in the direction perpendicular to the stroke direction
at the point. The offset is scaled by the 2D curvature (i.e., how
quickly the stroke curve is) at the point."""
def __init__(self, lambda1, nbIter):
StrokeShader.__init__(self)
self._lambda = lambda1
self._nbIter = nbIter
self._normalInfo = Normal2DF0D()
self._curvatureInfo = Curvature2DAngleF0D()
def getName(self):
return "pyDiffusionShader"
def shade(self, stroke):
for i in range (1, self._nbIter):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
v = it.getObject()
p1 = v.point
p2 = self._normalInfo(it.castToInterface0DIterator())*self._lambda*self._curvatureInfo(it.castToInterface0DIterator())
v.point = p1+p2
it.increment()
stroke.update_length()
class pyTipRemoverShader(StrokeShader):
def __init__(self, l):
StrokeShader.__init__(self)
self._l = l
def getName(self):
return "pyTipRemoverShader"
def shade(self, stroke):
originalSize = stroke.stroke_vertices_size()
if originalSize < 4:
return
verticesToRemove = []
oldAttributes = []
it = stroke.stroke_vertices_begin()
while not it.isEnd():
v = it.getObject()
if v.curvilinear_abscissa < self._l or v.stroke_length-v.curvilinear_abscissa < self._l:
verticesToRemove.append(v)
oldAttributes.append(StrokeAttribute(v.attribute))
it.increment()
if originalSize-len(verticesToRemove) < 2:
return
for sv in verticesToRemove:
stroke.remove_vertex(sv)
stroke.update_length()
stroke.resample(originalSize)
if stroke.stroke_vertices_size() != originalSize:
print("pyTipRemover: Warning: resampling problem")
it = stroke.stroke_vertices_begin()
for a in oldAttributes:
if it.isEnd():
break
it.getObject().attribute = a
it.increment()
stroke.update_length()
class pyTVertexRemoverShader(StrokeShader):
def getName(self):
return "pyTVertexRemoverShader"
def shade(self, stroke):
if stroke.stroke_vertices_size() <= 3:
return
predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX)
it = stroke.stroke_vertices_begin()
itlast = stroke.stroke_vertices_end()
itlast.decrement()
if predTVertex(it):
stroke.remove_vertex(it.getObject())
if predTVertex(itlast):
stroke.remove_vertex(itlast.getObject())
stroke.update_length()
class pyExtremitiesOrientationShader(StrokeShader):
def __init__(self, x1,y1,x2=0,y2=0):
StrokeShader.__init__(self)
self._v1 = Vector([x1,y1])
self._v2 = Vector([x2,y2])
def getName(self):
return "pyExtremitiesOrientationShader"
def shade(self, stroke):
#print(self._v1.x,self._v1.y)
stroke.setBeginningOrientation(self._v1.x,self._v1.y)
stroke.setEndingOrientation(self._v2.x,self._v2.y)
def get_fedge(it1, it2):
return it1.get_fedge(it2)
class pyHLRShader(StrokeShader):
def getName(self):
return "pyHLRShader"
def shade(self, stroke):
originalSize = stroke.stroke_vertices_size()
if originalSize < 4:
return
it = stroke.stroke_vertices_begin()
invisible = 0
it2 = StrokeVertexIterator(it)
it2.increment()
fe = get_fedge(it.getObject(), it2.getObject())
if fe.viewedge.qi != 0:
invisible = 1
while not it2.isEnd():
v = it.getObject()
vnext = it2.getObject()
if (v.nature & Nature.VIEW_VERTEX) != 0:
#if (v.nature & Nature.T_VERTEX) != 0:
fe = get_fedge(v, vnext)
qi = fe.viewedge.qi
if qi != 0:
invisible = 1
else:
invisible = 0
if invisible:
v.attribute.visible = False
it.increment()
it2.increment()
class pyTVertexOrientationShader(StrokeShader):
def __init__(self):
StrokeShader.__init__(self)
self._Get2dDirection = Orientation2DF1D()
def getName(self):
return "pyTVertexOrientationShader"
## finds the TVertex orientation from the TVertex and
## the previous or next edge
def findOrientation(self, tv, ve):
mateVE = tv.get_mate(ve)
if ve.qi != 0 or mateVE.qi != 0:
ait = AdjacencyIterator(tv,1,0)
winner = None
incoming = True
while not ait.isEnd():
ave = ait.getObject()
if ave.id != ve.id and ave.id != mateVE.id:
winner = ait.getObject()
if not ait.isIncoming(): # FIXME
incoming = False
break
ait.increment()
if winner is not None:
if not incoming:
direction = self._Get2dDirection(winner.last_fedge)
else:
direction = self._Get2dDirection(winner.first_fedge)
return direction
return None
def castToTVertex(self, cp):
if cp.t2d() == 0.0:
return cp.first_svertex.viewvertex
elif cp.t2d() == 1.0:
return cp.second_svertex.viewvertex
return None
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
it2 = StrokeVertexIterator(it)
it2.increment()
## case where the first vertex is a TVertex
v = it.getObject()
if (v.nature & Nature.T_VERTEX) != 0:
tv = self.castToTVertex(v)
if tv is not None:
ve = get_fedge(v, it2.getObject()).viewedge
dir = self.findOrientation(tv, ve)
if dir is not None:
#print(dir.x, dir.y)
v.attribute.set_attribute_vec2("orientation", dir)
while not it2.isEnd():
vprevious = it.getObject()
v = it2.getObject()
if (v.nature & Nature.T_VERTEX) != 0:
tv = self.castToTVertex(v)
if tv is not None:
ve = get_fedge(vprevious, v).viewedge
dir = self.findOrientation(tv, ve)
if dir is not None:
#print(dir.x, dir.y)
v.attribute.set_attribute_vec2("orientation", dir)
it.increment()
it2.increment()
## case where the last vertex is a TVertex
v = it.getObject()
if (v.nature & Nature.T_VERTEX) != 0:
itPrevious = StrokeVertexIterator(it)
itPrevious.decrement()
tv = self.castToTVertex(v)
if tv is not None:
ve = get_fedge(itPrevious.getObject(), v).viewedge
dir = self.findOrientation(tv, ve)
if dir is not None:
#print(dir.x, dir.y)
v.attribute.set_attribute_vec2("orientation", dir)
class pySinusDisplacementShader(StrokeShader):
def __init__(self, f, a):
StrokeShader.__init__(self)
self._f = f
self._a = a
self._getNormal = Normal2DF0D()
def getName(self):
return "pySinusDisplacementShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
v = it.getObject()
#print(self._getNormal.getName())
n = self._getNormal(it.castToInterface0DIterator())
p = v.point
u = v.u
a = self._a*(1-2*(fabs(u-0.5)))
n = n*a*cos(self._f*u*6.28)
#print(n.x, n.y)
v.point = p+n
#v.point = v.point+n*a*cos(f*v.u)
it.increment()
stroke.update_length()
class pyPerlinNoise1DShader(StrokeShader):
def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1):
StrokeShader.__init__(self)
self.__noise = Noise(seed)
self.__freq = freq
self.__amp = amp
self.__oct = oct
def getName(self):
return "pyPerlinNoise1DShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
v = it.getObject()
i = v.projected_x + v.projected_y
nres = self.__noise.turbulence1(i, self.__freq, self.__amp, self.__oct)
v.point = (v.projected_x + nres, v.projected_y + nres)
it.increment()
stroke.update_length()
class pyPerlinNoise2DShader(StrokeShader):
def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1):
StrokeShader.__init__(self)
self.__noise = Noise(seed)
self.__freq = freq
self.__amp = amp
self.__oct = oct
def getName(self):
return "pyPerlinNoise2DShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
v = it.getObject()
vec = Vector([v.projected_x, v.projected_y])
nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct)
v.point = (v.projected_x + nres, v.projected_y + nres)
it.increment()
stroke.update_length()
class pyBluePrintCirclesShader(StrokeShader):
def __init__(self, turns = 1, random_radius = 3, random_center = 5):
StrokeShader.__init__(self)
self.__turns = turns
self.__random_center = random_center
self.__random_radius = random_radius
def getName(self):
return "pyBluePrintCirclesShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
if it.isEnd():
return
p_min = it.getObject().point.copy()
p_max = it.getObject().point.copy()
while not it.isEnd():
p = it.getObject().point
if p.x < p_min.x:
p_min.x = p.x
if p.x > p_max.x:
p_max.x = p.x
if p.y < p_min.y:
p_min.y = p.y
if p.y > p_max.y:
p_max.y = p.y
it.increment()
stroke.resample(32 * self.__turns)
sv_nb = stroke.stroke_vertices_size()
# print("min :", p_min.x, p_min.y) # DEBUG
# print("mean :", p_sum.x, p_sum.y) # DEBUG
# print("max :", p_max.x, p_max.y) # DEBUG
# print("----------------------") # DEBUG
#######################################################
sv_nb = sv_nb // self.__turns
center = (p_min + p_max) / 2
radius = (center.x - p_min.x + center.y - p_min.y) / 2
p_new = Vector([0, 0])
#######################################################
R = self.__random_radius
C = self.__random_center
i = 0
it = stroke.stroke_vertices_begin()
for j in range(self.__turns):
prev_radius = radius
prev_center = center
radius = radius + randint(-R, R)
center = center + Vector([randint(-C, C), randint(-C, C)])
while i < sv_nb and not it.isEnd():
t = float(i) / float(sv_nb - 1)
r = prev_radius + (radius - prev_radius) * t
c = prev_center + (center - prev_center) * t
p_new.x = c.x + r * cos(2 * pi * t)
p_new.y = c.y + r * sin(2 * pi * t)
it.getObject().point = p_new
i = i + 1
it.increment()
i = 1
verticesToRemove = []
while not it.isEnd():
verticesToRemove.append(it.getObject())
it.increment()
for sv in verticesToRemove:
stroke.remove_vertex(sv)
stroke.update_length()
class pyBluePrintEllipsesShader(StrokeShader):
def __init__(self, turns = 1, random_radius = 3, random_center = 5):
StrokeShader.__init__(self)
self.__turns = turns
self.__random_center = random_center
self.__random_radius = random_radius
def getName(self):
return "pyBluePrintEllipsesShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
if it.isEnd():
return
p_min = it.getObject().point.copy()
p_max = it.getObject().point.copy()
while not it.isEnd():
p = it.getObject().point
if p.x < p_min.x:
p_min.x = p.x
if p.x > p_max.x:
p_max.x = p.x
if p.y < p_min.y:
p_min.y = p.y
if p.y > p_max.y:
p_max.y = p.y
it.increment()
stroke.resample(32 * self.__turns)
sv_nb = stroke.stroke_vertices_size()
sv_nb = sv_nb // self.__turns
center = (p_min + p_max) / 2
radius = center - p_min
p_new = Vector([0, 0])
#######################################################
R = self.__random_radius
C = self.__random_center
i = 0
it = stroke.stroke_vertices_begin()
for j in range(self.__turns):
prev_radius = radius
prev_center = center
radius = radius + Vector([randint(-R, R), randint(-R, R)])
center = center + Vector([randint(-C, C), randint(-C, C)])
while i < sv_nb and not it.isEnd():
t = float(i) / float(sv_nb - 1)
r = prev_radius + (radius - prev_radius) * t
c = prev_center + (center - prev_center) * t
p_new.x = c.x + r.x * cos(2 * pi * t)
p_new.y = c.y + r.y * sin(2 * pi * t)
it.getObject().point = p_new
i = i + 1
it.increment()
i = 1
verticesToRemove = []
while not it.isEnd():
verticesToRemove.append(it.getObject())
it.increment()
for sv in verticesToRemove:
stroke.remove_vertex(sv)
stroke.update_length()
class pyBluePrintSquaresShader(StrokeShader):
def __init__(self, turns = 1, bb_len = 10, bb_rand = 0):
StrokeShader.__init__(self)
self.__turns = turns
self.__bb_len = bb_len
self.__bb_rand = bb_rand
def getName(self):
return "pyBluePrintSquaresShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
if it.isEnd():
return
p_min = it.getObject().point.copy()
p_max = it.getObject().point.copy()
while not it.isEnd():
p = it.getObject().point
if p.x < p_min.x:
p_min.x = p.x
if p.x > p_max.x:
p_max.x = p.x
if p.y < p_min.y:
p_min.y = p.y
if p.y > p_max.y:
p_max.y = p.y
it.increment()
stroke.resample(32 * self.__turns)
sv_nb = stroke.stroke_vertices_size()
#######################################################
sv_nb = sv_nb // self.__turns
first = sv_nb // 4
second = 2 * first
third = 3 * first
fourth = sv_nb
p_first = Vector([p_min.x - self.__bb_len, p_min.y])
p_first_end = Vector([p_max.x + self.__bb_len, p_min.y])
p_second = Vector([p_max.x, p_min.y - self.__bb_len])
p_second_end = Vector([p_max.x, p_max.y + self.__bb_len])
p_third = Vector([p_max.x + self.__bb_len, p_max.y])
p_third_end = Vector([p_min.x - self.__bb_len, p_max.y])
p_fourth = Vector([p_min.x, p_max.y + self.__bb_len])
p_fourth_end = Vector([p_min.x, p_min.y - self.__bb_len])
#######################################################
R = self.__bb_rand
r = self.__bb_rand // 2
it = stroke.stroke_vertices_begin()
visible = True
for j in range(self.__turns):
p_first = p_first + Vector([randint(-R, R), randint(-r, r)])
p_first_end = p_first_end + Vector([randint(-R, R), randint(-r, r)])
p_second = p_second + Vector([randint(-r, r), randint(-R, R)])
p_second_end = p_second_end + Vector([randint(-r, r), randint(-R, R)])
p_third = p_third + Vector([randint(-R, R), randint(-r, r)])
p_third_end = p_third_end + Vector([randint(-R, R), randint(-r, r)])
p_fourth = p_fourth + Vector([randint(-r, r), randint(-R, R)])
p_fourth_end = p_fourth_end + Vector([randint(-r, r), randint(-R, R)])
vec_first = p_first_end - p_first
vec_second = p_second_end - p_second
vec_third = p_third_end - p_third
vec_fourth = p_fourth_end - p_fourth
i = 0
while i < sv_nb and not it.isEnd():
if i < first:
p_new = p_first + vec_first * float(i)/float(first - 1)
if i == first - 1:
visible = False
elif i < second:
p_new = p_second + vec_second * float(i - first)/float(second - first - 1)
if i == second - 1:
visible = False
elif i < third:
p_new = p_third + vec_third * float(i - second)/float(third - second - 1)
if i == third - 1:
visible = False
else:
p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1)
if i == fourth - 1:
visible = False
if it.getObject() == None:
i = i + 1
it.increment()
if not visible:
visible = True
continue
it.getObject().point = p_new
it.getObject().attribute.visible = visible
if not visible:
visible = True
i = i + 1
it.increment()
verticesToRemove = []
while not it.isEnd():
verticesToRemove.append(it.getObject())
it.increment()
for sv in verticesToRemove:
stroke.remove_vertex(sv)
stroke.update_length()
class pyBluePrintDirectedSquaresShader(StrokeShader):
def __init__(self, turns = 1, bb_len = 10, mult = 1):
StrokeShader.__init__(self)
self.__mult = mult
self.__turns = turns
self.__bb_len = 1 + float(bb_len) / 100
def getName(self):
return "pyBluePrintDirectedSquaresShader"
def shade(self, stroke):
stroke.resample(32 * self.__turns)
p_mean = Vector([0, 0])
it = stroke.stroke_vertices_begin()
while not it.isEnd():
p = it.getObject().point
p_mean = p_mean + p
it.increment()
sv_nb = stroke.stroke_vertices_size()
p_mean = p_mean / sv_nb
p_var_xx = 0
p_var_yy = 0
p_var_xy = 0
it = stroke.stroke_vertices_begin()
while not it.isEnd():
p = it.getObject().point
p_var_xx = p_var_xx + pow(p.x - p_mean.x, 2)
p_var_yy = p_var_yy + pow(p.y - p_mean.y, 2)
p_var_xy = p_var_xy + (p.x - p_mean.x) * (p.y - p_mean.y)
it.increment()
p_var_xx = p_var_xx / sv_nb
p_var_yy = p_var_yy / sv_nb
p_var_xy = p_var_xy / sv_nb
## print(p_var_xx, p_var_yy, p_var_xy)
trace = p_var_xx + p_var_yy
det = p_var_xx * p_var_yy - p_var_xy * p_var_xy
sqrt_coeff = sqrt(trace * trace - 4 * det)
lambda1 = (trace + sqrt_coeff) / 2
lambda2 = (trace - sqrt_coeff) / 2
## print(lambda1, lambda2)
theta = atan(2 * p_var_xy / (p_var_xx - p_var_yy)) / 2
## print(theta)
if p_var_yy > p_var_xx:
e1 = Vector([cos(theta + pi / 2), sin(theta + pi / 2)]) * sqrt(lambda1) * self.__mult
e2 = Vector([cos(theta + pi), sin(theta + pi)]) * sqrt(lambda2) * self.__mult
else:
e1 = Vector([cos(theta), sin(theta)]) * sqrt(lambda1) * self.__mult
e2 = Vector([cos(theta + pi / 2), sin(theta + pi / 2)]) * sqrt(lambda2) * self.__mult
#######################################################
sv_nb = sv_nb // self.__turns
first = sv_nb // 4
second = 2 * first
third = 3 * first
fourth = sv_nb
bb_len1 = self.__bb_len
bb_len2 = 1 + (bb_len1 - 1) * sqrt(lambda1 / lambda2)
p_first = p_mean - e1 - e2 * bb_len2
p_second = p_mean - e1 * bb_len1 + e2
p_third = p_mean + e1 + e2 * bb_len2
p_fourth = p_mean + e1 * bb_len1 - e2
vec_first = e2 * bb_len2 * 2
vec_second = e1 * bb_len1 * 2
vec_third = vec_first * -1
vec_fourth = vec_second * -1
#######################################################
it = stroke.stroke_vertices_begin()
visible = True
for j in range(self.__turns):
i = 0
while i < sv_nb:
if i < first:
p_new = p_first + vec_first * float(i)/float(first - 1)
if i == first - 1:
visible = False
elif i < second:
p_new = p_second + vec_second * float(i - first)/float(second - first - 1)
if i == second - 1:
visible = False
elif i < third:
p_new = p_third + vec_third * float(i - second)/float(third - second - 1)
if i == third - 1:
visible = False
else:
p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1)
if i == fourth - 1:
visible = False
it.getObject().point = p_new
it.getObject().attribute.visible = visible
if not visible:
visible = True
i = i + 1
it.increment()
verticesToRemove = []
while not it.isEnd():
verticesToRemove.append(it.getObject())
it.increment()
for sv in verticesToRemove:
stroke.remove_vertex(sv)
stroke.update_length()
class pyModulateAlphaShader(StrokeShader):
def __init__(self, min = 0, max = 1):
StrokeShader.__init__(self)
self.__min = min
self.__max = max
def getName(self):
return "pyModulateAlphaShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
alpha = it.getObject().attribute.alpha
p = it.getObject().point
alpha = alpha * p.y / 400
if alpha < self.__min:
alpha = self.__min
elif alpha > self.__max:
alpha = self.__max
it.getObject().attribute.alpha = alpha
it.increment()
## various
class pyDummyShader(StrokeShader):
def getName(self):
return "pyDummyShader"
def shade(self, stroke):
it = stroke.stroke_vertices_begin()
while not it.isEnd():
toto = it.castToInterface0DIterator()
att = it.getObject().attribute
att.color = (0.3, 0.4, 0.4)
att.thickness = (0, 5)
it.increment()
class pyDebugShader(StrokeShader):
def getName(self):
return "pyDebugShader"
def shade(self, stroke):
fe = GetSelectedFEdgeCF()
id1 = fe.first_svertex.id
id2 = fe.second_svertex.id
#print(id1.first, id1.second)
#print(id2.first, id2.second)
it = stroke.stroke_vertices_begin()
found = True
foundfirst = True
foundsecond = False
while not it.isEnd():
cp = it.getObject()
if cp.first_svertex.id == id1 or cp.second_svertex.id == id1:
foundfirst = True
if cp.first_svertex.id == id2 or cp.second_svertex.id == id2:
foundsecond = True
if foundfirst and foundsecond:
found = True
break
it.increment()
if found:
print("The selected Stroke id is: ", stroke.id.first, stroke.id.second)