def widen_line(linestring: sg.LineString, width: float) -> sg.Polygon: linestrings = [ linestring, linestring.parallel_offset(width, "left"), linestring.parallel_offset(width, "right"), ] return sg.MultiLineString(linestrings).minimum_rotated_rectangle
def _make_xyz(row, distance_main, distance_help, bottom_level, bottom_width, talud_l, talud_r, total_depth = 10): # Set up basic profile parameters: bottom width & total width based on talud if math.isnan(bottom_width): bottom_width = 2 logging.info(f"Profielen maken: {row['CODE']} geen bodembreedte gevonden, bodembreedte op 2 gezet.") total_width = bottom_width + total_depth * talud_l + total_depth * talud_r if math.isnan(total_width): total_width = bottom_width + 2 * total_depth * 2 logging.info(f"Profielen maken: {row['CODE']} geen taluds gevonden, talud op 2 gezet.") upper_level = bottom_level + total_depth # Profile will be created using a short sub-segment of the source-line-geometry. l = row['geometry'].length logging.info(f'Profielen maken: {row["CODE"]}, op afstand: {distance_main} van lengte: {l}, ' f'bodembreedte: {bottom_width}, ' f'bodemhoogte: {bottom_level}, totale diepte: {total_depth}') point1 = row['geometry'].interpolate(distance_main) point2 = row['geometry'].interpolate(distance_help) baseline = LineString([point1, point2]) left_inner = baseline.parallel_offset(bottom_width/2, 'left') right_inner = baseline.parallel_offset(bottom_width/2, 'right') left_inner_point = shapely.ops.transform(lambda x, y: (x, y, bottom_level), Point(left_inner.coords[0])) right_inner_point = shapely.ops.transform(lambda x, y: (x, y, bottom_level), Point(right_inner.coords[-1])) left_outer = baseline.parallel_offset(total_width/2, 'left') right_outer = baseline.parallel_offset(total_width/2, 'right') left_outer_point = shapely.ops.transform(lambda x, y: (x, y, upper_level), Point(left_outer.coords[0])) right_outer_point = shapely.ops.transform(lambda x, y: (x, y, upper_level), Point(right_outer.coords[-1])) profile_line = LineString([left_outer_point, left_inner_point, right_inner_point, right_outer_point]) return profile_line
def _make_dwp(row, up_or_down: str = 'upstream', profile_dist: float = 5): width = row['WS_BODEMBREEDTE_L'] + 2 * row['WS_TALUD_LINKS_L'] + 2 * row[ 'WS_TALUD_RECHTS_L'] l = row['geometry'].length logging.info( f'DWP maken: {up_or_down}, {row["CODE"]}, lengte: {l}, breedte: {width}' ) if l > (profile_dist * 2 + 1): dist1 = profile_dist dist2 = profile_dist - 1 else: dist1 = l * 0.2 dist2 = l * 0.4 if up_or_down.lower().startswith('down'): dist1 = dist1 * -1 dist2 = dist2 * -1 if math.isnan(width): width = 6 logging.info( f"Normgeparametriseerdprofiel maken: {row['CODE']} er kon geen breedte gemaakt worden, geometrie wordt 6 meter breed" ) point1 = row['geometry'].interpolate(dist1) point2 = row['geometry'].interpolate(dist2) baseline = LineString([point1, point2]) left = baseline.parallel_offset(width / 2, 'left') right = baseline.parallel_offset(width / 2, 'right') left_point = left.coords[0] right_point = right.coords[-1] profile_line = LineString([left_point, right_point]) return profile_line
def create_edge(self, edges): """Create the SUMO edge XML node(s) matching with the Webots road.""" if self.startJunctionID == self.endJunctionID: print( 'Warning: cannot export edge "%s" because start and end junctions are identical.' % self.id) return if len(self.wayPoints) < 2: print( 'Warning: cannot export edge "%s" because it has less than 2 way-points.' % self.id) return laneWidth = self.width / self.lanes # The original path should be slightly shifted if the case where the # forwardLanes and backwardLanes are not matching. originalCoords = [[-x - self.translation[0], z + self.translation[2]] for [x, y, z] in self.wayPoints] originalLineString = LineString(originalCoords) if self.oneWay: originalLineString = originalLineString.parallel_offset( 0.5 * laneWidth * self.forwardLanes, 'left') else: offset = (self.forwardLanes - self.backwardLanes) * laneWidth * 0.5 if offset > 0.0: originalLineString = originalLineString.parallel_offset( offset, 'left') elif offset < 0.0: originalLineString = originalLineString.parallel_offset( offset, 'left') originalLineString = LineString( list(originalLineString.coords[::-1])) if isinstance(originalLineString, MultiLineString): originalPath = originalCoords else: originalPath = list(originalLineString.coords) # Create the forward edge if self.forwardLanes > 0: edge = ET.SubElement(edges, 'edge') edge.attrib['id'] = self.id edge.attrib['from'] = self.startJunctionID edge.attrib['to'] = self.endJunctionID edge.attrib['numLanes'] = str(self.forwardLanes) edge.attrib['width'] = str(laneWidth) edge.attrib['shape'] = Road._pathToString(originalPath) # Create the backward edge if self.backwardLanes > 0: edge = ET.SubElement(edges, 'edge') edge.attrib['id'] = '-' + self.id edge.attrib['to'] = self.startJunctionID edge.attrib['from'] = self.endJunctionID edge.attrib['numLanes'] = str(self.backwardLanes) edge.attrib['width'] = str(laneWidth) edge.attrib['shape'] = Road._pathToString(originalPath[::-1])
def create_line_string(geom, is_forward): ls = LineString([(geom.lonlats[i], geom.lonlats[i + 1]) for i in range(0, len(geom.lonlats), 2)]) offset = .000045 if is_forward: ls = ls.parallel_offset(offset, 'right') else: ls = ls.parallel_offset(offset, 'left') return ls
def draw_tick(segment, x, y, length=0.25): line = LineString(segment) left = line.parallel_offset(length, 'left') right0 = line.parallel_offset(length, 'right') right = LineString([right0.boundary.geoms[1], right0.boundary.geoms[0] ]) # flip because 'right' orientation point = Point(x, y) a = left.interpolate(line.project(point)) b = right.interpolate(line.project(point)) line = LineString([a, b]) return line
def perpendicular(point_a, baseline): b = point_a a = baseline[1] cd_length = 800 ab = LineString([a, b]) left = ab.parallel_offset(cd_length / 2, 'left') right = ab.parallel_offset(cd_length / 2, 'right') c = left.boundary[1] d = right.boundary[0] # note the different orientation for right offset cd = LineString([c, d]) return cd
def get_linestring_side(ls: LineString, p: Point) -> str: """ Return which side of the LineString is the given point, order by the sequence of the coordinates. Args: ls: reference LineString p: point to check Returns: Either "left" or "right" """ right = ls.parallel_offset(0.1, side="right") left = ls.parallel_offset(0.1, side="left") return "left" if left.distance(p) < right.distance(p) else "right"
class Threshold: def __init__(self, name, points, color): self.name = name self.line = LineString(points) self.parallel_in = self.line.parallel_offset(30, side='left') self.parallel_out = self.line.parallel_offset(30, side='right') length = self.line.length self.midpoint = self.line.interpolate(length / 2) self.mid_in = self.parallel_in.interpolate(length / 2) self.mid_out = self.parallel_out.interpolate(length / 2) self.p_in = int(self.mid_in.x), int(self.mid_in.y) self.p_out = int(self.mid_out.x), int(self.mid_out.y) t_array = np.array(self.line) self.t_vec = t_array[1] - t_array[0] self.color = color self.counter = {"in": 0, "out": 0} def check(self, line): if self.line.intersects(line): p_array = np.array(line) p_vec = p_array[1] - p_array[0] direction = np.inner(self.t_vec, p_vec) if direction > 0: self.counter["in"] += 1 return True elif direction < 0: self.counter["out"] += 1 return True def draw(self, image): print(self.counter) line = np.array(self.line, np.uint32) cv2.line(image, tuple(line[0]), tuple(line[1]), self.color, 2) cv2.circle(image, tuple(self.p_in), 18, self.color, -9) in_count = self.counter["in"] cv2.putText(image, "{}:{}".format(self.name, str(in_count)), (int(self.p_in[0]) - 17, int(self.p_in[1]) + 5), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 1) out_count = self.counter["out"] cv2.circle(image, tuple(self.p_out), 18, self.color, -9) cv2.putText(image, "{}:{}".format(self.name, str(out_count)), (int(self.p_out[0]) - 17, int(self.p_out[1]) + 5), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 1)
def draw_ticks(segment, xList, yList, length=0.25): xdata = list(segment.get_xdata()) ydata = list(segment.get_ydata()) line = LineString([(xdata[0], ydata[0]), (xdata[1], ydata[1])]) left = line.parallel_offset(length, 'left') right0 = line.parallel_offset(length, 'right') right = LineString([right0.boundary.geoms[1], right0.boundary.geoms[0]]) # flip because 'right' orientation ticks = [] for i,x in enumerate(xList): p = Point(xList[i],yList[i]) a = left.interpolate(line.project(p)) b = right.interpolate(line.project(p)) ticks.append(LineString([a, p, b]).coords) # keep p point to sort from distance later return ticks
def getContour(self, poly, side, offset): line = LineString(PolygonPath(poly).vertices) contour = [line.parallel_offset(offset, side, join_style=2)] for part in contour: #get offset paths x, y = part.xy self.offsetX.append(x) self.offsetY.append(y)
def generate_path(self): """Generate parallel coverage path lines""" starting_breakdown = self.rP.bounds[0:2] # poly.bounds = bounding box line = LineString([ starting_breakdown, (starting_breakdown[0], starting_breakdown[1] + self.rP.bounds[3] - self.rP.bounds[1]) ]) try: bounded_line = self.rP.intersection(line) except TopologicalError as e: error("Problem looking for intersection.", exc_info=1) return lines = [bounded_line] # iterations = int(ceil((self.rP.bounds[2] - self.rP.bounds[0]) / ft)) + 1 iterations = int((self.rP.bounds[2] - self.rP.bounds[0]) / self.ft) + 2 for x in range(1, iterations): bounded_line = line.parallel_offset(x * self.ft, 'right') if self.rP.intersects(bounded_line): try: bounded_line = self.rP.intersection(bounded_line) except TopologicalError as e: error("Problem looking for intersection.", exc_info=1) continue lines.append(bounded_line) return lines
def find_cut_distance(current_string: LineString, pair, frequency: int, offset_distance: float, side: str): neighbor_string = LineString( [[pair.node_from.utm.north, pair.node_from.utm.east], [pair.node_to.utm.north, pair.node_to.utm.east]]) offsetted_neighbor_string = neighbor_string.parallel_offset( frequency * offset_distance, side='left', resolution=10) # Project neighbor string onto current string. if side == 'back': projected_point = Point( nearest_points( current_string, Point(list(offsetted_neighbor_string.coords)[-1]))[0]) else: projected_point = Point( nearest_points( current_string, Point(list(offsetted_neighbor_string.coords)[0]))[0]) # Create a line from the side of the current string to the projected points. if side == 'back': line = LineString( [Point(list(current_string.coords)[0]), projected_point]) else: line = LineString( [Point(list(current_string.coords)[-1]), projected_point]) return line.length
def offset(self, distance): self.points.append(self.points[0]) line = LineString(self.getSequence()) offset = line.parallel_offset(distance, 'right', join_style=1) # return list(offset.coords) self.setSequence(list(offset.coords)) return self
def _cont_to_polys(self, cont_lats, cont_lons): polys = [] start_idx = 0 splits = [] while True: try: split_idx = cont_lats[start_idx:].index(99.99) splits.append(start_idx + split_idx) start_idx += split_idx + 1 except ValueError: break splits = [ -1 ] + splits + [ len(cont_lats) + 1 ] poly_lats = [ cont_lats[splits[i] + 1:splits[i + 1]] for i in xrange(len(splits) - 1) ] poly_lons = [ cont_lons[splits[i] + 1:splits[i + 1]] for i in xrange(len(splits) - 1) ] # Intersect with the US boundary shape file. for plat, plon in zip(poly_lats, poly_lons): cont = LineString(zip(plon, plat)) if plat[0] != plat[-1] or plon[0] != plon[-1]: # If the line is not a closed contour, then it intersects with the edge of the US. Extend # the ends a little bit to make sure it's outside the edge. dln = np.diff(plon) dlt = np.diff(plat) pre = [ (plon[0] - 0.5 * dln[0], plat[0] - 0.5 * dlt[0]) ] post = [ (plon[-1] + 0.5 * dln[-1], plat[-1] + 0.5 * dlt[-1]) ] cont.coords = pre + list(cont.coords) + post # polygonize() will split the country into two parts: one inside the outlook and one outside. # Construct test_ln that is to the right of (inside) the contour and keep only the polygon # that contains the line test_ln = cont.parallel_offset(0.05, 'right') for poly in polygonize(self._conus.boundary.union(cont)): if (poly.crosses(test_ln) or poly.contains(test_ln)) and self._conus.contains(poly.buffer(-0.01)): polys.append(poly) # Sort the polygons by area so we intersect the big ones with the big ones first. polys.sort(key=lambda p: p.area, reverse=True) # If any polygons intersect, replace them with their intersection. intsct_polys = [] while len(polys) > 0: intsct_poly = polys.pop(0) pops = [] for idx, poly in enumerate(polys): if intsct_poly.intersects(poly): intsct_poly = intsct_poly.intersection(poly) pops.append(idx) for pop_idx in pops[::-1]: polys.pop(pop_idx) intsct_polys.append(intsct_poly) return intsct_polys
def generate_intersections(poly, width): """ Get coverage lines inside a cell. Lines will be centered throught cell with padding of width/2. :param poly: Polygon data :param width: Width of distance between vertical lines :return: Intersected lines """ initial_line = LineString([(poly.bounds[0] + width / 2.0, poly.bounds[1] - 1), (poly.bounds[0] + width / 2.0, poly.bounds[3] + 1)]) line = initial_line.parallel_offset(0, 'right') lines = [] if poly.bounds[2] - poly.bounds[0] >= width / 2: iterations = int(math.ceil((poly.bounds[2] - poly.bounds[0] - width / 2.0) / width)) for x in range(0, iterations): if poly.intersects(line): try: bounded_line = deepcopy(line) intersection_line = poly.intersection(line) if intersection_line.bounds[1] != bounded_line.bounds[1]: if intersection_line.bounds[1] > bounded_line.bounds[1]: bounds = list(bounded_line.bounds) bounds[1] = intersection_line.bounds[1] + width / 2.0 else: bounds = list(bounded_line.bounds) bounds[1] = intersection_line.bounds[1] - width / 2.0 bounded_line = LineString([tuple(bounds[:2]), tuple(bounds[2:])]) if intersection_line.bounds[3] != bounded_line.bounds[3]: if intersection_line.bounds[3] > bounded_line.bounds[3]: bounds = list(bounded_line.bounds) bounds[3] = intersection_line.bounds[3] + width / 2.0 else: bounds = list(bounded_line.bounds) bounds[3] = intersection_line.bounds[3] - width / 2.0 bounded_line = LineString([tuple(bounds[:2]), tuple(bounds[2:])]) except TopologicalError: error("Problem looking for intersection.", exc_info=1) continue lines.append(bounded_line) line = initial_line.parallel_offset(width * (x + 1), 'right') return lines
def applyOffset( xN, yN, d): line = LineString( tuple(zip(xN , yN)) ) #create a linestring with a list of turple offLine= line.parallel_offset(d , side='right' , resolution=16, join_style=2, mitre_limit=5) if "Multi" in str(type(offLine)) : offLineXY = offLine[0].xy #extract the coordinate else: offLineXY = offLine.xy #extract the coordinate # there is a bug in the Offset function. With side = right, sequence is revered and have to be reversed afterward return np.array(list(reversed(offLineXY[0]))) , np.array(list(reversed(offLineXY[1])))
def getContour(self, poly, side, offset): list = [[], []] line = LineString(PolygonPath(poly).vertices) contour = [line.parallel_offset(offset, side, join_style=2)] for part in contour: #get offset paths x, y = part.xy list[0].append(x) list[1].append(y) return list
def __init__(self, id, points_list, traffic_signs_idx, right_offset, left_offset, lanes_list): ''' Class Area is defined by an ID, a list GPS points of the desired area, indices of the traffic signals, right and left offsets and the number of lanes of each line connecting each two consecutive GPS points ''' # Assining ID to the Area self.id = id # Converting GPS coordinates to UTM coordinates p = Proj(proj='utm', zone=34, ellps='WGS84', preserve_units=False) utm_points = [None]*len(points_list) for idx, point in enumerate(points_list): utm_points[idx] = p(point[0], point[1]) # Creating lines from given points and their right and left offsets center_line = LineString(utm_points) right_line = center_line.parallel_offset(right_offset, 'right', join_style=2).coords[:] left_line = center_line.parallel_offset(left_offset, 'left', join_style=2).coords[:] # Generating area polygon self.polygon = Polygon(right_line + left_line) self.polygon_pixels = [] # Obtaining bounding box of the generated polygon x, y = list(zip(*self.polygon.exterior.coords)) self.bbox = [min(x), max(x), min(y), max(y)] # Dividing area into regions = number of given points -1 self.regions = [None]*(len(utm_points)-1) start_line = [self.polygon.exterior.coords[len(utm_points)-1], self.polygon.exterior.coords[len(utm_points)]] for i in range(len(self.regions)): center_line = LineString([utm_points[i], utm_points[i+1]]) right_line = center_line.parallel_offset(right_offset, 'right', join_style=2).coords[:] left_line = center_line.parallel_offset(left_offset, 'left', join_style=2).coords[:] normal_line = np.array([right_line[0], left_line[-1]]) end_point = utm_points[i+1] traffic_sign = True if i+1 in traffic_signs_idx else False self.regions[i] = Region(self, i, start_line, normal_line, end_point, lanes_list[i], traffic_sign) start_line = normal_line self.regions.reverse() # Initializing maximum queue and maximum queue time and region of the area self.max_queue = [] self.max_queue_time = 0.0 self.max_queue_region = None
def draw_star(self, _=None): self.starsLayout.canvas.clear() Globals = self.Globals centerX, centerY = Globals.width / 2, Globals.height / 2 width = Globals.width / Globals.GameSettings.intro_ship_star_width_divider height = Globals.height / Globals.GameSettings.intro_ship_star_height_divider cd_length = height for i in range(Globals.GameSettings.intro_ship_star_amount): x, y = random.randint(0, Globals.width), random.randint(0, Globals.height / 2) + Globals.height / 2 line = LineString([(centerX, centerY), (x, y)]) left = line.parallel_offset(cd_length / 2, 'left') right = line.parallel_offset(cd_length / 2, 'right') p1 = left.boundary[1] p2 = right.boundary[0] x1, y1 = p1.coords[0] x2, y2 = p2.coords[0] a = 0, y1 b = x1, y1 c = x2, y2 angle = math.degrees(math.atan2(c[1] - b[1], c[0] - b[0]) - math.atan2(a[1] - b[1], a[0] - b[0])) angle = angle + 360 if angle < 0 else angle rect = LineString([(x, y), (x, y + height), (x + width, y + height), (x + width, y)]) rect = affinity.rotate(rect, angle + 90, "center") rect = rect.coords with self.starsLayout.canvas: Color(1, 1, 1) Mesh(indices=(0, 1, 2, 3), vertices=(rect[0][0], rect[0][1], 0, 0, rect[1][0], rect[1][1], 0, 1, rect[2][0], rect[2][1], 1, 1, rect[3][0], rect[3][1], 1, 0), mode="triangle_fan", texture=self.Globals.Textures.star)
def create_path(a, b, contour, distancia, dir=0): conf_1 = -90 conf_2 = -1 conf_3 = "left" conf_4 = 0 if dir == 1: conf_3 = "right" path = [] contorno_points = [] for c in contour: c = utils.to_utm(c) utm_pos = Point(c.x, c.y) contorno_points.append(utm_pos) a2 = utils.to_utm(a) a_utm = Point(a2.x, a2.y) b2 = utils.to_utm(b) b_utm = Point(b2.x, b2.y) ab_course = utils.bearing(a_utm, b_utm) a_utm = utils.offset(a2, ab_course - 90, distancia * 80) b_utm = utils.offset(b2, ab_course - 90, distancia * 80) a2, b2 = utils.extend(a_utm, b_utm) AB = LineString([a2, b2]) contorno = Polygon(contorno_points) eroded = contorno.buffer(-distancia, resolution=16, join_style=1) line = AB.intersection(eroded) for x in range(1, 200): ab_1 = AB.parallel_offset(x * distancia, conf_3) line = ab_1.intersection(eroded) if (line.geom_type == "LineString"): if (len(line.coords) > 1): p1 = 1 p2 = conf_2 if x % 2 == 0: p1 = 0 p2 = -conf_2 centro = utils.offset(utils.toCoord(line.coords[p1]), ab_course + conf_1, distancia / 2) radius = distancia / 2 start_angle, end_angle = 90 - ab_course - 90, 90 - ab_course + 90 # In degrees if x % 2 == 0: start_angle, end_angle = 90 - ab_course + 90, 90 - ab_course - 90 numsegments = 200 theta = np.radians( np.linspace(start_angle, end_angle, numsegments)) x = centro.x + (radius * np.cos(theta)) * p2 y = centro.y + (radius * np.sin(theta)) * p2 arc = LineString(np.column_stack([x, y])) for c in arc.coords: path.append(Point(c)) final = LineString(path) path2 = [] for x in range(0, int(final.length / 2)): p = final.interpolate(x * 2) path2.append(p) return path2
def build_baseline_offset(baseline, offset=50): """ build a simple polygon of width $offset around the provided baseline, 75% over the baseline and 25% below. """ try: line = LineString(baseline) up_offset = line.parallel_offset(offset * 0.75, "right", join_style=2) bot_offset = line.parallel_offset(offset * 0.25, "left", join_style=2) except: #--- TODO: check if this baselines can be saved return False, None if (up_offset.type != "LineString" or up_offset.is_empty == True or bot_offset.type != "LineString" or bot_offset.is_empty == True): return False, None else: up_offset = np.array(up_offset.coords).astype(np.int) bot_offset = np.array(bot_offset.coords).astype(np.int) return True, np.vstack((up_offset, bot_offset))
def parallel_offset_wrapper(line_string: LineString, distance, side): offseted = line_string.parallel_offset(distance, side) if side == "right": offseted = LineString(reversed(offseted.coords)) z = line_string.coords[0][2] coords_3d = [(c[0], c[1], z) for c in offseted.coords] return LineString(coords_3d)
def plot_arrow(ax, ob, color=GRAY, scale_factor=1.0, offset=0.00, offset_side='right', index=None, center_text=True, fontsize=10, **kwargs): ls_ = scale(ob, xfact=scale_factor, yfact=scale_factor) ls_ = ls_.parallel_offset(offset, offset_side) if offset_side == 'right': ls_ = LineString(list(reversed(ls_.coords))) x, y = ls_.xy ax.arrow(x[0], y[0], x[1] - x[0], y[1]-y[0], color=color, zorder=1, **kwargs) if index is not None: # Get angle of this edge v0 = np.array([1, 0]) v1 = np.array([x[1] - x[0], y[1] - y[0]]) v0_ = v0 / np.linalg.norm(v0) v1_ = v1 / np.linalg.norm(v1) deg = get360Angle(v0_, v1_) deg_rot = deg # print("Index: {}; Degree: {}".format(index, deg)) offset_ = offset * 2 x_shift = 0 y_shift = 0 if deg > 0 and deg < 90: offset_ = offset * 4 elif deg >= 90 and deg < 180: deg_rot = deg - 180 offset_ = offset * 6 elif deg == 180: deg_rot = deg - 180 offset_ = offset * 6 elif deg > 180 and deg < 270: deg_rot = deg - 180 elif deg >= 270 and deg < 360: deg_rot = deg - 360 if deg == 180 or deg == 0: x_shift = -0.25 elif deg == 90 or deg == 270: y_shift = -0.20 x_shift = -0.05 elif deg > 90 and deg < 315: x_shift = -.1 y_shift = -.2 elif deg > 42 and deg <= 45 or (deg == 315.0): x_shift = -0.2 y_shift = -0.2 # print(ls_.centroid) # print("Index; {}; DegRot: {}; x_shift: {}; y_shift: {}".format(index, deg_rot, x_shift, y_shift)) # print("Offset: " , offset_) ls_ = ls_.parallel_offset(offset_, 'left') center = ls_.centroid # print(center, index) ax.text(center.x + x_shift, center.y + y_shift, str(index), rotation=deg_rot, fontsize=fontsize)
def create_subrooms(areas_gdf, rooms_gdf): """In case of overlapping rooms, create subrooms. Args: areas_gdf (gpd.GeoDataFrame): Geodataframe. rooms_gdf (gpd.GeoDataFrame): Geodataframe. """ areas_gdf = areas_gdf.copy() areas_gdf = areas_gdf.sort_values("floor_index") indices_occuring_multiple_times = (areas_gdf["polygon_index"].value_counts( )[areas_gdf["polygon_index"].value_counts() > 1].index.values) if len(indices_occuring_multiple_times) > 0: subset = areas_gdf.loc[areas_gdf["polygon_index"].isin( indices_occuring_multiple_times)].copy() for ind, grp in subset.groupby(["polygon_index"]): temp = rooms_gdf.loc[grp["floor_index"].values].copy().head(2) # Todo make it handle n number of locs using voronoi. temp.geometry = temp.centroid line_between = LineString(list(temp.geometry.values)) if line_between.length == 0: continue p_1 = line_between.parallel_offset(200, "left").centroid p_2 = line_between.parallel_offset(200, "right").centroid orthogonal_line_between = LineString([p_1, p_2]) res = (gpd.GeoDataFrame(geometry=[ ops.split(grp.geometry.values[0], orthogonal_line_between) ]).explode().reset_index(drop=True)) matching_gdf = (gpd.sjoin(res, temp).rename(columns={ "index_right": "floor_index" }).sort_values("floor_index")) areas_gdf.loc[areas_gdf["floor_index"].isin(temp.index), "geometry"] = matching_gdf.geometry.values areas_gdf["area_size"] = areas_gdf.geometry.area return areas_gdf
def drawTrack(centerline, width = .75): # draws the track BLUE = '#0000FF' BLACK = '#000000' YELLOW = '#FFFF00' WHITE = '#000000' track = LineString(centerline) #track_bounds = track.bounds #ax_range = [int(track_bounds[0] - 1.0), int(track_bounds[2] + 1.0)] #ay_range = [int(track_bounds[1] - 1.0), int(track_bounds[3] + 1.0)] def plot_coords(ax, x, y, color='#999999', zorder=1): ax.plot(x, y, 'o', color=color, zorder=zorder) def plot_line(ax, ob, color='#0000FF', linestyle='-'): parts = hasattr(ob, 'geoms') and ob or [ob] for part in parts: x, y = part.xy ax.plot(x, y, color=color, linewidth=3, solid_capstyle='round', zorder=1, linestyle=linestyle) ### Plot the track # define the figure fig = pyplot.figure(1, figsize= [25,20], dpi=90) ax = fig.add_subplot(111) plot_line(ax, track, BLACK, '--') #x, y = list(track.coords)[0] #plot_coords(ax, x, y) offset_outer = track.parallel_offset(width, 'left', join_style=1) plot_line(ax, offset_outer, color=BLACK) offset_inner = track.parallel_offset(width, 'right', join_style=1) plot_line(ax, offset_inner, color=BLACK) ax.set_aspect('equal') ax.grid(True, which='both') pyplot.show() return 1
def exteriorRectangle(p0, p1, minWidth): segment = LineString([p0, p1]) if segment.length > posDelta: exterior_offset = segment.parallel_offset(minWidth, 'left') exteriorRect = [p0, p1] toAdd = list(exterior_offset.coords) exteriorRect.extend(toAdd) if len(interiorRect) < 3: logger.error("Even worse, got to what should be a failure!") logger.error(str(segment.length)) logger.error("ToAdd " + str(toAdd)) logger.error("InteriorRect: " + str(exteriorRect)) else: return Polygon(exteriorRect)
def _cont_to_polys(self, cont_lats, cont_lons, cont_val): """ Take the lat/lon contours, split them into their different segments, and create polygons out of them. Contours that stretch from border to border will end up covering large sections of the country. That's okay; we'll take care of that later. """ polys = {} start_idx = 0 splits = [] while True: try: split_idx = cont_lats[start_idx:].index(99.99) splits.append(start_idx + split_idx) start_idx += split_idx + 1 except ValueError: break splits = [ -1 ] + splits + [ len(cont_lats) + 1 ] poly_lats = [ cont_lats[splits[i] + 1:splits[i + 1]] for i in xrange(len(splits) - 1) ] poly_lons = [ cont_lons[splits[i] + 1:splits[i + 1]] for i in xrange(len(splits) - 1) ] # Intersect with the US boundary shape file. for plat, plon in zip(poly_lats, poly_lons): cont = LineString(zip(plon, plat)) if plat[0] != plat[-1] or plon[0] != plon[-1]: # If the line is not a closed contour, then it intersects with the edge of the US. Extend # the ends a little bit to make sure it's outside the edge. dln = np.diff(plon) dlt = np.diff(plat) pre = [ (plon[0] - 0.03 * dln[0], plat[0] - 0.03 * dlt[0]) ] post = [ (plon[-1] + 0.03 * dln[-1], plat[-1] + 0.03 * dlt[-1]) ] cont.coords = pre + list(cont.coords) + post # polygonize() will split the country into two parts: one inside the outlook and one outside. # Construct test_ln that is to the right of (inside) the contour and keep only the polygon # that contains the line test_ln = cont.parallel_offset(0.05, 'right') polys[cont] = [] for poly in polygonize(self._conus.boundary.union(cont)): if (poly.crosses(test_ln) or poly.contains(test_ln)) and self._conus.contains(poly.buffer(-0.01)): polys[cont].append(poly) return polys
def _calculate_parallel_coords(offset: float, line_width: float) \ -> Optional[List[Tuple[float, float, float, float]]]: original_line = LineString(zip(new_x_vals, new_y_vals)) try: offset_line = original_line.parallel_offset(offset) coords = offset_line.coords.xy except (NotImplementedError, Exception): # FIXME Where is TopologyException _logger.exception( "Creating an offset line for lane markings failed") return None # NOTE The parallel LineString may have a different number of points than initially given num_coords = len(coords[0]) z_vals = repeat(0.01, num_coords) marking_widths = repeat(line_width, num_coords) return list( zip(coords[0], coords[1], z_vals, marking_widths))
def generate_intersections(poly, width): "Subdivide a filed into coverage lines." starting_breakdown = poly.bounds[0:2] line = LineString([ starting_breakdown, (starting_breakdown[0], starting_breakdown[1] + poly.bounds[3] - poly.bounds[1]) ]) # numCoords = len(line.coords) - 1 # for i in range(0,numCoords): # point1 = line.coords[i] # point2 = line.coords[i+1] # print "Index " + str(i) + str(point1) + str(point2) # print("----------line: %d",poly.bounds[3] - poly.bounds[1]) # ############ # ax, _ = make_axis() # plot_line(line, ax) # ax.axvline(x=0, color='black') # ax.axhline(y=0, color='black') # import pylab; pylab.show() # ####################### try: bounded_line = poly.intersection(line) except TopologicalError as e: error("Problem looking for intersection.", exc_info=1) return lines = [bounded_line] iterations = int(math.ceil((poly.bounds[2] - poly.bounds[0]) / width)) + 1 for x in range(1, iterations): bounded_line = line.parallel_offset(x * width, 'right') if poly.intersects(bounded_line): try: bounded_line = poly.intersection(bounded_line) except TopologicalError as e: error("Problem looking for intersection.", exc_info=1) continue lines.append(bounded_line) # print("lines append count %d",bounded_line.type) # print "+++++++++++++++++++++",bounded_line return lines
def offset_linestring(zone_latlon: LatLon, string: LineString, offset_distance: float, offset_multiplier: int) -> List[Node]: offsetted_string = string.parallel_offset( (offset_multiplier + 1) * offset_distance, side='left', resolution=10) nodes = [] if isinstance(offsetted_string, LineString): for north, east in list(offsetted_string.coords): utm = UTM(north, east) nodes.append(Node(utm.convert_to_latlon(zone_latlon))) else: raise Exception( f"Error while offsetting linestring. The result geometry is not a LineString." ) return nodes
def sgm(x_t, y_t): sgm_length = 20000.0 sgm_width = 30000.0 zipxy = zip(x_t, y_t) line_t = LineString(zipxy) line_t_length = line_t.length sgm_nr = int(line_t_length / sgm_length) sgm_l = [] sgm_l_left = [] for sgm_i in range(0, sgm_nr, 1): t_startp = sgm_i * sgm_length t_endp = (sgm_i + 1) * sgm_length sgm_l_i_start = line_t.interpolate(t_startp) sgm_l_i_end = line_t.interpolate(t_endp) sgm_l_i = LineString([sgm_l_i_start, sgm_l_i_end]) sgm_l_left_i = sgm_l_i.parallel_offset(sgm_width + 1000.0, 'left', join_style=1) sgm_l.append(sgm_l_i) sgm_l_left.append(sgm_l_left_i) return sgm_nr, sgm_l, sgm_l_left
def test_parallel_offset_linestring(self): line1 = LineString([(0, 0), (10, 0)]) left = line1.parallel_offset(5, 'left') self.assertEqual(left, LineString([(0, 5), (10, 5)])) right = line1.parallel_offset(5, 'right') self.assertEqual(right, LineString([(10, -5), (0, -5)])) right = line1.parallel_offset(-5, 'left') self.assertEqual(right, LineString([(10, -5), (0, -5)])) left = line1.parallel_offset(-5, 'right') self.assertEqual(left, LineString([(0, 5), (10, 5)])) # by default, parallel_offset is right-handed self.assertEqual(line1.parallel_offset(5), right) line2 = LineString([(0, 0), (5, 0), (5, -5)]) self.assertEqual(line2.parallel_offset(2, 'left', resolution=1), LineString([(0, 2), (5, 2), (7, 0), (7, -5)])) self.assertEqual( line2.parallel_offset(2, 'left', join_style=2, resolution=1), LineString([(0, 2), (7, 2), (7, -5)]))
def test_parallel_offset_linestring(self): line1 = LineString([(0, 0), (10, 0)]) left = line1.parallel_offset(5, 'left') self.assertEqual(left, LineString([(0, 5), (10, 5)])) right = line1.parallel_offset(5, 'right') self.assertEqual(right, LineString([(10, -5), (0, -5)])) right = line1.parallel_offset(-5, 'left') self.assertEqual(right, LineString([(10, -5), (0, -5)])) left = line1.parallel_offset(-5, 'right') self.assertEqual(left, LineString([(0, 5), (10, 5)])) # by default, parallel_offset is right-handed self.assertEqual(line1.parallel_offset(5), right) line2 = LineString([(0, 0), (5, 0), (5, -5)]) self.assertEqual(line2.parallel_offset(2, 'left', resolution=1), LineString([(0, 2), (5, 2), (7, 0), (7, -5)])) self.assertEqual(line2.parallel_offset(2, 'left', join_style=2, resolution=1), LineString([(0, 2), (7, 2), (7, -5)]))
def generate_intersections(poly, width): "Subdivide a filed into coverage lines." starting_breakdown = poly.bounds[0:2] line = LineString([starting_breakdown, (starting_breakdown[0], starting_breakdown[1] + poly.bounds[3] - poly.bounds[1])]) try: bounded_line = poly.intersection(line) except TopologicalError as e: error("Problem looking for intersection.", exc_info=1) return lines = [bounded_line] iterations = int(math.ceil((poly.bounds[2] - poly.bounds[0]) / width)) + 1 for x in range(1, iterations): bounded_line = line.parallel_offset(x * width, 'right') if poly.intersects(bounded_line): try: bounded_line = poly.intersection(bounded_line) except TopologicalError as e: error("Problem looking for intersection.", exc_info=1) continue lines.append(bounded_line) return lines
ax.set_aspect(1) line = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) line_bounds = line.bounds ax_range = [int(line_bounds[0] - 1.0), int(line_bounds[2] + 1.0)] ay_range = [int(line_bounds[1] - 1.0), int(line_bounds[3] + 1.0)] fig = pyplot.figure(1, figsize=(SIZE[0], 2 * SIZE[1]), dpi=90) # 1 ax = fig.add_subplot(221) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=1) plot_line(ax, offset, color=BLUE) ax.set_title('a) left, round') set_limits(ax, ax_range, ay_range) #2 ax = fig.add_subplot(222) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=2) plot_line(ax, offset, color=BLUE)
def run(self): # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result == 1: layers = iface.legendInterface().layers() if len(layers) != 0: #Check that there is a selected layer layer = iface.mapCanvas().currentLayer() if layer.type() == 0: #check selected layer is a vector layer if layer.geometryType() == 1: #check to see if selected layer is a linestring geometry if len(layer.selectedFeatures()) != 0: #Dir = float(self.dlg.ui.radLeft.isChecked() layers = iface.legendInterface().layers() Lexists = "false" #check to see if the virtual layer already exists for layer in layers: if layer.name() == "Parallel_Offset": Lexists = "true" vl = layer #if it doesn't exist create it if Lexists == "false": vl = QgsVectorLayer("Linestring?field=offset:integer&field=direction:string(10)&field=method:string(10)","Parallel_Offset","memory") #vl = QgsVectorLayer("Linestring", "Parallel_Offset", "memory") pr = vl.dataProvider() vl.startEditing() #pr.addAttributes( [ QgsField("offset", Double), QgsField("direction", String), QgsField("method", String) ] ) else: pr = vl.dataProvider() vl.startEditing() #get the direction Dir = 'right' if self.dlg.ui.radLeft.isChecked(): Dir = 'left' #get the method if self.dlg.ui.radRound.isChecked(): js = 1 if self.dlg.ui.radMitre.isChecked(): js = 2 if self.dlg.ui.radBevel.isChecked(): js = 3 #get the offset loffset = float(self.dlg.ui.txtDistance.text()) #create the new feature from the selection for feature in layer.selectedFeatures(): geom = feature.geometry() h = geom.asPolyline() line = LineString(h) nline = line.parallel_offset(loffset, Dir,resolution=16,join_style=js,mitre_limit=10.0) #turn nline back into a polyline and add it to the map as a new layer. fet = QgsFeature() fet.setGeometry(QgsGeometry.fromWkt(str(nline))) fet.setAttributes( [loffset,Dir ,js] ) pr.addFeatures( [ fet ] ) vl.commitChanges() QgsMapLayerRegistry.instance().addMapLayer(vl) mc=self.iface.mapCanvas() mc.refresh()
def draw_text_on_line( self, coords, text, color=(0, 0, 0), font_size=10, font_family='Tahoma', font_style=cairo.FONT_SLANT_NORMAL, font_weight=cairo.FONT_WEIGHT_NORMAL, text_halo_width=1, text_halo_color=(1, 1, 1), text_halo_line_cap=cairo.LINE_CAP_ROUND, text_halo_line_join=cairo.LINE_JOIN_ROUND, text_halo_line_dash=None, text_transform=None, ): ''' Draws text on a line. Tries to find a position with the least change in gradient and which is closest to the middle of the line. :param coords: iterable containing all coordinates as ``(lon, lat)`` :param text: text to be drawn :param color: ``(r, g, b[, a])`` :param font_size: font-size in unit (pixel/point) :param font_family: font name :param font_style: ``cairo.FONT_SLANT_NORMAL``, ``cairo.FONT_SLANT_ITALIC`` or ``cairo.FONT_SLANT_OBLIQUE`` :param font_weight: ``cairo.FONT_WEIGHT_NORMAL`` or ``cairo.FONT_WEIGHT_BOLD`` :param text_halo_width: border-width in unit (pixel/point) :param text_halo_color: ``(r, g, b[, a])`` :param text_halo_line_cap: one of :const:`cairo.LINE_CAP_*` :param text_halo_line_join: one of :const:`cairo.LINE_JOIN_*` :param text_halo_line_dash: list/tuple used by :meth:`cairo.Context.set_dash` :param text_transform: one of ``'lowercase'``, ``'uppercase'`` or ``'capitalize'`` ''' text = text.strip() if not text: return coords = map(lambda c: self.transform_coords(*c), coords) self.context.select_font_face(font_family, font_style, font_weight) self.context.set_font_size(font_size) text = utils.text_transform(text, text_transform) width, height = self.context.text_extents(text)[2:4] font_ascent, font_descent = self.context.font_extents()[0:2] self.context.new_path() #: make sure line does not intersect other conflict objects line = LineString(coords) line = self.map_area.intersection(line) line = line.difference(self.map_area.exterior.buffer(height)) line = line.difference(self.conflict_area) #: check whether line is empty or is split into several different parts if line.geom_type == 'GeometryCollection': return elif line.geom_type == 'MultiLineString': longest = None min_len = width * 1.2 for seg in line.geoms: seg_len = seg.length if seg_len > min_len: longest = seg min_len = seg_len if longest is None: return line = longest coords = tuple(line.coords) seg = utils.linestring_text_optimal_segment(coords, width) # line has either to much change in gradients or is too short if seg is None: return #: crop optimal segment of linestring start, end = seg coords = coords[start:end+1] #: make sure text is rendered from left to right if coords[-1][0] < coords[0][0]: coords = tuple(reversed(coords)) # translate linestring so text is rendered vertically in the middle line = LineString(tuple(coords)) offset = font_ascent / 2. - font_descent line = line.parallel_offset(offset, 'left', resolution=3) # make sure text is rendered centered on line start_len = (line.length - width) / 2. char_coords = None chars = utils.generate_char_geoms(self.context, text) #: draw all character paths for char in utils.iter_chars_on_line(chars, line, start_len): for geom in char.geoms: char_coords = iter(geom.exterior.coords) self.context.move_to(*char_coords.next()) for lon, lat in char_coords: self.context.line_to(lon, lat) self.context.close_path() #: only add line to reserved area if text was drawn if char_coords is not None: covered = line.buffer(height) self.conflict_union(covered) #: draw border around characters self.context.set_line_cap(cairo.LINE_CAP_ROUND) self.context.set_source_rgba(*text_halo_color) self.context.set_line_width(2 * text_halo_width) self.context.set_line_cap(text_halo_line_cap) self.context.set_line_join(text_halo_line_join) self.context.set_dash(text_halo_line_dash or tuple()) self.context.stroke_preserve() #: fill actual text self.context.set_source_rgba(*color) self.context.fill()
ax.set_aspect(1) line = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) line_bounds = line.bounds ax_range = [int(line_bounds[0] - 1.0), int(line_bounds[2] + 1.0)] ay_range = [int(line_bounds[1] - 1.0), int(line_bounds[3] + 1.0)] fig = pyplot.figure(1, figsize=(SIZE[0], 2 * SIZE[1]), dpi=90) # 1 ax = fig.add_subplot(221) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=2, mitre_limit=0.1) plot_line(ax, offset, color=BLUE) ax.set_title('a) left, limit=0.1') set_limits(ax, ax_range, ay_range) #2 ax = fig.add_subplot(222) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=2, mitre_limit=10.0) plot_line(ax, offset, color=BLUE)
xPoints, yPoints = zip(*PolylineCodec(). decode(str(polylines[i][POLYLINE].values()[0]))) abcisses += xPoints images += yPoints resultPoints = list(imap(list, izip(abcisses, images))) reducedList = [] #Reduce the number of points to optimize further computation. for i in range (0, len(resultPoints), 100): reducedList.append(resultPoints[i]) #Convert the line into a LineString to use the parallel_offset function. line = LineString(reducedList) #Build the left Buffer. leftBuffer = line.parallel_offset(BUFFER_OFFSET,'left') xLeft, yLeft = leftBuffer.xy xLeftPoints = xLeft.tolist() yLeftPoints = yLeft.tolist() bufferLeftPoints = list(imap(list, izip(xLeftPoints, yLeftPoints))) #Build the right Buffer. rightBuffer = line.parallel_offset(BUFFER_OFFSET,'right') xRight, yRight = rightBuffer.xy xRightPoints = xRight.tolist() yRightPoints = yRight.tolist() bufferRightPoints = list(imap(list, izip(xRightPoints, yRightPoints))) #Create a map. map = folium.Map()