def roundoff(tau, R_pz, dist_mod, xy, nd, n_t1, n_t2, vertexes, xyc): r_tc = R_pz / tau v_tc = np.add(np.array(dist_mod / tau * nd), xy) #circle's center point1 = r_tc * np.array([-n_t1[1], n_t1[0] ]) + v_tc #intersection of leg2 with the circle point2 = r_tc * np.array([n_t2[1], -n_t2[0] ]) + v_tc #intersection of leg1 with the circle legs_points = [[point1[0], point1[1]], [point2[0], point2[1]], list(vertexes[0]), list(vertexes[1])] #Define the circle's coordinates circle_lst = [list(map(list, np.flipud(xyc * r_tc)))] circle1 = np.array(circle_lst[0]) circle1 = np.add(circle1, v_tc) #add center of circle legs = pyclipper.Pyclipper() legs.AddPath(pyclipper.scale_to_clipper(legs_points), pyclipper.PT_SUBJECT, True) circle_cut = tuple(map(tuple, circle1)) legs.AddPath(pyclipper.scale_to_clipper(circle_cut), pyclipper.PT_CLIP, True) union = pyclipper.scale_from_clipper( legs.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)) union = np.array(union[0]) #PUT THE UNION IN TUPLE SO IT CAN BE ADDED AS AN OBJECT TO A PYCLIPPER OBJECT VO_round = tuple(map(tuple, union)) return VO_round, legs_points
def basic_rib(self, le_size, te_size, sp_size, to_mm=1): ''' defines a classic balsa model plane rib pattern with solid leading and tailing edges and one main spar at 33% of the chord. ''' # Apply conversion to the spars sizes le_size = [to_mm * x for x in le_size] te_size = [to_mm * x for x in te_size] sp_size = [to_mm * x for x in sp_size] # add_spar( surface, size, percent, aligment, pinned) #self.add_spar(self.lower, le_size, 0.00, (0,0), True) # LE self.add_spar(self.upper, sp_size, 0.27, (0,1), False) # Spar self.add_spar(self.upper, te_size, 1.00, (1,0), True) # TE # Optionally make LE a diamond self.add_diamond_le(self.upper, le_size[0], .5) # Add the profile to the clipper self.clipper.AddPath(pyclipper.scale_to_clipper(self.profile, self.SCALING_FACTOR), pyclipper.PT_SUBJECT, True) # The second operand is a list of spars self.clipper.AddPaths(pyclipper.scale_to_clipper(self.spars, self.SCALING_FACTOR), pyclipper.PT_CLIP, True) # Subtract the spar cutouts from the profile rib_path = self.clipper.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) return(pyclipper.scale_from_clipper(rib_path, self.SCALING_FACTOR))
def generateHalfCircle(self, position, r, saddleDir, exPos, funcValue): x0 = position[0] y0 = position[1] r = r / float(self.maxContourSize) * self.scale items = 10 + int( 3.14 * pyclipper.scale_to_clipper(r) / self.tessResolution) # print "generateHalfCircle:", items path = [] #compute test dirVec sDirOrth = np.array([saddleDir[1], -saddleDir[0]]) exDir = self.normalize(np.array(exPos) - np.array(position)) if np.dot(sDirOrth, exDir) < 0.0: sDirOrth = -sDirOrth for i in range(items): x = x0 + r * math.cos(2 * math.pi * i / items) y = y0 + r * math.sin(2 * math.pi * i / items) p2Center = self.normalize(np.array([x, y]) - np.array(position)) if np.dot(sDirOrth, p2Center) >= 0.0: path.append([x, y]) path = pyclipper.scale_to_clipper(path) return path
def shapely_to_clipper(polygon): ext = np.array(polygon.exterior.coords) ext = pyclipper.scale_to_clipper(ext) ints = [pyclipper.scale_to_clipper(np.array(inters.coords)) for inters in polygon.interiors] ints.insert(0, ext) return ints
def offset_polygon(polygon, distance, join_type=JOIN_MITER): ''' Offsets a the vertices of a `polygon` by `distance` units. Negative `distance` insets the polygon. See :py:func:`offset` for details. >>> offset_polygon([Point3d(0,0,0), Point3d(2,0,0), Point3d(2,2,0), Point3d(0,2,0), Point3d(0,0,0)], 0.5) [Point3d(2.5, 2.5, 0), Point3d(-0.5, 2.5, 0), Point3d(-0.5, -0.5, 0), Point3d(2.5, -0.5, 0), Point3d(2.5, 2.5, 0)] Note: The point order is not stable! >>> offset_polygon([Point3d(0,0,0), Point3d(2,0,0), Point3d(2,2,0), Point3d(0,2,0), Point3d(0,0,0)], -0.5) [Point3d(1.5, 1.5, 0), Point3d(0.5, 1.5, 0), Point3d(0.5, 0.5, 0), Point3d(1.5, 0.5, 0), Point3d(1.5, 1.5, 0)] ''' poly2d = [p.xy for p in polygon] clipper = clip.PyclipperOffset() clipper.AddPath(clip.scale_to_clipper(poly2d), join_type, clip.ET_CLOSEDPOLYGON) solution = clip.scale_from_clipper( clipper.Execute(clip.scale_to_clipper(distance))) try: return [Point3d(*p) for p in solution[0]] + [Point3d(*solution[0][0])] except IndexError: return []
def getroomcontour(origin, room): room_fname = os.path.join(suncg_root, "room", origin, room + "f.obj") if (not os.path.isfile(room_fname)): room_fname = os.path.join( os.path.split(housef)[0].replace(house_root, room_root), room["modelId"] + "c.obj") with open(room_fname, "r") as inf: lines = inf.read().split("\n") vertices_lines = lfilter(lambda x: x.startswith("v "), lines) vertices = np.array( lmap(lambda x: lmap(float, x.split()[1:]), vertices_lines))[:, [0, 2]] faces_lines = lfilter(lambda x: x.startswith("f "), lines) faces = lmap( lambda x: lmap(lambda y: int(y.split("/")[0]) - 1, x.split()[1:]), faces_lines) paths = pyclipper.scale_to_clipper([vertices[faces[0]]]) for face in faces: if (np.abs(area(vertices[face])) < 1e-5): continue pc = pyclipper.Pyclipper() pc.AddPaths(paths, pyclipper.PT_SUBJECT, True) clipface = pyclipper.scale_to_clipper(vertices[face]) pc.AddPath(clipface, pyclipper.PT_CLIP, True) paths = pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) paths = pyclipper.scale_from_clipper(paths) return paths
def intersect_polygons(polygon1, polygon2): """ Intersect two polygons. Parameters ---------- polygon1 : list of arrays Vertices of the first polygon in counterclockwise order. polygon1 : list of arrays Vertices of the second polygon in counterclockwise order. Returns ------- intersection : list of arrays Vertices of the intersection in counterclockwise order. """ from pyclipper import Pyclipper, PT_CLIP, PT_SUBJECT, CT_INTERSECTION from pyclipper import scale_to_clipper, scale_from_clipper # could be accelerated by removing the scale_to/from_clipper() subj, clip = (polygon1,), polygon2 pc = Pyclipper() pc.AddPath(scale_to_clipper(clip), PT_CLIP) pc.AddPaths(scale_to_clipper(subj), PT_SUBJECT) solution = pc.Execute(CT_INTERSECTION) if not solution: return [] return scale_from_clipper(solution)[0]
def basic_rib(self, le_size, te_size, sp_size, to_mm=1): ''' defines a classic balsa model plane rib pattern with solid leading and tailing edges and one main spar at 33% of the chord. ''' # Apply conversion to the spars sizes le_size = [to_mm * x for x in le_size] te_size = [to_mm * x for x in te_size] sp_size = [to_mm * x for x in sp_size] # add_spar( surface, size, percent, aligment, pinned) #self.add_spar(self.lower, le_size, 0.00, (0,0), True) # LE self.add_spar(self.upper, sp_size, 0.33, (0,1), False) # Spar self.add_spar(self.upper, te_size, 1.00, (1,0), True) # TE # Optionally make LE a diamond self.add_diamond_le(self.upper, le_size[0], .65) # Add the profile to the clipper self.clipper.AddPath(pyclipper.scale_to_clipper(self.profile, self.SCALING_FACTOR), pyclipper.PT_SUBJECT, True) # The second operand is a list of spars self.clipper.AddPaths(pyclipper.scale_to_clipper(self.spars, self.SCALING_FACTOR), pyclipper.PT_CLIP, True) # Subtract the spar cutouts from the profile rib_path = self.clipper.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) return(pyclipper.scale_from_clipper(rib_path, self.SCALING_FACTOR))
def prep_3D_polys(poly1, poly2): # type: (Polygon3D, Polygon3D) -> pc.Pyclipper """Prepare two 3D polygons for clipping operations. Parameters ---------- poly1 : Polygon3D The subject polygon. poly2 : Polygon3D The clip polygon. Returns ------- pc.Pyclipper object """ if not poly1.is_coplanar(poly2): return False poly1 = poly1.project_to_2D() poly2 = poly2.project_to_2D() s1 = pc.scale_to_clipper(poly1.vertices_list) s2 = pc.scale_to_clipper(poly2.vertices_list) clipper = pc.Pyclipper() clipper.AddPath(s1, poly_type=pc.PT_SUBJECT, closed=True) clipper.AddPath(s2, poly_type=pc.PT_CLIP, closed=True) return clipper
def _offset_profile(poly): pco = pyclipper.PyclipperOffset() pco.AddPath(pyclipper.scale_to_clipper(poly), pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON) offset = pco.Execute(-pyclipper.scale_to_clipper(Layer.bead_width/2)) offset = pyclipper.scale_from_clipper(offset) offset = np.reshape(offset, (-1,2)) return offset
def generate_offset_polygon(lot): nodes, ways = {}, {} subj = [] for x, y in lot: subj.append((pyclipper.scale_to_clipper(x), pyclipper.scale_to_clipper(y))) pco = pyclipper.PyclipperOffset() pco.AddPath(subj, pyclipper.JT_MITER, pyclipper.ET_CLOSEDPOLYGON) solution = pco.Execute(-150000.0) building_lot = [(pyclipper.scale_from_clipper(x), pyclipper.scale_from_clipper(y)) for x, y in solution[0]] if len(building_lot) == 0: # failed to get offset polygon with the fixed param return nodes, ways building_nodes = [] for x, y in building_lot: n = new_node(x, y) building_nodes.append(n.id) nodes[n.id] = n way = new_way() way.nodes = building_nodes+[building_nodes[0]] way.tags = {"building":"residential"} ways[way.id] = way return nodes, ways
def paths_contain(pt, paths): cnt = 0 pt = pyclipper.scale_to_clipper([pt], SCALING_FACTOR)[0] for path in paths: path = pyclipper.scale_to_clipper(path, SCALING_FACTOR) if pyclipper.PointInPolygon(pt, path): cnt = 1 - cnt return cnt % 2 != 0
def offset(self, r): r = pyclipper.scale_to_clipper(r) t = time.time() pco = pyclipper.PyclipperOffset() pco.AddPaths(pyclipper.scale_to_clipper(self.items), pyclipper.JT_SQUARE, pyclipper.ET_CLOSEDPOLYGON) res = pyclipper.scale_from_clipper(pco.Execute(r)) return res
def intersectionOfShapes(self, mask, polys): pc = pyclipper.Pyclipper() pc.AddPaths(pyclipper.scale_to_clipper(mask), pyclipper.PT_CLIP, True) pc.AddPaths(pyclipper.scale_to_clipper(polys), pyclipper.PT_SUBJECT, True) solution = pyclipper.scale_from_clipper( pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)) return solution
def joinPolys(self, clip, subj): pc = pyclipper.Pyclipper() pc.AddPath(pyclipper.scale_to_clipper(clip), pyclipper.PT_CLIP, True) pc.AddPath(pyclipper.scale_to_clipper(subj), pyclipper.PT_SUBJECT, True) solution = pyclipper.scale_from_clipper( pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)) return solution
def getClipSolutions(self, clip, subj): pc = pyclipper.Pyclipper() pc.AddPath(pyclipper.scale_to_clipper(clip), pyclipper.PT_CLIP, True) pc.AddPaths(pyclipper.scale_to_clipper(subj), pyclipper.PT_SUBJECT, True) solution = pyclipper.scale_from_clipper( pc.Execute(pyclipper.CT_XOR, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)) return solution
def find_common_coverage(locuses): clipper = Pyclipper() current_locus = locuses[0] for locus in locuses[1:]: clipper.AddPaths(scale_to_clipper(current_locus), PT_SUBJECT) clipper.AddPaths(scale_to_clipper(locus), PT_CLIP) current_locus = scale_from_clipper(clipper.Execute(CT_INTERSECTION)) clipper.Clear() l_x, l_y = split_locus_lists([current_locus]) return l_x, l_y
def joinManyPolys(self, polys): pc = pyclipper.Pyclipper() pc.AddPath(pyclipper.scale_to_clipper(polys[0]), pyclipper.PT_CLIP, True) pc.AddPaths(pyclipper.scale_to_clipper(polys[1:]), pyclipper.PT_SUBJECT, True) solution = pyclipper.scale_from_clipper( pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)) return solution
def preprocess_obstacles(self, obstacle_list): inflation = pyclipper.scale_to_clipper(self.config.vehicle_width) inflated_obstacles = [] for obs in obstacle_list: obstacle = pyclipper.scale_to_clipper(obs) inflated_obstacle = self.preprocess_obstacle(obstacle, inflation, boundary=False) inflated_obstacle.reverse() # obstacles are ordered clockwise inflated_obstacles.append(inflated_obstacle) return inflated_obstacles
def computePath(leader_waypoints, offset_id = 1): leader_waypoints = [[w[0], w[1]] for w in leader_waypoints] OFFSET_CONSTANT = 2 * 70000 ARC_TOLERANCE = 2000 scaled_waypoints = [] print leader_waypoints for wypt in leader_waypoints: scaled_waypoints.append([pyclipper.scale_to_clipper(wypt[0]), pyclipper.scale_to_clipper(wypt[1])]) pco = pyclipper.PyclipperOffset(0, ARC_TOLERANCE) pco.AddPath(scaled_waypoints, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON) scaled_path = pco.Execute(offset_id * OFFSET_CONSTANT) #pyclipper.scale_to_clipper(OFFSET_CONSTANT)) unscaled_path = [] for wypt in scaled_path[0]: unscaled_path.append([pyclipper.scale_from_clipper(wypt[0]), pyclipper.scale_from_clipper(wypt[1])]) print scaled_path # gaphing here for visual check of correctness ''' leader_x = [] leader_y = [] for waypoint in leader_waypoints: leader_x.append(waypoint[0]) leader_y.append(waypoint[1]) follower1_x = [] follower1_y = [] for waypoint in unscaled_path: follower1_x.append(waypoint[0]) follower1_y.append(waypoint[1]) for i in range(0, len(leader_x)): plt.plot(leader_x[i:i+2], leader_y[i:i+2], 'ro-') for i in range(0, len(follower1_x)): plt.plot(follower1_x[i:i+2], follower1_y[i:i+2], 'go-') plt.show() ''' total_distance = 0 for i in range(len(unscaled_path) - 1): total_distance += getDistanceMeters(unscaled_path[i][0], unscaled_path[i][1], unscaled_path[i + 1][0], unscaled_path[i + 1][1]) shifted_unscaled_path = unscaled_path[16:] + unscaled_path[:16] output = { 'waypoints': shifted_unscaled_path, 'distance': total_distance } return output
def diff(subj, clip_paths, subj_closed=True): pc = pyclipper.Pyclipper() if subj: subj = pyclipper.scale_to_clipper(subj, SCALING_FACTOR) pc.AddPaths(subj, pyclipper.PT_SUBJECT, subj_closed) if clip_paths: clip_paths = pyclipper.scale_to_clipper(clip_paths, SCALING_FACTOR) pc.AddPaths(clip_paths, pyclipper.PT_CLIP, True) outpaths = pc.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) outpaths = pyclipper.scale_from_clipper(outpaths, SCALING_FACTOR) return outpaths
def hatches(self, l=10, st=0.1, num=0): self.clean() b0 = self.bounds() b = [b0[0] - l, b0[1] - l, b0[2] + l, b0[3] + l] h = [] ls = l / math.sqrt(2) sts = st / math.sqrt(2) i = 0 if num % 2 == 0: x0 = b[0] while x0 < b[2] + b[3] - b[1]: x = x0 y = b[1] while x > b[0] and y < b[3]: x -= sts y += sts if i % 2 == 0: h.append([[x, y], [x - ls, y - ls]]) else: h.append([[x - ls, y - ls], [x, y]]) i += 1 x0 += l * math.sqrt(2) else: x0 = b[0] - (b[3] - b[1]) while x0 < b[2]: x = x0 y = b[1] while y < b[3] and x < b[2]: x += sts y += sts if i % 2 == 0: h.append([[x, y], [x + ls, y - ls]]) else: h.append([[x + ls, y - ls], [x, y]]) i += 1 x0 += l * math.sqrt(2) def check_sp(sp, b): return b[0] < sp[0][0] < b[2] and b[1] < sp[0][1] < b[3] or b[ 0] < sp[1][0] < b[2] and b[1] < sp[1][1] < b[3] h = [sp for sp in h if check_sp(sp, b)] pc = pyclipper.Pyclipper() pc.AddPaths(pyclipper.scale_to_clipper(self.items), pyclipper.PT_CLIP, True) pc.AddPaths(pyclipper.scale_to_clipper(h), pyclipper.PT_SUBJECT, False) solution = pc.Execute2(pyclipper.CT_INTERSECTION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) h = pyclipper.scale_from_clipper(pyclipper.PolyTreeToPaths(solution)) return Path(h)
def offset(self, distance, offset_style=pyclipper.JT_MITER): # JT_MITER = 2 # JT_ROUND = 1 # JT_SQUARE = 0 clipper_offset = pyclipper.PyclipperOffset() coordinates_scaled = pyclipper.scale_to_clipper(self.points) clipper_offset.AddPath(coordinates_scaled, offset_style, pyclipper.ET_CLOSEDPOLYGON) new_coordinates = clipper_offset.Execute( pyclipper.scale_to_clipper(distance)) new_coordinates_scaled = pyclipper.scale_from_clipper(new_coordinates) self.points = new_coordinates_scaled[0]
def clip(subj_pts, clip_pts, scale=2**16): system = subj_pts[0].system clip_coords = [p.in_system(system).coords for p in clip_pts] subj_coords = [p.in_system(system).coords for p in subj_pts] pc = pyclipper.Pyclipper() pc.AddPath(pyclipper.scale_to_clipper(clip_coords, scale), pyclipper.PT_CLIP, True) pc.AddPath(pyclipper.scale_to_clipper(subj_coords, scale), pyclipper.PT_SUBJECT, True) solution = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) return [ImagePoint(coord, system) for coord in pyclipper.scale_from_clipper(solution, scale)[0]]
def clip(subj, clip_paths, subj_closed=True): pc = pyclipper.Pyclipper() if subj: subj = pyclipper.scale_to_clipper(subj, SCALING_FACTOR) pc.AddPaths(subj, pyclipper.PT_SUBJECT, subj_closed) if clip_paths: clip_paths = pyclipper.scale_to_clipper(clip_paths, SCALING_FACTOR) pc.AddPaths(clip_paths, pyclipper.PT_CLIP, True) out_tree = pc.Execute2(pyclipper.CT_INTERSECTION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) outpaths = pyclipper.PolyTreeToPaths(out_tree) outpaths = pyclipper.scale_from_clipper(outpaths, SCALING_FACTOR) return outpaths
def get_xor(first, second): """Takes two list of loops(list of(x, y) points), and returns the exclusive-or""" clipper = pyclipper.Pyclipper() # pylint: disable=c-extension-no-member scaled_first = pyclipper.scale_to_clipper(first, SCALING_FACTOR) scaled_second = pyclipper.scale_to_clipper(second, SCALING_FACTOR) clipper.AddPaths(scaled_first, pyclipper.PT_SUBJECT) clipper.AddPaths(scaled_second, pyclipper.PT_CLIP) scaled_xor = clipper.Execute(pyclipper.CT_XOR) xor = pyclipper.scale_from_clipper( scaled_xor, SCALING_FACTOR) return xor
def get_union(first, second): """Takes two list of loops(list of(x, y) points), and returns the union""" clipper = pyclipper.Pyclipper() # pylint: disable=c-extension-no-member scaled_first = pyclipper.scale_to_clipper(first, SCALING_FACTOR) scaled_second = pyclipper.scale_to_clipper(second, SCALING_FACTOR) clipper.AddPaths(scaled_first, pyclipper.PT_SUBJECT) clipper.AddPaths(scaled_second, pyclipper.PT_CLIP) scaled_union = clipper.Execute(pyclipper.CT_UNION) union = pyclipper.scale_from_clipper( scaled_union, SCALING_FACTOR) return union
def InwardOffset(feature, output, thickness): coordinates = feature.points[:-1] pco = pyclipper.PyclipperOffset() coordsScaled = pyclipper.scale_to_clipper(coordinates) pco.AddPath(coordsScaled, pyclipper.JT_SQUARE, pyclipper.ET_CLOSEDPOLYGON) result = pco.Execute(pyclipper.scale_to_clipper(thickness)) resultScaled = pyclipper.scale_from_clipper(result) resultScaledList = resultScaled[0] lastCoord = resultScaledList[0] resultScaledList.append(lastCoord) output.append(resultScaledList)
def _prepare_clipper(self, poly): """Prepare 2D polygons for clipping operations. :param poly: The clip polygon. :returns: A Pyclipper object. """ s1 = pc.scale_to_clipper(self.vertices_list) s2 = pc.scale_to_clipper(poly.vertices_list) clipper = pc.Pyclipper() clipper.AddPath(s1, poly_type=pc.PT_SUBJECT, closed=True) clipper.AddPath(s2, poly_type=pc.PT_CLIP, closed=True) return clipper
def prep_2D_polys(poly1, poly2): # type: (Polygon, Polygon) -> pc.Pyclipper """Prepare two 2D polygons for clipping operations. :param poly1: The subject polygon. :param poly2: The clip polygon. :returns: A Pyclipper object. """ s1 = pc.scale_to_clipper(poly1.vertices_list) s2 = pc.scale_to_clipper(poly2.vertices_list) clipper = pc.Pyclipper() clipper.AddPath(s1, poly_type=pc.PT_SUBJECT, closed=True) clipper.AddPath(s2, poly_type=pc.PT_CLIP, closed=True) return clipper
def bevel(curve, radius): """ Imposes a minimum radius on a 2D curve. Args: curve (tuple): (x,y) points radius (int): the desired minimum radius Returns: beveled (tuple): (x,y) points with min radius """ import pyclipper scale = 10000 radius *= scale transposed = pyclipper.scale_to_clipper(list(zip(*curve)), scale=scale) pco = pyclipper.PyclipperOffset() pco.AddPath(transposed, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON) inset = pco.Execute(-radius)[0] pco2 = pyclipper.PyclipperOffset() pco2.AddPath(inset, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON) solution = pco2.Execute(radius)[0] # solution.pop(0) # TODO: decide if necessary beveled = pyclipper.scale_from_clipper(list(zip(*solution)), scale=scale) return beveled
def point_inside_loop(point, loop): """tests to see if a point is inside (1), on(-1), or outside (0) of a loop""" scaled_loop = pyclipper.scale_to_clipper(loop, SCALING_FACTOR) scaled_point = [int(point[0] * SCALING_FACTOR), int(point[1] * SCALING_FACTOR)] is_point_inside = pyclipper.PointInPolygon(scaled_point, scaled_loop) return is_point_inside
def calculateImprint(tsf_file_left, tsf_file_right, path_to_write_left_segs, path_to_write_right_segs, th=0.5): paths_write = [path_to_write_left_segs,path_to_write_right_segs] for idx_path, path in enumerate([tsf_file_left, tsf_file_right]): file = open(path, 'r') reader = csv.DictReader(file, delimiter=',', quotechar='"') segs =[] currentSeg = [] old_SID = 0 for row in reader: SID = int(row['SID']) PID = int(row['PID']) cords = [float(row['x']), float(row['z']), float(row['y'])] if SID != old_SID: segs.append(currentSeg) currentSeg= [] currentSeg.append(cords) old_SID = SID segs.append(currentSeg) file.close() segs = np.array(segs) segs = segs_cutoff(segs, th) segs = np.array([np.array([pts[:2] for pts in seg]) for seg in segs]) signed_area = [sum((seg[np.r_[1:len(seg), 0],0]-seg[:,0])*(seg[np.r_[1:len(seg), 0],1]+seg[:,1]))/2. for seg in segs] to_reverse = [i for i,a in enumerate(signed_area) if a>0] for i in to_reverse: segs[i] = segs[i][::-1] union = pyclipper.scale_to_clipper(segs) clipper = pyclipper.Pyclipper() clipper.AddPaths(union, pyclipper.PT_CLIP, True) union = clipper.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO) union = pyclipper.scale_from_clipper(union) union2 = np.array(union) for i, u in enumerate(union2): union2[i]= np.array(union2[i]) signed_area2 = [sum((seg[np.r_[1:len(seg), 0],0]-seg[:,0])*(seg[np.r_[1:len(seg), 0],1]+seg[:,1]))/2. for seg in union2] union_without_holes = union2[[i for i, a in enumerate(signed_area2) if a<0]] if idx_path == 0: segs_left = union_without_holes else: segs_right = union_without_holes for idx_side, segs in enumerate([segs_left, segs_right]): output_path = path_to_write_left_segs if idx_side==0 else path_to_write_right_segs write_segs_to_file(segs, output_path) return([path_to_write_left_segs, path_to_write_right_segs])
def area(vset): """ This function calculates the area of the set of FRV or ARV """ # Initialize A as it could be calculated iteratively A = 0 # Check multiple exteriors if type(vset[0][0]) == list: # Calc every exterior separately for i in range(len(vset)): A += pyclipper.scale_from_clipper(pyclipper.scale_from_clipper(pyclipper.Area(pyclipper.scale_to_clipper(vset[i])))) else: # Single exterior A = pyclipper.scale_from_clipper(pyclipper.scale_from_clipper(pyclipper.Area(pyclipper.scale_to_clipper(vset)))) return A
def intersect_polygons(polygon1, polygon2): """ Intersect two polygons. INPUT: - ``polygon1`` -- list of vertices in counterclockwise order - ``polygon2`` -- same OUTPUT: Vertices of the intersection in counterclockwise order. """ # could be accelerated by removing the scale_to/from_clipper() subj, clip = (polygon1,), polygon2 pc = Pyclipper() pc.AddPath(scale_to_clipper(clip), PT_CLIP) pc.AddPaths(scale_to_clipper(subj), PT_SUBJECT) solution = pc.Execute(CT_INTERSECTION) if not solution: return [] return scale_from_clipper(solution)[0]
def constructSSD(asas, traf, priocode = "RS1"): """ Calculates the FRV and ARV of the SSD """ N = 0 # Parameters N_angle = 180 # [-] Number of points on circle (discretization) vmin = asas.vmin # [m/s] Defined in asas.py vmax = asas.vmax # [m/s] Defined in asas.py hsep = asas.R # [m] Horizontal separation (5 NM) margin = asas.mar # [-] Safety margin for evasion hsepm = hsep * margin # [m] Horizontal separation with safety margin alpham = 0.4999 * np.pi # [rad] Maximum half-angle for VO betalos = np.pi / 4 # [rad] Minimum divertion angle for LOS (45 deg seems optimal) adsbmax = 65. * nm # [m] Maximum ADS-B range beta = np.pi/4 + betalos/2 if priocode == "RS7" or priocode == "RS8": adsbmax /= 2 # Relevant info from traf gsnorth = traf.gsnorth gseast = traf.gseast lat = traf.lat lon = traf.lon ntraf = traf.ntraf hdg = traf.hdg gs_ap = traf.ap.tas hdg_ap = traf.ap.trk apnorth = np.cos(hdg_ap / 180 * np.pi) * gs_ap apeast = np.sin(hdg_ap / 180 * np.pi) * gs_ap # Local variables, will be put into asas later FRV_loc = [None] * traf.ntraf ARV_loc = [None] * traf.ntraf # For calculation purposes ARV_calc_loc = [None] * traf.ntraf FRV_area_loc = np.zeros(traf.ntraf, dtype=np.float32) ARV_area_loc = np.zeros(traf.ntraf, dtype=np.float32) # # Use velocity limits for the ring-shaped part of the SSD # Discretize the circles using points on circle angles = np.arange(0, 2 * np.pi, 2 * np.pi / N_angle) # Put points of unit-circle in a (180x2)-array (CW) xyc = np.transpose(np.reshape(np.concatenate((np.sin(angles), np.cos(angles))), (2, N_angle))) # Map them into the format pyclipper wants. Outercircle CCW, innercircle CW circle_tup = (tuple(map(tuple, np.flipud(xyc * vmax))), tuple(map(tuple , xyc * vmin))) circle_lst = [list(map(list, np.flipud(xyc * vmax))), list(map(list , xyc * vmin))] # If no traffic if ntraf == 0: return # If only one aircraft elif ntraf == 1: # Map them into the format ARV wants. Outercircle CCW, innercircle CW ARV_loc[0] = circle_lst FRV_loc[0] = [] ARV_calc_loc[0] = ARV_loc[0] # Calculate areas and store in asas FRV_area_loc[0] = 0 ARV_area_loc[0] = np.pi * (vmax **2 - vmin ** 2) return # Function qdrdist_matrix needs 4 vectors as input (lat1,lon1,lat2,lon2) # To be efficient, calculate all qdr and dist in one function call # Example with ntraf = 5: ind1 = [0,0,0,0,1,1,1,2,2,3] # ind2 = [1,2,3,4,2,3,4,3,4,4] # This way the qdrdist is only calculated once between every aircraft # To get all combinations, use this function to get the indices ind1, ind2 = qdrdist_matrix_indices(ntraf) # Get absolute bearing [deg] and distance [nm] # Not sure abs/rel, but qdr is defined from [-180,180] deg, w.r.t. North [qdr, dist] = geo.qdrdist_matrix(lat[ind1], lon[ind1], lat[ind2], lon[ind2]) # Put result of function from matrix to ndarray qdr = np.reshape(np.array(qdr), np.shape(ind1)) dist = np.reshape(np.array(dist), np.shape(ind1)) # SI-units from [deg] to [rad] qdr = np.deg2rad(qdr) # Get distance from [nm] to [m] dist = dist * nm # In LoS the VO can't be defined, act as if dist is on edge dist[dist < hsepm] = hsepm # Calculate vertices of Velocity Obstacle (CCW) # These are still in relative velocity space, see derivation in appendix # Half-angle of the Velocity obstacle [rad] # Include safety margin alpha = np.arcsin(hsepm / dist) # Limit half-angle alpha to 89.982 deg. Ensures that VO can be constructed alpha[alpha > alpham] = alpham # Relevant sin/cos/tan sinqdr = np.sin(qdr) cosqdr = np.cos(qdr) tanalpha = np.tan(alpha) cosqdrtanalpha = cosqdr * tanalpha sinqdrtanalpha = sinqdr * tanalpha # Relevant x1,y1,x2,y2 (x0 and y0 are zero in relative velocity space) x1 = (sinqdr + cosqdrtanalpha) * 2 * vmax x2 = (sinqdr - cosqdrtanalpha) * 2 * vmax y1 = (cosqdr - sinqdrtanalpha) * 2 * vmax y2 = (cosqdr + sinqdrtanalpha) * 2 * vmax # Consider every aircraft for i in range(ntraf): # Calculate SSD only for aircraft in conflict (See formulas appendix) if asas.inconf[i]: # SSD for aircraft i # Get indices that belong to aircraft i ind = np.where(np.logical_or(ind1 == i,ind2 == i))[0] # Check whether there are any aircraft in the vicinity if len(ind) == 0: # No aircraft in the vicinity # Map them into the format ARV wants. Outercircle CCW, innercircle CW ARV_loc[i] = circle_lst FRV_loc[i] = [] ARV_calc_loc[i] = ARV_loc[i] # Calculate areas and store in asas FRV_area_loc[i] = 0 ARV_area_loc[i] = np.pi * (vmax **2 - vmin ** 2) else: # The i's of the other aircraft i_other = np.delete(np.arange(0, ntraf), i) # Aircraft that are within ADS-B range ac_adsb = np.where(dist[ind] < adsbmax)[0] # Now account for ADS-B range in indices of other aircraft (i_other) ind = ind[ac_adsb] i_other = i_other[ac_adsb] if not priocode == "RS7" and not priocode == "RS8": # Put it in class-object (not for RS7 and RS8) asas.inrange[i] = i_other else: asas.inrange2[i] = i_other # VO from 2 to 1 is mirror of 1 to 2. Only 1 to 2 can be constructed in # this manner, so need a correction vector that will mirror the VO fix = np.ones(np.shape(i_other)) fix[i_other < i] = -1 # Relative bearing [deg] from [-180,180] # (less required conversions than rad in RotA) fix_ang = np.zeros(np.shape(i_other)) fix_ang[i_other < i] = 180. # Get vertices in an x- and y-array of size (ntraf-1)*3x1 x = np.concatenate((gseast[i_other], x1[ind] * fix + gseast[i_other], x2[ind] * fix + gseast[i_other])) y = np.concatenate((gsnorth[i_other], y1[ind] * fix + gsnorth[i_other], y2[ind] * fix + gsnorth[i_other])) # Reshape [(ntraf-1)x3] and put arrays in one array [(ntraf-1)x3x2] x = np.transpose(x.reshape(3, np.shape(i_other)[0])) y = np.transpose(y.reshape(3, np.shape(i_other)[0])) xy = np.dstack((x,y)) # Make a clipper object pc = pyclipper.Pyclipper() # Add circles (ring-shape) to clipper as subject pc.AddPaths(pyclipper.scale_to_clipper(circle_tup), pyclipper.PT_SUBJECT, True) # Extra stuff needed for RotA if priocode == "RS6": # Make another clipper object for RotA pc_rota = pyclipper.Pyclipper() pc_rota.AddPaths(pyclipper.scale_to_clipper(circle_tup), pyclipper.PT_SUBJECT, True) # Bearing calculations from own view and other view brg_own = np.mod((np.rad2deg(qdr[ind]) + fix_ang - hdg[i]) + 540., 360.) - 180. brg_other = np.mod((np.rad2deg(qdr[ind]) + 180. - fix_ang - hdg[i_other]) + 540., 360.) - 180. # Add each other other aircraft to clipper as clip for j in range(np.shape(i_other)[0]): ## Debug prints ## print(traf.id[i] + " - " + traf.id[i_other[j]]) ## print(dist[ind[j]]) # Scale VO when not in LOS if dist[ind[j]] > hsepm: # Normally VO shall be added of this other a/c VO = pyclipper.scale_to_clipper(tuple(map(tuple,xy[j,:,:]))) else: # Pair is in LOS, instead of triangular VO, use darttip # Check if bearing should be mirrored if i_other[j] < i: qdr_los = qdr[ind[j]] + np.pi else: qdr_los = qdr[ind[j]] # Length of inner-leg of darttip leg = 1.1 * vmax / np.cos(beta) * np.array([1,1,1,0]) # Angles of darttip angles_los = np.array([qdr_los + 2 * beta, qdr_los, qdr_los - 2 * beta, 0.]) # Calculate coordinates (CCW) x_los = leg * np.sin(angles_los) y_los = leg * np.cos(angles_los) # Put in array of correct format xy_los = np.vstack((x_los,y_los)).T # Scale darttip VO = pyclipper.scale_to_clipper(tuple(map(tuple,xy_los))) # Add scaled VO to clipper pc.AddPath(VO, pyclipper.PT_CLIP, True) # For RotA it is possible to ignore if priocode == "RS6": if brg_own[j] >= -20. and brg_own[j] <= 110.: # Head-on or converging from right pc_rota.AddPath(VO, pyclipper.PT_CLIP, True) elif brg_other[j] <= -110. or brg_other[j] >= 110.: # In overtaking position pc_rota.AddPath(VO, pyclipper.PT_CLIP, True) # Detect conflicts for smaller layer in RS7 and RS8 if priocode == "RS7" or priocode == "RS8": if pyclipper.PointInPolygon(pyclipper.scale_to_clipper((gseast[i],gsnorth[i])),VO): asas.inconf2[i] = True if priocode == "RS5": if pyclipper.PointInPolygon(pyclipper.scale_to_clipper((apeast[i],apnorth[i])),VO): asas.ap_free[i] = False # Execute clipper command FRV = pyclipper.scale_from_clipper(pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)) ARV = pc.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO) if not priocode == "RS1" and not priocode == "RS5" and not priocode == "RS7" and not priocode == "RS8": # Make another clipper object for extra intersections pc2 = pyclipper.Pyclipper() # When using RotA clip with pc_rota if priocode == "RS6": # Calculate ARV for RotA ARV_rota = pc_rota.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO) if len(ARV_rota) > 0: pc2.AddPaths(ARV_rota, pyclipper.PT_CLIP, True) else: # Put the ARV in there, make sure it's not empty if len(ARV) > 0: pc2.AddPaths(ARV, pyclipper.PT_CLIP, True) # Scale back ARV = pyclipper.scale_from_clipper(ARV) # Check if ARV or FRV is empty if len(ARV) == 0: # No aircraft in the vicinity # Map them into the format ARV wants. Outercircle CCW, innercircle CW ARV_loc[i] = [] FRV_loc[i] = circle_lst ARV_calc_loc[i] = [] # Calculate areas and store in asas FRV_area_loc[i] = np.pi * (vmax **2 - vmin ** 2) ARV_area_loc[i] = 0 elif len(FRV) == 0: # Should not happen with one a/c or no other a/c in the vicinity. # These are handled earlier. Happens when RotA has removed all # Map them into the format ARV wants. Outercircle CCW, innercircle CW ARV_loc[i] = circle_lst FRV_loc[i] = [] ARV_calc_loc[i] = circle_lst # Calculate areas and store in asas FRV_area_loc[i] = 0 ARV_area_loc[i] = np.pi * (vmax **2 - vmin ** 2) else: # Check multi exteriors, if this layer is not a list, it means it has no exteriors # In that case, make it a list, such that its format is consistent with further code if not type(FRV[0][0]) == list: FRV = [FRV] if not type(ARV[0][0]) == list: ARV = [ARV] # Store in asas FRV_loc[i] = FRV ARV_loc[i] = ARV # Calculate areas and store in asas FRV_area_loc[i] = area(FRV) ARV_area_loc[i] = area(ARV) # For resolution purposes sometimes extra intersections are wanted if priocode == "RS2" or priocode == "RS9" or priocode == "RS6" or priocode == "RS3" or priocode == "RS4": # Make a box that covers right or left of SSD own_hdg = hdg[i] * np.pi / 180 # Efficient calculation of box, see notes if priocode == "RS2" or priocode == "RS6": # CW or right-turning sin_table = np.array([[1,0],[-1,0],[-1,-1],[1,-1]], dtype=np.float64) cos_table = np.array([[0,1],[0,-1],[1,-1],[1,1]], dtype=np.float64) elif priocode == "RS9": # CCW or left-turning sin_table = np.array([[1,0],[1,1],[-1,1],[-1,0]], dtype=np.float64) cos_table = np.array([[0,1],[-1,1],[-1,-1],[0,-1]], dtype=np.float64) # Overlay a part of the full SSD if priocode == "RS2" or priocode == "RS9" or priocode == "RS6": # Normalized coordinates of box xyp = np.sin(own_hdg) * sin_table + np.cos(own_hdg) * cos_table # Scale with vmax (and some factor) and put in tuple part = pyclipper.scale_to_clipper(tuple(map(tuple, 1.1 * vmax * xyp))) pc2.AddPath(part, pyclipper.PT_SUBJECT, True) elif priocode == "RS3": # Small ring xyp = (tuple(map(tuple, np.flipud(xyc * min(vmax,gs_ap[i] + 0.1)))), tuple(map(tuple , xyc * max(vmin,gs_ap[i] - 0.1)))) part = pyclipper.scale_to_clipper(xyp) pc2.AddPaths(part, pyclipper.PT_SUBJECT, True) elif priocode == "RS4": hdg_sel = hdg[i] * np.pi / 180 xyp = np.array([[np.sin(hdg_sel-0.0087),np.cos(hdg_sel-0.0087)], [0,0], [np.sin(hdg_sel+0.0087),np.cos(hdg_sel+0.0087)]], dtype=np.float64) part = pyclipper.scale_to_clipper(tuple(map(tuple, 1.1 * vmax * xyp))) pc2.AddPath(part, pyclipper.PT_SUBJECT, True) # Execute clipper command ARV_calc = pyclipper.scale_from_clipper(pc2.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)) N += 1 # If no smaller ARV is found, take the full ARV if len(ARV_calc) == 0: ARV_calc = ARV # Check multi exteriors, if this layer is not a list, it means it has no exteriors # In that case, make it a list, such that its format is consistent with further code if not type(ARV_calc[0][0]) == list: ARV_calc = [ARV_calc] # Shortest way out prio, so use full SSD (ARV_calc = ARV) else: ARV_calc = ARV # Update calculatable ARV for resolutions ARV_calc_loc[i] = ARV_calc # If sequential approach, the local should go elsewhere if not priocode == "RS7" and not priocode == "RS8": asas.FRV = FRV_loc asas.ARV = ARV_loc asas.ARV_calc = ARV_calc_loc asas.FRV_area = FRV_area_loc asas.ARV_area = ARV_area_loc else: asas.ARV_calc2 = ARV_calc_loc return
def calculateStatistics(path_to_imprint_file_left, path_to_imprint_file_right, path_to_zones_left, path_to_zones_right, path_to_transform_imprint, path_to_transform_left_zones, path_to_transform_right_zones, path_to_pressure_data, path_to_pressure_metadata, path_to_write_statistics): transform_imprint = np.matrix(np.loadtxt(path_to_transform_imprint, delimiter=",")) transform_left_zones = np.loadtxt(path_to_transform_left_zones, delimiter=",") transform_right_zones = np.loadtxt(path_to_transform_right_zones, delimiter=",") segs_left_orig = segs_from_file(path_to_imprint_file_left) segs_right_orig = segs_from_file(path_to_imprint_file_right) segs_zones_left_orig = segs_from_file(path_to_zones_left) segs_zones_right_orig = segs_from_file(path_to_zones_right) segs_left = transformSegments(segs_left_orig, transform_imprint) segs_right = transformSegments(segs_right_orig, transform_imprint) segs_zones_left = transformSegments(segs_zones_left_orig, transform_left_zones) segs_zones_right = transformSegments(segs_zones_right_orig, transform_right_zones) col_spacing = 0.5 row_spacing = 0.5 with open(path_to_pressure_metadata, "rb") as metadata_file: reader = csv.DictReader(metadata_file) for row in reader: variable = row["variable"] value = row["value"] if str(variable).lower()=="COL_SPACING".lower(): col_spacing = float(value) elif str(variable).lower()=="ROW_SPACING".lower(): row_spacing = float(value) elif str(variable).lower() == "UNITS".lower(): units = value with open(path_to_pressure_data, "rb") as pressure_file: reader = csv.reader(pressure_file) header = reader.next() pressure_data = [] for row in reader: pressure_data.append([float(val) for val in row]) pressure_data = np.array(pressure_data) pressure_data_x_col = next(i for i, var in enumerate(header) if var=="x") pressure_data_y_col = next(i for i, var in enumerate(header) if var == "y") pressure_data_pressure_col = next(i for i, var in enumerate(header) if var == "pressure") pressure_data_not_null = pressure_data[pressure_data[:,pressure_data_pressure_col]!=0] pressure_meas = [] area = [] area_intersect = [] sensor_segs = [] sensor_clipped_against_imprint_scaled_for_clipper = [] pc = pyclipper.Pyclipper() for row in pressure_data_not_null: x = row[pressure_data_x_col] y = row[pressure_data_y_col] subj = ((x-row_spacing/2., y-col_spacing/2.), (x+row_spacing/2., y-col_spacing/2.), (x+row_spacing/2., y+col_spacing/2.), (x-row_spacing/2., y+col_spacing/2.)) sensor_segs.append(subj) ar = col_spacing*row_spacing area.append(ar) pressure_meas.append(row[pressure_data_pressure_col]*ar) # clip against segments # left pc.Clear() pc.AddPaths(pyclipper.scale_to_clipper(segs_left), pyclipper.PT_CLIP, True) pc.AddPaths(pyclipper.scale_to_clipper(segs_right), pyclipper.PT_CLIP, True) pc.AddPath(pyclipper.scale_to_clipper(subj), pyclipper.PT_SUBJECT, True) sol = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO) sensor_clipped_against_imprint_scaled_for_clipper.append(sol) sol_for_ar = np.array([np.array(seg) for seg in pyclipper.scale_from_clipper(sol)]) ar_intersect = sum(abs(np.array([sum((seg[np.r_[1:len(seg), 0],0]-seg[:,0])*(seg[np.r_[1:len(seg), 0],1]+seg[:,1]))/2. for seg in sol_for_ar]))) area_intersect.append(ar_intersect) pc.Clear() area_zones = [[abs(sum((seg[np.r_[1:len(seg), 0],0]-seg[:,0])*(seg[np.r_[1:len(seg), 0],1]+seg[:,1]))/2.) for seg in np.array(segs)] for segs in (segs_zones_left, segs_zones_right)] area_intersect_zones=[[],[]] for side in (0, 1): segs_zone = segs_zones_left if side == 0 else segs_zones_right for seg_zone in segs_zone: ar_segment_with_pressure_points = [] for sensor_clipped_segs in sensor_clipped_against_imprint_scaled_for_clipper: if sensor_clipped_segs!=[]: pc.Clear() pc.AddPath(pyclipper.scale_to_clipper(seg_zone), pyclipper.PT_CLIP, True) pc.AddPaths(sensor_clipped_segs, pyclipper.PT_SUBJECT, True) sol = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO) sol_for_ar = np.array([np.array(seg) for seg in pyclipper.scale_from_clipper(sol)]) ar = sum(abs(np.array([sum((seg[np.r_[1:len(seg), 0],0]-seg[:,0])*(seg[np.r_[1:len(seg), 0],1]+seg[:,1]))/2. for seg in sol_for_ar]))) else: ar = 0 ar_segment_with_pressure_points.append(ar) area_intersect_zones[side].append(ar_segment_with_pressure_points) area_zones_clipped_against_imprint = [[],[]] for side in (0, 1): segs_zone = segs_zones_left if side == 0 else segs_zones_right segs_imprint = segs_left if side == 0 else segs_right for seg_zone in segs_zone: pc.Clear() pc.AddPath(pyclipper.scale_to_clipper(seg_zone), pyclipper.PT_CLIP, True) pc.AddPaths(pyclipper.scale_to_clipper(segs_imprint), pyclipper.PT_SUBJECT, True) sol = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO) sol_for_ar = np.array([np.array(seg) for seg in pyclipper.scale_from_clipper(sol)]) ar = sum(abs(np.array([sum((seg[np.r_[1:len(seg), 0],0]-seg[:,0])*(seg[np.r_[1:len(seg), 0],1]+seg[:,1]))/2. for seg in sol_for_ar]))) area_zones_clipped_against_imprint[side].append(ar) pressure_calculated_for_zones = [[sum([(ar_zone[k]/area_intersect[k])*pressure_meas[k] if area_intersect[k]!=0 else 0 for k in range(0, len(area_intersect))]) for j, ar_zone in enumerate(ar_zones_s)] for i, ar_zones_s in enumerate(area_intersect_zones)] pressure_all = sum(pressure_meas) if path_to_write_statistics!="": with open(path_to_write_statistics, 'w') as statistics_file: statistics_file.write('side,' 'SID,' 'force,' 'force_rel_to_all,' 'force_rel_to_side,' 'force_rel_to_area,' 'area,' 'area_unclipped,' 'area_with_pressure,' 'area_with_pressure_unclipped' '\n') for side_idx in (0,1): side = "left" if side_idx==0 else "right" segs_zone = segs_zones_left if side_idx==0 else segs_zones_right pressure_side =sum(pressure_calculated_for_zones[side_idx]) for sid in range(0, len(segs_zone)): area_clipped = area_zones_clipped_against_imprint[side_idx][sid] area_unclipped = area_zones[side_idx][sid] area_with_pressure_clipped = sum(area_intersect_zones[side_idx][sid]) area_with_pressure_unclipped =sum([1 if a >0 else 0 for a in area_intersect_zones[side_idx][sid]])*row_spacing*col_spacing pressure = pressure_calculated_for_zones[side_idx][sid] statistics_file.write('"{}",{},{},{},{},{},{},{},{},{}\n'.format( side, sid, pressure, (pressure/pressure_all), (pressure/pressure_side), (pressure/area_clipped), area_clipped, area_unclipped, area_with_pressure_clipped, area_with_pressure_unclipped )) return(pressure_calculated_for_zones)
area += corners[i][0] * corners[j][1] area -= corners[j][0] * corners[i][1] area = abs(area) / 2.0 return area #Remove too big regions regions = filter(lambda region: area([vor.vertices[r] for r in region]) < 3, regions) #Assemble extruded sections print "Building openscad file" holes = [] for region in regions: verts = [vor.vertices[r] for r in region] pco = pyclipper.PyclipperOffset() pco.AddPath( pyclipper.scale_to_clipper( [[v[0], v[1]] for v in verts] ), pyclipper.JT_MITER, pyclipper.ET_CLOSEDPOLYGON ) p2 = pyclipper.scale_from_clipper( pco.Execute( pyclipper.scale_to_clipper( -.1 ) ) ) cutout = union() ( [down( 1 ) ( linear_extrude( height=h+2 ) ( polygon( points=path ) )) for path in p2] ) holes.append( cutout ) # Add Frame parts = cube( [width, height, 1] ) - holes parts += cube( [width, height, 1] ) - translate( [1, 1, -1] ) ( cube( [width-2, height-2, 3] ) ) print "Saving File" with open( __file__ + ".scad", "w" ) as f: f.write( scad_render( union() ( parts ) ) )