mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	New Point::projection_onto() methods
This commit is contained in:
		
							parent
							
								
									874c7a6e8b
								
							
						
					
					
						commit
						254ab29a97
					
				
					 4 changed files with 83 additions and 1 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci