/*
* Implement the Bezier clipping algorithm for finding
* Bezier curve intersection points and collinear normals
*
* Authors:
* Marco Cecchetti <mrcekets at gmail.com>
*
* Copyright 2008 authors
*
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*/
#include <cassert>
#include <vector>
#include <algorithm>
#include <utility>
//#include <iomanip>
#define VERBOSE 0
#define CHECK 0
namespace Geom {
////////////////////////////////////////////////////////////////////////////////
// for debugging
//
{
}
template< class charT >
{
return os;
}
{
return (180 * a / M_PI);
}
{
double d = I.extent();
double e = 0.1, p = 10;
int n = 0;
while (n < 16 && d < e)
{
p *= 10;
e = 1/p;
++n;
}
return n;
}
{
if ( k < m || k > n)
{
<< "value: " << k
assert (k >= m && k <= n);
}
}
////////////////////////////////////////////////////////////////////////////////
// numerical routines
/*
* Compute the binomial coefficient (n, k)
*/
double binomial(unsigned int n, unsigned int k)
{
}
/*
* Compute the determinant of the 2x2 matrix with column the point P1, P2
*/
{
}
/*
* Solve the linear system [P1,P2] * P = Q
* in case there isn't exactly one solution the routine returns false
*/
{
if (d == 0) return false;
d = 1 / d;
return true;
}
////////////////////////////////////////////////////////////////////////////////
// interval routines
/*
* Map the sub-interval I in [0,1] into the interval J and assign it to J
*/
{
}
////////////////////////////////////////////////////////////////////////////////
// bezier curve routines
/*
* Return true if all the Bezier curve control points are near,
* false otherwise
*/
// Bezier.isConstant(precision)
{
for (unsigned int i = 1; i < A.size(); ++i)
{
return false;
}
return true;
}
/*
* Compute the hodograph of the bezier curve B and return it in D
*/
// derivative(Bezier)
{
D.clear();
if (sz == 0) return;
if (sz == 1)
{
return;
}
D.reserve(n);
for (size_t i = 0; i < n; ++i)
{
D.push_back(n*(B[i+1] - B[i]));
}
}
/*
* Compute the hodograph of the Bezier curve B rotated of 90 degree
* and return it in D; we have N(t) orthogonal to B(t) for any t
*/
// rot90(derivative(Bezier))
{
derivative(N,B);
{
N[i] = rot90(N[i]);
}
}
/*
* Compute the portion of the Bezier curve "B" wrt the interval [0,t]
*/
// portion(Bezier, 0, t)
{
for (size_t i = 1; i < n; ++i)
{
{
B[j] = lerp(t, B[j-1], B[j]);
}
}
}
/*
* Compute the portion of the Bezier curve "B" wrt the interval [t,1]
*/
// portion(Bezier, t, 1)
{
for (size_t i = 1; i < n; ++i)
{
for (size_t j = 0; j < n-i; ++j)
{
B[j] = lerp(t, B[j], B[j+1]);
}
}
}
/*
* Compute the portion of the Bezier curve "B" wrt the interval "I"
*/
// portion(Bezier, I)
{
if (I.min() == 0)
{
if (I.max() == 1) return;
left_portion(I.max(), B);
return;
}
right_portion(I.min(), B);
if (I.max() == 1) return;
left_portion(t, B);
}
////////////////////////////////////////////////////////////////////////////////
// tags
struct intersection_point_tag;
struct collinear_normal_tag;
template <typename Tag>
double precision);
template <typename Tag>
double precision );
////////////////////////////////////////////////////////////////////////////////
// intersection
/*
* Make up an orientation line using the control points c[i] and c[j]
* the line is returned in the output parameter "l" in the form of a 3 element
* vector : l[0] * x + l[1] * y + l[2] == 0; the line is normalized.
*/
// Line(c[i], c[j])
{
l[0] = c[j][Y] - c[i][Y];
l[1] = c[i][X] - c[j][X];
l[2] = cross(c[j], c[i]);
l[0] /= length;
l[1] /= length;
l[2] /= length;
}
/*
* Pick up an orientation line for the Bezier curve "c" and return it in
* the output parameter "l"
*/
{
{}
// this should never happen because when a new curve portion is created
// we check that it is not constant;
// however this requires that the precision used in the is_constant
// routine has to be the same used here in the are_near test
assert(i != 0);
return line;
//std::cerr << "i = " << i << std::endl;
}
/*
* Make up an orientation line for constant bezier curve;
* the orientation line is made up orthogonal to the other curve base line;
* the line is returned in the output parameter "l" in the form of a 3 element
* vector : l[0] * x + l[1] * y + l[2] == 0; the line is normalized.
*/
Point const &p,
double precision)
{
// this should never happen
return line;
}
/*
* Compute the signed distance of the point "P" from the normalized line l
*/
{
Coord a, b, c;
l.coefficients(a, b, c);
return a * p[X] + b * p[Y] + c;
}
/*
* Compute the min and max distance of the control points of the Bezier
* curve "c" from the normalized orientation line "l".
* This bounds are returned through the output Interval parameter"bound".
*/
Line const &l)
{
}
return bound;
}
/*
* return the x component of the intersection point between the line
* passing through points p1, p2 and the line Y = "y"
*/
{
// we are sure that p2[Y] != p1[Y] because this routine is called
// only when the lower or the upper bound is crossed
}
/*
* Clip the Bezier curve "B" wrt the fat line defined by the orientation
* line "l" and the interval range "bound", the new parameter interval for
* the clipped curve is returned through the output parameter "dom"
*/
Line const &l,
{
{
const double d = signed_distance(B[i], l);
}
//print(D);
ConvexHull p;
p.swap(D);
//print(p);
// std::cerr << "bound : " << bound << std::endl;
{
// std::cerr << "0 : inside " << p[0]
// << " : tmin = " << tmin << ", tmax = " << tmax << std::endl;
}
{
{
// std::cerr << i << " : inside " << p[i]
// << " : tmin = " << tmin << ", tmax = " << tmax
// << std::endl;
}
{
// std::cerr << i << " : lower " << p[i]
// << " : tmin = " << tmin << ", tmax = " << tmax
// << std::endl;
}
{
// std::cerr << i << " : higher " << p[i]
// << " : tmin = " << tmin << ", tmax = " << tmax
// << std::endl;
}
}
// we have to test the closing segment for intersection
{
// std::cerr << "0 : lower " << p[0]
// << " : tmin = " << tmin << ", tmax = " << tmax << std::endl;
}
{
// std::cerr << "0 : higher " << p[0]
// << " : tmin = " << tmin << ", tmax = " << tmax << std::endl;
}
return OptInterval();
} else {
}
}
/*
* Clip the Bezier curve "B" wrt the Bezier curve "A" for individuating
* intersection points the new parameter interval for the clipped curve
* is returned through the output parameter "dom"
*/
template <>
double precision)
{
if (is_constant(A, precision)) {
} else {
}
}
///////////////////////////////////////////////////////////////////////////////
// collinear normal
/*
* Compute a closed focus for the Bezier curve B and return it in F
* A focus is any curve through which all lines perpendicular to B(t) pass.
*/
{
normal(F, B);
#if VERBOSE
if (!solve(c, F[0], -F[n-1], B[n]-B[0]))
{
}
#else
solve(c, F[0], -F[n-1], B[n]-B[0]);
#endif
// std::cerr << "c = " << c << std::endl;
// B(t) + c(t) * N(t)
F[n] += B[n];
for (size_t i = n-1; i > 0; --i)
{
F[i] *= -c[0];
c0ni = F[i];
F[i] += (c[1] * F[i-1]);
F[i] *= (i * n_inv);
F[i] -= c0ni;
F[i] += B[i];
}
F[0] *= c[0];
F[0] += B[0];
}
/*
* Compute the projection on the plane (t, d) of the control points
* (t, u, D(t,u)) where D(t,u) = <(B(t) - F(u)), B'(t)> with 0 <= t, u <= 1
* B is a Bezier curve and F is a focus of another Bezier curve.
* See Sederberg, Nishita, 1990 - Curve intersection using Bezier clipping.
*/
{
D.clear();
for (size_t k = 0; k < n; ++k)
{
}
for (size_t i = 0; i < n; ++i)
for (size_t i = 0; i < n; ++i)
size_t l;
double bc;
for (size_t i = 0; i <= r; ++i)
{
for (size_t j = 0; j <= m; ++j)
{
d[j] = 0;
}
{
//if (k > i || (i-k) > n) continue;
l = i - k;
#if CHECK
assert (l <= n);
#endif
for (size_t j = 0; j <= m; ++j)
{
//d[j] += bc * dot(dB[k], B[l] - F[j]);
}
}
for (size_t j = 0; j < m; ++j)
{
}
}
}
/*
* Clip the Bezier curve "B" wrt the focus "F"; the new parameter interval for
* the clipped curve is returned through the output parameter "dom"
*/
{
distance_control_points(D, B, F);
//print(D, "D");
// ConvexHull chD(D);
// std::vector<Point>& p = chD.boundary; // convex hull vertices
ConvexHull p;
p.swap(D);
//print(p, "CH(D)");
plower = (p[0][Y] < 0);
if (p[0][Y] == 0) // on the x axis
{
// std::cerr << "0 : on x axis " << p[0]
// << " : tmin = " << tmin << ", tmax = " << tmax << std::endl;
}
{
clower = (p[i][Y] < 0);
if (p[i][Y] == 0) // on x axis
{
// std::cerr << i << " : on x axis " << p[i]
// << " : tmin = " << tmin << ", tmax = " << tmax
// << std::endl;
}
{
t = intersect(p[i-1], p[i], 0);
// std::cerr << i << " : lower " << p[i]
// << " : tmin = " << tmin << ", tmax = " << tmax
// << std::endl;
}
}
// we have to test the closing segment for intersection
clower = (p[0][Y] < 0);
{
// std::cerr << "0 : lower " << p[0]
// << " : tmin = " << tmin << ", tmax = " << tmax << std::endl;
}
return OptInterval();
} else {
}
}
/*
* Clip the Bezier curve "B" wrt the Bezier curve "A" for individuating
* points which have collinear normals; the new parameter interval
* for the clipped curve is returned through the output parameter "dom"
*/
template <>
double /*precision*/)
{
make_focus(F, A);
return clip_interval(B, F);
}
/*
* iterate
*
* input:
* A, B: control point sets of two bezier curves
* domA, domB: real parameter intervals of the two curves
* precision: required computational precision of the returned parameter ranges
* output:
* domsA, domsB: sets of parameter intervals
*
* The parameter intervals are computed by using a Bezier clipping algorithm,
* in case the clipping doesn't shrink the initial interval more than 20%,
* a subdivision step is performed.
* If during the computation both curves collapse to a single point
* the routine exits indipendently by the precision reached in the computation
* of the curve intervals.
*/
template <>
double precision )
{
// in order to limit recursion
if (++counter > 100) return;
#if VERBOSE
// std::cerr << "angle(A) : " << angle(A) << std::endl;
// std::cerr << "angle(B) : " << angle(B) << std::endl;
#endif
if (precision < MAX_PRECISION)
}
return;
}
while (++iter < 100
{
#if VERBOSE
#endif
{
#if VERBOSE
#endif
return;
}
#if VERBOSE
#endif
// all other cases where dom[0] > dom[1] are invalid
{
#if VERBOSE
#endif
break; // append the new interval
else
return; // exit without appending any new interval
}
// if we have clipped less than 20% than we need to subdive the curve
// with the largest domain into two sub-curves
{
#if VERBOSE
#endif
{
}
else
{
}
return;
}
#if VERBOSE
#endif
}
}
/*
* iterate
*
* input:
* A, B: control point sets of two bezier curves
* domA, domB: real parameter intervals of the two curves
* precision: required computational precision of the returned parameter ranges
* output:
* domsA, domsB: sets of parameter intervals
*
* The parameter intervals are computed by using a Bezier clipping algorithm,
* in case the clipping doesn't shrink the initial interval more than 20%,
* a subdivision step is performed.
* If during the computation one of the two curve interval length becomes less
* than MAX_PRECISION the routine exits indipendently by the precision reached
* in the computation of the other curve interval.
*/
template <>
double precision)
{
// in order to limit recursion
if (++counter > 100) return;
#if VERBOSE
// std::cerr << "angle(A) : " << angle(A) << std::endl;
// std::cerr << "angle(B) : " << angle(B) << std::endl;
#endif
if (precision < MAX_PRECISION)
while (++iter < 100
{
#if VERBOSE
#endif
#if VERBOSE
#endif
return;
}
#if VERBOSE
#endif
// it's better to stop before losing computational precision
{
#if VERBOSE
#endif
break;
}
{
#if VERBOSE
#endif
break;
}
// if we have clipped less than 20% than we need to subdive the curve
// with the largest domain into two sub-curves
{
#if VERBOSE
#endif
{
{
break;
}
{
#if VERBOSE
#endif
break;
}
{
#if VERBOSE
#endif
break;
}
}
else
{
{
break;
}
{
#if VERBOSE
#endif
break;
}
{
#if VERBOSE
#endif
break;
}
}
return;
}
#if VERBOSE
#endif
}
}
/*
* get_solutions
*
* input: A, B - set of control points of two Bezier curve
* input: precision - required precision of computation
* input: clip - the routine used for clipping
* output: xs - set of pairs of parameter values
* at which the clipping algorithm converges
*
* This routine is based on the Bezier Clipping Algorithm,
* see: Sederberg - Computer Aided Geometric Design
*/
template <typename Tag>
double precision)
{
{
}
{
#if VERBOSE
#endif
}
}
} /* end namespace bezier_clipping */ } /* end namespace detail */
/*
* find_collinear_normal
*
* input: A, B - set of control points of two Bezier curve
* input: precision - required precision of computation
* output: xs - set of pairs of parameter values
* at which there are collinear normals
*
* This routine is based on the Bezier Clipping Algorithm,
* see: Sederberg, Nishita, 1990 - Curve intersection using Bezier clipping
*/
double precision)
{
}
/*
* find_intersections_bezier_clipping
*
* input: A, B - set of control points of two Bezier curve
* input: precision - required precision of computation
* output: xs - set of pairs of parameter values
* at which crossing happens
*
* This routine is based on the Bezier Clipping Algorithm,
* see: Sederberg, Nishita, 1990 - Curve intersection using Bezier clipping
*/
double precision)
{
}
} // end namespace Geom
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :