New Point::projection_onto() methods
This commit is contained in:
parent
874c7a6e8b
commit
254ab29a97
@ -1,5 +1,6 @@
|
|||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "Line.hpp"
|
#include "Line.hpp"
|
||||||
|
#include "MultiPoint.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@ -138,6 +139,63 @@ Point::ccw(const Line &line) const
|
|||||||
return this->ccw(line.a, line.b);
|
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
|
#ifdef SLIC3RXS
|
||||||
|
|
||||||
REGISTER_CLASS(Point, "Point");
|
REGISTER_CLASS(Point, "Point");
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class Line;
|
class Line;
|
||||||
|
class MultiPoint;
|
||||||
class Point;
|
class Point;
|
||||||
class Pointf;
|
class Pointf;
|
||||||
typedef Point Vector;
|
typedef Point Vector;
|
||||||
@ -37,6 +38,8 @@ class Point
|
|||||||
double distance_to(const Line &line) const;
|
double distance_to(const Line &line) const;
|
||||||
double ccw(const Point &p1, const Point &p2) const;
|
double ccw(const Point &p1, const Point &p2) const;
|
||||||
double ccw(const Line &line) const;
|
double ccw(const Line &line) const;
|
||||||
|
Point projection_onto(const MultiPoint &poly) const;
|
||||||
|
Point projection_onto(const Line &line) const;
|
||||||
|
|
||||||
#ifdef SLIC3RXS
|
#ifdef SLIC3RXS
|
||||||
void from_SV(SV* point_sv);
|
void from_SV(SV* point_sv);
|
||||||
@ -45,6 +48,9 @@ class Point
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Point operator+(const Point& point1, const Point& point2);
|
||||||
|
Point operator*(double scalar, const Point& point2);
|
||||||
|
|
||||||
class Point3 : public Point
|
class Point3 : public Point
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 10;
|
use Test::More tests => 13;
|
||||||
|
|
||||||
my $point = Slic3r::Point->new(10, 15);
|
my $point = Slic3r::Point->new(10, 15);
|
||||||
is_deeply [ @$point ], [10, 15], 'point roundtrip';
|
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';
|
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__
|
__END__
|
||||||
|
@ -29,6 +29,12 @@
|
|||||||
%code{% RETVAL = THIS->distance_to(*line); %};
|
%code{% RETVAL = THIS->distance_to(*line); %};
|
||||||
double ccw(Point* p1, Point* p2)
|
double ccw(Point* p1, Point* p2)
|
||||||
%code{% RETVAL = THIS->ccw(*p1, *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