New Point::projection_onto() methods
This commit is contained in:
parent
874c7a6e8b
commit
254ab29a97
@ -1,5 +1,6 @@
|
||||
#include "Point.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "MultiPoint.hpp"
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
@ -138,6 +139,63 @@ Point::ccw(const Line &line) const
|
||||
return this->ccw(line.a, line.b);
|
||||
}
|
||||
|
||||
Point
|
||||
Point::projection_onto(const MultiPoint &poly) const
|
||||
{
|
||||
Point running_projection = poly.first_point();
|
||||
double running_min = this->distance_to(running_projection);
|
||||
|
||||
Lines lines = poly.lines();
|
||||
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
|
||||
Point point_temp = this->projection_onto(*line);
|
||||
if (this->distance_to(point_temp) < running_min) {
|
||||
running_projection = point_temp;
|
||||
running_min = this->distance_to(running_projection);
|
||||
}
|
||||
}
|
||||
return running_projection;
|
||||
}
|
||||
|
||||
Point
|
||||
Point::projection_onto(const Line &line) const
|
||||
{
|
||||
if (line.a.coincides_with(line.b)) return line.a;
|
||||
|
||||
/*
|
||||
(Ported from VisiLibity by Karl J. Obermeyer)
|
||||
The projection of point_temp onto the line determined by
|
||||
line_segment_temp can be represented as an affine combination
|
||||
expressed in the form projection of
|
||||
Point = theta*line_segment_temp.first + (1.0-theta)*line_segment_temp.second.
|
||||
If theta is outside the interval [0,1], then one of the Line_Segment's endpoints
|
||||
must be closest to calling Point.
|
||||
*/
|
||||
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) )
|
||||
/ ( (double)pow(line.b.x - line.a.x, 2) + (double)pow(line.b.y - line.a.y, 2) );
|
||||
|
||||
if (0.0 <= theta && theta <= 1.0)
|
||||
return theta * line.a + (1.0-theta) * line.b;
|
||||
|
||||
// Else pick closest endpoint.
|
||||
if (this->distance_to(line.a) < this->distance_to(line.b)) {
|
||||
return line.a;
|
||||
} else {
|
||||
return line.b;
|
||||
}
|
||||
}
|
||||
|
||||
Point
|
||||
operator+(const Point& point1, const Point& point2)
|
||||
{
|
||||
return Point(point1.x + point2.x, point1.y + point2.y);
|
||||
}
|
||||
|
||||
Point
|
||||
operator*(double scalar, const Point& point2)
|
||||
{
|
||||
return Point(scalar * point2.x, scalar * point2.y);
|
||||
}
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
|
||||
REGISTER_CLASS(Point, "Point");
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace Slic3r {
|
||||
|
||||
class Line;
|
||||
class MultiPoint;
|
||||
class Point;
|
||||
class Pointf;
|
||||
typedef Point Vector;
|
||||
@ -37,6 +38,8 @@ class Point
|
||||
double distance_to(const Line &line) const;
|
||||
double ccw(const Point &p1, const Point &p2) const;
|
||||
double ccw(const Line &line) const;
|
||||
Point projection_onto(const MultiPoint &poly) const;
|
||||
Point projection_onto(const Line &line) const;
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
void from_SV(SV* point_sv);
|
||||
@ -45,6 +48,9 @@ class Point
|
||||
#endif
|
||||
};
|
||||
|
||||
Point operator+(const Point& point1, const Point& point2);
|
||||
Point operator*(double scalar, const Point& point2);
|
||||
|
||||
class Point3 : public Point
|
||||
{
|
||||
public:
|
||||
|
@ -4,7 +4,7 @@ use strict;
|
||||
use warnings;
|
||||
|
||||
use Slic3r::XS;
|
||||
use Test::More tests => 10;
|
||||
use Test::More tests => 13;
|
||||
|
||||
my $point = Slic3r::Point->new(10, 15);
|
||||
is_deeply [ @$point ], [10, 15], 'point roundtrip';
|
||||
@ -46,4 +46,16 @@ ok !$point->coincides_with($point2), 'coincides_with';
|
||||
ok $p0->ccw($p1, $p2) < 0, 'ccw() does not overflow';
|
||||
}
|
||||
|
||||
{
|
||||
my $point = Slic3r::Point->new(15,15);
|
||||
my $line = Slic3r::Line->new([10,10], [20,10]);
|
||||
is_deeply $point->projection_onto_line($line)->pp, [15,10], 'project_onto_line';
|
||||
|
||||
$point = Slic3r::Point->new(0, 15);
|
||||
is_deeply $point->projection_onto_line($line)->pp, [10,10], 'project_onto_line';
|
||||
|
||||
$point = Slic3r::Point->new(25, 15);
|
||||
is_deeply $point->projection_onto_line($line)->pp, [20,10], 'project_onto_line';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
@ -29,6 +29,12 @@
|
||||
%code{% RETVAL = THIS->distance_to(*line); %};
|
||||
double ccw(Point* p1, Point* p2)
|
||||
%code{% RETVAL = THIS->ccw(*p1, *p2); %};
|
||||
Clone<Point> projection_onto_polygon(Polygon* polygon)
|
||||
%code{% RETVAL = new Point(THIS->projection_onto(*polygon)); %};
|
||||
Clone<Point> projection_onto_polyline(Polyline* polyline)
|
||||
%code{% RETVAL = new Point(THIS->projection_onto(*polyline)); %};
|
||||
Clone<Point> projection_onto_line(Line* line)
|
||||
%code{% RETVAL = new Point(THIS->projection_onto(*line)); %};
|
||||
|
||||
%{
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user