natural-agi-common 0.1.33__tar.gz → 0.1.34__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/PKG-INFO +1 -1
  2. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/model/point.py +4 -0
  3. natural_agi_common-0.1.34/common/traversal/graph_traversal.py +73 -0
  4. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/visitors/direction_visitor.py +8 -2
  5. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/visitors/length_comparison_visitor.py +2 -1
  6. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/visitors/quadrant_visitor.py +13 -5
  7. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/visitors/visitor.py +1 -1
  8. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/natural_agi_common.egg-info/PKG-INFO +1 -1
  9. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/natural_agi_common.egg-info/SOURCES.txt +0 -2
  10. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/setup.py +1 -1
  11. natural_agi_common-0.1.33/common/traversal/graph_traversal.py +0 -52
  12. natural_agi_common-0.1.33/common/traversal/visitors/half_plane_visitor.py +0 -64
  13. natural_agi_common-0.1.33/common/traversal/visitors/relative_position_visitor.py +0 -209
  14. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/README.md +0 -0
  15. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/__init__.py +0 -0
  16. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/critical_graph_utils.py +0 -0
  17. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/critical_point.py +0 -0
  18. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/decorator.py +0 -0
  19. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/graph_utils.py +0 -0
  20. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/model/__init__.py +0 -0
  21. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/model/dlq.py +0 -0
  22. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/model/enums.py +0 -0
  23. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/model/half_plane.py +0 -0
  24. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/model/length_comparison_result.py +0 -0
  25. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/model/vector.py +0 -0
  26. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/params.py +0 -0
  27. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/__init__.py +0 -0
  28. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/start_point_selector.py +0 -0
  29. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/visitors/__init__.py +0 -0
  30. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/visitors/angle_visitor.py +0 -0
  31. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/common/traversal/visitors/visitor_result_persistence_service.py +0 -0
  32. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/natural_agi_common.egg-info/dependency_links.txt +0 -0
  33. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/natural_agi_common.egg-info/requires.txt +0 -0
  34. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/natural_agi_common.egg-info/top_level.txt +0 -0
  35. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/pyproject.toml +0 -0
  36. {natural_agi_common-0.1.33 → natural_agi_common-0.1.34}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: natural-agi-common
3
- Version: 0.1.33
3
+ Version: 0.1.34
4
4
  Requires-Dist: pydantic
5
5
  Requires-Dist: networkx
6
6
  Requires-Dist: neo4j
@@ -6,6 +6,8 @@ class Point:
6
6
  id: str
7
7
  x: float
8
8
  y: float
9
+ normalized_x: float
10
+ normalized_y: float
9
11
 
10
12
  @classmethod
11
13
  def from_node_data(cls, node_data: dict) -> "Point":
@@ -13,6 +15,8 @@ class Point:
13
15
  x=node_data["x"],
14
16
  y=node_data["y"],
15
17
  id=node_data["id"],
18
+ normalized_x=node_data["normalized_x"],
19
+ normalized_y=node_data["normalized_y"],
16
20
  )
17
21
 
18
22
  def __hash__(self):
@@ -0,0 +1,73 @@
1
+ from typing import Generator, Any, Tuple, Optional, List
2
+ from dataclasses import dataclass
3
+ import networkx as nx
4
+ import logging
5
+ from ..model.point import Point
6
+ from ..model.vector import Vector
7
+
8
+
9
+ @dataclass
10
+ class TraversalSequence:
11
+ start_point: Point
12
+ vector: Vector
13
+ end_point: Point
14
+
15
+
16
+ class GraphTraversal:
17
+ def __init__(self, graph: nx.Graph):
18
+ self.graph = graph
19
+ self.logger = logging.getLogger(__name__)
20
+
21
+ def dfs_traversal(
22
+ self, start_node: Any
23
+ ) -> Generator[TraversalSequence, None, None]:
24
+ visited_vectors = set()
25
+ visited_nodes = set()
26
+
27
+ def dfs_recursive(current_node: Any, path: List[Any]) -> None:
28
+ if current_node in visited_nodes:
29
+ return
30
+
31
+ visited_nodes.add(current_node)
32
+ path.append(current_node)
33
+
34
+ # If we have a sequence of 3 nodes, check if it follows point-vector-point pattern
35
+ if len(path) >= 3:
36
+ start_node_id = path[-3]
37
+ vector_node_id = path[-2]
38
+ end_node_id = path[-1]
39
+
40
+ start_data = self.graph.nodes[start_node_id]
41
+ vector_data = self.graph.nodes[vector_node_id]
42
+ end_data = self.graph.nodes[end_node_id]
43
+
44
+ # Check if sequence follows point-vector-point pattern
45
+ if (
46
+ self._is_point(start_data)
47
+ and self._is_vector(vector_data)
48
+ and self._is_point(end_data)
49
+ and vector_node_id not in visited_vectors
50
+ ):
51
+ self.logger.info(
52
+ f"Found sequence: {start_node_id} -> {vector_node_id} -> {end_node_id}"
53
+ )
54
+ visited_vectors.add(vector_node_id)
55
+
56
+ start_point = Point.from_node_data(start_data)
57
+ vector = Vector.from_node_data(vector_data)
58
+ end_point = Point.from_node_data(end_data)
59
+
60
+ yield TraversalSequence(start_point, vector, end_point)
61
+
62
+ # Continue DFS to neighbors
63
+ for neighbor in self.graph.neighbors(current_node):
64
+ if neighbor not in visited_nodes:
65
+ yield from dfs_recursive(neighbor, path.copy())
66
+
67
+ yield from dfs_recursive(start_node, [])
68
+
69
+ def _is_vector(self, node_data: dict) -> bool:
70
+ return "Vector" in node_data["labels"]
71
+
72
+ def _is_point(self, node_data: dict) -> bool:
73
+ return "Point" in node_data["labels"]
@@ -53,10 +53,16 @@ class DirectionVisitor(Visitor):
53
53
  # No specific operation for points in this visitor
