@@ -178,6 +178,8 @@ def setup(self, MainWindow):
178
178
self .path_all_cb .setToolTip ('Apply to all slices' )
179
179
self .path_outline_cb = QtWidgets .QCheckBox ('Path outline' )
180
180
self .path_outline_cb .setToolTip ('Include outline in pathing' )
181
+ self .path_central_line_cb = QtWidgets .QCheckBox ('Path central line' )
182
+ self .path_central_line_cb .setToolTip ('Get the central line of the outline' )
181
183
self .rotate_z_path_sb = QtWidgets .QDoubleSpinBox ()
182
184
self .rotate_z_path_sb .setToolTip ('Rotational offset for pathing of slice. Positive is clockwise.' )
183
185
self .rotate_z_path_sb .setSingleStep (5.00 )
@@ -209,11 +211,12 @@ def setup(self, MainWindow):
209
211
#populate pathing layout
210
212
path_gen_layout .addWidget (self .path_all_cb ,0 ,0 ,1 ,1 )
211
213
path_gen_layout .addWidget (self .path_outline_cb ,0 ,1 ,1 ,1 )
212
- path_gen_layout .addWidget (self .rotate_z_path_sb ,0 ,2 ,1 ,1 )
213
- path_gen_layout .addWidget (self .by_width_sb ,0 ,3 ,1 ,1 )
214
- path_gen_layout .addWidget (self .bead_offset_sb ,0 ,4 ,1 ,1 )
214
+ path_gen_layout .addWidget (self .path_central_line_cb ,0 ,2 ,1 ,1 )
215
+ path_gen_layout .addWidget (self .rotate_z_path_sb ,0 ,3 ,1 ,1 )
216
+ path_gen_layout .addWidget (self .by_width_sb ,0 ,4 ,1 ,1 )
217
+ path_gen_layout .addWidget (self .bead_offset_sb ,0 ,5 ,1 ,1 )
215
218
path_gen_layout .addWidget (self .num_paths_label ,1 ,0 ,1 ,2 )
216
- path_gen_layout .addWidget (self .activate_path_pb ,1 ,4 ,1 ,1 )
219
+ path_gen_layout .addWidget (self .activate_path_pb ,1 ,5 ,1 ,1 )
217
220
218
221
self .path_box .setEnabled (False )
219
222
@@ -661,6 +664,8 @@ def draw_slice(self):
661
664
self .slice_data [entry ] = slice_obj (self .outlines [entry ])
662
665
663
666
outline = self .slice_data [entry ].outline
667
+ central_line = self .slice_data [entry ].central_line
668
+ intermediate_line = self .slice_data [entry ].intermediate_line
664
669
665
670
self .current_outline_actor = gen_outline_actor (outline , (1 ,0 ,0 ), 4 )
666
671
self .outline_caption_actor = gen_caption_actor ('%s' % entry , self .current_outline_actor , (1 ,0 ,0 ))
@@ -674,6 +679,15 @@ def draw_slice(self):
674
679
675
680
ax = self .ui .figure .add_subplot (111 )
676
681
ax .plot (outline [:,0 ], outline [:,1 ], 'k-' )
682
+ if intermediate_line != []:
683
+ for line in intermediate_line :
684
+ x_coords = [point [0 ] for point in line ]
685
+ y_coords = [point [1 ] for point in line ]
686
+ ax .plot (x_coords , y_coords , 'g-' )
687
+ # # plot the points
688
+ # ax.plot(x_coords, y_coords, 'ro')
689
+ if len (central_line ) != 0 :
690
+ ax .plot (central_line [:,0 ], central_line [:,1 ], 'r-' )
677
691
ax .set_ylabel ("y (mm)" )
678
692
ax .set_xlabel ("x (mm)" )
679
693
ax .grid (visible = True , which = 'major' , color = '#666666' , linestyle = '-' , alpha = 0.1 )
@@ -734,14 +748,25 @@ def make_paths(self):
734
748
interior = offset_poly (outline ,- self .ui .by_width_sb .value ())
735
749
midline = offset_poly (outline ,- self .ui .by_width_sb .value ()* 0.5 )
736
750
innie = offset_poly (outline ,- self .ui .by_width_sb .value ())
737
- intersecting_lines , param = get_intersections (innie ,theta ,self .ui .by_width_sb .value (),offset )
751
+ intersecting_lines , param , _ = get_intersections (
752
+ innie ,theta ,self .ui .by_width_sb .value (),offset )
738
753
local_path_collection .append (midline )
739
754
local_path_collection .extend (intersecting_lines )
755
+ self .ui .num_paths_label .setText ('N = %i at %0.2f%%' % (len (intersecting_lines ),param * 100 ))
756
+ # update interactor with result
757
+ self .ui .num_paths_label .setText ('N = %i at %0.2f%%' % (len (intersecting_lines ),param * 100 ))
758
+
759
+ elif self .ui .path_central_line_cb .isChecked ():
760
+ ordered_certral_line_path , skeleton_path = self .get_ordered_central_line_path (outline , entry )
761
+ self .slice_data [entry ].central_line = np .array (ordered_certral_line_path )
762
+ self .slice_data [entry ].intermediate_line = skeleton_path
763
+
740
764
else :
741
- intersecting_lines , param = get_intersections (outline ,theta ,self .ui .by_width_sb .value (),offset )
765
+ intersecting_lines , param , _ = get_intersections (
766
+ outline ,theta ,self .ui .by_width_sb .value (),offset )
742
767
local_path_collection = intersecting_lines
743
768
744
- self .slice_data [entry ].paths = local_path_collection #list of paths
769
+ self .slice_data [entry ].paths = local_path_collection #list of paths
745
770
746
771
else : #iterate over all entries
747
772
for i in range (self .ui .slice_num_cb .count ()):
@@ -754,20 +779,61 @@ def make_paths(self):
754
779
interior = offset_poly (outline ,- self .ui .by_width_sb .value ())
755
780
midline = offset_poly (outline ,- self .ui .by_width_sb .value ()* 0.5 )
756
781
innie = offset_poly (outline ,- self .ui .by_width_sb .value ())
757
- intersecting_lines , param = get_intersections (innie ,theta ,self .ui .by_width_sb .value (),offset )
782
+ intersecting_lines , param , _ = get_intersections (
783
+ innie ,theta ,self .ui .by_width_sb .value (),offset )
758
784
local_path_collection .append (midline )
759
785
local_path_collection .extend (intersecting_lines )
786
+ # update interactor with result
787
+ self .ui .num_paths_label .setText ('N = %i at %0.2f%%' % (len (intersecting_lines ),param * 100 ))
788
+
789
+ elif self .ui .path_central_line_cb .isChecked ():
790
+ ordered_certral_line_path , skeleton_path = self .get_ordered_central_line_path (outline , entry )
791
+ self .slice_data [entry ].central_line = np .array (ordered_certral_line_path )
792
+ self .slice_data [entry ].intermediate_line = skeleton_path
793
+
760
794
else :
761
- intersecting_lines , param = get_intersections (outline ,theta ,self .ui .by_width_sb .value (),offset )
795
+ intersecting_lines , param , _ = get_intersections (
796
+ outline ,theta ,self .ui .by_width_sb .value (),offset )
762
797
local_path_collection = intersecting_lines
763
798
764
799
self .slice_data [entry ].paths = local_path_collection #list of paths
765
800
766
- # update interactor with result
767
- self .ui .num_paths_label .setText ('N = %i at %0.2f%%' % (len (intersecting_lines ),param * 100 ))
801
+
768
802
self .ui .export_slice .setEnabled (True )
769
803
self .draw_slice () #to clear any existing intersections
770
804
805
+ def get_ordered_central_line_path (self , outline , entry ):
806
+ step_size = 30.01
807
+ limits = get_limits (outline ,0 )
808
+ suggested_hatching_offset = min ((limits [1 ]- limits [0 ]),(limits [3 ]- limits [2 ]))/ 15
809
+ whole_angle = 180
810
+ skeleton_dict = get_skeleton_dict (outline ,whole_angle ,step_size ,
811
+ suggested_hatching_offset )
812
+
813
+ certral_line_path = get_central_line_path (skeleton_dict , entry )
814
+ ordered_certral_line_path = order_points_in_loop (certral_line_path )
815
+ starting_point_index = get_starting_point (ordered_certral_line_path )
816
+ ordered_certral_line_path = np .concatenate ((ordered_certral_line_path [starting_point_index :],
817
+ ordered_certral_line_path [:starting_point_index ]), axis = 0 )
818
+ ordered_certral_line_path = self .remove_repeated_points_preserve_order (ordered_certral_line_path )
819
+ ordered_certral_line_path = order_points_in_loop (ordered_certral_line_path )[:- 1 ]
820
+ # get the skeleton of the outline
821
+ skeleton = []
822
+ for key in skeleton_dict .keys ():
823
+ for value in skeleton_dict [key ].values ():
824
+ skeleton .append (value )
825
+ return ordered_certral_line_path , skeleton
826
+
827
+ def remove_repeated_points_preserve_order (self , points ):
828
+ seen = set ()
829
+ unique_points = []
830
+ for point in points :
831
+ point_tuple = tuple (point )
832
+ if point_tuple not in seen :
833
+ seen .add (point_tuple )
834
+ unique_points .append (point )
835
+ return np .array (unique_points )
836
+
771
837
def draw_paths (self ):
772
838
773
839
#get active outline
@@ -797,6 +863,8 @@ def __init__(self, outline):
797
863
self .outline = outline
798
864
self .alpha = None
799
865
self .paths = None
866
+ self .central_line = []
867
+ self .intermediate_line = []
800
868
801
869
if __name__ == "__main__" :
802
870
launch ()
0 commit comments