def test_make_compound_path_stops(): zero = [0, 0] paths = 3*[Path([zero, zero], [Path.MOVETO, Path.STOP])] compound_path = Path.make_compound_path(*paths) # the choice to not preserve the terminal STOP is arbitrary, but # documented, so we test that it is in fact respected here assert np.sum(compound_path.codes == Path.STOP) == 0
def main(): imagery = OSM() fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection=imagery.crs) ax.set_extent([-0.14, -0.1, 51.495, 51.515], ccrs.PlateCarree()) # Construct concentric circles and a rectangle, # suitable for a London Underground logo. theta = np.linspace(0, 2 * np.pi, 100) circle_verts = np.vstack([np.sin(theta), np.cos(theta)]).T concentric_circle = Path.make_compound_path(Path(circle_verts[::-1]), Path(circle_verts * 0.6)) rectangle = Path([[-1.1, -0.2], [1, -0.2], [1, 0.3], [-1.1, 0.3]]) # Add the imagery to the map. ax.add_image(imagery, 14) # Plot the locations twice, first with the red concentric circles, # then with the blue rectangle. xs, ys = tube_locations().T ax.plot(xs, ys, transform=ccrs.OSGB(), marker=concentric_circle, color='red', markersize=9, linestyle='') ax.plot(xs, ys, transform=ccrs.OSGB(), marker=rectangle, color='blue', markersize=11, linestyle='') ax.set_title('London underground locations') plt.show()
def main(): imagery = OSM() fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection=imagery.crs) ax.set_extent([-0.14, -0.1, 51.495, 51.515], ccrs.PlateCarree()) # Construct concentric circles and a rectangle, # suitable for a London Underground logo. theta = np.linspace(0, 2 * np.pi, 100) circle_verts = np.vstack([np.sin(theta), np.cos(theta)]).T concentric_circle = Path.make_compound_path(Path(circle_verts[::-1]), Path(circle_verts * 0.6)) rectangle = Path([[-1.1, -0.2], [1, -0.2], [1, 0.3], [-1.1, 0.3]]) # Add the imagery to the map. ax.add_image(imagery, 14) # Plot the locations twice, first with the red concentric circles, # then with the blue rectangle. xs, ys = tube_locations().T ax.plot(xs, ys, transform=ccrs.OSGB(), marker=concentric_circle, color='red', markersize=9, linestyle='') ax.plot(xs, ys, transform=ccrs.OSGB(), marker=rectangle, color='blue', markersize=11, linestyle='') ax.set_title('London underground locations') plt.show()
def getPathFromShp(shpfile, region): try: sf = shapefile.Reader(shpfile) vertices = [] # 这块是已经修改的地方 codes = [] # 这块是已经修改的地方 paths = [] for shape_rec in sf.shapeRecords(): # if shape_rec.record[3] == region: # 这里需要找到和region匹配的唯一标识符,record[]中必有一项是对应的。 if region == [100000 ] or shape_rec.record[4] in region: # 这块是已经修改的地方 pts = shape_rec.shape.points prt = list(shape_rec.shape.parts) + [len(pts)] for i in range(len(prt) - 1): for j in range(prt[i], prt[i + 1]): vertices.append((pts[j][0], pts[j][1])) codes += [Path.MOVETO] codes += [Path.LINETO] * (prt[i + 1] - prt[i] - 2) codes += [Path.CLOSEPOLY] path = Path(vertices, codes) paths.append(path) if paths: path = Path.make_compound_path(*paths) else: path = None return path except Exception as err: print(err) return None
def transform_path(self, path): vertices = path.vertices # Intelligent interpolation needed # ipath = path.interpolated(self._resolution) ipath = path ipath = path.interpolated(10) # ipath = path.interpolated(3050) verts = self.transform_no_mod(ipath.vertices) codes = ipath.codes # print verts.shape # print 'transforming lon range:', np.min(verts[:, 0]), np.max(verts[:, 0]) # if np.isnan(np.max(verts[:, 0])): # print 'Got nan: ', path, verts paths = [] paths.append(Path(verts, codes)) # # Have any of the points wrapped? If so, pick up the pen, and start from -360 # if any(ipath.vertices[:, 0] > np.pi): # v = ipath.vertices.copy() # print 'splitting -:' # v[:, 0] -= 2 * np.pi # print v # v = self.transform_no_mod(v) # paths.append(Path(v)) # # # Have any of the points wrapped? If so, pick up the pen, and start from +360 # if any(ipath.vertices[:, 0] < -np.pi): # v = ipath.vertices.copy() # v[:, 0] += 2 * np.pi # print 'splitting +:' # v = self.transform_no_mod(v) # paths.append(Path(v)) s_pole = np.deg2rad(np.array([0, -89.9999])) if path.contains_point(s_pole): print 'POLE ALERT!!!', path path = Path(verts[:-31]) paths = [path] if len(paths) == 1: path = paths[0] else: for path in paths: if path.codes is not None: if path.codes[0] == Path.MOVETO and all(path.codes[1:] == Path.LINETO): path.codes = None else: # This is a bit strict... but a condition of make_compound_path raise ValueError('Cannot draw discontiguous polygons.') # print path.codes path = Path.make_compound_path(*paths) return path
def _plot(self, ax, legend, alpha, ec='#222222'): groups = self.groups('shape') for key in self.classes.index: group = groups.get_group(key) paths = [] for g in group['shape']: paths.append(PolygonPath(g)) patch = PathPatch(Path.make_compound_path(*paths), fc=legend[key], ec=ec, alpha=alpha, zorder=2, label='{} ({})'.format(key, len(group))) ax.add_patch(patch) ax.margins(0.025, 0.025) ax.get_yaxis().set_tick_params(which='both', direction='out') ax.get_xaxis().set_tick_params(which='both', direction='out') return ax
def shape_to_patch(shape, **kwargs): if isinstance(shape, Polygon): return patches.Polygon(list(shape.exterior.coords)[1:], **kwargs) if isinstance(shape, MultiPolygon): paths = [polygon_path(list(o.exterior.coords)[1:]) for o in shape.geoms] for p in paths: print("path", p) path = Path.make_compound_path(*paths) return PathPatch(path, **kwargs) if isinstance(shape, LineString): path_data = [(Path.MOVETO, shape.coords[0])] for coord in shape.coords[1:]: path_data.append((Path.LINETO, coord)) codes, verts = zip(*path_data) path = Path(verts, codes, closed=False) return PathPatch(path, **kwargs)
def _PolygonPatch(polygon, **kwargs): """Constructs a matplotlib patch from a Polygon geometry The `kwargs` are those supported by the matplotlib.patches.PathPatch class constructor. Returns an instance of matplotlib.patches.PathPatch. Example (using Shapely Point and a matplotlib axes):: b = shapely.geometry.Point(0, 0).buffer(1.0) patch = _PolygonPatch(b, fc='blue', ec='blue', alpha=0.5) ax.add_patch(patch) GeoPandas originally relied on the descartes package by Sean Gillies (BSD license, https://pypi.org/project/descartes) for PolygonPatch, but this dependency was removed in favor of the below matplotlib code. """ from matplotlib.patches import PathPatch from matplotlib.path import Path path = Path.make_compound_path( Path(np.asarray(polygon.exterior.coords)[:, :2]), *[Path(np.asarray(ring.coords)[:, :2]) for ring in polygon.interiors]) return PathPatch(path, **kwargs)
def test_make_compound_path_empty(): # We should be able to make a compound path with no arguments. # This makes it easier to write generic path based code. r = Path.make_compound_path() assert r.vertices.shape == (0, 2)
def test_make_compound_path_empty(): # We should be able to make a compound path with no arguments. # This makes it easier to write generic path based code. r = Path.make_compound_path() assert r.vertices.shape == (0, 2)
def pcolor_mask_geoms(cube, geoms, transform): path = Path.make_compound_path(*geos_to_path(geoms)) im = iplt.pcolor(cube) im.set_clip_path(path, transform=transform)
ax.yaxis.set_major_formatter(lat_formatter) #刻度字体大小 ax.tick_params(labelsize=15) contourf = ax.contourf(lon,lat,u1_avg,lev,cmap='Blues',transform=proj,extend='both') countries = shp.records() cn_multipoly, = [country.geometry for country in countries if country.attributes['CNTRY_NAME'] == 'China'] # 选择地图属性下'NAME'属性里名字是'China'的一条多边形 paths = [] for i in range(len(cn_multipoly)): cn_geom, = geos_to_path(cn_multipoly.geoms[i]) paths.append(cn_geom) path = Path.make_compound_path(*paths) for collection in contourf.collections: collection.set_clip_path(path, proj._as_mpl_transform(ax)) # 白化刻度 # contour = ax.contour(lon,lat,u1_avg,lev,cmap='Blues',transform=proj,extend='both') # cn_label = plt.clabel(contour,inline=1,fontsize=10,fmt="%.fr") # if cn_label: # clip_map_shapely = Polygon(path.vertices) # for text_object in cn_label: # if not clip_map_shapely.contains(Point(text_object.get_position())): # text_object.set_visible(False) ax.add_geometries(cn_multipoly, crs=proj, edgecolor='black', linewidths=1, facecolor='none', zorder=10, alpha=0.8) #ax.gridlines(color="black", linestyle="--")
def compress_points(points): bi, bj, bx, by = get_boundary_intersections(points) f = bi == bj alone_points = points[bi[f]] alone_paths = [Path.circle(xy, 0.5) for xy in alone_points] edge_lists = [[] for i in range(len(points))] n = 0 for i, j, x, y in zip(bi, bj, bx, by): if i != j: edge_lists[j].append((i, x, y)) n += 1 print("%s points in total: %s edges, %s alone points" % (len(points), n, len(alone_points))) def patan2(dy, dx): """ Return pseudo-arctangent of dy/dx such that patan2(y1, x1) < patan2(y2, x2) if and only if atan2(y1, x1) < atan2(y2, x2) """ if dy > 0 and dx > 0: return (0, dy - dx) elif dy > 0 and dx <= 0: return (1, -dy - dx) elif dy <= 0 and dx > 0: return (2, dx - dy) else: return (3, dx + dy) def shift(u, v): if v < u: return (v[0] + 4, v[1]) else: return v def pop_next(i, ox, oy): def local_patan2(y, x): return patan2(y - points[i, 1], x - points[i, 0]) u = local_patan2(oy, ox) j = min(range(len(edge_lists[i])), key=lambda j: shift(u, local_patan2(edge_lists[i][j][2], edge_lists[i][j][1]))) return edge_lists[i].pop(j) paths = [] # print("<path fill=\"black\" fillrule=\"wind\">") while n > 0: assert sum(len(e) for e in edge_lists) == n i = 0 while not edge_lists[i]: i += 1 start = i j, ox, oy = edge_lists[i].pop(0) startx, starty = ox, oy ux, uy = ox, oy # path = ['%s %s m' % (startx, starty)] path_vert_lists = [[[startx, starty]]] path_code_lists = [[Path.MOVETO]] n -= 1 while j != start: i = j j, vx, vy = pop_next(i, ux, uy) n -= 1 # path.append( # '%s 0 0 %s %s %s %s %s a' % # (R, R, points[i, 0], points[i, 1], ox, oy)) ox, oy = points[i] theta1 = np.arctan2(uy - oy, ux - ox) theta2 = np.arctan2(vy - oy, vx - ox) a = Path.arc(theta1 * 180 / np.pi, theta2 * 180 / np.pi) a = a.transformed(Affine2D().scale(0.5).translate(ox, oy)) path_vert_lists.append(a._vertices[1:]) path_code_lists.append(a._codes[1:]) ux, uy = vx, vy # path.append( # '%s 0 0 %s %s %s %s %s a' % # (R, R, points[j, 0], points[j, 1], startx, starty)) ox, oy = points[j] theta1 = np.arctan2(uy - oy, ux - ox) theta2 = np.arctan2(starty - oy, startx - ox) a = Path.arc(theta1 * 180 / np.pi, theta2 * 180 / np.pi) a = a.transformed(Affine2D().scale(0.5).translate(ox, oy)) path_vert_lists.append(a._vertices[1:]) path_code_lists.append(a._codes[1:]) # print('\n'.join(path)) paths.append( Path(np.concatenate(path_vert_lists), np.concatenate(path_code_lists).astype(Path.code_type))) # print("</path>") return Path.make_compound_path(*(alone_paths + paths))
def plot(self): if self.filetype == "geotiff": f, fname = tempfile.mkstemp() os.close(f) driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create( fname, self.latitude.shape[1], self.longitude.shape[0], 1, gdal.GDT_Float64, ) x = np.array([self.longitude[0, 0], self.longitude[-1, -1]]) y = np.array([self.latitude[0, 0], self.latitude[-1, -1]]) outRasterSRS = osr.SpatialReference() pts = self.plot_projection.transform_points( self.pc_projection, x, y) x = pts[:, 0] y = pts[:, 1] outRasterSRS.ImportFromProj4(self.plot_projection.proj4_init) pixelWidth = (x[-1] - x[0]) / self.longitude.shape[0] pixelHeight = (y[-1] - y[0]) / self.latitude.shape[0] outRaster.SetGeoTransform( (x[0], pixelWidth, 0, y[0], 0, pixelHeight)) outband = outRaster.GetRasterBand(1) d = self.data.astype(np.float64) ndv = d.fill_value outband.WriteArray(d.filled(ndv)) outband.SetNoDataValue(ndv) outRaster.SetProjection(outRasterSRS.ExportToWkt()) outband.FlushCache() outRaster = None with open(fname, "r", encoding="latin-1") as f: buf = f.read() os.remove(fname) return (buf, self.mime, self.filename.replace(".geotiff", ".tif")) # Figure size figuresize = list(map(float, self.size.split("x"))) fig, map_plot = basemap.load_map( self.plot_projection, self.plot_extent, figuresize, self.dpi, self.plot_res, ) ax = plt.gca() if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin, vmax = utils.normalize_scale( self.data, self.dataset_config.variable[f"{self.variables[0]}"]) c = map_plot.imshow( self.data, vmin=vmin, vmax=vmax, cmap=self.cmap, extent=self.plot_extent, transform=self.plot_projection, origin="lower", zorder=0, ) if len(self.quiver_data) == 2: qx, qy = self.quiver_data qx, qy = self.plot_projection.transform_vectors( self.pc_projection, self.quiver_longitude, self.quiver_latitude, qx, qy) pts = self.plot_projection.transform_points( self.pc_projection, self.quiver_longitude, self.quiver_latitude) x = pts[:, :, 0] y = pts[:, :, 1] qx = np.ma.masked_where(np.ma.getmask(self.quiver_data[0]), qx) qy = np.ma.masked_where(np.ma.getmask(self.quiver_data[1]), qy) if self.quiver["magnitude"] != "length": qx = qx / self.quiver_magnitude qy = qy / self.quiver_magnitude qscale = 50 else: qscale = None if self.quiver["magnitude"] == "color": if (self.quiver["colormap"] is None or self.quiver["colormap"] == "default"): qcmap = colormap.colormaps.get("speed") else: qcmap = colormap.colormaps.get(self.quiver["colormap"]) q = map_plot.quiver( x, y, qx, qy, self.quiver_magnitude, width=0.0035, headaxislength=4, headlength=4, scale=qscale, pivot="mid", cmap=qcmap, transform=self.plot_projection, ) else: q = map_plot.quiver( x, y, qx, qy, width=0.0025, headaxislength=4, headlength=4, scale=qscale, pivot="mid", transform=self.plot_projection, zorder=6, ) if self.quiver["magnitude"] == "length": unit_length = np.mean(self.quiver_magnitude) * 2 unit_length = np.round(unit_length, -int(np.floor(np.log10(unit_length)))) if unit_length >= 1: unit_length = int(unit_length) plt.quiverkey( q, 0.65, 0.01, unit_length, self.quiver_name.title() + " " + str(unit_length) + " " + utils.mathtext(self.quiver_unit), coordinates="figure", labelpos="E", ) if self.show_bathymetry: # Plot bathymetry on top cs = map_plot.contour( self.longitude, self.latitude, self.bathymetry, linewidths=0.5, norm=FuncNorm((lambda x: np.log10(x), lambda x: 10**x), vmin=1, vmax=6000), cmap="Greys", levels=[100, 200, 500, 1000, 2000, 3000, 4000, 5000, 6000], transform=self.pc_projection, zorder=4, ) plt.clabel(cs, fontsize="x-large", fmt="%1.0fm") if self.area and self.show_area: for a in self.area: polys = [] for co in a["polygons"] + a["innerrings"]: coords = np.array(co).transpose() coords_transform = self.plot_projection.transform_points( self.pc_projection, coords[1], coords[0]) mx = coords_transform[:, 0] my = coords_transform[:, 1] map_coords = list(zip(mx, my)) polys.append(Polygon(map_coords)) paths = [] for poly in polys: paths.append(poly.get_path()) path = Path.make_compound_path(*paths) for ec, lw in zip(["w", "k"], [5, 3]): poly = PathPatch( path, fill=None, edgecolor=ec, linewidth=lw, transform=self.plot_projection, zorder=3, ) map_plot.add_patch(poly) if self.names is not None and len(self.names) > 1: for idx, name in enumerate(self.names): pts = self.plot_projection.transform_points( self.pc_projection, self.centroids[idx].x, self.centroids[idx].y) x = pts[:, 0] y = pts[:, 1] plt.annotate( xy=(x, y), s=name, ha="center", va="center", size=12, # weight='bold' ) if len(self.contour_data) > 0: if self.contour_data[0].min() != self.contour_data[0].max(): cmin, cmax = utils.normalize_scale( self.contour_data[0], self.dataset_config.variable[self.contour["variable"]], ) levels = None if (self.contour.get("levels") is not None and self.contour["levels"] != "auto" and self.contour["levels"] != ""): try: levels = list( set([ float(xx) for xx in self.contour["levels"].split(",") if xx.strip() ])) levels.sort() except ValueError: pass if levels is None: levels = np.linspace(cmin, cmax, 5) cmap = self.contour["colormap"] if cmap is not None: cmap = colormap.colormaps.get(cmap) if cmap is None: cmap = colormap.find_colormap(self.contour_name) if not self.contour.get("hatch"): contours = map_plot.contour( self.longitude, self.latitude, self.contour_data[0], linewidths=2, levels=levels, cmap=cmap, transform=self.pc_projection, zorder=5, ) else: hatches = [ "//", "xx", "\\\\", "--", "||", "..", "oo", "**" ] if len(levels) + 1 < len(hatches): hatches = hatches[0:len(levels) + 2] map_plot.contour( self.longitude, self.latitude, self.contour_data[0], linewidths=1, levels=levels, colors="k", transform=self.pc_projection, zorder=5, ) contours = map_plot.contourf( self.longitude, self.latitude, self.contour_data[0], colors=["none"], levels=levels, hatches=hatches, vmin=cmin, vmax=cmax, extend="both", transform=self.pc_projection, zorder=5, ) if self.contour["legend"]: handles, l = contours.legend_elements() labels = [] for i, lab in enumerate(l): if self.contour.get("hatch"): if self.contour_unit == "fraction": if i == 0: labels.append( "$x \\leq {0: .0f}\\%$".format( levels[i] * 100)) elif i == len(levels): labels.append("$x > {0: .0f}\\%$".format( levels[i - 1] * 100)) else: labels.append( "${0:.0f}\\% < x \\leq {1:.0f}\\%$". format(levels[i - 1] * 100, levels[i] * 100)) else: if i == 0: labels.append("$x \\leq %.3g$" % levels[i]) elif i == len(levels): labels.append("$x > %.3g$" % levels[i - 1]) else: labels.append("$%.3g < x \\leq %.3g$" % (levels[i - 1], levels[i])) else: if self.contour_unit == "fraction": labels.append("{0:.0%}".format(levels[i])) else: labels.append( "%.3g %s" % (levels[i], utils.mathtext(self.contour_unit))) ax = plt.gca() if self.contour_unit != "fraction" and not self.contour.get( "hatch"): contour_title = "%s (%s)" % ( self.contour_name, utils.mathtext(self.contour_unit), ) else: contour_title = self.contour_name leg = ax.legend( handles[::-1], labels[::-1], loc="lower left", fontsize="medium", frameon=True, framealpha=0.75, title=contour_title, ) leg.get_title().set_fontsize("medium") if not self.contour.get("hatch"): for legobj in leg.legendHandles: legobj.set_linewidth(3) title = self.plotTitle if self.plotTitle is None or self.plotTitle == "": area_title = "\n".join(wrap(", ".join(self.names), 60)) + "\n" title = "%s %s %s, %s" % ( area_title, self.variable_name.title(), self.depth_label, self.date_formatter(self.timestamp), ) plt.title(title.strip()) axpos = map_plot.get_position() pos_x = axpos.x0 + axpos.width + 0.01 pos_y = axpos.y0 cax = fig.add_axes([pos_x, pos_y, 0.03, axpos.height]) bar = plt.colorbar(c, cax=cax) bar.set_label( "%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit)), fontsize=14, ) if (self.quiver is not None and self.quiver["variable"] != "" and self.quiver["variable"] != "none" and self.quiver["magnitude"] == "color"): pos_x = axpos.x0 pos_y = axpos.y0 - 0.05 bax = fig.add_axes([pos_x, pos_y, axpos.width, 0.03]) qbar = plt.colorbar(q, orientation="horizontal", cax=bax) qbar.set_label( self.quiver_name.title() + " " + utils.mathtext(self.quiver_unit), fontsize=14, ) return super(MapPlotter, self).plot(fig)
def plot_working_area(l_1, l_2, theta_1_min, theta_1_max, theta_2_min, theta_2_max, plot=True): ################################################################ ################ Transform angles to radians ################ ################################################################ theta_1_min = math.radians(theta_1_min) theta_1_max = math.radians(theta_1_max) theta_2_min = math.radians(theta_2_min) theta_2_max = math.radians(theta_2_max) ################################################################ ################ Calculate Working Area ################ ################################################################ wa = l_1 * l_2 * (math.cos(theta_2_min) - math.cos(theta_2_max)) * (theta_1_max - theta_1_min) ################################################################ ################ Setup Graph ################ ################################################################ fig = plt.figure() ax = fig.add_subplot(1, 1, 1) ax.spines['left'].set_position('center') ax.spines['bottom'].set_position('center') ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') ax.autoscale(True, 'both') ################################################################ ################ Common Variables ################ ################################################################ o = [0, 0] ################################################################ ################ Link 2 at minimum ################ ################################################################ start_point = forward_kinematics(l_1, l_2, theta_1_min, theta_2_min, True) end_point = forward_kinematics(l_1, l_2, theta_1_max, theta_2_min, True) radius = math.dist(end_point, o) start_angle = angle(start_point, [1, 0]) end_angle = angle(end_point, [1, 0]) ################################################################ current_path = Path.arc(start_angle, end_angle) new_verts = current_path.deepcopy().vertices for new_vert in new_verts: new_vert[0] = new_vert[0] * radius new_vert[1] = new_vert[1] * radius new_verts = new_verts[:] current_path = Path(new_verts, current_path.deepcopy().codes[:]) paths.append(current_path) patches.append(PathPatch(current_path)) ax.add_patch(patches[0]) ################################################################ ################ Link 2 at maximum ################ ################################################################ end_point = forward_kinematics(l_1, l_2, theta_1_min, theta_2_max, True) start_point = forward_kinematics(l_1, l_2, theta_1_max, theta_2_max, True) radius = math.dist(end_point, o) start_angle = angle_clockwise(start_point, [1, 0]) end_angle = angle_clockwise(end_point, [1, 0]) ################################################################ current_path = Path.arc(start_angle, end_angle) new_verts = current_path.deepcopy().vertices for new_vert in new_verts: new_vert[0] = new_vert[0] * radius new_vert[1] = new_vert[1] * radius * -1 new_verts = new_verts[:] current_path = Path(new_verts, current_path.deepcopy().codes[:]) paths.append(current_path) patches.append(PathPatch(current_path)) ax.add_patch(patches[1]) ################################################################ ################ Link 1 at minimum ################ ################################################################ center = (l_1 * math.cos(theta_1_min), l_1 * math.sin(theta_1_min)) end_point = forward_kinematics(l_1, l_2, theta_1_min, theta_2_min, True) end_point = [end_point[0] - center[0], end_point[1] - center[1]] start_point = forward_kinematics(l_1, l_2, theta_1_min, theta_2_max, True) start_point = [start_point[0] - center[0], start_point[1] - center[1]] radius = l_2 start_angle = angle_clockwise(start_point, [1, 0]) end_angle = angle_clockwise(end_point, [1, 0]) ################################################################ current_path = Path.arc(start_angle, end_angle) new_verts = current_path.deepcopy().vertices for new_vert in new_verts: new_vert[0] = (new_vert[0] * radius + center[0]) new_vert[1] = (new_vert[1] * radius + center[1]) * -1 new_verts[np.shape(new_verts)[0] - 1] = paths[0].vertices[0] new_verts = new_verts[:] current_path = Path(new_verts, current_path.deepcopy().codes[:]) paths.append(current_path) patches.append(PathPatch(current_path)) ax.add_patch(patches[2]) ################################################################ ################ Link 1 at maximum ################ ################################################################ center = (l_1 * math.cos(theta_1_max), l_1 * math.sin(theta_1_max)) start_point = forward_kinematics(l_1, l_2, theta_1_max, theta_2_min, True) start_point = [start_point[0] - center[0], start_point[1] - center[1]] end_point = forward_kinematics(l_1, l_2, theta_1_max, theta_2_max, True) end_point = [end_point[0] - center[0], end_point[1] - center[1]] radius = l_2 start_angle = angle(start_point, [1, 0]) end_angle = angle(end_point, [1, 0]) ################################################################ current_path = Path.arc(start_angle, end_angle) new_verts = current_path.deepcopy().vertices for new_vert in new_verts: new_vert[0] = new_vert[0] * radius + center[0] new_vert[1] = new_vert[1] * radius + center[1] new_verts = new_verts[:] current_path = Path(new_verts, current_path.deepcopy().codes[:]) paths.append(current_path) patches.append(PathPatch(current_path)) ax.add_patch(patches[3]) ################################################################ ################ Plot curves ################ ################################################################ ax.set_title("Working Area = {wa:.3f}".format(wa=wa)) new_path = Path.make_compound_path( paths[0], paths[3], paths[1], paths[2], ) old_vertices = new_path.deepcopy().vertices old_codes = new_path.deepcopy().codes new_path_vertices = [] new_path_codes = [] for i, old_vertex in enumerate(old_vertices, start=0): if (i == 0): new_path_vertices.append(old_vertex) new_path_codes.append(old_codes[i]) else: if (old_codes[i] != 1): new_path_vertices.append(old_vertex) new_path_codes.append(old_codes[i]) new_path = Path(new_path_vertices, new_path_codes) patches[0].remove() patches[1].remove() patches[2].remove() patches[3].remove() path_patch = PathPatch(new_path, fill=False, hatch='/', clip_on=True) patches.append(path_patch) ax.add_patch(path_patch) if (plot == True): plt.show() return [ax, plt, fig]