54
54
  return None
55
55
 
56
- def visit_line(self, line: Vector) -> Dict[str, Any]:
56
+ def visit_line(self, line: Vector, start_point: Point) -> Dict[str, Any]:
57
57
  # Extract direction information
58
+ start_coords = (start_point.x, start_point.y)
59
+ end_coords = (
60
+ (line.x2, line.y2)
61
+ if line.x1 == start_point.x and line.y1 == start_point.y
62
+ else (line.x1, line.y1)
63
+ )
58
64
  h_direction, v_direction = self.calculate_direction(
59
- line.x1, line.y1, line.x2, line.y2
65
+ start_coords[0], start_coords[1], end_coords[0], end_coords[1]
60
66
  )
61
67
  line.horizontal_direction = h_direction
62
68
  line.vertical_direction = v_direction
@@ -2,6 +2,7 @@ from typing import Dict, Any, List
2
2
 
3
3
  from neo4j import ManagedTransaction
4
4
  from .visitor import Visitor
5
+ from ...model.point import Point
5
6
  from ...model.vector import Vector
6
7
  from ...model.length_comparison_result import LengthComparisonResult
7
8
 
@@ -16,7 +17,7 @@ class LengthComparisonVisitor(Visitor):
16
17
  # This visitor does not handle points
17
18
  return None
18
19
 
19
- def visit_line(self, line: Vector) -> Dict[str, Any]:
20
+ def visit_line(self, line: Vector, start_point: Point) -> Dict[str, Any]:
20
21
  comparison = LengthComparisonResult.N_A
21
22
  if self.previous_length:
22
23
  if line.length > self.previous_length:
@@ -13,8 +13,10 @@ class QuadrantVisitor(Visitor):
13
13
  self.quadrants: Dict[str, int] = {}
14
14
 
15
15
  def visit_point(self, point: Point) -> None:
16
- # Implementation for point-related operations
17
- return None
16
+ x = point.normalized_x
17
+ y = point.normalized_y
18
+ quadrant = self.determine_quadrant(x, y)
19
+ self.graph.nodes[point.id]["quadrant"] = quadrant
18
20
 
19
21
  def determine_vector_type(self, dx: float, dy: float) -> str:
