Fix for the WithinImageBorderUP1D predicate not working with a ViewEdge such that
none of the SVertices are within the image boundary but an FEdge intersects with the image boundary. The problem was reported by edna through the BA Freestyle thread, with a .blend file for reproducing the bug. Thanks!
This commit is contained in:
@@ -697,27 +697,6 @@ class ObjectNamesUP1D(UnaryPredicate1D):
|
||||
return not found
|
||||
return found
|
||||
|
||||
class WithinImageBorderUP1D(UnaryPredicate1D):
|
||||
def __init__(self, xmin, xmax, ymin, ymax):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self._xmin = xmin
|
||||
self._xmax = xmax
|
||||
self._ymin = ymin
|
||||
self._ymax = ymax
|
||||
def getName(self):
|
||||
return "WithinImageBorderUP1D"
|
||||
def __call__(self, inter):
|
||||
it = inter.verticesBegin()
|
||||
while not it.isEnd():
|
||||
if self.withinBorder(it.getObject()):
|
||||
return True
|
||||
it.increment()
|
||||
return False
|
||||
def withinBorder(self, vert):
|
||||
x = vert.getProjectedX()
|
||||
y = vert.getProjectedY()
|
||||
return self._xmin <= x <= self._xmax and self._ymin <= y <= self._ymax
|
||||
|
||||
# Stroke caps
|
||||
|
||||
def iter_stroke_vertices(stroke):
|
||||
@@ -1108,7 +1087,7 @@ def process(layer_name, lineset_name):
|
||||
else:
|
||||
xmin, xmax = 0.0, float(w)
|
||||
ymin, ymax = 0.0, float(h)
|
||||
upred = WithinImageBorderUP1D(xmin, xmax, ymin, ymax)
|
||||
upred = WithinImageBoundaryUP1D(xmin, ymin, xmax, ymax)
|
||||
selection_criteria.append(upred)
|
||||
# select feature edges
|
||||
upred = join_unary_predicates(selection_criteria, AndUP1D)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.h"
|
||||
#include "UnaryPredicate1D/BPy_ShapeUP1D.h"
|
||||
#include "UnaryPredicate1D/BPy_TrueUP1D.h"
|
||||
#include "UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -75,6 +76,11 @@ int UnaryPredicate1D_Init( PyObject *module )
|
||||
Py_INCREF( &TrueUP1D_Type );
|
||||
PyModule_AddObject(module, "TrueUP1D", (PyObject *)&TrueUP1D_Type);
|
||||
|
||||
if( PyType_Ready( &WithinImageBoundaryUP1D_Type ) < 0 )
|
||||
return -1;
|
||||
Py_INCREF( &WithinImageBoundaryUP1D_Type );
|
||||
PyModule_AddObject(module, "WithinImageBoundaryUP1D", (PyObject *)&WithinImageBoundaryUP1D_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "BPy_WithinImageBoundaryUP1D.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
static char WithinImageBoundaryUP1D___doc__[] =
|
||||
"Class hierarchy: :class:`UnaryPredicate1D` > :class:`WithinImageBoundaryUP1D`\n"
|
||||
"\n"
|
||||
".. method:: __init__(xmin, ymin, xmax, ymax)\n"
|
||||
"\n"
|
||||
" Builds an WithinImageBoundaryUP1D object.\n"
|
||||
"\n"
|
||||
" :arg xmin: X lower bound of the image boundary.\n"
|
||||
" :type xmin: float\n"
|
||||
" :arg ymin: Y lower bound of the image boundary.\n"
|
||||
" :type ymin: float\n"
|
||||
" :arg xmax: X upper bound of the image boundary.\n"
|
||||
" :type xmax: float\n"
|
||||
" :arg ymax: Y upper bound of the image boundary.\n"
|
||||
" :type ymax: float\n"
|
||||
"\n"
|
||||
".. method:: __call__(inter)\n"
|
||||
"\n"
|
||||
" Returns true if the Interface1D intersects with image boundary.\n";
|
||||
|
||||
static int WithinImageBoundaryUP1D___init__( BPy_WithinImageBoundaryUP1D* self, PyObject *args )
|
||||
{
|
||||
double xmin, ymin, xmax, ymax;
|
||||
|
||||
if(!( PyArg_ParseTuple(args, "dddd", &xmin, &ymin, &xmax, &ymax) ))
|
||||
return -1;
|
||||
self->py_up1D.up1D = new Predicates1D::WithinImageBoundaryUP1D(xmin, ymin, xmax, ymax);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------BPy_TrueUP1D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject WithinImageBoundaryUP1D_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"WithinImageBoundaryUP1D", /* tp_name */
|
||||
sizeof(BPy_WithinImageBoundaryUP1D), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
WithinImageBoundaryUP1D___doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
&UnaryPredicate1D_Type, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)WithinImageBoundaryUP1D___init__, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef FREESTYLE_PYTHON_WITHINIMAGEBOUNDARYUP1D_H
|
||||
#define FREESTYLE_PYTHON_WITHINIMAGEBOUNDARYUP1D_H
|
||||
|
||||
#include "../BPy_UnaryPredicate1D.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
extern PyTypeObject WithinImageBoundaryUP1D_Type;
|
||||
|
||||
#define BPy_WithinImageBoundaryUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &WithinImageBoundaryUP1D_Type) )
|
||||
|
||||
/*---------------------------Python BPy_WithinImageBoundaryUP1D structure definition----------*/
|
||||
typedef struct {
|
||||
BPy_UnaryPredicate1D py_up1D;
|
||||
} BPy_WithinImageBoundaryUP1D;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREESTYLE_PYTHON_WITHINIMAGEBOUNDARYUP1D_H */
|
||||
@@ -358,6 +358,63 @@ namespace Predicates1D {
|
||||
}
|
||||
};
|
||||
|
||||
// WithinImageBoundaryUP1D
|
||||
/*! Returns true if the Interface1D is (partly) within the image boundary.
|
||||
*/
|
||||
class WithinImageBoundaryUP1D: public UnaryPredicate1D
|
||||
{
|
||||
private:
|
||||
real _xmin, _ymin, _xmax, _ymax;
|
||||
public:
|
||||
/*! Builds the Predicate.
|
||||
* \param xmin
|
||||
* The X lower bound of the image boundary.
|
||||
* \param ymin
|
||||
* The Y lower bound of the image boundary.
|
||||
* \param xmax
|
||||
* The X upper bound of the image boundary.
|
||||
* \param ymax
|
||||
* The Y upper bound of the image boundary.
|
||||
*/
|
||||
WithinImageBoundaryUP1D(const real xmin, const real ymin, const real xmax, const real ymax) :
|
||||
_xmin(xmin), _ymin(ymin), _xmax(xmax), _ymax(ymax) {}
|
||||
/*! Returns the string "WithinImageBoundaryUP1D"*/
|
||||
string getName() const {
|
||||
return "WithinImageBoundaryUP1D";
|
||||
}
|
||||
/*! The () operator. */
|
||||
int operator()(Interface1D& inter) {
|
||||
// 1st pass: check if a point is within the image boundary.
|
||||
Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
|
||||
for (; it != itend; ++it) {
|
||||
real x = (*it).getProjectedX();
|
||||
real y = (*it).getProjectedY();
|
||||
if (_xmin <= x && x <= _xmax && _ymin <= y && y <= _ymax) {
|
||||
result = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// 2nd pass: check if a line segment intersects with the image boundary.
|
||||
it = inter.verticesBegin();
|
||||
if (it != itend) {
|
||||
Vec2r pmin(_xmin, _ymin);
|
||||
Vec2r pmax(_xmax, _ymax);
|
||||
Vec2r prev((*it).getPoint2D());
|
||||
++it;
|
||||
for (; it != itend; ++it) {
|
||||
Vec2r p((*it).getPoint2D());
|
||||
if (GeomUtils::intersect2dSeg2dArea (pmin, pmax, prev, p)) {
|
||||
result = true;
|
||||
return 0;
|
||||
}
|
||||
prev = p;
|
||||
}
|
||||
}
|
||||
result = false;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Binary Predicates definitions
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user