mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Slic3r should now be able to detect optimal bridging direction for any kind of bridge. #58
This commit is contained in:
		
							parent
							
								
									5375f5fef4
								
							
						
					
					
						commit
						792960aae1
					
				
					 9 changed files with 117 additions and 42 deletions
				
			
		
							
								
								
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							|  | @ -41,6 +41,7 @@ lib/Slic3r/TriangleMesh/IntersectionLine.pm | ||||||
| MANIFEST			This list of files | MANIFEST			This list of files | ||||||
| README.markdown | README.markdown | ||||||
| slic3r.pl | slic3r.pl | ||||||
|  | t/angles.t | ||||||
| t/arcs.t | t/arcs.t | ||||||
| t/clean_polylines.t | t/clean_polylines.t | ||||||
| t/clipper.t | t/clipper.t | ||||||
|  |  | ||||||
|  | @ -53,7 +53,7 @@ sub make_fill { | ||||||
|     { |     { | ||||||
|         my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->fill_surfaces}; |         my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->fill_surfaces}; | ||||||
|         foreach my $group (Slic3r::Surface->group({merge_solid => 1}, @{$layer->fill_surfaces})) { |         foreach my $group (Slic3r::Surface->group({merge_solid => 1}, @{$layer->fill_surfaces})) { | ||||||
|             my $union = union_ex([ map $_->p, @$group ]); |             my $union = union_ex([ map $_->p, @$group ], undef, 1); | ||||||
|              |              | ||||||
|             # subtract surfaces having a defined bridge_angle from any other |             # subtract surfaces having a defined bridge_angle from any other | ||||||
|             if (@surfaces_with_bridge_angle && !defined $group->[0]->bridge_angle) { |             if (@surfaces_with_bridge_angle && !defined $group->[0]->bridge_angle) { | ||||||
|  |  | ||||||
|  | @ -14,10 +14,11 @@ our @EXPORT_OK = qw( | ||||||
|     rotate_points move_points remove_coinciding_points clip_segment_polygon |     rotate_points move_points remove_coinciding_points clip_segment_polygon | ||||||
|     sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility |     sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility | ||||||
|     line_intersection bounding_box bounding_box_intersect same_point |     line_intersection bounding_box bounding_box_intersect same_point | ||||||
|     longest_segment angle3points three_points_aligned |     longest_segment angle3points three_points_aligned line_direction | ||||||
|     polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices |     polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices | ||||||
|     polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges |     polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges | ||||||
|     shortest_path collinear scale unscale merge_collinear_lines |     shortest_path collinear scale unscale merge_collinear_lines | ||||||
|  |     rad2deg_dir | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| use Slic3r::Geometry::DouglasPeucker qw(Douglas_Peucker); | use Slic3r::Geometry::DouglasPeucker qw(Douglas_Peucker); | ||||||
|  | @ -52,6 +53,14 @@ sub line_atan { | ||||||
|     return atan2($line->[B][Y] - $line->[A][Y], $line->[B][X] - $line->[A][X]); |     return atan2($line->[B][Y] - $line->[A][Y], $line->[B][X] - $line->[A][X]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub line_direction { | ||||||
|  |     my ($line) = @_; | ||||||
|  |     my $atan2 = line_atan($line); | ||||||
|  |     return ($atan2 == PI) ? 0 | ||||||
|  |         : ($atan2 < 0) ? ($atan2 + PI) | ||||||
|  |         : $atan2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub lines_parallel { | sub lines_parallel { | ||||||
|     my ($line1, $line2) = @_; |     my ($line1, $line2) = @_; | ||||||
|      |      | ||||||
|  | @ -311,6 +320,13 @@ sub rad2deg { | ||||||
|     return $rad / PI() * 180; |     return $rad / PI() * 180; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub rad2deg_dir { | ||||||
|  |     my ($rad) = @_; | ||||||
|  |     $rad = ($rad < PI) ? (-$rad + PI/2) : ($rad + PI/2); | ||||||
|  |     $rad += PI if $rad < 0; | ||||||
|  |     return rad2deg($rad); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub rotate_points { | sub rotate_points { | ||||||
|     my ($radians, $center, @points) = @_; |     my ($radians, $center, @points) = @_; | ||||||
|     $center ||= [0,0]; |     $center ||= [0,0]; | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ our @EXPORT_OK = qw(explode_expolygon explode_expolygons safety_offset offset | ||||||
|     is_counter_clockwise); |     is_counter_clockwise); | ||||||
| 
 | 
 | ||||||
| use Math::Clipper 1.02 ':all'; | use Math::Clipper 1.02 ':all'; | ||||||
|  | use Slic3r::Geometry qw(scale); | ||||||
| our $clipper = Math::Clipper->new; | our $clipper = Math::Clipper->new; | ||||||
| 
 | 
 | ||||||
| sub explode_expolygon { | sub explode_expolygon { | ||||||
|  | @ -23,15 +24,15 @@ sub explode_expolygons { | ||||||
| 
 | 
 | ||||||
| sub safety_offset { | sub safety_offset { | ||||||
|     my ($polygons) = @_; |     my ($polygons) = @_; | ||||||
|     return Math::Clipper::offset($polygons, 100, 100, JT_MITER, 2); |     return Math::Clipper::offset($polygons, scale 1e-05, 100, JT_MITER, 2); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub diff_ex { | sub diff_ex { | ||||||
|     my ($subject, $clip) = @_; |     my ($subject, $clip, $safety_offset) = @_; | ||||||
|      |      | ||||||
|     $clipper->clear; |     $clipper->clear; | ||||||
|     $clipper->add_subject_polygons($subject); |     $clipper->add_subject_polygons($subject); | ||||||
|     $clipper->add_clip_polygons($clip); |     $clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip); | ||||||
|     return [ |     return [ | ||||||
|         map Slic3r::ExPolygon->new($_), |         map Slic3r::ExPolygon->new($_), | ||||||
|             @{ $clipper->ex_execute(CT_DIFFERENCE, PFT_NONZERO, PFT_NONZERO) }, |             @{ $clipper->ex_execute(CT_DIFFERENCE, PFT_NONZERO, PFT_NONZERO) }, | ||||||
|  | @ -43,10 +44,10 @@ sub diff { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub union_ex { | sub union_ex { | ||||||
|     my ($polygons, $jointype) = @_; |     my ($polygons, $jointype, $safety_offset) = @_; | ||||||
|     $jointype = PFT_NONZERO unless defined $jointype; |     $jointype = PFT_NONZERO unless defined $jointype; | ||||||
|     $clipper->clear; |     $clipper->clear; | ||||||
|     $clipper->add_subject_polygons($polygons); |     $clipper->add_subject_polygons($safety_offset ? safety_offset($polygons) : $polygons); | ||||||
|     return [ |     return [ | ||||||
|         map Slic3r::ExPolygon->new($_), |         map Slic3r::ExPolygon->new($_), | ||||||
|             @{ $clipper->ex_execute(CT_UNION, $jointype, $jointype) }, |             @{ $clipper->ex_execute(CT_UNION, $jointype, $jointype) }, | ||||||
|  | @ -54,11 +55,11 @@ sub union_ex { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub intersection_ex { | sub intersection_ex { | ||||||
|     my ($subject, $clip, $jointype) = @_; |     my ($subject, $clip, $jointype, $safety_offset) = @_; | ||||||
|     $jointype = PFT_NONZERO unless defined $jointype; |     $jointype = PFT_NONZERO unless defined $jointype; | ||||||
|     $clipper->clear; |     $clipper->clear; | ||||||
|     $clipper->add_subject_polygons($subject); |     $clipper->add_subject_polygons($subject); | ||||||
|     $clipper->add_clip_polygons($clip); |     $clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip); | ||||||
|     return [ |     return [ | ||||||
|         map Slic3r::ExPolygon->new($_), |         map Slic3r::ExPolygon->new($_), | ||||||
|             @{ $clipper->ex_execute(CT_INTERSECTION, $jointype, $jointype) }, |             @{ $clipper->ex_execute(CT_INTERSECTION, $jointype, $jointype) }, | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ package Slic3r::Layer; | ||||||
| use Moo; | use Moo; | ||||||
| 
 | 
 | ||||||
| use Math::Clipper ':all'; | use Math::Clipper ':all'; | ||||||
| use Slic3r::Geometry qw(scale collinear X Y A B PI); | use Slic3r::Geometry qw(scale collinear X Y A B PI rad2deg_dir); | ||||||
| use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex is_counter_clockwise); | use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex is_counter_clockwise); | ||||||
| use XXX; | use XXX; | ||||||
| 
 | 
 | ||||||
|  | @ -224,7 +224,7 @@ sub process_bridges { | ||||||
|         # offset the contour and intersect it with the internal surfaces to discover  |         # offset the contour and intersect it with the internal surfaces to discover  | ||||||
|         # which of them has contact with our bridge |         # which of them has contact with our bridge | ||||||
|         my @supporting_surfaces = (); |         my @supporting_surfaces = (); | ||||||
|         my ($contour_offset) = $expolygon->contour->offset($Slic3r::flow_width / $Slic3r::resolution); |         my ($contour_offset) = $expolygon->contour->offset(scale $Slic3r::flow_width * sqrt(2)); | ||||||
|         foreach my $internal_surface (@internal_surfaces) { |         foreach my $internal_surface (@internal_surfaces) { | ||||||
|             my $intersection = intersection_ex([$contour_offset], [$internal_surface->contour->p]); |             my $intersection = intersection_ex([$contour_offset], [$internal_surface->contour->p]); | ||||||
|             if (@$intersection) { |             if (@$intersection) { | ||||||
|  | @ -236,7 +236,7 @@ sub process_bridges { | ||||||
|             require "Slic3r/SVG.pm"; |             require "Slic3r/SVG.pm"; | ||||||
|             Slic3r::SVG::output(undef, "bridge.svg", |             Slic3r::SVG::output(undef, "bridge.svg", | ||||||
|                 green_polygons  => [ map $_->p, @supporting_surfaces ], |                 green_polygons  => [ map $_->p, @supporting_surfaces ], | ||||||
|                 red_polygons    => [ @$expolygon ], |                 #red_polygons    => [ @$expolygon ], | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  | @ -257,6 +257,7 @@ sub process_bridges { | ||||||
|                     $bridge_over_hole = 1; |                     $bridge_over_hole = 1; | ||||||
|                 } else { |                 } else { | ||||||
|                     foreach my $edge (@surface_edges) { |                     foreach my $edge (@surface_edges) { | ||||||
|  |                         next unless @{$edge->points} >= 4; | ||||||
|                         shift @{$edge->points}; |                         shift @{$edge->points}; | ||||||
|                         pop @{$edge->points}; |                         pop @{$edge->points}; | ||||||
|                     } |                     } | ||||||
|  | @ -272,15 +273,21 @@ sub process_bridges { | ||||||
|                 Slic3r::SVG::output(undef, "bridge.svg", |                 Slic3r::SVG::output(undef, "bridge.svg", | ||||||
|                     polylines       => [ map $_->p, @edges ], |                     polylines       => [ map $_->p, @edges ], | ||||||
|                 ); |                 ); | ||||||
|                 exit if $self->id == 30; |  | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             if (@edges == 2) { |             { | ||||||
|                 my @chords = map Slic3r::Line->new($_->points->[0], $_->points->[-1]), @edges; |                 my $weighted_sum = 0; | ||||||
|                 my @midpoints = map $_->midpoint, @chords; |                 my $total_length = 0; | ||||||
|                 $bridge_angle = -Slic3r::Geometry::rad2deg(Slic3r::Geometry::line_atan(\@midpoints) + PI/2); |                 foreach my $line (map $_->lines, @edges) { | ||||||
|                 Slic3r::debugf "Optimal infill angle of bridge on layer %d is %d degrees\n", $self->id, $bridge_angle; |                     my $len = $line->length; | ||||||
|  |                     $weighted_sum += $len * $line->direction; | ||||||
|  |                     $total_length += $len; | ||||||
|  |                 } | ||||||
|  |                 $bridge_angle = rad2deg_dir(($weighted_sum / $total_length) + PI/2); | ||||||
|             } |             } | ||||||
|  |              | ||||||
|  |             Slic3r::debugf "Optimal infill angle of bridge on layer %d is %d degrees\n", | ||||||
|  |                 $self->id, $bridge_angle if defined $bridge_angle; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         # now, extend our bridge by taking a portion of supporting surfaces |         # now, extend our bridge by taking a portion of supporting surfaces | ||||||
|  |  | ||||||
|  | @ -85,6 +85,11 @@ sub atan { | ||||||
|     return Slic3r::Geometry::line_atan($self); |     return Slic3r::Geometry::line_atan($self); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub direction { | ||||||
|  |     my $self = shift; | ||||||
|  |     return Slic3r::Geometry::line_direction($self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub intersection { | sub intersection { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($line, $require_crossing) = @_; |     my ($line, $require_crossing) = @_; | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ use Moo; | ||||||
| 
 | 
 | ||||||
| use Math::Clipper qw(); | use Math::Clipper qw(); | ||||||
| use Slic3r::Geometry qw(A B polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices | use Slic3r::Geometry qw(A B polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices | ||||||
|     polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges move_points); |     polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges move_points same_point); | ||||||
| use Sub::Quote; | use Sub::Quote; | ||||||
| use XXX; | use XXX; | ||||||
| 
 | 
 | ||||||
|  | @ -156,9 +156,14 @@ sub clip_with_expolygon { | ||||||
|         push @polylines, $current_polyline; |         push @polylines, $current_polyline; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     if (@polylines > 1 && scalar(@{$polylines[-1]}) == 2 && $polylines[-1][-1] eq $polylines[0][0]) { |     if (@polylines > 1 && same_point($polylines[-1][-1], $polylines[0][0])) { | ||||||
|         unshift @{$polylines[0]}, $polylines[-1][0]; |         if (scalar(@{$polylines[-1]}) == 2) { | ||||||
|         pop @polylines; |             unshift @{$polylines[0]}, $polylines[-1][0]; | ||||||
|  |             pop @polylines; | ||||||
|  |         } else { | ||||||
|  |             push @{$polylines[-1]}, $polylines[0][-1]; | ||||||
|  |             shift @polylines; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     return map Slic3r::Polyline->cast($_), @polylines; |     return map Slic3r::Polyline->cast($_), @polylines; | ||||||
|  |  | ||||||
|  | @ -177,6 +177,7 @@ sub detect_surfaces_type { | ||||||
|         my $expolygons = diff_ex( |         my $expolygons = diff_ex( | ||||||
|             [ map { ref $_ eq 'ARRAY' ? $_ : ref $_ eq 'Slic3r::ExPolygon' ? @$_ : $_->p } @$subject_surfaces ], |             [ map { ref $_ eq 'ARRAY' ? $_ : ref $_ eq 'Slic3r::ExPolygon' ? @$_ : $_->p } @$subject_surfaces ], | ||||||
|             [ map { ref $_ eq 'ARRAY' ? $_ : ref $_ eq 'Slic3r::ExPolygon' ? @$_ : $_->p } @$clip_surfaces ], |             [ map { ref $_ eq 'ARRAY' ? $_ : ref $_ eq 'Slic3r::ExPolygon' ? @$_ : $_->p } @$clip_surfaces ], | ||||||
|  |             1, | ||||||
|         ); |         ); | ||||||
|         return grep $_->contour->is_printable, |         return grep $_->contour->is_printable, | ||||||
|             map Slic3r::Surface->cast_from_expolygon($_, surface_type => $result_type),  |             map Slic3r::Surface->cast_from_expolygon($_, surface_type => $result_type),  | ||||||
|  | @ -206,7 +207,6 @@ sub detect_surfaces_type { | ||||||
|         # of current layer and upper one) |         # of current layer and upper one) | ||||||
|         if ($upper_layer) { |         if ($upper_layer) { | ||||||
|             @top = $surface_difference->($layer->surfaces, $upper_layer->surfaces, 'top'); |             @top = $surface_difference->($layer->surfaces, $upper_layer->surfaces, 'top'); | ||||||
|              |  | ||||||
|         } else { |         } else { | ||||||
|             # if no upper layer, all surfaces of this one are solid |             # if no upper layer, all surfaces of this one are solid | ||||||
|             @top = @{$layer->surfaces}; |             @top = @{$layer->surfaces}; | ||||||
|  | @ -217,22 +217,6 @@ sub detect_surfaces_type { | ||||||
|         # of current layer and lower one) |         # of current layer and lower one) | ||||||
|         if ($lower_layer) { |         if ($lower_layer) { | ||||||
|             @bottom = $surface_difference->($layer->surfaces, $lower_layer->surfaces, 'bottom'); |             @bottom = $surface_difference->($layer->surfaces, $lower_layer->surfaces, 'bottom'); | ||||||
|              |  | ||||||
|             $_->contour->merge_continuous_lines for @bottom; |  | ||||||
|              |  | ||||||
|             # merge_continuous_lines could return polylines with less than 3 points (thus invalid) |  | ||||||
|             # actually, this shouldn't happen so it deserves further investigation |  | ||||||
|             @bottom = grep $_->contour->is_valid, @bottom; |  | ||||||
|              |  | ||||||
|             foreach my $surface (@bottom) { |  | ||||||
|                 $surface->contour->remove_acute_vertices; |  | ||||||
|          |  | ||||||
|                 # okay, this is an Ugly Hack(tm) to avoid floating point math problems |  | ||||||
|                 # with diagonal bridges. will find a nicer solution, promised. |  | ||||||
|                 my $offset = safety_offset([$surface->contour->p]); |  | ||||||
|                 @{$surface->contour->points} = map Slic3r::Point->new($_), @{ $offset->[0] }; |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|         } else { |         } else { | ||||||
|             # if no lower layer, all surfaces of this one are solid |             # if no lower layer, all surfaces of this one are solid | ||||||
|             @bottom = @{$layer->surfaces}; |             @bottom = @{$layer->surfaces}; | ||||||
|  | @ -391,7 +375,6 @@ sub infill_every_layers { | ||||||
|                 [ map $_->p, grep $_->surface_type eq 'internal', @{$layer->fill_surfaces} ], |                 [ map $_->p, grep $_->surface_type eq 'internal', @{$layer->fill_surfaces} ], | ||||||
|             ); |             ); | ||||||
|             next if !@$intersection; |             next if !@$intersection; | ||||||
|             my $intersection_offsetted = safety_offset([ map @$_, @$intersection ]); |  | ||||||
|              |              | ||||||
|             # new fill surfaces of the current layer are: |             # new fill surfaces of the current layer are: | ||||||
|             # - any non-internal surface |             # - any non-internal surface | ||||||
|  | @ -414,7 +397,8 @@ sub infill_every_layers { | ||||||
|                                 map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,  |                                 map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,  | ||||||
|                                     @{$layer->fill_surfaces}, |                                     @{$layer->fill_surfaces}, | ||||||
|                             ], |                             ], | ||||||
|                             $intersection_offsetted, |                             $intersection, | ||||||
|  |                             1, | ||||||
|                         )}; |                         )}; | ||||||
|                 } |                 } | ||||||
|                 @{$layer->fill_surfaces} = @new_surfaces; |                 @{$layer->fill_surfaces} = @new_surfaces; | ||||||
|  | @ -435,7 +419,8 @@ sub infill_every_layers { | ||||||
|                                 map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,  |                                 map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,  | ||||||
|                                     @{$lower_layer->fill_surfaces}, |                                     @{$lower_layer->fill_surfaces}, | ||||||
|                             ], |                             ], | ||||||
|                             $intersection_offsetted, |                             $intersection, | ||||||
|  |                             1, | ||||||
|                         )}; |                         )}; | ||||||
|                 } |                 } | ||||||
|                 @{$lower_layer->fill_surfaces} = @new_surfaces; |                 @{$lower_layer->fill_surfaces} = @new_surfaces; | ||||||
|  |  | ||||||
							
								
								
									
										55
									
								
								t/angles.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								t/angles.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | ||||||
|  | use Test::More; | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  | 
 | ||||||
|  | plan tests => 23; | ||||||
|  | 
 | ||||||
|  | BEGIN { | ||||||
|  |     use FindBin; | ||||||
|  |     use lib "$FindBin::Bin/../lib"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | use Slic3r; | ||||||
|  | use Slic3r::Geometry qw(line_atan line_direction rad2deg_dir PI); | ||||||
|  | 
 | ||||||
|  | #========================================================== | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     is line_atan([ [0, 0],  [10, 0] ]),  (0),      'E atan2'; | ||||||
|  |     is line_atan([ [10, 0], [0, 0]  ]),  (PI),     'W atan2'; | ||||||
|  |     is line_atan([ [0, 0],  [0, 10] ]),  (PI/2),   'N atan2'; | ||||||
|  |     is line_atan([ [0, 10], [0, 0]  ]), -(PI/2),   'S atan2'; | ||||||
|  |      | ||||||
|  |     is line_atan([ [10, 10], [0, 0] ]), -(PI*3/4), 'SW atan2'; | ||||||
|  |     is line_atan([ [0, 0], [10, 10] ]),  (PI*1/4), 'NE atan2'; | ||||||
|  |     is line_atan([ [0, 10], [10, 0] ]), -(PI*1/4), 'SE atan2'; | ||||||
|  |     is line_atan([ [10, 0], [0, 10] ]),  (PI*3/4), 'NW atan2'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #========================================================== | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     is line_direction([ [0, 0],  [10, 0] ]), (0),      'E direction'; | ||||||
|  |     is line_direction([ [10, 0], [0, 0]  ]), (0),      'W direction'; | ||||||
|  |     is line_direction([ [0, 0],  [0, 10] ]), (PI/2),   'N direction'; | ||||||
|  |     is line_direction([ [0, 10], [0, 0]  ]), (PI/2),   'S direction'; | ||||||
|  |      | ||||||
|  |     is line_direction([ [10, 10], [0, 0] ]), (PI*1/4), 'SW direction'; | ||||||
|  |     is line_direction([ [0, 0], [10, 10] ]), (PI*1/4), 'NE direction'; | ||||||
|  |     is line_direction([ [0, 10], [10, 0] ]), (PI*3/4), 'SE direction'; | ||||||
|  |     is line_direction([ [10, 0], [0, 10] ]), (PI*3/4), 'NW direction'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #========================================================== | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     is rad2deg_dir(0),        90, 'E (degrees)'; | ||||||
|  |     is rad2deg_dir(PI),      270, 'W (degrees)'; | ||||||
|  |     is rad2deg_dir(PI/2),      0, 'N (degrees)'; | ||||||
|  |     is rad2deg_dir(-(PI/2)), 180, 'S (degrees)'; | ||||||
|  |     is rad2deg_dir(PI*1/4),   45, 'NE (degrees)'; | ||||||
|  |     is rad2deg_dir(PI*3/4),  135, 'NW (degrees)'; | ||||||
|  |     is rad2deg_dir(PI/6),     60, '30°'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #========================================================== | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci