kopia lustrzana https://github.com/villares/sketch-a-day
				
				
				
			
		
			
				
	
	
		
			224 wiersze
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			224 wiersze
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Python
		
	
	
| from copy import deepcopy
 | |
| from arcs import *
 | |
| 
 | |
| class Poly():
 | |
| 
 | |
|     selected = -1
 | |
|     text_on = False
 | |
|     selected_drag = -1
 | |
|     drag_hole = -1
 | |
|     drag_pt = -1
 | |
|     id = 0
 | |
| 
 | |
|     def __init__(self, pts, holes=None, closed=True, lw=1):
 | |
|         self.pts = pts
 | |
|         self.holes = holes if holes else [[]]
 | |
|         self.closed = closed
 | |
|         self.lw = lw
 | |
| 
 | |
|     @classmethod
 | |
|     def setup_grid(cls, cell_size, order, x_offset, y_offset):
 | |
|         cls.cell_size = cell_size
 | |
|         cls.order = order
 | |
|         cls.x_offset, cls.y_offset = x_offset, y_offset
 | |
|         cls.polys = []
 | |
|         cls.text_on = False
 | |
| 
 | |
|     def plot(self):
 | |
|         for i, p in enumerate(self.polys):
 | |
|             self.id = i if self == p else self.id
 | |
|         pushStyle()
 | |
|         strokeJoin(ROUND)
 | |
|         strokeWeight(self.lw)
 | |
|         if self.selected_drag == self.id:
 | |
|             stroke(200, 0, 0)
 | |
|         else:
 | |
|             stroke(0)
 | |
|         if len(self.pts) >= 2:
 | |
|             if self.closed:
 | |
|                 fill(100)
 | |
|             else:
 | |
|                 noFill()
 | |
|             beginShape()
 | |
|             for i, pt in enumerate(self.pts):
 | |
|                 x, y = pt[0], pt[1]
 | |
|                 sx, sy = self.grid_to_screen(x, y)
 | |
|                 if len(pt) == 2 or pt[2] == 0:
 | |
|                     vertex(sx, sy)
 | |
|                 else:
 | |
|                     pp = self.grid_to_screen(self.pts[i - 1])
 | |
|                     np = self.grid_to_screen(self.pts[(i + 1)
 | |
|                                                        % len(self.pts)])
 | |
|                     r = pt[2] * self.cell_size
 | |
|                     b_roundedCorner((sx, sy), np, pp, r) # pt[2])
 | |
|                 
 | |
|             for h in self.holes:
 | |
|                 beginContour()
 | |
|                 for x, y in h:
 | |
|                     sx, sy = self.grid_to_screen(x, y)
 | |
|                     vertex(sx, sy)
 | |
|                 endContour()
 | |
|             if self.closed:
 | |
|                 endShape(CLOSE)
 | |
|             else:
 | |
|                 endShape()
 | |
|         if self.text_on:
 | |
|             self.annotate_pts(self.id, self.pts, color(200, 0, 0), 5)
 | |
|             self.annotate_pts(self.id, self.holes[0], color(0, 0, 200), 5)
 | |
|         popStyle()
 | |
| 
 | |
|     def remove_pt(self):
 | |
|         snap = self.mouse_snap()
 | |
|         if snap:
 | |
|             for pt in self.pts:
 | |
|                 if pt == snap:
 | |
|                     self.pts.remove(pt)
 | |
|                     return True
 | |
|                 for h in self.holes:
 | |
|                     for pt in h:
 | |
|                         if pt == snap:
 | |
|                             h.remove(pt)
 | |
|                             return True
 | |
| 
 | |
|     def set_drag(self):  # , io, jo):
 | |
|         snap = Poly.mouse_snap()
 | |
|         if snap:
 | |
|             for ipt, pt in enumerate(self.pts):
 | |
|                 if pt == snap:  # (io, jo):
 | |
|                     Poly.drag_pt = ipt
 | |
|                     return True
 | |
|             for ih, h in enumerate(self.holes):
 | |
|                 for ipt, pt in enumerate(h):
 | |
|                     if pt == snap:  # (io, jo):
 | |
|                         Poly.drag_hole = ih
 | |
|                         Poly.drag_pt = ipt
 | |
|                         return True
 | |
|         return False
 | |
| 
 | |
|     @classmethod
 | |
|     def annotate_pts(cls, id, pts, c, scale_m=1):
 | |
|         strokeWeight(5)
 | |
|         textSize(12)
 | |
|         fill(c)
 | |
|         stroke(c)
 | |
|         for pt in pts:
 | |
|             i, j = pt[0], pt[1]
 | |
|             sx, sy = cls.grid_to_screen(i, j)
 | |
|             point(sx, sy)
 | |
|             text(str(id) + ":" + str((i * scale_m, j * scale_m)), sx, sy)
 | |
| 
 | |
|     @classmethod
 | |
|     def draw_grid(cls):
 | |
|         stroke(128)
 | |
|         noFill()
 | |
|         for x in range(cls.order):
 | |
|             for y in range(cls.order):
 | |
|                 rect(x * cls.cell_size, y * cls.cell_size,
 | |
|                      cls.cell_size, cls.cell_size)
 | |
| 
 | |
|     @staticmethod
 | |
|     def clockwise_sort(xy_pairs):
 | |
|         # https://stackoverflow.com/questions/51074984/sorting-according-to-clockwise-point-coordinates
 | |
|         data_len = len(xy_pairs)
 | |
|         if data_len > 2:
 | |
|             x, y = zip(*xy_pairs)
 | |