20
22
  """Determine vector type based on relative dimensions.
@@ -37,9 +39,15 @@ class QuadrantVisitor(Visitor):
37
39
  else:
38
40
  return "VerticalVector"
39
41
 
40
- def visit_line(self, line: Vector) -> Dict[str, Any]:
41
- dx = line.x2 - line.x1
42
- dy = line.y2 - line.y1
42
+ def visit_line(self, line: Vector, start_point: Point) -> Dict[str, Any]:
43
+ start_coords = (start_point.x, start_point.y)
44
+ end_coords = (
45
+ (line.x2, line.y2)
46
+ if line.x1 == start_point.x and line.y1 == start_point.y
47
+ else (line.x1, line.y1)
48
+ )
49
+ dx = end_coords[0] - start_coords[0]
50
+ dy = end_coords[1] - start_coords[1]
43
51
  quadrant = self.determine_quadrant(dx, dy)
44
52
  vector_type = self.determine_vector_type(dx, dy)
45
53
 
@@ -16,7 +16,7 @@ class Visitor(ABC):
16
16
  pass
17
17
 
18
18
  @abstractmethod
19
- def visit_line(self, line: Vector) -> Any:
19
+ def visit_line(self, line: Vector, start_point: Point) -> Any:
20
20
  pass
21
21
 
22
22
  @abstractmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: natural-agi-common
3
- Version: 0.1.33
3
+ Version: 0.1.34
4
4
  Requires-Dist: pydantic
5
5
  Requires-Dist: networkx
6
6
  Requires-Dist: neo4j
@@ -20,10 +20,8 @@ common/traversal/start_point_selector.py
20
20
  common/traversal/visitors/__init__.py
21
21
  common/traversal/visitors/angle_visitor.py
22
22
  common/traversal/visitors/direction_visitor.py
23
- common/traversal/visitors/half_plane_visitor.py
24
23
  common/traversal/visitors/length_comparison_visitor.py
25
24
  common/traversal/visitors/quadrant_visitor.py
26
- common/traversal/visitors/relative_position_visitor.py
27
25
  common/traversal/visitors/visitor.py
28
26
  common/traversal/visitors/visitor_result_persistence_service.py
29
27
  natural_agi_common.egg-info/PKG-INFO
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="natural-agi-common",
5
- version="0.1.33",
5
+ version="0.1.34",
6
6
  packages=find_packages(include=["common", "common.*"]),
7
7
  install_requires=["pydantic", "networkx", "neo4j"],
8
8
  )
@@ -1,52 +0,0 @@
1
- from typing import Generator, Any, Tuple, Optional
2
- import networkx as nx
3
- import logging
4
- from ..model.point import Point
5
- from ..model.vector import Vector
6
-
7
-
8
- class GraphTraversal:
9
- def __init__(self, graph: nx.Graph):
10
- self.graph = graph
11
- self.logger = logging.getLogger(__name__)
12
-
13
- def dfs_traversal(
14
- self, start_node: Any
15
- ) -> Generator[Tuple[Point, Optional[Vector]], None, None]:
16
- visited_vector = set()
17
- for edge in nx.dfs_edges(self.graph, start_node):
18
- self.logger.info(f"Visiting edge: {edge}")
19
- source_node, target_node = edge
20
- if source_node in visited_vector or target_node in visited_vector:
21
- self.logger.info(f"Skipping edge: {edge} because vector was already visited")
22
- continue
23
-
24
- # Convert to your Point and Vector objects
25
- source_data = self.graph.nodes[source_node]
26
- target_data = self.graph.nodes[target_node]
27
-
28
- point = None
29
- vector = None
30
-
31
- if self._is_point(source_data):
32
- point = Point.from_node_data(source_data)
33
- elif self._is_vector(source_data):
34
- vector = Vector.from_node_data(source_data)
35
- visited_vector.add(source_node)
36
-
37
- if self._is_point(target_data):
38
- point = Point.from_node_data(target_data)
39
- elif self._is_vector(target_data):
40
- vector = Vector.from_node_data(target_data)
41
- visited_vector.add(target_node)
42
-
43
- if point is None and vector is None:
44
- raise ValueError(f"Invalid node data: {source_data} or {target_data}")
45
-
46
- yield point, vector
47
-
48
- def _is_vector(self, node_data: dict) -> bool:
49
- return "Vector" in node_data["labels"]
50
-
51
- def _is_point(self, node_data: dict) -> bool:
52
- return "Point" in node_data["labels"]
@@ -1,64 +0,0 @@
1
- from typing import Any, Dict
2
-
3
- from neo4j import ManagedTransaction
4
- from ...model.half_plane import HalfPlane
5
- from .visitor import Visitor
6
- from ...model.point import Point
7
- from ...model.vector import Vector
8
-
9
-
10
- class HalfPlaneVisitor(Visitor):
11
- def __init__(self, graph):
12
- super().__init__(graph)
13
- self.half_planes: Dict[str, HalfPlane] = {}
14
-
15
- def visit_point(self, _: Point) -> None:
16
- # This visitor does not handle points
17
- return None
18
-
19
- def visit_line(self, line: Vector) -> Dict[str, Any]:
20
- dx = line.x2 - line.x1
21
- dy = line.y2 - line.y1
22
- half_plane = self.determine_half_plane(dx, dy)
23
- self.half_planes[line.id] = half_plane
24
- self.graph.nodes[line.id]["half_plane"] = half_plane.value
25
-
26
- def save_result(
27
- self,
28
- tx: ManagedTransaction,
29
- image_id: str,
30
- session_id: str,
31
- result: Dict[str, Any],
32
- ) -> None:
33
- query = """
34
- MATCH (v:Vector {id: $id})
35
- MERGE (hp:HalfPlane:Feature {value: $half_plane, session_id: $session_id})
36
- ON CREATE SET hp.samples = [$image_id], v.half_plane = $half_plane
37
- ON MATCH SET hp.samples = CASE
38
- WHEN NOT $image_id IN hp.samples THEN hp.samples + $image_id
39
- ELSE hp.samples
40
- END, v.half_plane = $half_plane
41
- MERGE (v)-[:IS_IN_HALF_PLANE]->(hp)
42
- """
43
- tx.run(
44
- query,
45
- id=result["line_id"],
46
- half_plane=result["half_plane"],
47
- session_id=session_id,
48
- image_id=image_id,
49
- )
50
-
51
- def get_results(self) -> Dict[str, str]:
52
- return {k: v.value for k, v in self.half_planes.items()}
53
-
54
- def reset(self) -> None:
55
- self.half_planes.clear()
56
-
57
- @staticmethod
58
- def determine_half_plane(dx: float, dy: float) -> HalfPlane:
59
- if dx == 0 and dy == 0:
60
- return HalfPlane.ORIGIN
61
- elif abs(dy) > abs(dx):
62
- return HalfPlane.UPPER if dy > 0 else HalfPlane.LOWER
63
- else:
64
- return HalfPlane.RIGHT if dx > 0 else HalfPlane.LEFT
@@ -1,209 +0,0 @@
1
- from dataclasses import dataclass
2
- from enum import Enum
3
- from typing import Dict, Any, List
4
- import math
5
- import networkx as nx
6
- from neo4j import ManagedTransaction
7
-
8
- from .visitor import Visitor
9
- from ...model.point import Point
10
- from ...model.vector import Vector
11
-
12
-
13
- class RelativeSegment(Enum):
14
- TOP = "top"
15
- BOTTOM = "bottom"
16
- LEFT = "left"
17
- RIGHT = "right"
18
- CENTER_VERTICAL = "center_vertical"
19
- CENTER_HORIZONTAL = "center_horizontal"
20
-
21
-
22
- @dataclass
23
- class RelativePosition:
24
- distance_from_center: float
25
- segments: List[RelativeSegment]
26
- normalized_x: float # -1 to 1
27
- normalized_y: float # -1 to 1
28
-
29
-
30
- class RelativePositionVisitor(Visitor):
31
- def __init__(self, graph: nx.Graph):
32
- super().__init__(graph)
33
-
34
- # Find the bounding box and calculate center
35
- self._calculate_bounding_box_center()
36
-
37
- self.segment_threshold = 0.05 # 20% threshold for center segments
38
- self.point_positions: Dict[str, RelativePosition] = {}
39
- self.vector_positions: Dict[str, RelativePosition] = {}
40
-
41
- def _calculate_bounding_box_center(self) -> None:
42
- """Calculate the center based on the bounding box of all points in the graph."""
43
- min_x = float("inf")
44
- min_y = float("inf")
45
- max_x = float("-inf")
46
- max_y = float("-inf")
47
-
48
- # Find min and max coordinates to determine the bounding box
49
- for node_id, node_data in self.graph.nodes(data=True):
50
- if "Point" not in node_data["labels"]:
51
- continue
52
-
53
- x = node_data["x"]
54
- y = node_data["y"]
55
- min_x = min(min_x, x)
56
- min_y = min(min_y, y)
57
- max_x = max(max_x, x)
58
- max_y = max(max_y, y)
59
-
60
- # Calculate center of the bounding box
61
- self.center_x = (min_x + max_x) / 2
62
- self.center_y = (min_y + max_y) / 2
63
-
64
- # Calculate half-width and half-height of the bounding box
65
- half_width = (max_x - min_x) / 2
66
- half_height = (max_y - min_y) / 2
67
-
68
- # Maximum distance is from center to the corner of the bounding box
69
- self.max_distance = math.sqrt(half_width**2 + half_height**2)
70
-
71
- def visit_point(self, point: Point) -> Dict[str, Any]:
72
- position = self._calculate_relative_position(point.x, point.y)
73
- self.point_positions[point.id] = position
74
- node = self.graph.nodes[point.id]
75
- node["relative_distance"] = position.distance_from_center
76
- node["normalized_x"] = position.normalized_x
77
- node["normalized_y"] = position.normalized_y
78
- node["segments"] = [seg.value for seg in position.segments]
79
-
80
- return {
81
- "point_id": point.id,
82
- "distance": position.distance_from_center,
83
- "segments": [seg.value for seg in position.segments],
84
- "normalized_x": position.normalized_x,
85
- "normalized_y": position.normalized_y,
86
- }
87
-
88
- def visit_line(self, line: Vector) -> Dict[str, Any]:
89
- # Calculate midpoint of the line
90
- mid_x = (line.x1 + line.x2) / 2
91
- mid_y = (line.y1 + line.y2) / 2
92
-
93
- position = self._calculate_relative_position(mid_x, mid_y)
94
- self.vector_positions[line.id] = position
95
- node = self.graph.nodes[line.id]
96
- node["relative_distance"] = position.distance_from_center
97
- node["normalized_x"] = position.normalized_x
98
- node["normalized_y"] = position.normalized_y
99
- node["segments"] = [seg.value for seg in position.segments]
100
-
101
- return {
102
- "line_id": line.id,
103
- "distance": position.distance_from_center,
104
- "segments": [seg.value for seg in position.segments],
105
- "normalized_x": position.normalized_x,
106
- "normalized_y": position.normalized_y,
107
- }
108
-
109
- def _calculate_relative_position(self, x: float, y: float) -> RelativePosition:
110
- # Calculate normalized coordinates (-1 to 1) relative to bounding box center
111
- normalized_x = (x - self.center_x) / (
112
- self.max_distance if self.max_distance > 0 else 1
113
- )
114
- normalized_y = (y - self.center_y) / (
115
- self.max_distance if self.max_distance > 0 else 1
116
- )
117
-
118
- # Calculate distance from center
119
- dx = x - self.center_x
120
- dy = y - self.center_y
121
- distance = math.sqrt(dx**2 + dy**2) / self.max_distance
122
-
123
- # Determine segments
124
- segments = []
125
-
126
- # Vertical segments
127
- if abs(normalized_y) < self.segment_threshold:
128
- segments.append(RelativeSegment.CENTER_HORIZONTAL)
129
- elif normalized_y < 0:
130
- segments.append(RelativeSegment.TOP)
131
- else:
132
- segments.append(RelativeSegment.BOTTOM)
133
-
134
- # Horizontal segments
135
- if abs(normalized_x) < self.segment_threshold:
136
- segments.append(RelativeSegment.CENTER_VERTICAL)
137
- elif normalized_x < 0:
138
- segments.append(RelativeSegment.LEFT)
139
- else:
140
- segments.append(RelativeSegment.RIGHT)
141
-
142
- return RelativePosition(
143
- distance_from_center=round(distance, 2),
144
- segments=segments,
145
- normalized_x=round(normalized_x, 2),
146
- normalized_y=round(normalized_y, 2),
147
- )
148
-
149
- def save_result(
150
- self,
151
- tx: ManagedTransaction,
152
- image_id: str,
153
- session_id: str,
154
- result: Dict[str, Any],
155
- ) -> None:
156
- if "point_id" in result:
157
- self._save_point_position(tx, result)
158
- elif "line_id" in result:
159
- self._save_line_position(tx, result)
160
-
161
- def _save_point_position(
162
- self,
163
- tx: ManagedTransaction,
164
- result: Dict[str, Any],
165
- ) -> None:
166
- query = """
167
- MATCH (p:Point {id: $point_id})
168
- SET p.relative_distance = $distance,
169
- p.normalized_x = $normalized_x,
170
- p.normalized_y = $normalized_y,
171
- p.segments = $segments
172
- RETURN p
173
- """
174
- tx.run(
175
- query,
176
- point_id=result["point_id"],
177
- distance=result["distance"],
178
- normalized_x=result["normalized_x"],
179
- normalized_y=result["normalized_y"],
180
- segments=result["segments"],
181
- )
182
-
183
- def _save_line_position(
184
- self,
185
- tx: ManagedTransaction,
186
- result: Dict[str, Any],
187
- ) -> None:
188
- query = """
189
- MATCH (v:Vector {id: $line_id})
190
- SET v.relative_distance = $distance,
191
- v.normalized_x = $normalized_x,
192
- v.normalized_y = $normalized_y,
193
- v.segments = $segments
194
- """
195
- tx.run(
196
- query,
197
- line_id=result["line_id"],
198
- distance=result["distance"],
199
- normalized_x=result["normalized_x"],
200
- normalized_y=result["normalized_y"],
201
- segments=result["segments"],
202
- )
203
-
204
- def get_results(self) -> Dict[str, Dict[str, RelativePosition]]:
205
- return {"points": self.point_positions, "vectors": self.vector_positions}
206
-
207
- def reset(self) -> None:
208
- self.point_positions.clear()
209
- self.vector_positions.clear()