This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/release/scripts/freestyle/modules/freestyle/functions.py
Tamito Kajiyama 3ca0870023 Improvements to the Freestyle Python API (needed by the SVG Exporter)
This patch adds some new functionality to the Freestyle Python API, notably:

  - MaterialBP1D, checks whether the supplied arguments have the same material
  - Fixes a potential crash in CurvePoint.fedge (due to NULL pointer)
  - Makes (error handling in) boolean predicates more robust
  - Adds a BoundingBox type, to make working with bounding boxes easier
  - Adds several new functions (get_object_name, get_strokes, is_poly_clockwise, material_from_fedge)
  - Adds a StrokeCollector StrokeShader, that collects all the strokes from a specific call to Operators.create()
  - Adds hashing and rich comparison to the FrsMaterial type

These new features (most of them, anyway) are needed for making a more robust SVG exporter that supports holes in fills.

Reviewers: kjym3, campbellbarton

Subscribers: campbellbarton

Projects: #bf_blender

Differential Revision: https://developer.blender.org/D1245
2015-05-31 23:16:45 +09:00

319 lines
9.8 KiB
Python

# ##### 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 #####
"""
This module contains functions operating on vertices (0D elements) and
polylines (1D elements). The module is also intended to be a
collection of examples for function definition in Python.
User-defined functions inherit one of the following base classes,
depending on the object type (0D or 1D) to operate on and the return
value type:
- :class:`freestyle.types.UnaryFunction0DDouble`
- :class:`freestyle.types.UnaryFunction0DEdgeNature`
- :class:`freestyle.types.UnaryFunction0DFloat`
- :class:`freestyle.types.UnaryFunction0DId`
- :class:`freestyle.types.UnaryFunction0DMaterial`
- :class:`freestyle.types.UnaryFunction0DUnsigned`
- :class:`freestyle.types.UnaryFunction0DVec2f`
- :class:`freestyle.types.UnaryFunction0DVec3f`
- :class:`freestyle.types.UnaryFunction0DVectorViewShape`
- :class:`freestyle.types.UnaryFunction0DViewShape`
- :class:`freestyle.types.UnaryFunction1DDouble`
- :class:`freestyle.types.UnaryFunction1DEdgeNature`
- :class:`freestyle.types.UnaryFunction1DFloat`
- :class:`freestyle.types.UnaryFunction1DUnsigned`
- :class:`freestyle.types.UnaryFunction1DVec2f`
- :class:`freestyle.types.UnaryFunction1DVec3f`
- :class:`freestyle.types.UnaryFunction1DVectorViewShape`
- :class:`freestyle.types.UnaryFunction1DVoid`
"""
__all__ = (
"ChainingTimeStampF1D",
"Curvature2DAngleF0D",
"Curvature2DAngleF1D",
"CurveMaterialF0D",
"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",
"pyCurvilinearLengthF0D",
"pyDensityAnisotropyF0D",
"pyDensityAnisotropyF1D",
"pyGetInverseProjectedZF1D",
"pyGetSquareInverseProjectedZF1D",
"pyInverseCurvature2DAngleF0D",
"pyViewMapGradientNormF0D",
"pyViewMapGradientNormF1D",
"pyViewMapGradientVectorF0D",
)
# 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,
)
# constructs for function definition in Python
from freestyle.types import (
CurvePoint,
IntegrationType,
UnaryFunction0DDouble,
UnaryFunction0DMaterial,
UnaryFunction0DVec2f,
UnaryFunction1DDouble,
)
from freestyle.utils import ContextFunctions as CF
from freestyle.utils import integrate
from mathutils import Vector
# -- Functions for 0D elements (vertices) -- #
class CurveMaterialF0D(UnaryFunction0DMaterial):
"""
A replacement of the built-in MaterialF0D for stroke creation.
MaterialF0D does not work with Curves and Strokes. Line color
priority is used to pick one of the two materials at material
boundaries.
Notes: expects instances of CurvePoint to be iterated over
can return None if no fedge can be found
"""
def __call__(self, inter):
fe = inter.object.fedge
if fe is None:
return None
if fe.is_smooth:
return fe.material
else:
right, left = fe.material_right, fe.material_left
return right if (right.priority > left.priority) else 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
class pyDensityAnisotropyF0D(UnaryFunction0DDouble):
"""Estimates the anisotropy of density."""
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))
return 0 if (c_iso == 0) else (cMax - cMin) / c_iso
class pyViewMapGradientVectorF0D(UnaryFunction0DVec2f):
"""
Returns the gradient vector for a pixel.
.. method:: __init__(self, level)
Builds a pyViewMapGradientVectorF0D object.
:arg level: the level at which to compute the gradient
:type level: int
"""
def __init__(self, level):
UnaryFunction0DVec2f.__init__(self)
self._l = level
self._step = pow(2, self._l)
def __call__(self, iter):
p = iter.object.point_2d
gx = CF.read_complete_view_map_pixel(self._l, int(p.x + self._step), int(p.y)) - \
CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y))
gy = CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y + self._step)) - \
CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y))
return Vector((gx, gy))
class pyViewMapGradientNormF0D(UnaryFunction0DDouble):
def __init__(self, l):
UnaryFunction0DDouble.__init__(self)
self._l = l
self._step = pow(2, self._l)
def __call__(self, iter):
p = iter.object.point_2d
gx = CF.read_complete_view_map_pixel(self._l, int(p.x + self._step), int(p.y)) - \
CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y))
gy = CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y + self._step)) - \
CF.read_complete_view_map_pixel(self._l, int(p.x), int(p.y))
return Vector((gx, gy)).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 - pow(z, 2))
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.points_begin(self._sampling), inter.points_end(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.points_begin(self._sampling), inter.points_end(self._sampling), self._integration)
return v