def create_ship(x, y, **kwargs): return Entity( x, y, shape=Polygon.from_pointlist([ Vector(+0, +8), Vector(-5, -8), Vector(+5, -8), ]), color=Color(50, 100, 200), **kwargs, )
def create_asteroid(x, y, **kwargs): bright = randint(20, 50) return Entity( x, y, shape=Polygon.from_pointlist([ Vector(+0, -6), Vector(-5, +6), Vector(+5, +6), ]), color=Color(1 * bright, 3 * bright, 2 * bright), **kwargs, )
def get_centerpoint(self): """Get the center of mass for the polygon""" xes = [p.x for p in self.points] yes = [p.y for p in self.points] return Vector(float(sum(xes)) / len(xes), float(sum(yes)) / len(yes))
def intersect_lineseg_lineseg(p1, p2, q1, q2): """Intersect two line segments @type p1: Vector @param p1: The first point on the first line segment @type p2: Vector @param p2: The second point on the first line segment @type q1: Vector @param q1: The first point on the secondline segment @type q2: Vector @param q2: The second point on the second line segment """ if max(q1.x, q2.x) < min(p1.x, p2.x): return None if min(q1.x, q2.x) > max(p1.x, p2.x): return None if max(q1.y, q2.y) < min(p1.y, p2.y): return None if min(q1.y, q2.y) > max(p1.y, p2.y): return None ll = __intersect_line_line_u(p1, p2, q1, q2) if ll == None: return None if ll[0] < 0 or ll[0] > 1: return None if ll[1] < 0 or ll[1] > 1: return None return Vector(p1.x + ll[0] * (p2.x - p1.x), p1.y + ll[0] * (p2.y - p1.y))
def intersect_lineseg_ray(p1, p2, q1, q2): """Intersect a line segment and a ray @type p1: Vector @param p1: The starting point of the line segment @type p2: Vector @param p2: The ending point of the line segment @type q1: Vector @param q1: The first point on the ray @type q2: Vector @param q2: The second point on the ray @return: The point of intersection or None """ ll = __intersect_line_line_u(p1, p2, q1, q2) if ll == None: return None if ll[0] < 0 or ll[0] > 1: return None if ll[1] < 0: return None return Vector(p1.x + ll[0] * (p2.x - p1.x), p1.y + ll[0] * (p2.y - p1.y))
def __mul__(self, val): if isinstance(val, Vector): x = val.x * self.data[0][0] + val.y * self.data[0][1] + self.data[ 0][2] y = val.x * self.data[1][0] + val.y * self.data[1][1] + self.data[ 1][2] return Vector(x, y) elif isinstance(val, Transform): data = [[0 for y in range(3)] for x in range(3)] for i in range(3): for j in range(3): for k in range(3): data[i][j] += self.data[i][k] * val.data[k][j] return Transform(data) elif isinstance(val, Polygon): p_transform = [self * v for v in val.points] return Polygon.from_pointlist(p_transform) else: raise ValueError("Unknown multiplier: %s" % val)
def from_tuples(tuples): """Create a polygon from 2-tuples @type tuples: List @param tuples: List of tuples of x,y coordinates """ p = Polygon() p.points = [Vector(t[0], t[1]) for t in tuples] return p
def find_point_in_poly(pts): # find point inside of pts according to http://www.exaflop.org/docs/cgafaq/cga2.html#Subject%202.06:%20How%20do%20I%20find%20a%20single%20point%20inside%20a%20simple%20polygonu # alternative approaches at http://stackoverflow.com/questions/9797448/get-a-point-inside-the-polygon, http://www.dummies.com/how-to/content/how-to-pinpoint-the-center-of-a-triangle.html def threeways(iterable): import itertools args = [iter(iterable)] * 3 return itertools.izip_longest(fillvalue=None, *args) for a, b, c in threeways(pts): avgx = sum([each.x for each in (a, b, c)]) / 3.0 avgy = sum([each.y for each in (a, b, c)]) / 3.0 triangle_center = Vector(avgx, avgy) if Polygon.contains_point_s([a, b, c], triangle_center): print "triangle", (a, b, c), triangle_center return triangle_center
def regular(center, radius, points): """Create a regular polygon @type center: Vector @param center: The center point of the polygon @type radius: float @param radius: The radius of the polygon @type points: int @param points: The number of polygon points. 3 will create a triangle, 4 a square, and so on. """ angular_increment = 2 * math.pi / points p = Polygon() for i in range(points): p.add_point( Vector(center.x + radius * math.cos(i * angular_increment), center.y + radius * math.sin(i * angular_increment)) ) return p
def intersect_line_line(p1, p2, q1, q2): """Intersect two lines @type p1: Vector @param p1: The first point of the first line @type p2: Vector @param p2: The second point of the first line @type q1: Vector @param q1: The first point of the second line @type q2: Vector @param q2: The second point of the second line @return: The point of intersection or None """ ll = __intersect_line_line_u(p1, p2, q1, q2) if ll == None: return None return Vector(p1.x + ll[0] * (p2.x - p1.x), p1.y + ll[0] * (p2.y - p1.y))
def contains_point_s(pts, p) : """Checks if the polygon defined by the point list pts contains the point p""" # see if we find a line segment that p is on for a,b in list(zip(pts[0:], pts[1:])) + [(pts[-1], pts[0])]: d = distance_point_lineseg_squared(p, a, b) if d < EPSILON * EPSILON: return 2 # p is not on the boundary, cast ray and intersect to see if we are inside intersections = set(intersect_poly_ray(pts, p, p + Vector(1,0))) # filter intersection points that are boundary points for int_point in filter(lambda x: x in pts, intersections): i = pts.index(int_point) prv = pts[i-1] nxt = pts[(i+1) % len(pts)] if point_orientation(p, int_point, nxt) == point_orientation(p,int_point, prv): intersections.remove(int_point) # we are inside if we have an odd amount of polygon intersections return 1 if len(intersections) % 2 == 1 else 0
def parse_vec(s): x, y = s.split(",") return Vector(float(x), float(y))
def convert_element(e, transform): """Convert an SVG path element to one or multiple Py2D polygons.""" # get data from the <path> element id = e.get("id") d = e.get("d") #print "CONVERTING %s: %s" % (id, d) def parse_commands(draw_commands): """Generator Function to parse a SVG draw command sequence into command and parameter tuples""" tokens = draw_commands.split(" ") while tokens: # find the next token that is a command par_index = next(i for i, v in enumerate(tokens[1:] + ["E"]) if re.match('^[a-zA-Z]$', v)) + 1 # first token should always be the command, rest the parameters cmd = tokens[0] pars = tokens[1:par_index] # remove the parsed tokens del tokens[:par_index] yield cmd, pars def parse_vec(s): x, y = s.split(",") return Vector(float(x), float(y)) polys = [] verts = [] relative_pos = Vector(0.0, 0.0) last_control = None for cmd, pars in parse_commands(d): #print "cmd: %s, pars: %s" % (cmd, pars) if cmd == "m" or cmd == "l": for p in pars: relative_pos += parse_vec(p) verts.append(relative_pos) elif cmd == "M" or cmd == "L": for p in pars: relative_pos = parse_vec(p) verts.append(relative_pos) elif cmd == "c" or cmd == "C": # create cubic polybezier for i in range(0, len(pars), 3): c1, c2, b = parse_vec(pars[i]), parse_vec( pars[i + 1]), parse_vec(pars[i + 2]) if cmd == "c": # convert to relative c1 += relative_pos c2 += relative_pos b += relative_pos bez = flatten_cubic_bezier(relative_pos, b, c1, c2, bezier_max_divisions, bezier_max_flatness) last_control = c2 relative_pos = b verts.extend(bez) elif cmd == "s" or cmd == "S": # shorthand / smooth cubic polybezier for i in range(0, len(pars), 2): c2, b = parse_vec(pars[i]), parse_vec(pars[i + 1]) c1 = relative_pos + (relative_pos - last_control) if cmd == "s": # convert to relative c2 += relative_pos b += relative_pos bez = flatten_cubic_bezier(relative_pos, b, c1, c2, bezier_max_divisions, bezier_max_flatness) last_control = c2 relative_pos = b verts.extend(bez) elif cmd == "z": # close line by only moving relative_pos to first vertex polys.append(transform * Polygon.from_pointlist(verts)) relative_pos = verts[0] verts = [] else: warnings.warn( "Unrecognized SVG path command: %s - path skipped" % cmd) polys = [] break if verts: polys.append(transform * Polygon.from_pointlist(verts)) #print "----" return id, polys
def get_triangle(): return Polygon.from_pointlist([ Vector(1.1, 2.2), Vector(3.3, 4.4), Vector(5.5, 6.6), ])