~ubuntu-branches/ubuntu/utopic/slic3r/utopic

« back to all changes in this revision

Viewing changes to xs/src/Point.cpp

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2014-06-17 01:27:26 UTC
  • Revision ID: package-import@ubuntu.com-20140617012726-2wrs4zdo251nr4vg
Tags: upstream-1.1.4+dfsg
ImportĀ upstreamĀ versionĀ 1.1.4+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "Point.hpp"
 
2
#include "Line.hpp"
 
3
#include "MultiPoint.hpp"
 
4
#include <cmath>
 
5
#include <sstream>
 
6
 
 
7
namespace Slic3r {
 
8
 
 
9
Point::Point(double x, double y)
 
10
{
 
11
    this->x = lrint(x);
 
12
    this->y = lrint(y);
 
13
}
 
14
 
 
15
bool
 
16
Point::operator==(const Point& rhs) const
 
17
{
 
18
    return this->coincides_with(rhs);
 
19
}
 
20
 
 
21
std::string
 
22
Point::wkt() const
 
23
{
 
24
    std::ostringstream ss;
 
25
    ss << "POINT(" << this->x << " " << this->y << ")";
 
26
    return ss.str();
 
27
}
 
28
 
 
29
void
 
30
Point::scale(double factor)
 
31
{
 
32
    this->x *= factor;
 
33
    this->y *= factor;
 
34
}
 
35
 
 
36
void
 
37
Point::translate(double x, double y)
 
38
{
 
39
    this->x += x;
 
40
    this->y += y;
 
41
}
 
42
 
 
43
void
 
44
Point::rotate(double angle, const Point &center)
 
45
{
 
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) );
 
50
}
 
51
 
 
52
bool
 
53
Point::coincides_with(const Point &point) const
 
54
{
 
55
    return this->x == point.x && this->y == point.y;
 
56
}
 
57
 
 
58
int
 
59
Point::nearest_point_index(const Points &points) const
 
60
{
 
61
    PointConstPtrs p;
 
62
    p.reserve(points.size());
 
63
    for (Points::const_iterator it = points.begin(); it != points.end(); ++it)
 
64
        p.push_back(&*it);
 
65
    return this->nearest_point_index(p);
 
66
}
 
67
 
 
68
int
 
69
Point::nearest_point_index(const PointConstPtrs &points) const
 
70
{
 
71
    int idx = -1;
 
72
    double distance = -1;  // double because long is limited to 2147483647 on some platforms and it's not enough
 
73
    
 
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;
 
79
        
 
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;
 
84
        
 
85
        idx = it - points.begin();
 
86
        distance = d;
 
87
        
 
88
        if (distance < EPSILON) break;
 
89
    }
 
90
    
 
91
    return idx;
 
92
}
 
93
 
 
94
int
 
95
Point::nearest_point_index(const PointPtrs &points) const
 
96
{
 
97
    PointConstPtrs p;
 
98
    p.reserve(points.size());
 
99
    for (PointPtrs::const_iterator it = points.begin(); it != points.end(); ++it)
 
100
        p.push_back(*it);
 
101
    return this->nearest_point_index(p);
 
102
}
 
103
 
 
104
void
 
105
Point::nearest_point(const Points &points, Point* point) const
 
106
{
 
107
    *point = points.at(this->nearest_point_index(points));
 
108
}
 
109
 
 
110
double
 
111
Point::distance_to(const Point &point) const
 
112
{
 
113
    double dx = ((double)point.x - this->x);
 
114
    double dy = ((double)point.y - this->y);
 
115
    return sqrt(dx*dx + dy*dy);
 
116
}
 
117
 
 
118
double
 
119
Point::distance_to(const Line &line) const
 
120
{
 
121
    if (line.a.coincides_with(line.b)) return this->distance_to(line.a);
 
122
    
 
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);
 
125
    
 
126
    return std::abs(n) / line.length();
 
127
}
 
128
 
 
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
 
135
 */
 
136
double
 
137
Point::ccw(const Point &p1, const Point &p2) const
 
138
{
 
139
    return (double)(p2.x - p1.x)*(double)(this->y - p1.y) - (double)(p2.y - p1.y)*(double)(this->x - p1.x);
 
140
}
 
