Source code for session_py.session

import uuid
from typing import Any, Dict, Optional
from .objects import Objects
from .point import Point
from .tree import Tree
from .treenode import TreeNode
from .graph import Graph


[docs] class Session: """A Session containing geometry objects with hierarchical and graph structures. The Session class manages collections of geometry objects and provides: - Fast GUID-based lookup - Hierarchical tree structure for organization - Graph structure for object relationships - JSON serialization/deserialization Parameters ---------- name : str, optional Name of the Session. Defaults to "Session". Attributes ---------- objects : :class:`Objects` Collection of geometry objects in the Session. lookup : dict[UUID, :class:`Point`] Fast lookup dictionary mapping GUIDs to geometry objects. tree : :class:`Tree` Hierarchical tree structure for organizing geometry objects. graph : :class:`Graph` Graph structure for storing relationships between geometry objects. name : str Name of the Session. """
[docs] def __init__(self, name="my_session"): self.guid = str(uuid.uuid4()) self.name = name self.objects = Objects() self.lookup: Dict[str, Any] = {} self.tree = Tree(name=f"{name}_tree") self.graph = Graph(name=f"{name}_graph") # Create empty root node with session name root_node = TreeNode(name=self.name) self.tree.add(root_node)
# ToDo:s # - BVH Boundary Volume Hierarchy def __str__(self) -> str: return f"Session(objects={self.objects.to_str()}, tree={self.tree.to_str()}, graph={self.graph.to_str()})" def __repr__(self) -> str: return f"Session({self.guid}, {self.name}, {self.objects.to_str()}, {self.tree.to_str()}, {self.graph.to_str()})" ########################################################################################### # JSON (polymorphic) ########################################################################################### def __jsondump__(self) -> dict: """Serialize to polymorphic JSON format with type field.""" return { "type": f"{self.__class__.__name__}", "guid": self.guid, "name": self.name, "objects": self.objects.__jsondump__(), "tree": self.tree.__jsondump__(), "graph": self.graph.__jsondump__(), } @classmethod def __jsonload__( cls, data: dict, guid: Optional[str] = None, name: Optional[str] = None ) -> "Session": """Deserialize from polymorphic JSON format.""" from .encoders import decode_node session = cls(name=data.get("name", "my_session")) session.guid = guid if guid is not None else data.get("guid", session.guid) # Load nested structures via decode_node if data.get("objects"): session.objects = decode_node(data["objects"]) # Objects if data.get("tree"): session.tree = decode_node(data["tree"]) # Tree if data.get("graph"): session.graph = decode_node(data["graph"]) # Graph # Rebuild lookup from all objects for point in session.objects.points: session.lookup[point.guid] = point for line in session.objects.lines: session.lookup[line.guid] = line for plane in session.objects.planes: session.lookup[plane.guid] = plane for bbox in session.objects.bboxes: session.lookup[bbox.guid] = bbox for polyline in session.objects.polylines: session.lookup[polyline.guid] = polyline for pointcloud in session.objects.pointclouds: session.lookup[pointcloud.guid] = pointcloud for mesh in session.objects.meshes: session.lookup[mesh.guid] = mesh for cylinder in session.objects.cylinders: session.lookup[cylinder.guid] = cylinder for arrow in session.objects.arrows: session.lookup[arrow.guid] = arrow return session ########################################################################################### # Details - Add objects ###########################################################################################
[docs] def add_point(self, point: Point) -> TreeNode: """Add a point to the Session. Automatically creates corresponding nodes in both graph and tree structures. Parameters ---------- point : :class:`Point` The point to add to the session. Returns ------- TreeNode The TreeNode created for this point. """ self.objects.points.append(point) self.lookup[point.guid] = point self.graph.add_node(point.guid, f"point_{point.name}") tree_node = TreeNode(name=point.guid) return tree_node
[docs] def add_line(self, line) -> TreeNode: """Add a line to the Session. Returns ------- TreeNode The TreeNode created for this line. """ self.objects.lines.append(line) self.lookup[line.guid] = line self.graph.add_node(line.guid, f"line_{line.name}") tree_node = TreeNode(name=line.guid) return tree_node
[docs] def add_plane(self, plane) -> TreeNode: """Add a plane to the Session. Returns ------- TreeNode The TreeNode created for this plane. """ self.objects.planes.append(plane) self.lookup[plane.guid] = plane self.graph.add_node(plane.guid, f"plane_{plane.name}") tree_node = TreeNode(name=plane.guid) return tree_node
[docs] def add_bbox(self, bbox) -> TreeNode: """Add a bounding box to the Session. Returns ------- TreeNode The TreeNode created for this bounding box. """ self.objects.bboxes.append(bbox) self.lookup[bbox.guid] = bbox self.graph.add_node(bbox.guid, f"bbox_{bbox.name}") tree_node = TreeNode(name=bbox.guid) return tree_node
[docs] def add_polyline(self, polyline) -> TreeNode: """Add a polyline to the Session. Returns ------- TreeNode The TreeNode created for this polyline. """ self.objects.polylines.append(polyline) self.lookup[polyline.guid] = polyline self.graph.add_node(polyline.guid, f"polyline_{polyline.name}") tree_node = TreeNode(name=polyline.guid) return tree_node
[docs] def add_pointcloud(self, pointcloud) -> TreeNode: """Add a point cloud to the Session. Returns ------- TreeNode The TreeNode created for this point cloud. """ self.objects.pointclouds.append(pointcloud) self.lookup[pointcloud.guid] = pointcloud self.graph.add_node(pointcloud.guid, f"pointcloud_{pointcloud.name}") tree_node = TreeNode(name=pointcloud.guid) return tree_node
[docs] def add_mesh(self, mesh) -> TreeNode: """Add a mesh to the Session. Returns ------- TreeNode The TreeNode created for this mesh. """ self.objects.meshes.append(mesh) self.lookup[mesh.guid] = mesh self.graph.add_node(mesh.guid, f"mesh_{mesh.name}") tree_node = TreeNode(name=mesh.guid) return tree_node
[docs] def add_cylinder(self, cylinder) -> TreeNode: """Add a cylinder to the Session. Returns ------- TreeNode The TreeNode created for this cylinder. """ self.objects.cylinders.append(cylinder) self.lookup[cylinder.guid] = cylinder self.graph.add_node(cylinder.guid, f"cylinder_{cylinder.name}") tree_node = TreeNode(name=cylinder.guid) return tree_node
[docs] def add_arrow(self, arrow) -> TreeNode: """Add an arrow to the Session. Returns ------- TreeNode The TreeNode created for this arrow. """ self.objects.arrows.append(arrow) self.lookup[arrow.guid] = arrow self.graph.add_node(arrow.guid, f"arrow_{arrow.name}") tree_node = TreeNode(name=arrow.guid) return tree_node
[docs] def add(self, node: TreeNode, parent: TreeNode = None) -> None: """Add a TreeNode to the tree hierarchy. Parameters ---------- node : TreeNode The TreeNode to add. parent : TreeNode, optional Parent TreeNode (defaults to root if not provided). """ if parent is None: self.tree.add(node, self.tree.root) else: self.tree.add(node, parent)
[docs] def add_edge(self, guid1: str, guid2: str, attribute: str = "") -> None: """Add an edge between two geometry objects in the graph. Parameters ---------- guid1 : str GUID of the first geometry object. guid2 : str GUID of the second geometry object. attribute : str, optional Edge attribute description. """ self.graph.add_edge(guid1, guid2, attribute)
########################################################################################### # Details - Lookup ###########################################################################################
[docs] def get_object(self, guid: str) -> Optional[Point]: """Get a geometry object by its GUID. Parameters ---------- guid : str The string GUID of the geometry object to retrieve. Returns ------- :class:`Point` | None The geometry object if found, None otherwise. """ return self.lookup.get(guid)
[docs] def remove_object(self, guid: str) -> bool: """Remove a geometry object by its GUID. Args: guid: The UUID of the geometry object to remove. Returns: True if the object was removed, False if not found. """ geometry = self.lookup.get(guid) if not geometry: return False # Remove from points collection if isinstance(geometry, Point): self.objects.points.remove(geometry) # Remove from lookup table del self.lookup[guid] # Remove from tree - tree should handle GUID lookup self.tree.remove_node_by_guid(guid) # Remove from graph using string GUID if self.graph.has_node(str(guid)): self.graph.remove_node(str(guid)) return True
########################################################################################### # Details - Tree ###########################################################################################
[docs] def add_hierarchy(self, parent_guid: str, child_guid: str) -> bool: """Add a parent-child relationship in the tree structure. Parameters ---------- parent_guid : UUID The GUID of the parent geometry object. child_guid : UUID The GUID of the child geometry object. Returns ------- bool True if the relationship was added successfully. """ return self.tree.add_child_by_guid(parent_guid, child_guid)
[docs] def get_children(self, guid: str) -> list[str]: """Get all children GUIDs of a geometry object in the tree. Parameters ---------- guid : str The string GUID to search for. Returns ------- list[UUID] List of children GUIDs. """ return self.tree.get_children(guid)
########################################################################################### # Details - Graph ###########################################################################################
[docs] def add_relationship( self, from_guid: str, to_guid: str, relationship_type: str = "default" ) -> None: """Add a relationship edge in the graph structure. Parameters ---------- from_guid : UUID The GUID of the source geometry object. to_guid : UUID The GUID of the target geometry object. relationship_type : str, optional The type of relationship. Defaults to "default". """ self.graph.add_edge(from_guid, to_guid, relationship_type)
[docs] def get_neighbours(self, guid: str) -> list[str]: """Get all GUIDs connected to the given GUID in the graph. Parameters ---------- guid : UUID The GUID of the geometry object to find connections for. Returns ------- list[str] List of connected geometry GUIDs as strings. """ return self.graph.get_neighbors(guid)