| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * \file | ||
| 3 | * \brief Infinite straight ray | ||
| 4 | *//* | ||
| 5 | * Copyright 2008 Marco Cecchetti <mrcekets at gmail.com> | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or | ||
| 8 | * modify it either under the terms of the GNU Lesser General Public | ||
| 9 | * License version 2.1 as published by the Free Software Foundation | ||
| 10 | * (the "LGPL") or, at your option, under the terms of the Mozilla | ||
| 11 | * Public License Version 1.1 (the "MPL"). If you do not alter this | ||
| 12 | * notice, a recipient may use your version of this file under either | ||
| 13 | * the MPL or the LGPL. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the LGPL along with this library | ||
| 16 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | * You should have received a copy of the MPL along with this library | ||
| 19 | * in the file COPYING-MPL-1.1 | ||
| 20 | * | ||
| 21 | * The contents of this file are subject to the Mozilla Public License | ||
| 22 | * Version 1.1 (the "License"); you may not use this file except in | ||
| 23 | * compliance with the License. You may obtain a copy of the License at | ||
| 24 | * http://www.mozilla.org/MPL/ | ||
| 25 | * | ||
| 26 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY | ||
| 27 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for | ||
| 28 | * the specific language governing rights and limitations. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #ifndef LIB2GEOM_SEEN_RAY_H | ||
| 32 | #define LIB2GEOM_SEEN_RAY_H | ||
| 33 | |||
| 34 | #include <vector> | ||
| 35 | #include <2geom/point.h> | ||
| 36 | #include <2geom/bezier-curve.h> // for LineSegment | ||
| 37 | #include <2geom/exception.h> | ||
| 38 | #include <2geom/math-utils.h> | ||
| 39 | #include <2geom/transforms.h> | ||
| 40 | #include <2geom/angle.h> | ||
| 41 | |||
| 42 | namespace Geom | ||
| 43 | { | ||
| 44 | |||
| 45 | /** | ||
| 46 | * @brief Straight ray from a specific point to infinity. | ||
| 47 | * | ||
| 48 | * Rays are "half-lines" - they begin at some specific point and extend in a straight line | ||
| 49 | * to infinity. | ||
| 50 | * | ||
| 51 | * @ingroup Primitives | ||
| 52 | */ | ||
| 53 | class Ray { | ||
| 54 | private: | ||
| 55 | Point _origin; | ||
| 56 | Point _vector; | ||
| 57 | |||
| 58 | public: | ||
| 59 | ✗ | Ray() : _origin(0,0), _vector(1,0) {} | |
| 60 | ✗ | Ray(Point const& origin, Coord angle) | |
| 61 | ✗ | : _origin(origin) | |
| 62 | { | ||
| 63 | ✗ | sincos(angle, _vector[Y], _vector[X]); | |
| 64 | ✗ | } | |
| 65 | ✗ | Ray(Point const& A, Point const& B) { | |
| 66 | ✗ | setPoints(A, B); | |
| 67 | ✗ | } | |
| 68 | ✗ | Point origin() const { return _origin; } | |
| 69 | ✗ | Point vector() const { return _vector; } | |
| 70 | Point versor() const { return _vector.normalized(); } | ||
| 71 | ✗ | void setOrigin(Point const &o) { _origin = o; } | |
| 72 | ✗ | void setVector(Point const& v) { _vector = v; } | |
| 73 | Coord angle() const { return std::atan2(_vector[Y], _vector[X]); } | ||
| 74 | void setAngle(Coord a) { sincos(a, _vector[Y], _vector[X]); } | ||
| 75 | ✗ | void setPoints(Point const &a, Point const &b) { | |
| 76 | ✗ | _origin = a; | |
| 77 | ✗ | _vector = b - a; | |
| 78 | ✗ | if (are_near(_vector, Point(0,0)) ) | |
| 79 | ✗ | _vector = Point(0,0); | |
| 80 | else | ||
| 81 | ✗ | _vector.normalize(); | |
| 82 | ✗ | } | |
| 83 | ✗ | bool isDegenerate() const { | |
| 84 | ✗ | return ( _vector[X] == 0 && _vector[Y] == 0 ); | |
| 85 | } | ||
| 86 | ✗ | Point pointAt(Coord t) const { | |
| 87 | ✗ | return _origin + _vector * t; | |
| 88 | } | ||
| 89 | ✗ | Coord valueAt(Coord t, Dim2 d) const { | |
| 90 | ✗ | return _origin[d] + _vector[d] * t; | |
| 91 | } | ||
| 92 | ✗ | std::vector<Coord> roots(Coord v, Dim2 d) const { | |
| 93 | ✗ | std::vector<Coord> result; | |
| 94 | ✗ | if ( _vector[d] != 0 ) { | |
| 95 | ✗ | double t = (v - _origin[d]) / _vector[d]; | |
| 96 | ✗ | if (t >= 0) result.push_back(t); | |
| 97 | ✗ | } else if (_vector[(d+1)%2] == v) { | |
| 98 | ✗ | THROW_INFINITESOLUTIONS(); | |
| 99 | } | ||
| 100 | ✗ | return result; | |
| 101 | ✗ | } | |
| 102 | ✗ | Coord nearestTime(Point const& point) const { | |
| 103 | ✗ | if ( isDegenerate() ) return 0; | |
| 104 | ✗ | double t = dot(point - _origin, _vector); | |
| 105 | ✗ | if (t < 0) t = 0; | |
| 106 | ✗ | return t; | |
| 107 | } | ||
| 108 | ✗ | Ray reverse() const { | |
| 109 | ✗ | Ray result; | |
| 110 | ✗ | result.setOrigin(_origin); | |
| 111 | ✗ | result.setVector(-_vector); | |
| 112 | ✗ | return result; | |
| 113 | } | ||
| 114 | Curve *portion(Coord f, Coord t) const { | ||
| 115 | return new LineSegment(pointAt(f), pointAt(t)); | ||
| 116 | } | ||
| 117 | ✗ | LineSegment segment(Coord f, Coord t) const { | |
| 118 | ✗ | return LineSegment(pointAt(f), pointAt(t)); | |
| 119 | } | ||
| 120 | ✗ | Ray transformed(Affine const& m) const { | |
| 121 | ✗ | return Ray(_origin * m, (_origin + _vector) * m); | |
| 122 | } | ||
| 123 | }; // end class Ray | ||
| 124 | |||
| 125 | inline | ||
| 126 | ✗ | double distance(Point const& _point, Ray const& _ray) { | |
| 127 | ✗ | double t = _ray.nearestTime(_point); | |
| 128 | ✗ | return ::Geom::distance(_point, _ray.pointAt(t)); | |
| 129 | } | ||
| 130 | |||
| 131 | inline | ||
| 132 | ✗ | bool are_near(Point const& _point, Ray const& _ray, double eps = EPSILON) { | |
| 133 | ✗ | return are_near(distance(_point, _ray), 0, eps); | |
| 134 | } | ||
| 135 | |||
| 136 | inline | ||
| 137 | ✗ | bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) { | |
| 138 | ✗ | return are_near(r1.vector(), r2.vector(), eps) | |
| 139 | ✗ | && are_near(r1.origin(), r2.origin(), eps); | |
| 140 | } | ||
| 141 | |||
| 142 | // evaluate the angle between r1 and r2 rotating r1 in cw or ccw direction on r2 | ||
| 143 | // the returned value is an angle in the interval [0, 2PI[ | ||
| 144 | inline | ||
| 145 | ✗ | double angle_between(Ray const& r1, Ray const& r2, bool cw = true) { | |
| 146 | ✗ | double angle = angle_between(r1.vector(), r2.vector()); | |
| 147 | ✗ | if (angle < 0) angle += 2*M_PI; | |
| 148 | ✗ | if (!cw) angle = 2*M_PI - angle; | |
| 149 | ✗ | return angle; | |
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * @brief Returns the angle bisector for the two given rays. | ||
| 154 | * | ||
| 155 | * @a r1 is rotated half the way to @a r2 in either clockwise or counter-clockwise direction. | ||
| 156 | * | ||
| 157 | * @pre Both passed rays must have the same origin. | ||
| 158 | * | ||
| 159 | * @remarks If the versors of both given rays point in the same direction, the direction of the | ||
| 160 | * angle bisector ray depends on the third parameter: | ||
| 161 | * - If @a cw is set to @c true, the returned ray will equal the passed rays @a r1 and @a r2. | ||
| 162 | * - If @a cw is set to @c false, the returned ray will go in the opposite direction. | ||
| 163 | * | ||
| 164 | * @throws RangeError if the given rays do not have the same origins | ||
| 165 | */ | ||
| 166 | inline | ||
| 167 | ✗ | Ray make_angle_bisector_ray(Ray const& r1, Ray const& r2, bool cw = true) | |
| 168 | { | ||
| 169 | ✗ | if ( !are_near(r1.origin(), r2.origin()) ) | |
| 170 | { | ||
| 171 | ✗ | THROW_RANGEERROR("passed rays do not have the same origin"); | |
| 172 | } | ||
| 173 | |||
| 174 | ✗ | Ray bisector(r1.origin(), r1.origin() + r1.vector() * Rotate(angle_between(r1, r2) / 2.0)); | |
| 175 | |||
| 176 | ✗ | return (cw ? bisector : bisector.reverse()); | |
| 177 | } | ||
| 178 | |||
| 179 | } // end namespace Geom | ||
| 180 | |||
| 181 | #endif // LIB2GEOM_SEEN_RAY_H | ||
| 182 | |||
| 183 | /* | ||
| 184 | Local Variables: | ||
| 185 | mode:c++ | ||
| 186 | c-file-style:"stroustrup" | ||
| 187 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
| 188 | indent-tabs-mode:nil | ||
| 189 | fill-column:99 | ||
| 190 | End: | ||
| 191 | */ | ||
| 192 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : | ||
| 193 |