3
#include "MultiPoint.hpp"
9
Point::Point(double x, double y)
16
Point::operator==(const Point& rhs) const
18
return this->coincides_with(rhs);
24
std::ostringstream ss;
25
ss << "POINT(" << this->x << " " << this->y << ")";
30
Point::scale(double factor)
37
Point::translate(double x, double y)
44
Point::rotate(double angle, const Point ¢er)
46
double cur_x = (double)this->x;
47
double cur_y = (double)this->y;
48
this->x = (coord_t)round( (double)center.x + cos(angle) * (cur_x - (double)center.x) - sin(angle) * (cur_y - (double)center.y) );
49
this->y = (coord_t)round( (double)center.y + cos(angle) * (cur_y - (double)center.y) + sin(angle) * (cur_x - (double)center.x) );
53
Point::coincides_with(const Point &point) const
55
return this->x == point.x && this->y == point.y;
59
Point::nearest_point_index(const Points &points) const
62
p.reserve(points.size());
63
for (Points::const_iterator it = points.begin(); it != points.end(); ++it)
65
return this->nearest_point_index(p);
69
Point::nearest_point_index(const PointConstPtrs &points) const
72
double distance = -1; // double because long is limited to 2147483647 on some platforms and it's not enough
74
for (PointConstPtrs::const_iterator it = points.begin(); it != points.end(); ++it) {
75
/* If the X distance of the candidate is > than the total distance of the
76
best previous candidate, we know we don't want it */
77
double d = pow(this->x - (*it)->x, 2);
78
if (distance != -1 && d > distance) continue;
80
/* If the Y distance of the candidate is > than the total distance of the
81
best previous candidate, we know we don't want it */
82
d += pow(this->y - (*it)->y, 2);
83
if (distance != -1 && d > distance) continue;
85
idx = it - points.begin();
88
if (distance < EPSILON) break;
95
Point::nearest_point_index(const PointPtrs &points) const
98
p.reserve(points.size());
99
for (PointPtrs::const_iterator it = points.begin(); it != points.end(); ++it)
101
return this->nearest_point_index(p);
105
Point::nearest_point(const Points &points, Point* point) const
107
*point = points.at(this->nearest_point_index(points));
111
Point::distance_to(const Point &point) const
113
double dx = ((double)point.x - this->x);
114
double dy = ((double)point.y - this->y);
115
return sqrt(dx*dx + dy*dy);
119
Point::distance_to(const Line &line) const
121
if (line.a.coincides_with(line.b)) return this->distance_to(line.a);
123
double n = (double)(line.b.x - line.a.x) * (double)(line.a.y - this->y)
124
- (double)(line.a.x - this->x) * (double)(line.b.y - line.a.y);
126
return std::abs(n) / line.length();
129
/* Three points are a counter-clockwise turn if ccw > 0, clockwise if
130
* ccw < 0, and collinear if ccw = 0 because ccw is a determinant that
131
* gives the signed area of the triangle formed by p1, p2 and this point.
132
* In other words it is the 2D cross product of p1-p2 and p1-this, i.e.
133
* z-component of their 3D cross product.
134
* We return double because it must be big enough to hold 2*max(|coordinate|)^2
137
Point::ccw(const Point &p1, const Point &p2) const
139
return (double)(p2.x - p1.x)*(double)(this->y - p1.y) - (double)(p2.y - p1.y)*(double)(this->x - p1.x);
143
Point::ccw(const Line &line) const
145
return this->ccw(line.a, line.b);
149
Point::projection_onto(const MultiPoint &poly) const
151
Point running_projection = poly.first_point();
152
double running_min = this->distance_to(running_projection);
154
Lines lines = poly.lines();
155
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
156
Point point_temp = this->projection_onto(*line);
157
if (this->distance_to(point_temp) < running_min) {
158
running_projection = point_temp;
159
running_min = this->distance_to(running_projection);
162
return running_projection;
166
Point::projection_onto(const Line &line) const
168
if (line.a.coincides_with(line.b)) return line.a;
171
(Ported from VisiLibity by Karl J. Obermeyer)
172
The projection of point_temp onto the line determined by
173
line_segment_temp can be represented as an affine combination
174
expressed in the form projection of
175
Point = theta*line_segment_temp.first + (1.0-theta)*line_segment_temp.second.
176
If theta is outside the interval [0,1], then one of the Line_Segment's endpoints
177
must be closest to calling Point.
179
double theta = ( (double)(line.b.x - this->x)*(double)(line.b.x - line.a.x) + (double)(line.b.y- this->y)*(double)(line.b.y - line.a.y) )
180
/ ( (double)pow(line.b.x - line.a.x, 2) + (double)pow(line.b.y - line.a.y, 2) );
182
if (0.0 <= theta && theta <= 1.0)
183
return theta * line.a + (1.0-theta) * line.b;
185
// Else pick closest endpoint.
186
if (this->distance_to(line.a) < this->distance_to(line.b)) {
194
Point::negative() const
196
return Point(-this->x, -this->y);
200
operator+(const Point& point1, const Point& point2)
202
return Point(point1.x + point2.x, point1.y + point2.y);
206
operator*(double scalar, const Point& point2)
208
return Point(scalar * point2.x, scalar * point2.y);
213
REGISTER_CLASS(Point, "Point");
216
Point::to_SV_pureperl() const {
219
av_store(av, 0, newSViv(this->x));
220
av_store(av, 1, newSViv(this->y));
221
return newRV_noinc((SV*)av);
225
Point::from_SV(SV* point_sv)
227
AV* point_av = (AV*)SvRV(point_sv);
228
// get a double from Perl and round it, otherwise
229
// it would get truncated
230
this->x = lrint(SvNV(*av_fetch(point_av, 0, 0)));
231
this->y = lrint(SvNV(*av_fetch(point_av, 1, 0)));
235
Point::from_SV_check(SV* point_sv)
237
if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
238
if (!sv_isa(point_sv, perl_class_name(this)) && !sv_isa(point_sv, perl_class_name_ref(this)))
239
CONFESS("Not a valid %s object (got %s)", perl_class_name(this), HvNAME(SvSTASH(SvRV(point_sv))));
240
*this = *(Point*)SvIV((SV*)SvRV( point_sv ));
242
this->from_SV(point_sv);
249
Pointf::scale(double factor)
256
Pointf::translate(double x, double y)
264
REGISTER_CLASS(Pointf, "Pointf");
267
Pointf::to_SV_pureperl() const {
270
av_store(av, 0, newSVnv(this->x));
271
av_store(av, 1, newSVnv(this->y));
272
return newRV_noinc((SV*)av);
276
Pointf::from_SV(SV* point_sv)
278
AV* point_av = (AV*)SvRV(point_sv);
279
SV* sv_x = *av_fetch(point_av, 0, 0);
280
SV* sv_y = *av_fetch(point_av, 1, 0);
281
if (!looks_like_number(sv_x) || !looks_like_number(sv_y)) return false;
283
this->x = SvNV(sv_x);
284
this->y = SvNV(sv_y);
290
Pointf3::scale(double factor)
292
Pointf::scale(factor);
297
Pointf3::translate(double x, double y, double z)
299
Pointf::translate(x, y);
304
REGISTER_CLASS(Pointf3, "Pointf3");