From: johanengelen Date: Sat, 13 Dec 2008 20:09:58 +0000 (+0000) Subject: add missing files X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=19a11b8fc8f08b40b0612d70011a367c4e2b98ee;p=inkscape.git add missing files --- diff --git a/src/2geom/line.cpp b/src/2geom/line.cpp new file mode 100644 index 000000000..a91ff03a3 --- /dev/null +++ b/src/2geom/line.cpp @@ -0,0 +1,376 @@ +/* + * Infinite Straight Line + * + * Copyright 2008 Marco Cecchetti + * Nathan Hurst + * + * This library is free software; you can redistribute it and/or + * 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 + * http://www.mozilla.org/MPL/ + * + * 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 <2geom/line.h> + +#include + + +namespace Geom +{ + +namespace detail +{ + +inline +OptCrossing intersection_impl(Point const& V1, Point const O1, + Point const& V2, Point const O2 ) +{ + double detV1V2 = V1[X] * V2[Y] - V2[X] * V1[Y]; + if (are_near(detV1V2, 0)) return OptCrossing(); + + Point B = O2 - O1; + double detBV2 = B[X] * V2[Y] - V2[X] * B[Y]; + double detV1B = B[X] * V1[Y] - V1[X] * B[Y]; + double inv_detV1V2 = 1 / detV1V2; + + Crossing c; + c.ta = detBV2 * inv_detV1V2; + c.tb = detV1B * inv_detV1V2; +// std::cerr << "ta = " << solution.ta << std::endl; +// std::cerr << "tb = " << solution.tb << std::endl; + return OptCrossing(c); +} + + +OptCrossing intersection_impl(Ray const& r1, Line const& l2, unsigned int i) +{ + OptCrossing crossing = + intersection_impl(r1.versor(), r1.origin(), + l2.versor(), l2.origin() ); + + if (crossing) + { + if (crossing->ta < 0) + { + return OptCrossing(); + } + else + { + if (i != 0) + { + std::swap(crossing->ta, crossing->tb); + } + return crossing; + } + } + if (are_near(r1.origin(), l2)) + { + THROW_INFINITESOLUTIONS(); + } + else + { + return OptCrossing(); + } +} + + +OptCrossing intersection_impl( LineSegment const& ls1, + Line const& l2, + unsigned int i ) +{ + OptCrossing crossing = + intersection_impl(ls1.finalPoint() - ls1.initialPoint(), + ls1.initialPoint(), + l2.versor(), + l2.origin() ); + + if (crossing) + { + if ( crossing->getTime(0) < 0 + || crossing->getTime(0) > 1 ) + { + return OptCrossing(); + } + else + { + if (i != 0) + { + std::swap((*crossing).ta, (*crossing).tb); + } + return crossing; + } + } + if (are_near(ls1.initialPoint(), l2)) + { + THROW_INFINITESOLUTIONS(); + } + else + { + return OptCrossing(); + } +} + + +OptCrossing intersection_impl( LineSegment const& ls1, + Ray const& r2, + unsigned int i ) +{ + Point direction = ls1.finalPoint() - ls1.initialPoint(); + OptCrossing crossing = + intersection_impl( direction, + ls1.initialPoint(), + r2.versor(), + r2.origin() ); + + if (crossing) + { + if ( crossing->getTime(0) < 0 + || crossing->getTime(0) > 1 + || crossing->getTime(1) < 0 ) + { + return OptCrossing(); + } + else + { + if (i != 0) + { + std::swap(crossing->ta, crossing->tb); + } + return crossing; + } + } + + if ( are_near(r2.origin(), ls1) ) + { + bool eqvs = (dot(direction, r2.versor()) > 0); + if ( are_near(ls1.initialPoint(), r2.origin()) && !eqvs ) + { + crossing->ta = crossing->tb = 0; + return crossing; + } + else if ( are_near(ls1.finalPoint(), r2.origin()) && eqvs ) + { + if (i == 0) + { + crossing->ta = 1; + crossing->tb = 0; + } + else + { + crossing->ta = 0; + crossing->tb = 1; + } + return crossing; + } + else + { + THROW_INFINITESOLUTIONS(); + } + } + else if ( are_near(ls1.initialPoint(), r2) ) + { + THROW_INFINITESOLUTIONS(); + } + else + { + OptCrossing no_crossing; + return no_crossing; + } +} + +} // end namespace detail + + + +OptCrossing intersection(Line const& l1, Line const& l2) +{ + OptCrossing crossing = + detail::intersection_impl( l1.versor(), l1.origin(), + l2.versor(), l2.origin() ); + if (crossing) + { + return crossing; + } + if (are_near(l1.origin(), l2)) + { + THROW_INFINITESOLUTIONS(); + } + else + { + return crossing; + } +} + + +OptCrossing intersection(Ray const& r1, Ray const& r2) +{ + OptCrossing crossing = + detail::intersection_impl( r1.versor(), r1.origin(), + r2.versor(), r2.origin() ); + + if (crossing) + { + if ( crossing->ta < 0 + || crossing->tb < 0 ) + { + OptCrossing no_crossing; + return no_crossing; + } + else + { + return crossing; + } + } + + if ( are_near(r1.origin(), r2) || are_near(r2.origin(), r1) ) + { + if ( are_near(r1.origin(), r2.origin()) + && !are_near(r1.versor(), r2.versor()) ) + { + crossing->ta = crossing->tb = 0; + return crossing; + } + else + { + THROW_INFINITESOLUTIONS(); + } + } + else + { + OptCrossing no_crossing; + return no_crossing; + } +} + + +OptCrossing intersection( LineSegment const& ls1, LineSegment const& ls2 ) +{ + Point direction1 = ls1.finalPoint() - ls1.initialPoint(); + Point direction2 = ls2.finalPoint() - ls2.initialPoint(); + OptCrossing crossing = + detail::intersection_impl( direction1, + ls1.initialPoint(), + direction2, + ls2.initialPoint() ); + + if (crossing) + { + if ( crossing->getTime(0) < 0 + || crossing->getTime(0) > 1 + || crossing->getTime(1) < 0 + || crossing->getTime(1) > 1 ) + { + OptCrossing no_crossing; + return no_crossing; + } + else + { + return crossing; + } + } + + bool eqvs = (dot(direction1, direction2) > 0); + if ( are_near(ls2.initialPoint(), ls1) ) + { + if ( are_near(ls1.initialPoint(), ls2.initialPoint()) && !eqvs ) + { + crossing->ta = crossing->tb = 0; + return crossing; + } + else if ( are_near(ls1.finalPoint(), ls2.initialPoint()) && eqvs ) + { + crossing->ta = 1; + crossing->tb = 0; + return crossing; + } + else + { + THROW_INFINITESOLUTIONS(); + } + } + else if ( are_near(ls2.finalPoint(), ls1) ) + { + if ( are_near(ls1.finalPoint(), ls2.finalPoint()) && !eqvs ) + { + crossing->ta = crossing->tb = 1; + return crossing; + } + else if ( are_near(ls1.initialPoint(), ls2.finalPoint()) && eqvs ) + { + crossing->ta = 0; + crossing->tb = 1; + return crossing; + } + else + { + THROW_INFINITESOLUTIONS(); + } + } + else + { + OptCrossing no_crossing; + return no_crossing; + } +} + + + +Line make_angle_bisector_line(Line const& l1, Line const& l2) +{ + OptCrossing crossing; + try + { + crossing = intersection(l1, l2); + } + catch(InfiniteSolutions e) + { + return l1; + } + if (!crossing) + { + THROW_RANGEERROR("passed lines are parallel"); + } + Point O = l1.pointAt(crossing->ta); + Point A = l1.pointAt(crossing->ta + 1); + double angle = angle_between(l1.versor(), l2.versor()); + Point B = (angle > 0) ? l2.pointAt(crossing->tb + 1) + : l2.pointAt(crossing->tb - 1); + + 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 : +*/ diff --git a/src/2geom/line.h b/src/2geom/line.h new file mode 100644 index 000000000..e04c35c29 --- /dev/null +++ b/src/2geom/line.h @@ -0,0 +1,445 @@ +/** + * \file + * \brief Infinite Straight Line + * + * Copyright 2008 Marco Cecchetti + * + * This library is free software; you can redistribute it and/or + * 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 + * http://www.mozilla.org/MPL/ + * + * 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. + */ + +#ifndef _2GEOM_LINE_H_ +#define _2GEOM_LINE_H_ + + +#include + +#include <2geom/bezier-curve.h> // for LineSegment +#include <2geom/crossing.h> +#include <2geom/exception.h> + +#include <2geom/ray.h> + + +namespace Geom +{ + +class Line +{ + public: + Line() + : m_origin(0,0), m_versor(1,0) + { + } + + Line(Point const& _origin, Coord angle ) + : m_origin(_origin), m_versor(std::cos(angle), std::sin(angle)) + { + } + + Line(Point const& A, Point const& B) + { + setBy2Points(A, B); + } + + explicit + Line(LineSegment const& _segment) + { + setBy2Points(_segment.initialPoint(), _segment.finalPoint()); + } + + explicit + Line(Ray const& _ray) + : m_origin(_ray.origin()), m_versor(_ray.versor()) + { + } + + static Line fromNormalDistance(Point n, double c) { + Point P = n*c/(dot(n,n)); + + return Line(P, P+rot90(n)); + } + + Line* duplicate() const + { + return new Line(*this); + } + + Point origin() const + { + return m_origin; + } + + Point versor() const + { + return m_versor; + } + + void origin(Point const& _point) + { + m_origin = _point; + } + + void versor(Point const& _versor) + { + m_versor = _versor; + } + + // return the angle described by rotating the X-axis in cw direction + // until it overlaps the line + // the returned value is in the interval [0, PI[ + Coord angle() const + { + double a = std::atan2(m_versor[Y], m_versor[X]); + if (a < 0) a += M_PI; + if (a == M_PI) a = 0; + return a; + } + + void angle(Coord _angle) + { + m_versor[X] = std::cos(_angle); + m_versor[Y] = std::sin(_angle); + } + + void setBy2Points(Point const& A, Point const& B) + { + m_origin = A; + m_versor = B - A; + if ( are_near(m_versor, Point(0,0)) ) + m_versor = Point(0,0); + else + m_versor.normalize(); + } + + bool isDegenerate() const + { + return ( m_versor[X] == 0 && m_versor[Y] == 0 ); + } + + Point pointAt(Coord t) const + { + return m_origin + m_versor * t; + } + + Coord valueAt(Coord t, Dim2 d) const + { + if (d < 0 || d > 1) + THROW_RANGEERROR("Ray::valueAt, dimension argument out of range"); + return m_origin[d] + m_versor[d] * t; + } + + std::vector roots(Coord v, Dim2 d) const + { + if (d < 0 || d > 1) + THROW_RANGEERROR("Ray::roots, dimension argument out of range"); + std::vector result; + if ( m_versor[d] != 0 ) + { + result.push_back( (v - m_origin[d]) / m_versor[d] ); + } + // TODO: else ? + return result; + } + + // require are_near(_point, *this) + // on the contrary the result value is meaningless + Coord timeAt(Point const& _point) const + { + Coord t; + if ( m_versor[X] != 0 ) + { + t = (_point[X] - m_origin[X]) / m_versor[X]; + } + else if ( m_versor[Y] != 0 ) + { + t = (_point[Y] - m_origin[Y]) / m_versor[Y]; + } + else // degenerate case + { + t = 0; + } + return t; + } + + Coord timeAtProjection(Point const& _point) const + { + if ( isDegenerate() ) return 0; + return dot( _point - m_origin, m_versor ); + } + + Coord nearestPoint(Point const& _point) const + { + return timeAtProjection(_point); + } + + Line reverse() const + { + Line result; + result.origin(m_origin); + result.versor(-m_versor); + return result; + } + + Curve* portion(Coord f, Coord t) const + { + LineSegment* seg = new LineSegment(pointAt(f), pointAt(t)); + return seg; + } + + LineSegment segment(Coord f, Coord t) const + { + return LineSegment(pointAt(f), pointAt(t)); + } + + Ray ray(Coord t) + { + Ray result; + result.origin(pointAt(t)); + result.versor(m_versor); + return result; + } + + Line derivative() const + { + Line result; + result.origin(m_versor); + result.versor(Point(0,0)); + return result; + } + + Line transformed(Matrix const& m) const + { + return Line(m_origin * m, (m_origin + m_versor) * m); + } + + static Line from_normal_and_dist(Point const &n, double d) { + return Line(n*d, n*d + rot90(n)); + } + + private: + Point m_origin; + Point m_versor; + +}; // end class Line + + +inline +double distance(Point const& _point, Line const& _line) +{ + if ( _line.isDegenerate() ) + { + return distance( _point, _line.origin() ); + } + else + { + return fabs( dot(_point - _line.origin(), _line.versor().ccw()) ); + } +} + +inline +bool are_near(Point const& _point, Line const& _line, double eps = EPSILON) +{ + return are_near(distance(_point, _line), 0, eps); +} + +inline +bool are_parallel(Line const& l1, Line const& l2, double eps = EPSILON) +{ + return ( are_near(l1.versor(), l2.versor(), eps) + || are_near(l1.versor(), -l2.versor(), eps) ); +} + +inline +bool are_same(Line const& l1, Line const& l2, double eps = EPSILON) +{ + return are_parallel(l1, l2, eps) && are_near(l1.origin(), l2, eps); +} + +inline +bool are_orthogonal(Line const& l1, Line const& l2, double eps = EPSILON) +{ + return ( are_near(l1.versor(), l2.versor().cw(), eps) + || are_near(l1.versor(), l2.versor().ccw(), eps) ); +} + +inline +bool are_collinear(Point const& p1, Point const& p2, Point const& p3, + double eps = EPSILON) +{ + return are_near( cross(p3, p2) - cross(p3, p1) + cross(p2, p1), 0, eps); +} + +// evaluate the angle between l1 and l2 rotating l1 in cw direction +// until it overlaps l2 +// the returned value is an angle in the interval [0, PI[ +inline +double angle_between(Line const& l1, Line const& l2) +{ + double angle = angle_between(l1.versor(), l2.versor()); + if (angle < 0) angle += M_PI; + if (angle == M_PI) angle = 0; + return angle; +} + +inline +double distance(Point const& _point, LineSegment const& _segment) +{ + double t = _segment.nearestPoint(_point); + return L2(_point - _segment.pointAt(t)); +} + +inline +bool are_near(Point const& _point, LineSegment const& _segment, + double eps = EPSILON) +{ + return are_near(distance(_point, _segment), 0, eps); +} + +// build a line passing by _point and orthogonal to _line +inline +Line make_orthogonal_line(Point const& _point, Line const& _line) +{ + Line l; + l.origin(_point); + l.versor(_line.versor().cw()); + return l; +} + +// build a line passing by _point and parallel to _line +inline +Line make_parallel_line(Point const& _point, Line const& _line) +{ + Line l(_line); + l.origin(_point); + return l; +} + +// build a line passing by the middle point of _segment and orthogonal to it. +inline +Line make_bisector_line(LineSegment const& _segment) +{ + return make_orthogonal_line( middle_point(_segment), Line(_segment) ); +} + +// build the bisector line of the angle between ray(O,A) and ray(O,B) +inline +Line make_angle_bisector_line(Point const& A, Point const& O, Point const& B) +{ + Point M = middle_point(A,B); + return Line(O,M); +} + +// prj(P) = rot(v, Point( rot(-v, P-O)[X], 0 )) + O +inline +Point projection(Point const& _point, Line const& _line) +{ + return _line.pointAt( _line.nearestPoint(_point) ); +} + +inline +LineSegment projection(LineSegment const& _segment, Line const& _line) +{ + return _line.segment( _line.nearestPoint(_segment.initialPoint()), + _line.nearestPoint(_segment.finalPoint()) ); +} + + + + +namespace detail +{ + +OptCrossing intersection_impl(Ray const& r1, Line const& l2, unsigned int i); +OptCrossing intersection_impl( LineSegment const& ls1, + Line const& l2, + unsigned int i ); +OptCrossing intersection_impl( LineSegment const& ls1, + Ray const& r2, + unsigned int i ); +} + + +inline +OptCrossing intersection(Ray const& r1, Line const& l2) +{ + return detail::intersection_impl(r1, l2, 0); + +} + +inline +OptCrossing intersection(Line const& l1, Ray const& r2) +{ + return detail::intersection_impl(r2, l1, 1); +} + +inline +OptCrossing intersection(LineSegment const& ls1, Line const& l2) +{ + return detail::intersection_impl(ls1, l2, 0); +} + +inline +OptCrossing intersection(Line const& l1, LineSegment const& ls2) +{ + return detail::intersection_impl(ls2, l1, 1); +} + +inline +OptCrossing intersection(LineSegment const& ls1, Ray const& r2) +{ + return detail::intersection_impl(ls1, r2, 0); + +} + +inline +OptCrossing intersection(Ray const& r1, LineSegment const& ls2) +{ + return detail::intersection_impl(ls2, r1, 1); +} + + +OptCrossing intersection(Line const& l1, Line const& l2); + +OptCrossing intersection(Ray const& r1, Ray const& r2); + +OptCrossing intersection(LineSegment const& ls1, LineSegment const& ls2); + + +} // end namespace Geom + + +#endif // _2GEOM_LINE_H_ + + +/* + 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 : +*/ diff --git a/src/2geom/ray.h b/src/2geom/ray.h new file mode 100644 index 000000000..3156a944d --- /dev/null +++ b/src/2geom/ray.h @@ -0,0 +1,260 @@ +/** + * \file + * \brief Infinite Straight Ray + * + * Copyright 2008 Marco Cecchetti + * + * This library is free software; you can redistribute it and/or + * 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 + * http://www.mozilla.org/MPL/ + * + * 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. + */ + +#ifndef _2GEOM_RAY_H_ +#define _2GEOM_RAY_H_ + +#include <2geom/point.h> +#include <2geom/bezier-curve.h> // for LineSegment +#include <2geom/exception.h> + +#include + + +namespace Geom +{ + +class Ray +{ +public: + Ray() + : m_origin(0,0), m_versor(1,0) + { + } + + Ray(Point const& _origin, Coord angle ) + : m_origin(_origin), m_versor(std::cos(angle), std::sin(angle)) + { + } + + Ray(Point const& A, Point const& B) + { + setBy2Points(A, B); + } + + Point origin() const + { + return m_origin; + } + + Point versor() const + { + return m_versor; + } + + void origin(Point const& _point) + { + m_origin = _point; + } + + void versor(Point const& _versor) + { + m_versor = _versor; + } + + Coord angle() const + { + double a = std::atan2(m_versor[Y], m_versor[X]); + if (a < 0) a += 2*M_PI; + return a; + } + + void angle(Coord _angle) + { + m_versor[X] = std::cos(_angle); + m_versor[Y] = std::sin(_angle); + } + + void setBy2Points(Point const& A, Point const& B) + { + m_origin = A; + m_versor = B - A; + if ( are_near(m_versor, Point(0,0)) ) + m_versor = Point(0,0); + else + m_versor.normalize(); + } + + bool isDegenerate() const + { + return ( m_versor[X] == 0 && m_versor[Y] == 0 ); + } + + Point pointAt(Coord t) const + { + if (t < 0) THROW_RANGEERROR("Ray::pointAt, negative t value passed"); + return m_origin + m_versor * t; + } + + Coord valueAt(Coord t, Dim2 d) const + { + if (t < 0) + THROW_RANGEERROR("Ray::valueAt, negative t value passed"); + if (d < 0 || d > 1) + THROW_RANGEERROR("Ray::valueAt, dimension argument out of range"); + return m_origin[d] + m_versor[d] * t; + } + + std::vector roots(Coord v, Dim2 d) const + { + if (d < 0 || d > 1) + THROW_RANGEERROR("Ray::roots, dimension argument out of range"); + std::vector result; + if ( m_versor[d] != 0 ) + { + double t = (v - m_origin[d]) / m_versor[d]; + if (t >= 0) result.push_back(t); + } + // TODO: else ? + return result; + } + + // require are_near(_point, *this) + // on the contrary the result value is meaningless + Coord timeAt(Point const& _point) const + { + Coord t; + if ( m_versor[X] != 0 ) + { + t = (_point[X] - m_origin[X]) / m_versor[X]; + } + else if ( m_versor[Y] != 0 ) + { + t = (_point[Y] - m_origin[Y]) / m_versor[Y]; + } + else // degenerate case + { + t = 0; + } + return t; + } + + Coord nearestPoint(Point const& _point) const + { + if ( isDegenerate() ) return 0; + double t = dot( _point - m_origin, m_versor ); + if (t < 0) t = 0; + return t; + } + + Ray reverse() const + { + Ray result; + result.origin(m_origin); + result.versor(-m_versor); + return result; + } + + Curve* portion(Coord f, Coord t) const + { + LineSegment* seg = new LineSegment(pointAt(f), pointAt(t)); + return seg; + } + + LineSegment segment(Coord f, Coord t) const + { + return LineSegment(pointAt(f), pointAt(t)); + } + + Ray transformed(Matrix const& m) const + { + return Ray(m_origin * m, (m_origin + m_versor) * m); + } + +private: + Point m_origin; + Point m_versor; + +}; // end class ray + +inline +double distance(Point const& _point, Ray const& _ray) +{ + double t = _ray.nearestPoint(_point); + return distance(_point, _ray.pointAt(t)); +} + +inline +bool are_near(Point const& _point, Ray const& _ray, double eps = EPSILON) +{ + return are_near(distance(_point, _ray), 0, eps); +} + +inline +bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) +{ + return are_near(r1.versor(), r2.versor(), eps) + && are_near(r1.origin(), r2.origin(), eps); +} + +// evaluate the angle between r1 and r2 rotating r1 in cw or ccw direction on r2 +// the returned value is an angle in the interval [0, 2PI[ +inline +double angle_between(Ray const& r1, Ray const& r2, bool cw = true) +{ + double angle = angle_between(r1.versor(), r2.versor()); + if (angle < 0) angle += 2*M_PI; + if (!cw) angle = 2*M_PI - angle; + return angle; +} + + +inline +Ray make_angle_bisector_ray(Ray const& r1, Ray const& r2) +{ + if ( !are_near(r1.origin(), r2.origin()) ) + { + THROW_RANGEERROR("passed rays have not the same origin"); + } + + Point M = middle_point(r1.pointAt(1), r2.pointAt(1) ); + if (angle_between(r1, r2) > M_PI) M = 2 * r1.origin() - M; + return Ray(r1.origin(), M); +} + + +} // end namespace Geom + + + +#endif /*_2GEOM_RAY_H_*/ + + +/* + 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 : +*/