def nyc_boundary(): boroughs = {} # maps BoroCode to categorical borough_names = {5: 'SI', 4: 'Q', 3: 'BK', 1: 'M', 2: 'BX'} with fiona.open('data/indata/nybb_13a/nybb.shp', 'r') as source: # set up three projection types: boundary data start; google-standard # lat/lon, using WGS84; Albers Equal Area p1 = Proj(source.crs, preserve_units=True) p2 = Proj({'proj': 'longlat', 'datum': 'WGS84'}) p3 = Proj({'proj': 'aea', 'datum': 'WGS84', 'lon_0': '-96'}) # for each shape, convert its coordinates to AEA nyc = MultiPolygon() for borough in source: borough_shapes = MultiPolygon() borocode = borough['properties']['BoroCode'] for shape in borough['geometry']['coordinates']: p1_points = np.array(shape[0]) p2_points = transform(p1, p2, p1_points[:, 0], p1_points[:, 1]) p3_points = transform(p2, p3, p2_points[0], p2_points[1]) p3_points = np.vstack([p3_points[0], p3_points[1]]).T new = Polygon(p3_points) nyc = nyc.union(new) borough_shapes = borough_shapes.union(new) boroughs[borocode] = borough_shapes # i = 0 # for shape in nyc: # x,y = shape.exterior.xy # plt.plot(x,y) # bounds = np.array(shape.bounds) # bounds = bounds.reshape([2,2]) # cx = np.mean(bounds[:,0]) # cy = np.mean(bounds[:,1]) # plt.text(cx,cy,str(i)) # i = i+1 # By running the above, we identify the following islands that contain subway stations: # i borough name # 1. 3 staten island staten island # 2. 39 manhattan manhattan # 3. 36 manhattan roosevelt island # 4. 40 bronx bronx # 5. 10 brooklyn / queens rockaways # 6. 14 brooklyn / queens jamaica bay wildlife refuge / broad channel # 7. 15 brooklyn / queens brooklyn / queens # indices = [3, 39, 36, 40, 10, 14, 15] indices = [39, 36, 40, 10, 14, 15] boundary = [] for i in indices: boundary.append(nyc[i]) nyc = MultiPolygon(boundary) return nyc, boroughs, borough_names
def _make_polygon(gpd_obj): """select geometry which are from the type Polygon, MultiPolygon or GeometryCollection. The last one is converted to a Polygon/Multipolygon (Line Strings/MultiLineStrings are removed) Parameters ---------- gpd_obj : gpd.GeoDataFrame Returns ------- gpd.GeoDataFrame, that only contains Polygons or MultiPolygons """ gpd_obj = gpd_obj[(gpd_obj.type == 'GeometryCollection') | (gpd_obj.type == 'Polygon') | (gpd_obj.type == 'MultiPolygon')] if not gpd_obj.empty: collection = gpd_obj[(~gpd_obj.is_empty) & (gpd_obj.type == 'GeometryCollection')] # choose only polygons or multipolygons for c in collection.index: geo = collection.loc[c, 'geometry'] new = MultiPolygon() for obj in geo: if obj.type in ['Polygon', 'MultiPolygon']: new = new.union(obj) gpd_obj = gpd_obj.copy() gpd_obj.loc[c, 'geometry'] = new return gpd_obj
def flowshed_calculation(dem, shp): """ calculate flowsheds Parameters ---------- dem : str path to a raster file shp : str path to a shape file Returns ------- path to the shape file containing all the flowsheds (shapely.geometry.Polygon) """ dir = os.path.dirname(dem) watershed_dir = os.path.join(dir, 'all_watersheds.shp') flowshed_dir = os.path.join(dir, 'flowshed.shp') # calculate watersheds routing.delineate_watershed(dem, shp, 1, 100, watershed_dir, os.path.join(dir, 'snapped_outlet_points.shp'), os.path.join(dir, 'stream_out_uri.tif')) watersheds = gpd.read_file(watershed_dir).buffer(0) pour_points = gpd.read_file(dir + '/pour_points.shp') flowsheds = gpd.GeoSeries(watersheds.intersection(co), crs=crs) # remove empty objects flowsheds = flowsheds[(~flowsheds.is_empty) & (flowsheds.type != 'Point') & (flowsheds.type != 'MultiPoint') & (flowsheds.type != 'LineString') & (flowsheds.type != 'MultiLineString')] collections = flowsheds[flowsheds.type == 'GeometryCollection'] for index in collections.index: multi = MultiPolygon() for geo in collections.loc[index]: if geo.type is 'Polygon': multi = multi.union(geo) flowsheds.loc[index] = multi # if object is Multipolygon split it for i, shed in enumerate(flowsheds): if shed.type is 'MultiPolygon': # find polygon with minimal distance to pour point dist = [] for s0 in shed: dist.append(s0.distance(pour_points.loc[i, 'geometry'])) # add each polygon to all_watershed.shp for j, s1 in enumerate(shed): # polygon nearest to PP get current id if j == np.argmin(dist): flowsheds.loc[i] = shape(s1) # all other poylgons were added at the end else: s3 = gpd.GeoSeries(s1) flowsheds = flowsheds.append(s3, ignore_index=True) result = gpd.GeoDataFrame(geometry=flowsheds) result.to_file(flowshed_dir) return flowshed_dir
def iou(target_bboxes, predicted_bboxes): target_polys = MultiPolygon([Polygon(i) for i in target_bboxes]).buffer(0) predicted_polys = MultiPolygon([Polygon(i) for i in predicted_bboxes]).buffer(0) intersection = target_polys.intersection(predicted_polys).area union = target_polys.union(predicted_polys).area try: return intersection / union except ZeroDivisionError as e: return 0
def is_subset_polygon(left: geometry.MultiPolygon, right: geometry.MultiPolygon) -> bool: area_union = left.union(right).area area_intersection = left.intersection(right).area area_left = left.area area_right = right.area result = math.isclose(area_intersection, area_right, abs_tol=0.03**2) jaccard_expected = (area_left - area_right) / area_left jaccard_actual = (area_union - area_intersection) / area_union if DEBUG: logger.debug(f"left, right -> {area_left}, {area_right}") logger.debug( f"Je = ({area_left:.2f} - {area_right:.2f}) / {area_left:.2f} = {jaccard_expected:.2f}" ) logger.debug( f"Ja = ({area_union:.2f} - {area_intersection:.2f}) / {area_union:.2f} = {jaccard_actual:.2f}" ) logger.debug(f"{jaccard_expected} == {jaccard_actual} -> {result}") result = math.isclose(jaccard_expected, jaccard_actual, abs_tol=0.1) return result
class path_planner(Node): def __init__(self): super().__init__("wps") self.profile = qos_profile_sensor_data self.im_subscriber = self.create_subscription( Image, "/zenith_camera/image_raw", self.im_callback, qos_profile=self.profile) self.obj_subscriber = self.create_subscription( Pose2D, "/objectif", self.obj_callback, qos_profile=self.profile) self.p1_subscriber = self.create_subscription(Pose2D, "/player1Pose", self.obstacles_callback, qos_profile=self.profile) self.p2_subscriber = self.create_subscription(Pose2D, "/player2Pose", self.obstacles_callback, qos_profile=self.profile) self.wps_pub = self.create_publisher(Float64MultiArray, "/waypoints", self.profile) self.tfBuffer = tf2_ros.Buffer() self.listener = tf2_ros.TransformListener(self.tfBuffer, self) self.l_rob = 1.5 self.obstacles_fixes() self.terrain = Polygon(rect_from_center(HEIGHT, WIDHT)).buffer(-self.l_rob) self.small_terrain = Polygon(rect_from_center(HEIGHT, WIDHT)).buffer(-3) self.pos = (-5, 0) self.path = LineString(((0, 0), (0, 0))) self.polys = MultiPolygon() self.saved_obs self.i_player = 0 def obstacles_fixes(self): l_box, L_box = 2.3, 2.7 l_filet, L_filet = 13, 0.3 l_mur, e_mur = 0.1, 0.5 mur1 = rect_from_center(l_mur, e_mur, 5.7, 14.5) mur2 = rect_from_center(e_mur, l_mur, 7.5, 12.5) mur3 = rect_from_center(l_mur, e_mur, -5.7, -14.5) mur4 = rect_from_center(e_mur, l_mur, -7.5, -12.5) # cout("{}, {}".format(WIDHT/2 - l_box, HEIGHT/2 - L_box)) self.obstacles = MultiPolygon([ Polygon(mur1), Polygon(mur2), Polygon(mur3), Polygon(mur4), # Polygon(rect(l_box, L_box, -WIDHT/2, -HEIGHT/2)), # Polygon(rect(l_box, L_box, WIDHT/2 - l_box, HEIGHT/2 - L_box)), Polygon(rect_from_center(l_filet, L_filet)) ]).buffer(self.l_rob) self.saved_obs = self.obstacles def rec_path(self, A, B, d, sens=0): # print("d : ", d) line = LineString((A, B)) # if d>5: # return (A, B), d if not self.terrain.contains(line): return None, 0 for obs in self.obstacles: if line.crosses(obs): coords = (obs.union(line)).convex_hull.exterior.coords i = list(coords).index(A) if sens != 0: #print("AHHHH ! : ", (i+sens)%len(list(coords))) C = coords[(i + sens) % len(list(coords))] # print("C1, C2 : ", C1, C2) pts, d0 = self.rec_path(C, B, d, sens=sens) if pts == None: return None, 0 d += d0 else: C1, C2 = coords[i + 1], coords[(i - 2) % len(list(coords))] # print("C1, C2 : ", C1, C2) pts1, d1 = self.rec_path(C1, B, d, sens=1) pts2, d2 = self.rec_path(C2, B, d, sens=-2) if d1 > d2 or pts1 == None: C = C2 pts = pts2 d += d2 if pts == None: return None, 0 else: C = C1 pts = pts1 d += d1 d += cdist( np.array(A).reshape(1, -1), np.array(C).reshape(1, -1)) pts.insert(0, A) return pts, d d += cdist(np.array(A).reshape(1, -1), np.array(B).reshape(1, -1)) return [A, B], d def im_callback(self, msg): if DEBUG: bridge = cv_bridge.CvBridge() cv_im = bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8') # plot obstacle et safe_zones for obs in self.obstacles.geoms: pts = world_to_img(obs.exterior.coords).reshape((-1, 1, 2)) cv2.polylines(cv_im, [pts], True, (0, 0, 255)) # if self.path.crosses(obs): # coords = (obs.union(self.path)).convex_hull.exterior.coords # coords = world_to_img(coords) # cv2.polylines(cv_im,[coords],True,(255,0,255)) # for poly in self.polys.geoms: # pts = world_to_img(poly.exterior.coords).reshape((-1,1,2)) # cv2.polylines(cv_im,[pts],True,(255,0,255)) pts = world_to_img(self.terrain.exterior.coords).reshape( (-1, 1, 2)) cv2.polylines(cv_im, [pts], True, (0, 255, 0)) im_path = world_to_img(self.path.coords) for i in range(1, im_path.shape[0]): # cv2.line(cv_im, self.path[i-1, :], self.path[i, :], (0, 255, 255), thickness=5) cv2.line(cv_im, (im_path[i - 1, 0], im_path[i - 1, 1]), (im_path[i, 0], im_path[i, 1]), (0, 255, 255), thickness=3) cv2.imshow("cv_im", cv_im) cv2.waitKey(1) def obj_callback(self, msg): A = (msg.x, msg.y) transform = self.tfBuffer.lookup_transform('odom', 'base_link', tf2_ros.Time()) self.pos = (transform.transform.translation.x, transform.transform.translation.y) if not self.terrain.contains(Point(A)): cout("Objectif not in safe zone") #box = Point(A).buffer(2*self.l_rob) box = Polygon( rect_from_center(3 * self.l_rob, 3 * self.l_rob, A[0], A[1])) self.polys = self.polys.union(box) #pts, d = self.rec_path(self.pos, A, 0) I = self.terrain.exterior.intersection(box.exterior) if len(I.geoms) == 2: B = I.geoms[0] C = I.geoms[1] if cdist( np.array(self.pos).reshape(1, -1), np.array(B).reshape(1, -1)) > cdist( np.array(self.pos).reshape(1, -1), np.array(C).reshape(1, -1)): B, C = C, B pts, d1 = self.rec_path(self.pos, B, 0) if pts != None: pts.append(C) self.path = LineString(pts) self.send_wps() # if pts != None: # I = self.terrain.exterior.intersection(box.exterior) # for B in I: # cout(B) # self.path = LineString(pts) else: pts, d = self.rec_path(self.pos, A, 0) if pts != None: self.path = LineString(pts) self.send_wps() def obstacles_callback(self, msg): dalpha = np.pi / 6 r = 4 x, y, theta = msg.x, msg.y, msg.theta A, B = (x + r * np.cos(theta + dalpha), y + r * np.sin(theta + dalpha)), (x + r * np.cos(theta - dalpha), y + r * np.sin(theta - dalpha)) poly = Polygon((A, B, (x, y))).intersection(self.small_terrain) if self.i_player < 2: self.obstacles = self.obstacles.union(poly) self.i_player += 1 else: self.obstacles = self.saved_obs.union(poly) self.i_player = 0 def send_wps(self): data_to_send = Float64MultiArray( ) # the data to be sent, initialise the array data_to_send.data = [1.0, 2.0] data_to_send.data = list(np.array(self.path.coords).flatten( )) # assign the array with the value you want to send self.wps_pub.publish(data_to_send)
p1 = Proj(source.crs,preserve_units=True) p2 = Proj({'proj':'longlat', 'datum':'WGS84'}) p3 = Proj({'proj':'aea', 'datum':'WGS84', 'lon_0':'-96'}) # for each shape, convert its coordinates to AEA nyc = MultiPolygon() for shape in source: for subshape in shape['geometry']['coordinates']: p1_points = np.array(subshape[0]) p2_points = transform(p1, p2, p1_points[:,0], p1_points[:,1]) p3_points = transform(p2, p3, p2_points[0], p2_points[1]) p3_points = np.vstack([p3_points[0], p3_points[1]]).T new = Polygon(p3_points) nyc = nyc.union(new) # i = 0 # for shape in nyc: # x,y = shape.exterior.xy # plt.plot(x,y) # bounds = np.array(shape.bounds) # bounds = bounds.reshape([2,2]) # cx = np.mean(bounds[:,0]) # cy = np.mean(bounds[:,1]) # plt.text(cx,cy,str(i)) # i = i+1 # By running the above, we identify the following islands that contain subway stations: # i borough name
sectorkeys = sorted(sectors.iterkeys()) whole1 = sectors[sectorkeys[0]]['1'] whole2 = sectors[sectorkeys[0]]['2'] if whole1 == None: whole1 = MultiPolygon() if whole2 == None: whole2 = MultiPolygon() counter = 0 curx = 0 curstrip1 = Polygon() curstrip2 = Polygon() for s in sectorkeys[1:]: if s[0] > curx: whole1 = whole1.union(curstrip1) whole2 = whole2.union(curstrip2) curx = s[0] curstrip1 = Polygon() curstrip2 = Polygon() print "-->" + str(s) if sectors[s]['1']: curstrip1 = curstrip1.union(sectors[s]['1']) if sectors[s]['2']: curstrip2 = curstrip2.union(sectors[s]['2']) #counter+=1 #if counter > 100: # break whole1.buffer(1.0)
def DiagnoseAndFixMultiPolygon(attributeName, boundariesList, printDiagnostic=False): print "---" print "*** %s is invalid. Running diagnostic... ***" % (attributeName) # Note: we have already tested each polygon, so the problem is when we add them to a multipolygon # the likely cause is overlapping polygons, so we will automatically union those polygons #printDiagnostic = True goodPolygons = [] badPolygons = [] useSlowerCode = False numPolygons = len(boundariesList) if useSlowerCode: for i in range(0, numPolygons): if i % 20 == 0: print "processing polygon", i thisPolygon = boundariesList[i] shapelyMultiPoly = MultiPolygon(goodPolygons + [thisPolygon]) if shapelyMultiPoly.is_valid: goodPolygons.append(thisPolygon) else: print "*** problem when adding polygon %d ***" % (i) print thisPolygon badPolygons.append(thisPolygon) else: ''' it can be very slow trying these one at a time, so lets try jumping when we can and dropping back to one at a time when we have a problem ''' numPolygons = len(boundariesList) if printDiagnostic: print "numPolygons", numPolygons i = 0 lineReported = 0 while True: if i >= numPolygons: if printDiagnostic: print "reached end of list" break # end of list lineToReport = (i / 100) * 100 if lineToReport != lineReported: lineReported = lineToReport if i > 0: print "processing polygon %d of %d" % (i, numPolygons) continueToTop = False for numToJump in [100, 50, 20, 10]: if continueToTop: continue if i + numToJump > numPolygons: numToJump = numPolygons - i if printDiagnostic: print "adjusting numToJump to", numToJump #try the jump if printDiagnostic: print "trying jump" polygonsToAdd = boundariesList[i:i + numToJump] shapelyMultiPoly = MultiPolygon(goodPolygons + polygonsToAdd) if shapelyMultiPoly.is_valid: goodPolygons = goodPolygons + polygonsToAdd i = i + numToJump if printDiagnostic: print "jumped to %i" % (i) continueToTop = True if continueToTop: continue #resort to one at a time if printDiagnostic: print "resorting to one at a time. i = %d" % (i) for j in range(0, numToJump): thisPolygon = boundariesList[i] shapelyMultiPoly = MultiPolygon(goodPolygons + [thisPolygon]) if shapelyMultiPoly.is_valid: goodPolygons.append(thisPolygon) else: if True: print "polygon %d is bad" % (i) badPolygons.append(thisPolygon) i = i + 1 # now automatically generate a "fixed" multipolygon by unioning the bad polygons shapelyMultiPoly = MultiPolygon(goodPolygons) if len(badPolygons) > 0: print "---" print "*** Handling bad polygons ***" for poly in badPolygons: print "Bad polygon:", poly islandPoly = MultiPolygon([poly]) if islandPoly.is_valid: print "Fixed: The bad polygon was a valid polygon, it has been unioned to the whole." shapelyMultiPoly = shapelyMultiPoly.union(islandPoly) else: # try to fix this polygon ''' Outer boundary problems: Sometimes with clipping of shoreline, there are cases of the outer boundary of the shoreline crossing itself. There is not really anything we can do about such cases. ''' # check to see if the outer boundary is valid outerBoundary, innerBoundaries = poly islandPoly = MultiPolygon([(outerBoundary, [])]) if not islandPoly.is_valid: print "Outer boundary is not valid." print "Unable to fix this polygon." if attributeName == "MAPLAND": print "This is a minor error, it just means the oil contours will not be clipped to this part of the land." else: print "This is a serious error. Part of the %s area will be missing." % ( attributeName) print "---" continue # we will omit this polygon print "The outer boundary of the polygon is valid." ############################## ''' Hole problems: There are two kinds of problems that can occur with GNOME Analyst contours. Sometimes the holes stick slightly out of the outerboundary. In such a case we will rely on the fact that the holes were just areas to be removed. Sometimes there seem to be holes within holes. I'm not sure why GNOME Analyst is doing that, but we will assume that the holes were just areas to be removed. ''' numHoles = len(innerBoundaries) if numHoles > 0: print "Examing the %d holes..." % (numHoles) assert numHoles > 0 # the only way to get to this part of the code is for a hole to be causing the problem numOmittedHoles = 0 for innerBoundary in innerBoundaries: hole = Polygon(innerBoundary) if not hole.is_valid: numOmittedHoles = numOmittedHoles + 1 print "Hole is not valid:", hole print "Omitting this hole. This is a minor error." else: # subtract this hole from the islandPolygon islandPoly = islandPoly.difference(hole) if numOmittedHoles > 0: print "Partially fixed: %d invalid holes were not subtracted from this polygon, but this polygon has been unioned to the whole." % ( numOmittedHoles) elif numHoles > 0: print "Fixed: all holes successfully subtracted from this polygon and the polygon unioned to the whole." else: print "Fixed: polygon unioned to the whole." shapelyMultiPoly = shapelyMultiPoly.union(islandPoly) print "---" return shapelyMultiPoly
p1 = Proj(source.crs, preserve_units=True) p2 = Proj({'proj': 'longlat', 'datum': 'WGS84'}) p3 = Proj({'proj': 'aea', 'datum': 'WGS84', 'lon_0': '-96'}) # for each shape, convert its coordinates to AEA nyc = MultiPolygon() for shape in source: for subshape in shape['geometry']['coordinates']: p1_points = np.array(subshape[0]) p2_points = transform(p1, p2, p1_points[:, 0], p1_points[:, 1]) p3_points = transform(p2, p3, p2_points[0], p2_points[1]) p3_points = np.vstack([p3_points[0], p3_points[1]]).T new = Polygon(p3_points) nyc = nyc.union(new) # i = 0 # for shape in nyc: # x,y = shape.exterior.xy # plt.plot(x,y) # bounds = np.array(shape.bounds) # bounds = bounds.reshape([2,2]) # cx = np.mean(bounds[:,0]) # cy = np.mean(bounds[:,1]) # plt.text(cx,cy,str(i)) # i = i+1 # By running the above, we identify the following islands that contain subway stations: # i borough name
def custom_render(self, level_render_data, access_permissions, full_levels): if full_levels: levels = get_full_levels(level_render_data) else: levels = get_main_levels(level_render_data) buildings = None areas = None main_building_block = None main_building_block_diff = None current_upper_bound = None for geoms in levels: # hide indoor and outdoor rooms if their access restriction was not unlocked restricted_spaces_indoors = unary_union( tuple(area.geom for access_restriction, area in geoms.restricted_spaces_indoors.items() if access_restriction not in access_permissions) ) restricted_spaces_outdoors = unary_union( tuple(area.geom for access_restriction, area in geoms.restricted_spaces_outdoors.items() if access_restriction not in access_permissions) ) restricted_spaces = unary_union((restricted_spaces_indoors, restricted_spaces_outdoors)) # noqa # crop altitudeareas for altitudearea in geoms.altitudeareas: altitudearea.geometry = altitudearea.geometry.geom.difference(restricted_spaces) altitudearea.geometry_prep = prepared.prep(altitudearea.geometry) # crop heightareas new_heightareas = [] for geometry, height in geoms.heightareas: geometry = geometry.geom.difference(restricted_spaces) geometry_prep = prepared.prep(geometry) new_heightareas.append((geometry, geometry_prep, height)) geoms.heightareas = new_heightareas if geoms.on_top_of_id is None: buildings = geoms.buildings areas = MultiPolygon() current_upper_bound = geoms.upper_bound holes = geoms.holes.difference(restricted_spaces) buildings = buildings.difference(holes) areas = areas.union(holes.buffer(0).buffer(0.01, join_style=JOIN_STYLE.mitre)) main_building_block = OpenScadBlock('union()', comment='Level %s' % geoms.short_label) self.root.append(main_building_block) main_building_block_diff = OpenScadBlock('difference()') main_building_block.append(main_building_block_diff) main_building_block_inner = OpenScadBlock('union()') main_building_block_diff.append(main_building_block_inner) main_building_block_inner.append( self._add_polygon(None, buildings.intersection(self.bbox), geoms.lower_bound, geoms.upper_bound) ) for altitudearea in sorted(geoms.altitudeareas, key=attrgetter('altitude')): if not altitudearea.geometry.intersects(self.bbox): continue if altitudearea.altitude2 is not None: name = 'Altitudearea %s-%s' % (altitudearea.altitude/1000, altitudearea.altitude2/1000) else: name = 'Altitudearea %s' % (altitudearea.altitude / 1000) # why all this buffering? # buffer(0) ensures a valid geometry, this is sadly needed sometimes # the rest of the buffering is meant to make polygons overlap a little so no glitches appear # the intersections below will ensure that they they only overlap with each other and don't eat walls geometry = altitudearea.geometry.buffer(0) inside_geometry = geometry.intersection(buildings).buffer(0).buffer(0.01, join_style=JOIN_STYLE.mitre) outside_geometry = geometry.difference(buildings).buffer(0).buffer(0.01, join_style=JOIN_STYLE.mitre) geometry_buffered = geometry.buffer(0.01, join_style=JOIN_STYLE.mitre) if geoms.on_top_of_id is None: areas = areas.union(geometry) buildings = buildings.difference(geometry).buffer(0) inside_geometry = inside_geometry.intersection(areas).buffer(0) outside_geometry = outside_geometry.intersection(areas).buffer(0) geometry_buffered = geometry_buffered.intersection(areas).buffer(0) outside_geometry = outside_geometry.intersection(self.bbox) if not inside_geometry.is_empty: if altitudearea.altitude2 is not None: min_slope_altitude = min(altitudearea.altitude, altitudearea.altitude2) max_slope_altitude = max(altitudearea.altitude, altitudearea.altitude2) bounds = inside_geometry.bounds # cut in polygon = self._add_polygon(None, inside_geometry, min_slope_altitude-10, current_upper_bound+1000) slope = self._add_slope(bounds, altitudearea.altitude, altitudearea.altitude2, altitudearea.point1, altitudearea.point2, bottom=True) main_building_block_diff.append( OpenScadBlock('difference()', children=[polygon, slope], comment=name+' inside cut') ) # actual thingy if max_slope_altitude > current_upper_bound and inside_geometry.intersects(self.bbox): polygon = self._add_polygon(None, inside_geometry.intersection(self.bbox), current_upper_bound-10, max_slope_altitude+10) slope = self._add_slope(bounds, altitudearea.altitude, altitudearea.altitude2, altitudearea.point1, altitudearea.point2, bottom=False) main_building_block.append( OpenScadBlock('difference()', children=[polygon, slope], comment=name + 'outside') ) else: if altitudearea.altitude < current_upper_bound: main_building_block_diff.append( self._add_polygon(name+' inside cut', inside_geometry, altitudearea.altitude, current_upper_bound+1000) ) else: main_building_block.append( self._add_polygon(name+' inside', inside_geometry.intersection(self.bbox), min(altitudearea.altitude-700, current_upper_bound-10), altitudearea.altitude) ) if not outside_geometry.is_empty: if altitudearea.altitude2 is not None: min_slope_altitude = min(altitudearea.altitude, altitudearea.altitude2) max_slope_altitude = max(altitudearea.altitude, altitudearea.altitude2) bounds = outside_geometry.bounds polygon = self._add_polygon(None, outside_geometry, min_slope_altitude-710, max_slope_altitude+10) slope1 = self._add_slope(bounds, altitudearea.altitude, altitudearea.altitude2, altitudearea.point1, altitudearea.point2, bottom=False) slope2 = self._add_slope(bounds, altitudearea.altitude-700, altitudearea.altitude2-700, altitudearea.point1, altitudearea.point2, bottom=True) union = OpenScadBlock('union()', children=[slope1, slope2], comment=name+'outside') main_building_block.append( OpenScadBlock('difference()', children=[polygon, union], comment=name+'outside') ) else: if geoms.on_top_of_id is None: lower = geoms.lower_bound else: lower = altitudearea.altitude-700 if lower == current_upper_bound: lower -= 10 main_building_block.append( self._add_polygon(name+' outside', outside_geometry, lower, altitudearea.altitude) ) # obstacles if altitudearea.altitude2 is not None: obstacles_diff_block = OpenScadBlock('difference()', comment=name + ' obstacles') had_obstacles = False obstacles_block = OpenScadBlock('union()') obstacles_diff_block.append(obstacles_block) min_slope_altitude = min(altitudearea.altitude, altitudearea.altitude2) max_slope_altitude = max(altitudearea.altitude, altitudearea.altitude2) bounds = geometry.bounds for height, obstacles in altitudearea.obstacles.items(): height_diff = OpenScadBlock('difference()') had_height_obstacles = None height_union = OpenScadBlock('union()') height_diff.append(height_union) for obstacle in obstacles: if not obstacle.geom.intersects(self.bbox): continue obstacle = obstacle.geom.buffer(0).buffer(0.01, join_style=JOIN_STYLE.mitre) if self.min_width: obstacle = obstacle.union(self._satisfy_min_width(obstacle)).buffer(0) obstacle = obstacle.intersection(geometry_buffered) if not obstacle.is_empty: had_height_obstacles = True had_obstacles = True height_union.append( self._add_polygon(None, obstacle.intersection(self.bbox), min_slope_altitude-20, max_slope_altitude+height+10) ) if had_height_obstacles: obstacles_block.append(height_diff) height_diff.append( self._add_slope(bounds, altitudearea.altitude+height, altitudearea.altitude2+height, altitudearea.point1, altitudearea.point2, bottom=False) ) if had_obstacles: main_building_block.append(obstacles_diff_block) obstacles_diff_block.append( self._add_slope(bounds, altitudearea.altitude-10, altitudearea.altitude2-10, altitudearea.point1, altitudearea.point2, bottom=True) ) else: obstacles_block = OpenScadBlock('union()', comment=name + ' obstacles') had_obstacles = False for height, obstacles in altitudearea.obstacles.items(): for obstacle in obstacles: if not obstacle.geom.intersects(self.bbox): continue obstacle = obstacle.geom.buffer(0).buffer(0.01, join_style=JOIN_STYLE.mitre) if self.min_width: obstacle = obstacle.union(self._satisfy_min_width(obstacle)).buffer(0) obstacle = obstacle.intersection(geometry_buffered).intersection(self.bbox) if not obstacle.is_empty: had_obstacles = True obstacles_block.append( self._add_polygon(None, obstacle, altitudearea.altitude-10, altitudearea.altitude+height) ) if had_obstacles: main_building_block.append(obstacles_block) if self.min_width and geoms.on_top_of_id is None: main_building_block_inner.append( self._add_polygon('min width', self._satisfy_min_width(buildings).intersection(self.bbox).buffer(0), geoms.lower_bound, geoms.upper_bound) )
def gen_macros_for_non_fence_region(macro_pos_x, macro_pos_y, macro_size_x, macro_size_y, regions, yl, yh, merge=False, plot=False): # tt = time.time() macros = MultiPolygon([ box( macro_pos_x[i], macro_pos_y[i], macro_pos_x[i] + macro_size_x[i], macro_pos_y[i] + macro_size_y[i], ) for i in range(macro_size_x.size(0)) ]) # print("macro:", time.time()-tt) # tt = time.time() num_boxes = regions.size(0) regions = regions.view(num_boxes, 2, 2) fence_regions = MultiPolygon([ box(regions[i, 0, 0], regions[i, 0, 1], regions[i, 1, 0], regions[i, 1, 1]) for i in range(num_boxes) ]) # print("fence region:", time.time()-tt) merged_macros = macros.union(fence_regions) slices = [] for p in merged_macros: boundary_x, _ = p.boundary.xy boundary_x = boundary_x.tolist() if len(boundary_x) == 5: slices.append(p.bounds) else: xs = sorted(list(set(boundary_x))) for i, x_l in enumerate(xs[:-1]): x_h = xs[i + 1] cvx_hull = box(x_l, yl, x_h, yh) intersect = p.intersection(cvx_hull) if isinstance(intersect, Polygon): slices.append(intersect.bounds) elif isinstance(intersect, (GeometryCollection, MultiPolygon)): slices.extend([ j.bounds for j in intersect if (isinstance(j, Polygon)) ]) # tt = time.time() if merge: raw_bbox_list = sorted(slices, key=lambda x: (x[1], x[0])) cur_bbox = None bbox_list = [] for i, p in enumerate(raw_bbox_list): minx, miny, maxx, maxy = p if cur_bbox is None: cur_bbox = [minx, miny, maxx, maxy] elif cur_bbox[1] == miny and cur_bbox[3] == maxy: cur_bbox[2:] = p[2:] else: bbox_list.append(cur_bbox) cur_bbox = [minx, miny, maxx, maxy] else: bbox_list.append(cur_bbox) else: bbox_list = slices # print("merge:", time.time()-tt) bbox_list = torch.tensor(bbox_list).float() pos_x = bbox_list[:, 0] pos_y = bbox_list[:, 1] node_size_x = bbox_list[:, 2] - bbox_list[:, 0] node_size_y = bbox_list[:, 3] - bbox_list[:, 1] if plot: from descartes.patch import PolygonPatch from matplotlib import pyplot as plt from figures import BLUE, SIZE, color_isvalid, plot_coords, set_limits res = [] for bbox in bbox_list: res.append(box(*bbox)) res = MultiPolygon(res) fig = plt.figure(1, figsize=SIZE, dpi=90) ax = fig.add_subplot(111) for polygon in res: # plot_coords(ax, polygon.exterior) patch = PolygonPatch( polygon, facecolor=color_isvalid(merged_macros), edgecolor=color_isvalid(merged_macros, valid=BLUE), alpha=0.5, zorder=2, ) ax.add_patch(patch) set_limits(ax, -1, 20, -1, 20) # ax = fig.add_subplot(122) # patch = PolygonPatch(reverse, facecolor=color_isvalid(reverse), edgecolor=color_isvalid(reverse, valid=BLUE), alpha=0.5, zorder=2) # ax.add_patch(patch) # set_limits(ax, -1, 20, -1, 20) plt.savefig("macro.png") return pos_x, pos_y, node_size_x, node_size_y
def DiagnoseAndFixMultiPolygon(attributeName,boundariesList, printDiagnostic = False): print "---" print "*** %s is invalid. Running diagnostic... ***"%(attributeName) # Note: we have already tested each polygon, so the problem is when we add them to a multipolygon # the likely cause is overlapping polygons, so we will automatically union those polygons #printDiagnostic = True goodPolygons = [] badPolygons = [] useSlowerCode = False numPolygons = len(boundariesList) if useSlowerCode: for i in range(0,numPolygons) : if i % 20 == 0: print "processing polygon", i thisPolygon = boundariesList[i] shapelyMultiPoly = MultiPolygon(goodPolygons + [thisPolygon]) if shapelyMultiPoly.is_valid: goodPolygons.append(thisPolygon) else: print "*** problem when adding polygon %d ***"%(i) print thisPolygon badPolygons.append(thisPolygon) else: ''' it can be very slow trying these one at a time, so lets try jumping when we can and dropping back to one at a time when we have a problem ''' numPolygons = len(boundariesList) if printDiagnostic: print "numPolygons",numPolygons i = 0 lineReported = 0 while True: if i >= numPolygons: if printDiagnostic: print "reached end of list" break # end of list lineToReport = (i/100)*100 if lineToReport != lineReported: lineReported = lineToReport if i > 0: print "processing polygon %d of %d"%(i,numPolygons) continueToTop = False for numToJump in [100,50,20,10]: if continueToTop: continue if i + numToJump > numPolygons: numToJump = numPolygons - i; if printDiagnostic: print "adjusting numToJump to",numToJump #try the jump if printDiagnostic: print "trying jump" polygonsToAdd = boundariesList[i:i+numToJump] shapelyMultiPoly = MultiPolygon(goodPolygons + polygonsToAdd) if shapelyMultiPoly.is_valid: goodPolygons = goodPolygons + polygonsToAdd i = i + numToJump if printDiagnostic: print "jumped to %i"%(i) continueToTop = True if continueToTop: continue #resort to one at a time if printDiagnostic: print "resorting to one at a time. i = %d"%(i) for j in range(0,numToJump): thisPolygon = boundariesList[i] shapelyMultiPoly = MultiPolygon(goodPolygons + [thisPolygon]) if shapelyMultiPoly.is_valid: goodPolygons.append(thisPolygon) else: if True: print "polygon %d is bad"%(i) badPolygons.append(thisPolygon) i = i+1 # now automatically generate a "fixed" multipolygon by unioning the bad polygons shapelyMultiPoly = MultiPolygon(goodPolygons) if len(badPolygons) > 0: print "---" print "*** Handling bad polygons ***" for poly in badPolygons: print "Bad polygon:", poly islandPoly = MultiPolygon([poly]) if islandPoly.is_valid: print "Fixed: The bad polygon was a valid polygon, it has been unioned to the whole." shapelyMultiPoly = shapelyMultiPoly.union(islandPoly) else: # try to fix this polygon ''' Outer boundary problems: Sometimes with clipping of shoreline, there are cases of the outer boundary of the shoreline crossing itself. There is not really anything we can do about such cases. ''' # check to see if the outer boundary is valid outerBoundary,innerBoundaries = poly islandPoly = MultiPolygon([(outerBoundary,[])]) if not islandPoly.is_valid: print "Outer boundary is not valid." print "Unable to fix this polygon." if attributeName == "MAPLAND": print "This is a minor error, it just means the oil contours will not be clipped to this part of the land." else: print "This is a serious error. Part of the %s area will be missing."%(attributeName) print "---" continue # we will omit this polygon print "The outer boundary of the polygon is valid." ############################## ''' Hole problems: There are two kinds of problems that can occur with GNOME Analyst contours. Sometimes the holes stick slightly out of the outerboundary. In such a case we will rely on the fact that the holes were just areas to be removed. Sometimes there seem to be holes within holes. I'm not sure why GNOME Analyst is doing that, but we will assume that the holes were just areas to be removed. ''' numHoles = len(innerBoundaries) if numHoles > 0: print "Examing the %d holes..."%(numHoles) assert numHoles > 0 # the only way to get to this part of the code is for a hole to be causing the problem numOmittedHoles = 0 for innerBoundary in innerBoundaries: hole = Polygon(innerBoundary) if not hole.is_valid: numOmittedHoles = numOmittedHoles + 1 print "Hole is not valid:", hole print "Omitting this hole. This is a minor error." else: # subtract this hole from the islandPolygon islandPoly = islandPoly.difference(hole) if numOmittedHoles > 0: print "Partially fixed: %d invalid holes were not subtracted from this polygon, but this polygon has been unioned to the whole."%(numOmittedHoles) elif numHoles > 0: print "Fixed: all holes successfully subtracted from this polygon and the polygon unioned to the whole." else : print "Fixed: polygon unioned to the whole." shapelyMultiPoly = shapelyMultiPoly.union(islandPoly) print "---" return shapelyMultiPoly
# Find convex hull for points; find mean of x and y values xy = np.vstack([concat['x'].values,concat['y']]).T vertices = xy if len(xy) > 2: hull = ConvexHull(xy) vertices = hull.points[hull.simplices] vertices = np.vstack([vertices[:,0],vertices[:,1]]) vertices = DataFrame(vertices).drop_duplicates().values x = np.mean(vertices[:,0]) new['x'] = x y = np.mean(vertices[:,1]) new['y'] = y new_poly = MultiPolygon() for poly in concat['region']: new_poly = new_poly.union(poly) new['region'] = [new_poly] new['v_area'] = new['region'][0].area new['v_larea'] = np.log(new['v_area']) new = DataFrame(new) stops = stops.append(new) print "OK" print 'calculating connectedness...' print ' building representation of subway system...' # # 2.3 calculate connectedness # # 2.3.1 generate unique routes
def custom_render(self, level_render_data, access_permissions, full_levels): if full_levels: levels = get_full_levels(level_render_data) else: levels = get_main_levels(level_render_data) buildings = None areas = None main_building_block = None main_building_block_diff = None current_upper_bound = None for geoms in levels: # hide indoor and outdoor rooms if their access restriction was not unlocked restricted_spaces_indoors = unary_union( tuple(area.geom for access_restriction, area in geoms.restricted_spaces_indoors.items() if access_restriction not in access_permissions)) restricted_spaces_outdoors = unary_union( tuple(area.geom for access_restriction, area in geoms.restricted_spaces_outdoors.items() if access_restriction not in access_permissions)) restricted_spaces = unary_union( (restricted_spaces_indoors, restricted_spaces_outdoors)) # noqa # crop altitudeareas for altitudearea in geoms.altitudeareas: altitudearea.geometry = altitudearea.geometry.geom.difference( restricted_spaces) altitudearea.geometry_prep = prepared.prep( altitudearea.geometry) # crop heightareas new_heightareas = [] for geometry, height in geoms.heightareas: geometry = geometry.geom.difference(restricted_spaces) geometry_prep = prepared.prep(geometry) new_heightareas.append((geometry, geometry_prep, height)) geoms.heightareas = new_heightareas if geoms.on_top_of_id is None: buildings = geoms.buildings areas = MultiPolygon() current_upper_bound = geoms.upper_bound holes = geoms.holes.difference(restricted_spaces) buildings = buildings.difference(holes) areas = areas.union( holes.buffer(0).buffer(0.01, join_style=JOIN_STYLE.mitre)) main_building_block = OpenScadBlock('union()', comment='Level %s' % geoms.short_label) self.root.append(main_building_block) main_building_block_diff = OpenScadBlock('difference()') main_building_block.append(main_building_block_diff) main_building_block_inner = OpenScadBlock('union()') main_building_block_diff.append(main_building_block_inner) main_building_block_inner.append( self._add_polygon(None, buildings.intersection(self.bbox), geoms.lower_bound, geoms.upper_bound)) for altitudearea in sorted(geoms.altitudeareas, key=attrgetter('altitude')): if not altitudearea.geometry.intersects(self.bbox): continue if altitudearea.altitude2 is not None: name = 'Altitudearea %s-%s' % ( altitudearea.altitude / 1000, altitudearea.altitude2 / 1000) else: name = 'Altitudearea %s' % (altitudearea.altitude / 1000) # why all this buffering? # buffer(0) ensures a valid geometry, this is sadly needed sometimes # the rest of the buffering is meant to make polygons overlap a little so no glitches appear # the intersections below will ensure that they they only overlap with each other and don't eat walls geometry = altitudearea.geometry.buffer(0) inside_geometry = geometry.intersection(buildings).buffer( 0).buffer(0.01, join_style=JOIN_STYLE.mitre) outside_geometry = geometry.difference(buildings).buffer( 0).buffer(0.01, join_style=JOIN_STYLE.mitre) geometry_buffered = geometry.buffer( 0.01, join_style=JOIN_STYLE.mitre) if geoms.on_top_of_id is None: areas = areas.union(geometry) buildings = buildings.difference(geometry).buffer(0) inside_geometry = inside_geometry.intersection( areas).buffer(0) outside_geometry = outside_geometry.intersection( areas).buffer(0) geometry_buffered = geometry_buffered.intersection( areas).buffer(0) outside_geometry = outside_geometry.intersection(self.bbox) if not inside_geometry.is_empty: if altitudearea.altitude2 is not None: min_slope_altitude = min(altitudearea.altitude, altitudearea.altitude2) max_slope_altitude = max(altitudearea.altitude, altitudearea.altitude2) bounds = inside_geometry.bounds # cut in polygon = self._add_polygon(None, inside_geometry, min_slope_altitude - 10, current_upper_bound + 1000) slope = self._add_slope(bounds, altitudearea.altitude, altitudearea.altitude2, altitudearea.point1, altitudearea.point2, bottom=True) main_building_block_diff.append( OpenScadBlock('difference()', children=[polygon, slope], comment=name + ' inside cut')) # actual thingy if max_slope_altitude > current_upper_bound and inside_geometry.intersects( self.bbox): polygon = self._add_polygon( None, inside_geometry.intersection(self.bbox), current_upper_bound - 10, max_slope_altitude + 10) slope = self._add_slope(bounds, altitudearea.altitude, altitudearea.altitude2, altitudearea.point1, altitudearea.point2, bottom=False) main_building_block.append( OpenScadBlock('difference()', children=[polygon, slope], comment=name + 'outside')) else: if altitudearea.altitude < current_upper_bound: main_building_block_diff.append( self._add_polygon(name + ' inside cut', inside_geometry, altitudearea.altitude, current_upper_bound + 1000)) else: main_building_block.append( self._add_polygon( name + ' inside', inside_geometry.intersection(self.bbox), min(altitudearea.altitude - 700, current_upper_bound - 10), altitudearea.altitude)) if not outside_geometry.is_empty: if altitudearea.altitude2 is not None: min_slope_altitude = min(altitudearea.altitude, altitudearea.altitude2) max_slope_altitude = max(altitudearea.altitude, altitudearea.altitude2) bounds = outside_geometry.bounds polygon = self._add_polygon(None, outside_geometry, min_slope_altitude - 710, max_slope_altitude + 10) slope1 = self._add_slope(bounds, altitudearea.altitude, altitudearea.altitude2, altitudearea.point1, altitudearea.point2, bottom=False) slope2 = self._add_slope(bounds, altitudearea.altitude - 700, altitudearea.altitude2 - 700, altitudearea.point1, altitudearea.point2, bottom=True) union = OpenScadBlock('union()', children=[slope1, slope2], comment=name + 'outside') main_building_block.append( OpenScadBlock('difference()', children=[polygon, union], comment=name + 'outside')) else: if geoms.on_top_of_id is None: lower = geoms.lower_bound else: lower = altitudearea.altitude - 700 if lower == current_upper_bound: lower -= 10 main_building_block.append( self._add_polygon(name + ' outside', outside_geometry, lower, altitudearea.altitude)) # obstacles if altitudearea.altitude2 is not None: obstacles_diff_block = OpenScadBlock('difference()', comment=name + ' obstacles') had_obstacles = False obstacles_block = OpenScadBlock('union()') obstacles_diff_block.append(obstacles_block) min_slope_altitude = min(altitudearea.altitude, altitudearea.altitude2) max_slope_altitude = max(altitudearea.altitude, altitudearea.altitude2) bounds = geometry.bounds for height, obstacles in altitudearea.obstacles.items(): height_diff = OpenScadBlock('difference()') had_height_obstacles = None height_union = OpenScadBlock('union()') height_diff.append(height_union) for obstacle in obstacles: if not obstacle.geom.intersects(self.bbox): continue obstacle = obstacle.geom.buffer(0).buffer( 0.01, join_style=JOIN_STYLE.mitre) if self.min_width: obstacle = obstacle.union( self._satisfy_min_width(obstacle)).buffer( 0) obstacle = obstacle.intersection(geometry_buffered) if not obstacle.is_empty: had_height_obstacles = True had_obstacles = True height_union.append( self._add_polygon( None, obstacle.intersection(self.bbox), min_slope_altitude - 20, max_slope_altitude + height + 10)) if had_height_obstacles: obstacles_block.append(height_diff) height_diff.append( self._add_slope(bounds, altitudearea.altitude + height, altitudearea.altitude2 + height, altitudearea.point1, altitudearea.point2, bottom=False)) if had_obstacles: main_building_block.append(obstacles_diff_block) obstacles_diff_block.append( self._add_slope(bounds, altitudearea.altitude - 10, altitudearea.altitude2 - 10, altitudearea.point1, altitudearea.point2, bottom=True)) else: obstacles_block = OpenScadBlock('union()', comment=name + ' obstacles') had_obstacles = False for height, obstacles in altitudearea.obstacles.items(): for obstacle in obstacles: if not obstacle.geom.intersects(self.bbox): continue obstacle = obstacle.geom.buffer(0).buffer( 0.01, join_style=JOIN_STYLE.mitre) if self.min_width: obstacle = obstacle.union( self._satisfy_min_width(obstacle)).buffer( 0) obstacle = obstacle.intersection( geometry_buffered).intersection(self.bbox) if not obstacle.is_empty: had_obstacles = True obstacles_block.append( self._add_polygon( None, obstacle, altitudearea.altitude - 10, altitudearea.altitude + height)) if had_obstacles: main_building_block.append(obstacles_block) if self.min_width and geoms.on_top_of_id is None: main_building_block_inner.append( self._add_polygon( 'min width', self._satisfy_min_width(buildings).intersection( self.bbox).buffer(0), geoms.lower_bound, geoms.upper_bound))