line.cpp revision a16a494f042310ee849a6f717ffea70846f1f22c
/*
* Infinite Straight Line
*
* Copyright 2008 Marco Cecchetti <mrcekets at gmail.com>
* Nathan Hurst
*
* 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 <algorithm>
namespace Geom
{
/**
* @class Line
* @brief Infinite line on a plane.
*
* A line is specified as two points through which it passes. Lines can be interpreted as functions
* \f$ f: (-\infty, \infty) \to \mathbb{R}^2\f$. Zero corresponds to the first (origin) point,
* one corresponds to the second (final) point. All other points are computed as a linear
* interpolation between those two: \f$p = (1-t) a + t b\f$. Many such functions have the same
* image and therefore represent the same lines; for example, adding \f$b-a\f$ to both points
* yields the same line.
*
* 2Geom can represent the same line in many ways by design: using a different representation
* would lead to precision loss. For example, a line from (1e30, 1e30) to (10,0) would actually
* evaluate to (0,0) at time 1 if it was stored as origin and normalized versor,
* or origin and angle.
*
* @ingroup Primitives
*/
/** @brief Set the line by solving the line equation.
* A line is a set of points that satisfies the line equation
* \f$Ax + By + C = 0\f$. This function changes the line so that its points
* satisfy the line equation with the given coefficients. */
{
// degenerate case
if (a == 0 && b == 0) {
if (c != 0) {
THROW_LOGICALERROR("the passed coefficients give the empty set");
}
return;
}
// The way final / initial points are set based on coefficients is somewhat unusual.
// This is done to make sure that calling coefficients() will give back
// (almost) the same values.
// vertical case
if (a == 0) {
// b must be nonzero
_final[X] = b/2;
return;
}
// horizontal case
if (b == 0) {
_final[Y] = -a/2;
return;
}
// This gives reasonable results regardless of the magnitudes of a, b and c.
}
{
a = v[X];
b = v[Y];
}
/** @brief Get the implicit line equation coefficients.
* Note that conversion to implicit form always causes loss of
* precision when dealing with lines that start far from the origin
* and end very close to it. It is recommended to normalize the line
* before converting it to implicit form.
* @return Vector with three values corresponding to the A, B and C
* coefficients of the line equation for this line. */
{
return c;
}
/** @brief Find intersection with an axis-aligned line.
* @param v Coordinate of the axis-aligned line
* @param d Which axis the coordinate is on. X means a vertical line, Y means a horizontal line.
* @return Time values at which this line intersects the query line. */
if (IS_FINITE(r)) {
}
return result;
}
{
assert(d == X || d == Y);
if (vs[d] != 0) {
} else {
return nan("");
}
}
{
// handle horizontal and vertical lines first,
// since the root-based code below will break for them
for (unsigned i = 0; i < 2; ++i) {
Dim2 o = other_dimension(d);
if (v[d] != 0) continue;
Point a, b;
a[o] = r[o].min();
b[o] = r[o].max();
a[d] = b[d] = _initial[d];
if (v[o] > 0) {
return LineSegment(a, b);
} else {
return LineSegment(b, a);
}
} else {
}
}
}
if (common) {
return result;
} else {
}
/* old implementation using coefficients:
if (fabs(b) > fabs(a)) {
p0 = Point(r[X].min(), (-c - a*r[X].min())/b);
if (p0[Y] < r[Y].min())
p0 = Point((-c - b*r[Y].min())/a, r[Y].min());
if (p0[Y] > r[Y].max())
p0 = Point((-c - b*r[Y].max())/a, r[Y].max());
p1 = Point(r[X].max(), (-c - a*r[X].max())/b);
if (p1[Y] < r[Y].min())
p1 = Point((-c - b*r[Y].min())/a, r[Y].min());
if (p1[Y] > r[Y].max())
p1 = Point((-c - b*r[Y].max())/a, r[Y].max());
} else {
p0 = Point((-c - b*r[Y].min())/a, r[Y].min());
if (p0[X] < r[X].min())
p0 = Point(r[X].min(), (-c - a*r[X].min())/b);
if (p0[X] > r[X].max())
p0 = Point(r[X].max(), (-c - a*r[X].max())/b);
p1 = Point((-c - b*r[Y].max())/a, r[Y].max());
if (p1[X] < r[X].min())
p1 = Point(r[X].min(), (-c - a*r[X].min())/b);
if (p1[X] > r[X].max())
p1 = Point(r[X].max(), (-c - a*r[X].max())/b);
}
return LineSegment(p0, p1); */
}
/** @brief Get a time value corresponding to a point.
* @param p Point on the line. If the point is not on the line,
* the returned value will be meaningless.
* @return Time value t such that \f$f(t) = p\f$.
* @see timeAtProjection */
{
// degenerate case
if (v[X] == 0 && v[Y] == 0) {
return 0;
}
// use the coordinate that will give better precision
return (p[X] - _initial[X]) / v[X];
} else {
return (p[Y] - _initial[Y]) / v[Y];
}
}
/** @brief Create a transformation that maps one line to another.
* This will return a transformation \f$A\f$ such that
* \f$L_1(t) \cdot A = L_2(t)\f$, where \f$L_1\f$ is this line
* and \f$L_2\f$ is the line passed as the parameter. The returned
* transformation will preserve angles. */
{
return result;
}
{
return result;
}
{
filter_ray_intersections(result, false, true);
return result;
}
{
filter_line_segment_intersections(result, false, true);
return result;
}
{
while (i != last) {
} else {
++i;
}
}
}
{
while (i != last) {
} else {
++i;
}
}
}
namespace detail
{
inline
{
if (cp == 0) return OptCrossing();
Crossing c;
return c;
}
{
if (crossing) {
return OptCrossing();
} else {
if (i != 0) {
}
return crossing;
}
}
} else {
return OptCrossing();
}
}
unsigned int i )
{
ls1.initialPoint(),
if (crossing) {
{
return OptCrossing();
} else {
if (i != 0) {
}
return crossing;
}
}
} else {
return OptCrossing();
}
}
unsigned int i )
{
ls1.initialPoint(),
if (crossing) {
{
return OptCrossing();
} else {
if (i != 0) {
}
return crossing;
}
}
return crossing;
if (i == 0) {
} else {
}
return crossing;
} else {
}
} else {
return no_crossing;
}
}
} // end namespace detail
{
}
return c;
}
{
if (crossing)
{
{
return no_crossing;
}
else
{
return crossing;
}
}
{
{
return crossing;
}
else
{
}
}
else
{
return no_crossing;
}
}
{
ls1.initialPoint(),
ls2.initialPoint() );
if (crossing)
{
{
return no_crossing;
}
else
{
return crossing;
}
}
{
{
return crossing;
}
{
return crossing;
}
else
{
}
}
{
{
return crossing;
}
{
return crossing;
}
else
{
}
}
else
{
return no_crossing;
}
}
{
try
{
}
catch(InfiniteSolutions const &e)
{
return l1;
}
if (!crossing)
{
THROW_RANGEERROR("passed lines are parallel");
}
return make_angle_bisector_line(A, O, B);
}
} // end namespace Geom
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/