def process_boundaries(self, new_vertices, boundary_points, lower_bound_x, lower_bound_y, upper_bound_x, upper_bound_y): #First task is to remove duplicate points in new vertices #Start with first point in list #Then loop, if this point is identical to the one before it, dont add no_dups = gen_utils.remove_ordered_duplicates(new_vertices) #Now do second round of processing to insert boundary points #Need to find Exit->enter pairs #Re shape boudnary list for easier processing #If first element is enter, push to back #want Exit then Enter in list if boundary_points[0][0] == ENTER: boundary_points = boundary_points[1:] + [boundary_points[0]] #Loop to process exit,enter pairs for i in range(0,len(boundary_points)-1): #Only look at element i if i is exit, i+1 is enter if boundary_points[i][0] == EXIT and boundary_points[i+1][0] == ENTER: #Look up points to insert, i #Insert them after the exit point int the vertices list exit_point = boundary_points[i][1] enter_point = boundary_points[i+1][1] points_to_insert = exit_enter_window_points_lookup(exit_point,enter_point, lower_bound_x, lower_bound_y, upper_bound_x, upper_bound_y) #Now loop through list of vertices and insert after exit for i in range(0,len(no_dups)): if no_dups[i] == exit_point: #Insert points after index i no_dups = no_dups[:i+1] + points_to_insert + no_dups[i+1:] #End now break else: #Go to next i, currently looking at backwards Enter,Exit pair continue return no_dups
def get_fill_points(self): #Fill points to return rv = [] #First determine scan line ranges top_right,bottom_left = self.get_bounding_box_points() #Scan lines are horizontal, loop over Y range for y in range(int(bottom_left.y),int(top_right.y+1)): #Fill points just for this scan line scan_line_fill_points = [] #Scan line goes from xmin to x max scan_line_p1 = Point() scan_line_p1.x = bottom_left.x scan_line_p1.y = y scan_line_p2 = Point() scan_line_p2.x = top_right.x scan_line_p2.y = y scan_line = Line() #The whole line scan_line.p1 = scan_line_p1 scan_line.p2 = scan_line_p2 #For this scan line collect intsection points intersection_points = [] #of all lines from poly poly_lines = self.to_lines() for poly_line in poly_lines: intersection = poly_line.get_intersection_point(scan_line) if not(intersection is None): #Add intersection point to list intersection_points = intersection_points + [intersection] #Sort the interesection points by x values (for scanning left to right) intersection_points.sort(key = lambda p: p.x) #Pythonic indeed #Remove duplicate intersection points intersection_points = gen_utils.remove_ordered_duplicates(intersection_points) #Process points in groups of 2 # p0 p1 p2 p3 # enter exit enter exit # line p0->p1 and line p2->p3 i = 0 p0_is_enter = True while i < (len(intersection_points) - 1): #Look at two points p0 = intersection_points[i] p1 = intersection_points[i+1] #Get points on this line, dont store yet fill_line = Line() fill_line.p1 = p0 fill_line.p2 = p1 #Get points on this fill line scan_line_fill_points = fill_line.render_points() #If this is an entering point, draw line if p0_is_enter: rv = rv + scan_line_fill_points #Now detemine what to do with next point #Determine if next intersection point is entering or exiting #If the next intsection point is not a vertex it must be exiting if not(p1 in self.vertices): #print "p1 NOT in self.vertices" #Since p1 is exiting, incrementt i by 2 so next iteration p0 enters p0_is_enter = True #Inrement i by 2 i = i + 2 else: #print "p1 in self.vertices" #p1 is a vertex #Need to decide if it is an entering vertex or exiting #Find the index of this vertex in the poly vertex list index = -1 for j in range(0, len(self.vertices)): if self.vertices[j] == p1: #Found at index i index = j break if index == -1: print "Could not find vertex?" else: #Knowing vertices are in CC order #And knowing scan lines are horozontal #The vertex to the right of p1 determines if p1 is entering or exiting vertex_right_of_p1 = None vertex_before_p1 = None #before after in CC order vertex_after_p1 = None #print "len(self.vertices)",len(self.vertices) #print "vertex index",index #Check if this vertex is at beginning or end of list #Beginning if index == 0: #First vertex in list, so 'before' that is last vertex vertex_before_p1 = self.vertices[len(self.vertices)-1] vertex_after_p1 = self.vertices[1] #End of list elif index == len(self.vertices) - 1: vertex_before_p1 = self.vertices[len(self.vertices)-2] vertex_after_p1 = self.vertices[0] #Middle of list else: vertex_before_p1 = self.vertices[index - 1] vertex_after_p1 = self.vertices[index + 1] #Select vertex to right of p1 if vertex_before_p1.x >= p1.x: vertex_right_of_p1 = vertex_before_p1 elif vertex_after_p1.x >= p1.x: vertex_right_of_p1 = vertex_after_p1 else: #No vertex to right? Points saved by now #Just exit break; #Need to know if this vertex was before or after and above or below p1 vertex_right_of_p1_is_above = (vertex_right_of_p1.y >= p1.y) vertex_right_of_p1_is_before = (vertex_right_of_p1 == vertex_before_p1) if vertex_right_of_p1_is_above and vertex_right_of_p1_is_before: #Above and before, entering #Increment i by 1, next p0 is entering p0_is_enter = True i = i+1 elif vertex_right_of_p1_is_above and not(vertex_right_of_p1_is_before): #Above and after, exiting #Since p1 is exiting, increment i by 2 so next iteration p0 enters p0_is_enter = True #Inrement i by 2 i = i + 2 elif not(vertex_right_of_p1_is_above) and vertex_right_of_p1_is_before: #Below and before, exiting #Since p1 is exiting, increment i by 2 so next iteration p0 enters p0_is_enter = True #Inrement i by 2 i = i + 2 elif not(vertex_right_of_p1_is_above) and not(vertex_right_of_p1_is_before): #Below and and after, entering #Increment i by 1, next p0 is entering p0_is_enter = True i = i+1 else: print "Whoops! Issue with vertex above and below section?" #Return the fill points return rv
def clip_to_window(self,lower_bound_x, lower_bound_y,upper_bound_x, upper_bound_y): #Sutherland-Hodgman does not account for polygons that 'leave' the window on one bound #and return into the window through another bound (ex. leave through top, enter through bottom) #Keep track of points of enter and exit #Then use those points to look up #which points need to be inserted to complete polygon #Will be list of tuples ([ENTER|EXIT],<Point>) boundary_points = [] #Make new list of vertices for this clipped polygon new_vertices = [] #Loop over vertices #Easiest to loop through if has duplicate end vertex wduplicate = self.vertices + [self.vertices[0]] for i in range(0,len(wduplicate)-1): current_v = wduplicate[i] next_v = wduplicate[i+1] #Make line using these line = Line() #Do not reference points, copy line.p1 = copy.deepcopy(current_v) line.p2 = copy.deepcopy(next_v) #Make copy that will not be modified orig_line = copy.deepcopy(line) #print "Clipping line p1->p2:" #print orig_line #Clip this line clipped_line = line.clip_to_window(lower_bound_x, lower_bound_y,upper_bound_x, upper_bound_y) if clipped_line is None: #No part of line this is in window #Do not add either vertex to new polygon #print "Line not in window" #print continue elif clipped_line == orig_line: #Line did not change #print "Line unchanged" #print orig_line,"=",clipped_line #print #Save these vertices new_vertices = new_vertices + [clipped_line.p1,clipped_line.p2] else: #Line was clipped #print "Line clipped p1->p2:" #print clipped_line #Need to figure out if p1,p2 or both were clipped p1_clipped = not(clipped_line.p1 == orig_line.p1) p2_clipped = not(clipped_line.p2 == orig_line.p2) #print "P1 Clipped?:",p1_clipped #print "P2 Clipped?:",p2_clipped #Knowing points are in cc order #print #p1 clipped only means p1 entering #p2 clipped only means p2 exiting if p1_clipped: #Just p1 clipped enter_point = copy.deepcopy(clipped_line.p1) boundary_points = boundary_points + [(ENTER,enter_point)] if p2_clipped: #Just p2 clipped exit_point = copy.deepcopy(clipped_line.p2) boundary_points = boundary_points + [(EXIT,exit_point)] #Still save both points of clipped line new_vertices = new_vertices + [clipped_line.p1,clipped_line.p2] #Do we have boundary points to process? rv = None if len(boundary_points) <= 0: #No, return now self.vertices = new_vertices rv = self else: #Do boundary processing and return vertices verts = self.process_boundaries(new_vertices, boundary_points, lower_bound_x, lower_bound_y, upper_bound_x, upper_bound_y) self.vertices = verts rv = self #Remove duplicate vertices self.vertices = gen_utils.remove_ordered_duplicates(self.vertices) #Before returning, final check of if the whole polygon was clipped away if len(self.vertices) <= 0: return None elif len(self.vertices) <= 2: #Clipped down to a line? #print "Polygon clipped to line?" return None else: return rv