def load_segments(filename): """ loads given .bo file. returns a vector of segments. """ coordinates_struct = struct.Struct('4d') segments = [] with open(filename, "rb") as bo_file: packed_segment = bo_file.read(32) while packed_segment: coordinates = coordinates_struct.unpack(packed_segment) points = [Point(coordinates[0:2]), Point(coordinates[2:])] segments.append(Segment(points)) packed_segment = bo_file.read(32) return segments
def get_segments(polygones): max_length = 9999.0 couples_indice_segment = [] couples_indice_ligne = [] quadrants = [polygon.bounding_quadrant() for polygon in polygones] areas = [polygon.absolute_area for polygon in polygones] for indice, polygone in sorted(enumerate(polygones), key=lambda couple: couple[1].absolute_area): point = polygone.points[0].coordinates couples_indice_ligne.append(( indice, Segment( [Point([point[0], point[1]]), Point([max_length, point[1]])]), )) for segment in polygone.segments(): couples_indice_segment.append((indice, segment)) return couples_indice_segment, couples_indice_ligne, quadrants, areas
def main(): """ petit exemple sur l'utilisation de tycat """ print("lancez moi dans terminology") print("tycat permet d'afficher des points et des segments") print("chaque argument doit etre un iterable sur des points \ et/ou segments (ou juste un point/segment)") print("chaque argument est affiche d'une couleur differente") # un point origine = Point([0.0, 0.0]) # un vecteur de points cercle = [Point([cos(c * pi / 10), sin(c * pi / 10)]) for c in range(20)] # un iterateur sur des segments (crees a la volee) segments = (Segment([p1, p2]) for p1, p2 in zip(cercle, islice(cycle(cercle), 1, None))) tycat(origine, cercle, segments)
def sweep_intersection(segment, current_point): """ computes and returns the abscissa of the intersection beetween the sweeping line and the segment. """ # Creates a segment that corresponds to the sweeping line around segment sweep = Segment([ Point([0, current_point.coordinates[1]]), Point([1, current_point.coordinates[1]]) ]) key_point = segment.line_intersection_with(sweep) # The key_point is None if segment is horizontal if key_point is not None: key_point = Segment.adjuster.hash_point(key_point) return key_point.coordinates else: return current_point.coordinates
def random_input_generator(nb_points, cas_general=1): """ fonction permettant de generer un couple (distance, points) où distance est un flottant aleatoire entre 0 et 0.2 et points un vecteur de nb_points objets de type Point. """ distance = random() / 6 if cas_general else 1 points = [Point([random(), random()]) for _ in range(nb_points)] return distance, points
def load_instance(filename): """ loads .pts file. returns distance limit and points. """ with open(filename, "r") as instance_file: lines = iter(instance_file) distance = float(next(lines)) points = [Point([float(f) for f in l.split(",")]) for l in lines] return distance, points
def load_segments(filename): """ loads given .bo file. returns a vector of segments. """ coordinates_struct = struct.Struct('4d') segments = [] adjuster = CoordinatesHash() with open(filename, "rb") as bo_file: packed_segment = bo_file.read(32) while packed_segment: coordinates = coordinates_struct.unpack(packed_segment) raw_points = [Point(coordinates[0:2]), Point(coordinates[2:])] adjusted_points = [adjuster.hash_point(p) for p in raw_points] segments.append(Segment(adjusted_points)) packed_segment = bo_file.read(32) return adjuster, segments
def old_main(): """main function""" nombre_de_points = 100 coordonnees_des_points = 10 limit = random.randrange(2, nombre_de_points) polygones = [Polygon([Point([1, 2]), Point([2, 4]), Point([-1, 2])])] for _ in range(3): points = [ Point([ random.randrange(coordonnees_des_points), random.randrange(coordonnees_des_points), ]) ] segments = [] for _ in range(limit): # on ajoute le polygone si aucun de ses segments ne s'intersecte avec un segment déjà existant point = Point([ random.randrange(coordonnees_des_points), random.randrange(coordonnees_des_points), ]) print(points, segments) failed = is_failed(polygones, segments, points, point) if not failed: segment = Segment([points[-1], point]) if point not in points: points.append(point) if segment not in segments: segments.append(segment) if len(points) > 2: polygon = Polygon(points) if polygon.area() != 0: polygones.append(polygon) with open("generated.poly", "w") as file: for indice, polygone in enumerate(polygones): for point in polygone.points: file.write( f"{indice} {point.coordinates[0]} {point.coordinates[1]}\n" )
def detection_inclusion(polygones, point, poly, nb_poly): """ renvoie le polygone avec la plus petite aire dans lequel le polynome actuel (celui du point) est inclus """ index_poly = -1 inclus_dans = [ ] # contient le plus petit polygone dans lequel le polynome actuel (celui du point_de_depart) est inclus for poly2 in polygones: index_poly += 1 nb_intersect = 0 if abs(poly2.area()) > abs( poly.area() ): # on teste seulement les polygones avec une aire supérieure à celle de poly for segment in poly2.segments( ): # on teste chaque segment de poly2 point1 = Point(list(segment.endpoints[0].coordinates)) point2 = Point(list(segment.endpoints[1].coordinates)) x1 = point1.coordinates[0] y1 = point1.coordinates[1] x2 = point2.coordinates[0] y2 = point2.coordinates[1] x = point.coordinates[0] y = point.coordinates[1] if (y1 > y) != (y2 > y) and (x < (x2 - x1) * (y - y1) / (y2 - y1) + x1): # s'il y a une intersection nb_intersect += 1 if nb_intersect % 2 == 1 and len( inclus_dans ) == 0: # si on est inclus dans rien pour le moment min_area = abs(poly2.area()) # l'aire minimale inclus_dans.append(index_poly) elif nb_intersect % 2 == 1 and abs( poly2.area() ) < min_area: # si on est deja inclus dans un poly mais qu'on est inclus dans un autre avec une plus petite aire min_area = abs(poly2.area()) inclus_dans[0] = index_poly if len(inclus_dans) == 0: # si on est inclus dans aucun polygone inclus_dans.append(-1) return inclus_dans[0]
def main(): point1 = Point([1, 1]) point2 = Point([1, 5]) s = Segment([point1, point2]) # print(s) # print(s.endpoints) # c = s.copy() # print(c) # print(c.endpoints) # q = s.bounding_quadrant() # print(q) # print(q.min_coordinates, q.max_coordinates) # print(s.svg_content()) # point = Point([1,2]) # print(s.endpoints[0]) # print(s.endpoints[1]) # print(s.endpoint_not(point1)) # print(s.endpoint_not(point2)) # print(s.contains(Point([2, 4.5]))) a = s.__repr__() print(a)
def intersection(self, other): if not self: raise ValueError() elif isinstance(other, Line): if not self.intersecting(other): raise ValueError() det = self._a * other._b - other._a * self._b return Point(-(self._c * other._b - other._c * self._b) / det, -(self._a * other._c - other._a * self._c) / det) elif hasattr(other, 'intersection'): return other.intersection(self) else: raise NotImplementedError
def point_aleatoire(nombre, bornes): """ fonction retourner un vecteur de nombre objets aleatoires de type Point. les abscisses et ordonnees des points generes sont comprises entre bornes[0] et bornes[1]. pre-conditions: - nombre est un entier """ points = [ Point([randint(bornes[0], bornes[1]), randint(bornes[0], bornes[1])]) for _ in range(nombre) ] return points
def test_point_in_polygon_upper_triangles(function): polygone, point = ( Polygon( [ Point([-1, 0]), Point([0, 1]), Point([1, 0]), Point([2, 1]), Point([3, 0]), Point([2, -2]), Point([0, -2]), ] ), Point([2, 0]), ) assert function(polygone, point) == True
def main(): """ tycat example """ points = [[Point([random(), random()]) for _ in range(5)] for _ in range(2)] segments = [[Segment(endpoints) for endpoints in combinations(p, r=2)] for p in points] print("tycat(points, segments)") tycat(points, segments) print("tycat(zip(iter(points), iter(segments)))") tycat(zip(iter(points), iter(segments))) print("tycat(*zip(iter(points), iter(segments)))") tycat(*zip(iter(points), iter(segments))) intersections = filter(None, (c[0].intersection_with(c[1]) for c in product(*segments))) print("intersections entre rouge et vert") tycat(segments[0], segments[1], intersections)
def angle(segment, adjuster): """ clockwise angle % pi between segment and the horizontal """ #we start by calculating the coordinates of the vector direction of the segment x_coordinate = segment.endpoints[0].coordinates[0] - segment.endpoints[1].coordinates[0] y_coordinate = segment.endpoints[0].coordinates[1] - segment.endpoints[1].coordinates[1] point = Point([x_coordinate, y_coordinate]) point = adjuster.hash_point(point) [x_coordinate, y_coordinate] = point.coordinates atan2_angle = atan2(y_coordinate, x_coordinate) if atan2_angle >= 0: return pi - atan2_angle else: return - atan2_angle
def hash_point(self, point): """ add a point to the hash, returning new point with adjusted coordinates. """ if point in self.fast_hash: return point new_coordinates = [ self.__hash_coordinate(c, i) for i, c in enumerate(point.coordinates) ] new_point = Point(new_coordinates) self.fast_hash.add(new_point) return new_point
def partition_segment(self, area): """ prend juste la partie du edge delimitee par la partition """ y_i, y_j = area[0], area[1] ptA = self.endpoints[0] ptB = self.endpoints[1] # Garder l'orientation du segment vecteur = self.segment_to_vector() # definir le point bas et le point haut du segment if ptA.y < ptB.y: pt_min, pt_max = ptA, ptB else: pt_min, pt_max = ptB, ptA # On nomine les abscisses des deux points definis auparavant x_min, x_max = pt_min.x, pt_max.x # On nomine les ordonnees des deux points definis auparavant y_min, y_max = pt_min.y, pt_max.y # Les cas particuliers if (y_min <= y_i and y_max <= y_i) or (y_max >= y_j and y_min >= y_j) or self.is_horizontal(): return None else: y_min_nv = max(y_i, y_min) y_max_nv = min(y_j, y_max) if self.is_vertical(): pt_min_nv = Point((x_min, y_min_nv)) pt_max_nv = Point((x_min, y_max_nv)) else: pente, ordonnee = self.equation_segment() x_min_nv = (y_min_nv - ordonnee)/pente x_max_nv = (y_max_nv - ordonnee)/pente pt_min_nv = Point((x_min_nv, y_min_nv)) pt_max_nv = Point((x_max_nv, y_max_nv)) new_edge = Segment([pt_min_nv, pt_max_nv]) return new_edge.orient_segment(vecteur)
def events_init_test(): """ test the init of a segment in the series of event """ print("\n------------Segment init test------------") events = Events([Segment([Point([1.0, 2.0]), Point([3.0, 4.0])]), Segment([Point([-3.0, -4.0]), Point([3.0, -4.0])]), Segment([Point([-3.0, -4.0]), Point([2.0, 4.0])])]) print(events) print("-----------------------------------------\n")
def test_point_in_polygon_vertex_on_threshold(function): polygone, point = ( Polygon( [ Point([0, 0]), Point([1, 1]), Point([2, 0]), Point([2, -2]), Point([1, -1]), Point([0, -2]), ] ), Point([1, 0]), ) assert function(polygone, point) == True
def test_point_in_polygon_point_on_side(function): polygone, point = ( Polygon( [ Point([0, 0]), Point([1, 0]), Point([2, 1]), Point([3, 0]), Point([2, -2]), Point([0, -2]), ] ), Point([0.5, 0]), ) assert function(polygone, point) == True
def trouve_inclusions(polygones): """ renvoie le vecteur des inclusions la ieme case contient l'indice du polygone contenant le ieme polygone (-1 si aucun). (voir le sujet pour plus d'info) """ nb_poly = -1 # numéro du polygone dont on s'occupe table_des_inclusions = [] # table contenant toutes les inclusions for poly in polygones: nb_poly += 1 point_de_depart = Point( list(poly.points[0].coordinates) ) # on prend le tout premier point qui compose poly (c'est arbitraire on aurait pu en prendre un autre) nb = detection_inclusion(polygones, point_de_depart, poly, nb_poly) table_des_inclusions.append(nb) return table_des_inclusions
def main(): a = Point([0.7, 0.79]) b = Point([0.84, 0.62]) c = Point([b.x, a.y]) # tycat(points) d = a.cross_product(b, c) ab = a.distance_to(b) ac = a.distance_to(c) print(d) print(ab * ac) print(d / (ab * ac))
def trouve_inclusions(polygones): """ renvoie le vecteur des inclusions la ieme case contient l'indice du polygone contenant le ieme polygone (-1 si aucun). (voir le sujet pour plus d'info) """ nb_poly = -1 # numéro du polygone dont on s'occupe table_des_inclusions = [] # table contenant toutes les inclusions for poly in polygones: nb_poly += 1 point_de_depart = Point( list(poly.points[0].coordinates) ) # ou sinon: Point(list(poly.points[0].coordinates)) ou poly.points[0] tab = detection_inclusion(polygones, point_de_depart, nb_poly) table_des_inclusions.append(tab) table_triee = tri_inclusion(table_des_inclusions) return table_triee
def print_components_sizes(distance, points): """ affichage des tailles triees de chaque composante """ segments = [] research_base = [point for point in points] origine = Point([0.0, 0.0]) total = research_base.copy() s = 0 enveloppe = [] while len(research_base) > 0: current = research_base[0] research_base.pop(0) for point in research_base: if current.distance_to(point) < distance: s += 1 segments.append(Segment([current, point])) enveloppe.append(s) print(enveloppe) tycat(origine, total, segments)
def print_components_sizes(distance, points): """ affichage des tailles triees de chaque composante """ SortedX = sorted([point for point in points], key = abscisse) result = prochesX(SortedX, distance) dernier_pointX_1 = result[len(result)-1] dernier_indice = SortedX.index(dernier_pointX_1) origine = Point([0.0, 0.0]) segment_1 = Segment([Point([dernier_pointX_1.x, 0]), Point([dernier_pointX_1.x, 1])]) SortedY = sorted([point for point in result], key = ordonnee) result_bis = prochesY(SortedY, distance) dernier_pointXbis_1 = result_bis[len(result_bis)-1] dernier_indice_bis = SortedX.index(dernier_pointXbis_1) segment_2 = Segment([Point([0, dernier_pointXbis_1.y]), Point([1, dernier_pointXbis_1.y])]) tycat(origine, points, (segment_1, segment_2)) """ affichage des tailles triees de chaque composante """ segments = [] research_base = [point for point in points] origine = Point([0.0, 0.0]) total = research_base.copy() s = 0 enveloppe = [] while len(research_base) > 0: current = research_base[0] research_base.pop(0) for point in research_base: if current.distance_to(point) < distance: s += 1 segments.append(Segment([current, point])) enveloppe.append(s) tycat(origine, total, segments)
def test(filename): """ run bentley ottmann """ #debug = True --> debug version, debug = False --> no debug option version debug = False #print the event_queue_list before the suppression debug1 = False #print details when the event is an intersection debug2 = False #print the event_queue in the beginning debug3 = False #print the intersections debug4 = False #print details when the event is an ending segment point debug5 = False adjuster, segments = load_segments(filename) tycat(segments) event_queue_list = Event_Queue(None, None) intersections = [] for seg in segments: event_queue_list.add_segment(seg) if debug3: print("{}".format(seg)) print("") event_queue_list.parcourir() print("") print("") if debug3: event_queue_list.parcourir() event_queue = event_queue_list.tete sweep_line = Sweep_Line(None, None) current_event = event_queue.point_list iteration = 0 while event_queue is not None: if debug: print("je suis passé par le début") while current_event is not None: #case where event is the beginnig of a segment if (current_event.nature == -1): if debug: print("the algo take the way of a first segment point") seg = sweep_line.insert(current_event.segment1, event_queue.value) seg_above = seg.next seg_below = seg.precedent seg = seg.segment if seg_above != None: seg_above = seg_above.segment intersec = seg.intersection_with(seg_above) if intersec is not None: if intersec == seg_above.endpoints[ 0] or intersec == seg_above.endpoints[ 1] or intersec == seg.endpoints[ 0] or intersec == seg.endpoints[1]: intersec = None if intersec is not None: event_queue_list.insert(intersec, 0, seg, seg_above) if seg_below != None: seg_below = seg_below.segment intersec = seg.intersection_with(seg_below) if intersec is not None: if intersec == seg_below.endpoints[ 0] or intersec == seg_below.endpoints[ 1] or intersec == seg.endpoints[ 0] or intersec == seg.endpoints[1]: intersec = None if intersec is not None: event_queue_list.insert(intersec, 0, seg_below, seg) #case when event is the end of a segment elif (current_event.nature == 1): if debug: print("the algo take the way of an ending segment point") seg = sweep_line.tete while seg.segment != current_event.segment1: seg = seg.next seg_above = seg.next seg_below = seg.precedent if debug5: print(seg_below == None) print(seg_above == None) seg = seg.segment if seg_below is None and seg_above is None: sweep_line.tete = None sweep_line.queue = None elif seg_below is None: seg_above.precedent = None sweep_line.tete = seg_above elif seg_above is None: seg_below.next = None sweep_line.queue = seg_below else: seg_below.next = seg_above seg_above.precedent = seg_below seg_below = seg_below.segment seg_above = seg_above.segment intersec = seg_below.intersection_with(seg_above) if intersec is not None: if intersec == seg_below.endpoints[ 0] or intersec == seg_below.endpoints[ 1] or intersec == seg_above.endpoints[ 0] or intersec == seg_above.endpoints[ 1]: intersec = None if intersec is not None: if not event_queue_list.possess(intersec): event_queue_list.insert(intersec, 0, seg_below, seg_above) #case when event is an intersection else: if debug: print("the algo take the way of an intersection point") intersections.append( Point([event_queue.value, current_event.ordinate])) if debug2: print(current_event.ordinate) print(current_event.segment1) print(current_event.segment2) seg_above = sweep_line.tete while seg_above.segment != current_event.segment2: if debug2: print(seg_above.segment) seg_above = seg_above.next if seg_above is None: break seg_below = sweep_line.tete if debug2: print(seg_below.segment) while seg_below.segment != current_event.segment1: if debug2: print(seg_below.segment) seg_below = seg_below.next if seg_below is None: break if seg_below is None: if debug2: print("seg_below is None") elif seg_above is None: if debug2: print("seg_above is None") else: if debug2: print(seg_below.segment) print(seg_above.segment) seg_below.segment, seg_above.segment = seg_above.segment, seg_below.segment seg_above2 = seg_above.next seg_below2 = seg_below.precedent if debug2: print(seg_below.segment) print(seg_above.segment) if seg_below2 is not None: print(seg_below2.segment) else: print("SEG_BELOW2 IS NONE") if seg_above2 is not None: print(seg_above2.segment) else: print("SEG_ABOVE2 IS NONE") if seg_above2 is not None: intersec = seg_above.segment.intersection_with( seg_above2.segment) if intersec is not None: if intersec == seg_above.segment.endpoints[ 0] or intersec == seg_above.segment.endpoints[ 1] or intersec == seg_above2.segment.endpoints[ 0] or intersec == seg_above2.segment.endpoints[ 1]: intersec = None if intersec is not None: if not event_queue_list.possess(intersec): event_queue_list.insert( intersec, 0, seg_above.segment, seg_above2.segment) if seg_below2 is not None: intersec = seg_below.segment.intersection_with( seg_below2.segment) if intersec is not None: if intersec == seg_below.segment.endpoints[ 0] or intersec == seg_below.segment.endpoints[ 1] or intersec == seg_below2.segment.endpoints[ 0] or intersec == seg_below2.segment.endpoints[ 1]: intersec = None if intersec is not None: if not event_queue_list.possess(intersec): event_queue_list.insert( intersec, 0, seg_below2.segment, seg_below.segment) #exit the current point_list if debug1: print("BEFORE THE SUPPRESSION") print(event_queue.value) event_queue_list.parcourir() if (current_event.next is None) and (current_event.precedent is None): event_queue.point_list = None event_queue = event_queue.next if event_queue is not None: current_event = event_queue.point_list else: current_event = None elif current_event.next is None: current_event.precedent.next = None current_event = current_event.precedent elif current_event.precedent is None: current_event.next.precedent = None current_event = current_event.next event_queue.point_list = current_event else: current_event.precedent.next = current_event.next current_event.next.precedent = current_event.precedent current_event = current_event.next iteration += 1 if debug: #some prints allows the text color to change in the terminal, it's easier to debug #print ('\033[1;32m\033[1;m') print("IT IS ITERATION NUMBER '{}'".format(iteration)) #print ('\033[1;37m\033[1;m') #print ('\033[1;35m\033[1;m') event_queue_list.parcourir() #print ('\033[1;37m\033[1;m') sweep_line.parcourir() print("") if debug4: parcourir_liste(intersections) print("") if debug: print(iteration) tycat(segments, intersections) print( 'le nombre d intersections (= le nombre de points differents) est "{}"' .format(len(intersections)))
class Segment: """ oriented segment between two points. for example: - create a new segment between two points: segment = Segment([point1, point2]) - create a new segment from coordinates: segment = Segment([Point([1.0, 2.0]), Point([3.0, 4.0])]) - compute intersection point with other segment: intersection = segment1.intersection_with(segment2) """ point = Point([0, 0]) def __init__(self, points): """ create a segment from an array of two points. """ self.endpoints = points def key(self, point): """ Return the key """ x_0, y_0 = self.endpoints[0].coordinates x_1, y_1 = self.endpoints[1].coordinates x_pt, y_pt = point.coordinates if x_0 == x_1: return (x_0, (1 - 2 * (x_pt > x_0)) * pi/2) if y_0 == y_1: return (x_pt, 0) delta_x, delta_y = x_1 - x_0, y_1 - y_0 x_final = x_0 + (y_pt - y_0) * delta_x / delta_y angle = ((delta_x > 0 and delta_y < 0) or (delta_x < 0 and delta_y > 0)) * pi + atan(delta_y / delta_x) return(x_final, angle) def __lt__(self, o): return self.key(Segment.point) < o.key(Segment.point) def copy(self): """ return duplicate of given segment (no shared points with original, they are also copied). """ return Segment([p.copy() for p in self.endpoints]) def length(self): """ return length of segment. example: segment = Segment([Point([1, 1]), Point([5, 1])]) distance = segment.length() # distance is 4 """ return self.endpoints[0].distance_to(self.endpoints[1]) def bounding_quadrant(self): """ return min quadrant containing self. """ quadrant = Quadrant.empty_quadrant(2) for point in self.endpoints: quadrant.add_point(point) return quadrant def svg_content(self): """ svg for tycat. """ return '<line x1="{}" y1="{}" x2="{}" y2="{}"/>\n'.format( *self.endpoints[0].coordinates, *self.endpoints[1].coordinates) def intersection_with(self, other): """ intersect two 2d segments. only return point if included on the two segments. """ i = self.line_intersection_with(other) if i is None: return # parallel lines if self.contains(i) and other.contains(i): return i def line_intersection_with(self, other): """ return point intersecting with the two lines passing through the segments. none if lines are almost parallel. """ # solve following system : # intersection = start of self + alpha * direction of self # intersection = start of other + beta * direction of other directions = [s.endpoints[1] - s.endpoints[0] for s in (self, other)] denominator = directions[0].cross_product(directions[1]) if abs(denominator) < 0.000001: # almost parallel lines return start_diff = other.endpoints[0] - self.endpoints[0] alpha = start_diff.cross_product(directions[1]) / denominator return self.endpoints[0] + directions[0] * alpha def contains(self, possible_point): """ is given point inside us ? be careful, determining if a point is inside a segment is a difficult problem (it is in fact a meaningless question in most cases). you might get wrong results for points extremely near endpoints. """ distance = sum(possible_point.distance_to(p) for p in self.endpoints) return abs(distance - self.length()) < 0.000001 def __str__(self): return "Segment([" + str(self.endpoints[0]) + ", " + \ str(self.endpoints[1]) + "])" def __repr__(self): return "[" + repr(self.endpoints[0]) + ", " + \ repr(self.endpoints[1]) + "])"
def read_instance_v2(filename): with open(filename, "rt") as file: points = (tuple(map(float, ligne.split())) for ligne in file) for indice, poly_points in groupby(points, key=lambda t: t[0]): yield int(indice), Polygon([Point(p[1:]) for p in poly_points])
def bulk_insert(self,points): # points : np.ndarray of the shape (:,dim) for point in points: self.insert(Point(point)) return
## to keep imports uptodata import clustering_feature import cf_tree import imp imp.reload(clustering_feature) imp.reload(cf_tree) from geo.point import Point data=np.array([[1,0],[1,2],[1,3],[2,1],[1,4],[4,1],[1,0],[5,66]]) tree=CFTree(dim=2,thresh=20,max_nodes= 10) for i in range(len(data)): p=Point(data[i]) tree.insert(p) print(tree.root) tree.rebuild(100) print(tree.root) coreset,ws=tree.get_coreset() for c in coreset: print(c) # xs=[c.center.p[0] for c in coreset] # ys=[c.center.p[1] for c in coreset] # #ws=[50*c.weight for c in coreset] plt.subplot(121)