|         else:
 | |
|             return xy_pairs
 | |
|         centroid_x, centroid_y = sum(x) / data_len, sum(y) / data_len
 | |
|         xy_sorted = sorted(xy_pairs,
 | |
|                            key=lambda p: atan2((p[1] - centroid_y), (p[0] - centroid_x)))
 | |
|         xy_sorted_xy = [
 | |
|             coord for pair in list(zip(*xy_sorted)) for coord in pair]
 | |
|         half_len = int(len(xy_sorted_xy) / 2)
 | |
|         return list(zip(xy_sorted_xy[:half_len], xy_sorted_xy[half_len:]))
 | |
| 
 | |
|     @classmethod
 | |
|     def mouse_snap(cls):
 | |
|         for i in range(cls.order):
 | |
|             x = i * cls.cell_size
 | |
|             for j in range(cls.order):
 | |
|                 y = j * cls.cell_size
 | |
|                 # grid origin correction
 | |
|                 io, jo = i - cls.x_offset, j - cls.y_offset
 | |
|                 if dist(mouseX, mouseY, x, y) < cls.cell_size / 2:
 | |
|                     return (io, jo)
 | |
|         return None
 | |
| 
 | |
|     @classmethod
 | |
|     def mousePressed(cls):
 | |
|         if keyPressed and keyCode == CONTROL:
 | |
|             for p in cls.polys:
 | |
|                 if p.remove_pt():  # io, jo):
 | |
|                     return
 | |
|         else:
 | |
|             for ip, p in enumerate(cls.polys):
 | |
|                 if p.set_drag():  # io, jo):
 | |
|                     cls.selected_drag = ip
 | |
|                     return
 | |
|         cls.selected_drag = -1  # click outside known vertices deselects
 | |
| 
 | |
|     @classmethod
 | |
|     def mouseDragged(cls):
 | |
|         if cls.selected_drag >= 0 and not keyPressed:
 | |
|             # a Poly point has been selected to be dragged
 | |
|             # and no modifier key is pressed...
 | |
|             if cls.drag_hole == -1:  # if no hole was selected
 | |
|                 poly = cls.polys[cls.selected_drag]
 | |
|                 poly.pts[cls.drag_pt] = cls.screen_to_grid(mouseX, mouseY)
 | |
|             else:
 | |
|                 poly = cls.polys[cls.selected_drag]
 | |
|                 hole = poly.holes[cls.drag_hole]
 | |
|                 hole[cls.drag_pt] = cls.screen_to_grid(mouseX, mouseY)
 | |
| 
 | |
|         elif cls.selected_drag >= 0 and key == "m":
 | |
|             poly = cls.polys[cls.selected_drag]
 | |
|             dragged_pt = poly.pts[cls.drag_pt]
 | |
|             mx, my = cls.screen_to_grid(mouseX, mouseY)
 | |
|             dx, dy = mx - dragged_pt[0], my - dragged_pt[1]
 | |
|             for i, pt in enumerate(poly.pts):
 | |
|                 poly.pts[i] = (pt[0] + dx, pt[1] + dy)
 | |
|             for hole in poly.holes:
 | |
|                 for i, pt in enumerate(hole):
 | |
|                     hole[i] = (pt[0] + dx, pt[1] + dy)
 | |
|                     
 | |
|     @classmethod
 | |
|     def grid_to_screen(cls, *args):
 | |
|         if len(args) == 2:
 | |
|             x, y = args
 | |
|         else:
 | |
|             x, y = args[0][0], args[0][1]
 | |
|         return ((x + cls.x_offset) * cls.cell_size,
 | |
|                 (y + cls.y_offset) * cls.cell_size)
 | |
| 
 | |
|     @classmethod
 | |
|     def screen_to_grid(cls, x, y):
 | |
|         return (int(x / cls.cell_size) - cls.x_offset,
 | |
|                 int(y / cls.cell_size) - cls.y_offset)
 | |
| 
 | |
|     @classmethod
 | |
|     def mouseReleased(cls):
 | |
|         if cls.selected_drag >= 0 and keyPressed and keyCode == SHIFT:
 | |
|         # a Poly point has been selected to be dragged
 | |
|         # and SHIFT key is pressed...
 | |
|             if cls.drag_hole == -1:  # if no hole wase selected
 | |
|                 poly = cls.polys[cls.selected_drag]
 | |
|                 poly.pts.insert(cls.drag_pt, cls.screen_to_grid(mouseX, mouseY ))
 | |
|             else:
 | |
|                 poly = cls.polys[cls.selected_drag]
 | |
|                 hole = poly.holes[Poly.drag_hole]
 | |
|                 hole.insert(cls.drag_pt, cls.screen_to_grid(mouseX, mouseY))
 | |
|         # Poly.selected_drag = -1  # No poly selected
 | |
|         Poly.drag_hole = -1  # No hole selected
 | |
|         Poly.drag_pt = -1  # No point selected
 | |
|         
 | |
|     @classmethod
 | |
|     def duplicate_selected(cls):
 | |
|       if Poly.selected_drag >= 0:
 | |
|         new_poly = deepcopy(cls.polys[cls.selected_drag])
 | |
|         for i, pt in enumerate(new_poly.pts):
 | |
|             new_poly.pts[i] = (pt[0] + 2, pt[1] + 1)
 | |
|         for h in new_poly.holes:
 | |
|             for i, pt in enumerate(h):
 | |
|                 h[i] = (pt[0] + 2, pt[1] + 1)
 | |
|         cls.polys.append(new_poly)
 |