class SphericalVorAreas(Benchmark): params = [10, 100, 1000, 5000, 10000] param_names = ['num_points'] def setup(self, num_points): self.points = generate_spherical_points(num_points) self.sv = SphericalVoronoi(self.points, radius=1, center=np.zeros(3)) def time_spherical_polygon_area_calculation(self, num_points): """Time the area calculation in the Spherical Voronoi code.""" self.sv.calculate_areas()
def test_area_reconstitution(self, radius, center): for points in [self.points, self.hemisphere_points, self.hemisphere_points2]: sv = SphericalVoronoi(radius * points + center, radius=radius, center=center) areas = sv.calculate_areas() assert_almost_equal(areas.sum(), 4 * np.pi * radius**2)
def test_area_reconstitution_large_input(self, radius): np.random.seed(0) n = 1000 points = np.random.uniform(-1, 1, (n, 3)) points /= np.linalg.norm(points, axis=1).reshape((n, 1)) sv = SphericalVoronoi(radius * points, radius=radius) areas = sv.calculate_areas() assert_almost_equal(areas.sum(), 4 * np.pi * radius**2)
def test_ultra_close_gens(self): # use geometric_slerp to produce generators that # are close together, to push the limits # of the area (angle) calculations # also, limit generators to a single hemisphere path = geometric_slerp([0, 0, 1], [1, 0, 0], t=np.linspace(0, 1, 1000)) sv = SphericalVoronoi(path) areas = sv.calculate_areas() assert_almost_equal(areas.sum(), 4 * np.pi)
def test_area_reconstitution(self, n, dim, radius, shift, single_hemisphere): points = _sample_sphere(n, dim, seed=0) # move all points to one side of the sphere for single-hemisphere test if single_hemisphere: points[:, 0] = np.abs(points[:, 0]) center = (np.arange(dim) + 1) * shift points = radius * points + center sv = SphericalVoronoi(points, radius=radius, center=center) areas = sv.calculate_areas() assert_almost_equal(areas.sum(), _hypersphere_area(dim, radius))
def test_area_unsupported_dimension(self): dim = 4 points = np.concatenate((-np.eye(dim), np.eye(dim))) sv = SphericalVoronoi(points) with pytest.raises(TypeError, match="Only supported"): sv.calculate_areas()
def test_equal_area_reconstitution(self, poly): points = _generate_polytope(poly) n, dim = points.shape sv = SphericalVoronoi(points) areas = sv.calculate_areas() assert_almost_equal(areas, _hypersphere_area(dim, 1) / n)
def test_equal_area_regions(self, poly): points = _generate_polyhedron(poly) sv = SphericalVoronoi(points) areas = sv.calculate_areas() assert_almost_equal(areas, 4 * np.pi / len(points))
def createGraph(planet, planetGenerator): #the sphere is spanned into regions of closer points to the seeds with a spherical Voronoi mapping. sv = SphericalVoronoi(planet.meshPoints) sv.sort_vertices_of_regions() #ensure that the polygon is clockwise oriented and correct it if not. #For plotting, all the polygons must have the same orientation. for i, region in enumerate(sv.regions): if (np.dot(np.cross(sv.points[i], sv.vertices[region[0]]), sv.vertices[region[1]]) > 0): sv.regions[i].reverse() #the graph of regions centers is created. This is useful for checking travel between regions. #At this point it is not yet possible to set the connections between regions. centers = Graph(directed=False) centers.add_vertex(len(sv.regions)) #for each cell, register the corners points index delimiting it. centers.vertex_properties["corners"] = centers.new_vertex_property( "vector<int>") for v, corners in zip(centers.vertices(), sv.regions): centers.vp.corners[v] = corners #for each cell, set its center point. centers.vertex_properties["center"] = centers.new_vertex_property( "vector<float>") for v, center in zip(centers.vertices(), sv.points): centers.vp.center[v] = center #for each cell, set its area in km^2. This is often used as a weight for the cell. centers.vertex_properties["area"] = centers.new_vertex_property("float") for v, area in zip(centers.vertices(), sv.calculate_areas()): centers.vp.area[v] = area * planet.parameters.radius**2 #create the graph of corners points. It is the dual of the graph centers. #this graph is useful to plot the borders and check touching regions. corners = Graph(directed=False) corners.add_vertex(len(sv.vertices)) #for each corner, register its position. corners.vertex_properties["position"] = corners.new_vertex_property( "vector<float>") for v, position in zip(corners.vertices(), sv.vertices): corners.vp.position[v] = position #set the edges between corners cornerLinks = [] for region in sv.regions: cornerLinks += [(min(i, j), max(i, j)) for (i, j) in pairwiseRoll(region)] #the edges are converted to dictionnary and back to a list to remove the doublons corners.add_edge_list(list(dict.fromkeys(cornerLinks))) #set the polygons that each corner touches corners.vertex_properties["touches"] = corners.new_vertex_property( "vector<int>") for i, cornerList in enumerate(centers.vp.corners): for corner in cornerList: corners.vp.touches[corner].append(i) #compute length of each border in km corners.edge_properties["length"] = corners.new_edge_property("float") edges = corners.get_edges() positions = np.array(list(corners.vp.position))[edges] lengths = np.arccos(np.sum(positions[:, 0] * positions[:, 1], axis=-1)) * planet.parameters.radius for i, e in enumerate(corners.edges()): corners.ep.length[e] = lengths[i] corners.edge_properties["separates"] = corners.new_edge_property( "vector<int>") for e in corners.edges(): corners.ep.separates[e] = list( set(corners.vp.touches[e.source()]).intersection( corners.vp.touches[e.target()])) #add links between regions centerLinks = [] for c in corners.vertices(): l = corners.vp.touches[c] centerLinks += [(min(i, j), max(i, j)) for (i, j) in pairwiseRoll(l)] centers.add_edge_list(list(dict.fromkeys(centerLinks))) #compute distance between regions in km centers.edge_properties["length"] = centers.new_edge_property("float") edges = centers.get_edges() positions = np.array(list(centers.vp.center))[edges] lengths = np.arccos(np.sum(positions[:, 0] * positions[:, 1], axis=-1)) * planet.parameters.radius for i, e in enumerate(centers.edges()): centers.ep.length[e] = lengths[i] planet.meshCenters = centers planet.meshCorners = corners def plotTilesBorders(self, ax, *args, **kwargs): edges = self.meshCorners.get_edges() segments = np.array(list(self.meshCorners.vp.position))[edges] (x, y, z) = np.shape(segments) segments = np.reshape(segments, (x * y, z)) lat, long = Projection().toLatLong(segments) lat = np.reshape(lat, (x, y)) long = np.reshape(long, (x, y)) lines = [[(slong[0], slat[0]), (slong[1], slat[1])] for slat, slong in zip(lat, long)] ax.add_collection( mc.LineCollection(lines, *args, transform=ccrs.Geodetic(), **kwargs)) planet.plotTilesBorders = types.MethodType(plotTilesBorders, planet) def plotTilesJunctions(self, ax, *args, **kwargs): edges = self.meshCenters.get_edges() segments = np.array(list(self.meshCenters.vp.center))[edges] (x, y, z) = np.shape(segments) segments = np.reshape(segments, (x * y, z)) lat, long = Projection().toLatLong(segments) lat = np.reshape(lat, (x, y)) long = np.reshape(long, (x, y)) lines = [[(slong[0], slat[0]), (slong[1], slat[1])] for slat, slong in zip(lat, long)] ax.add_collection( mc.LineCollection(lines, *args, transform=ccrs.Geodetic(), **kwargs)) planet.plotTilesJunctions = types.MethodType(plotTilesJunctions, planet)