141
 
 
142
double
 
143
Point::ccw(const Line &line) const
 
144
{
 
145
    return this->ccw(line.a, line.b);
 
146
}
 
147
 
 
148
Point
 
149
Point::projection_onto(const MultiPoint &poly) const
 
150
{
 
151
    Point running_projection = poly.first_point();
 
152
    double running_min = this->distance_to(running_projection);
 
153
    
 
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);
 
160
        }
 
161
    }
 
162
    return running_projection;
 
163
}
 
164
 
 
165
Point
 
166
Point::projection_onto(const Line &line) const
 
167
{
 
168
    if (line.a.coincides_with(line.b)) return line.a;
 
169
    
 
170
    /*
 
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.
 
178
    */
 
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) );
 
181
    
 
182
    if (0.0 <= theta && theta <= 1.0)
 
183
        return theta * line.a + (1.0-theta) * line.b;
 
184
    
 
185
    // Else pick closest endpoint.
 
186
    if (this->distance_to(line.a) < this->distance_to(line.b)) {
 
187
        return line.a;
 
188
    } else {
 
189
        return line.b;
 
190
    }
 
191
}
 
192
 
 
193
Point
 
194
Point::negative() const
 
195
{
 
196
    return Point(-this->x, -this->y);
 
197
}
 
198
 
 
199
Point
 
200
operator+(const Point& point1, const Point& point2)
 
201
{
 
202
    return Point(point1.x + point2.x, point1.y + point2.y);
 
203
}
 
204
 
 
205
Point
 
206
operator*(double scalar, const Point& point2)
 
207
{
 
208
    return Point(scalar * point2.x, scalar * point2.y);
 
209
}
 
210
 
 
211
#ifdef SLIC3RXS
 
212
 
 
213
REGISTER_CLASS(Point, "Point");
 
214
 
 
215
SV*
 
216
Point::to_SV_pureperl() const {
 
217
    AV* av = newAV();
 
218
    av_fill(av, 1);
 
219
    av_store(av, 0, newSViv(this->x));
 
220
    av_store(av, 1, newSViv(this->y));
 
221
    return newRV_noinc((SV*)av);
 
222
}
 
223
 
 
224
void
 
225
Point::from_SV(SV* point_sv)
 
226
{
 
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)));
 
232
}
 
233
 
 
234
void
 
235
Point::from_SV_check(SV* point_sv)
 
236
{
 
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 ));
 
241
    } else {
 
242
        this->from_SV(point_sv);
 
243
    }
 
244
}
 
245
 
 
246
#endif
 
247
 
 
248
void
 
249
Pointf::scale(double factor)
 
250
{
 
251
    this->x *= factor;
 
252
    this->y *= factor;
 
253
}
 
254
 
 
255
void
 
256
Pointf::translate(double x, double y)
 
257
{
 
258
    this->x += x;
 
259
    this->y += y;
 
260
}
 
261
 
 
262
#ifdef SLIC3RXS
 
263
 
 
264
REGISTER_CLASS(Pointf, "Pointf");
 
265
 
 
266
SV*
 
267
Pointf::to_SV_pureperl() const {
 
268
    AV* av = newAV();
 
269
    av_fill(av, 1);
 
270
    av_store(av, 0, newSVnv(this->x));
 
271
    av_store(av, 1, newSVnv(this->y));
 
272
    return newRV_noinc((SV*)av);
 
273
}
 
274
 
 
275
bool
 
276
Pointf::from_SV(SV* point_sv)
 
277
{
 
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;
 
282
    
 
283
    this->x = SvNV(sv_x);
 
284
    this->y = SvNV(sv_y);
 
285
    return true;
 
286
}
 
287
#endif
 
288
 
 
289
void
 
290
Pointf3::scale(double factor)
 
291
{
 
292
    Pointf::scale(factor);
 
293
    this->z *= factor;
 
294
}
 
295
 
 
296
void
 
297
Pointf3::translate(double x, double y, double z)
 
298
{
 
299
    Pointf::translate(x, y);
 
300
    this->z += z;
 
301
}
 
302
 
 
303
#ifdef SLIC3RXS
 
304
REGISTER_CLASS(Pointf3, "Pointf3");
 
305
#endif
 
306
 
 
307
}