Source code for session_py.pointcloud

import uuid

from .color import Color
from .point import Point
from .vector import Vector
from .xform import Xform


[docs] class PointCloud: """A point cloud with points, normals, colors, and transformation. Parameters ---------- points : List[Point], optional Collection of points. normals : List[Vector], optional Collection of normals. colors : List[Color], optional Collection of colors. Attributes ---------- guid : str Unique identifier. name : str Name of the point cloud. points : List[Point] Collection of points. normals : List[Vector] Collection of normals. colors : List[Color] Collection of colors. xform : Xform Transformation matrix. """
[docs] def __init__(self, points=None, normals=None, colors=None): self.guid = str(uuid.uuid4()) self.name = "my_pointcloud" self.points = points if points is not None else [] self.normals = normals if normals is not None else [] self.colors = colors if colors is not None else [] self.xform = Xform()
########################################################################################### # Operators ########################################################################################### def __str__(self): return f"PointCloud(points={len(self.points)}, normals={len(self.normals)}, colors={len(self.colors)}, guid={self.guid}, name={self.name})" def __repr__(self): return self.__str__() def __len__(self): return len(self.points) ########################################################################################### # JSON ########################################################################################### def __jsondump__(self): """Serialize to polymorphic JSON format with type field. Returns ------- dict Dictionary with 'type', 'guid', 'name', and object fields. """ # Flatten points to [x, y, z, x, y, z, ...] points_flat = [] for p in self.points: points_flat.extend([p.x, p.y, p.z]) # Flatten normals to [x, y, z, x, y, z, ...] normals_flat = [] for n in self.normals: normals_flat.extend([n.x, n.y, n.z]) # Flatten colors to [r, g, b, r, g, b, ...] (no alpha) colors_flat = [] for c in self.colors: colors_flat.extend([c.r, c.g, c.b]) return { "type": f"{self.__class__.__name__}", "guid": self.guid, "name": self.name, "points": points_flat, "normals": normals_flat, "colors": colors_flat, "xform": self.xform.__jsondump__(), } @classmethod def __jsonload__(cls, data, guid=None, name=None): """Deserialize from polymorphic JSON format. Parameters ---------- data : dict Dictionary containing pointcloud data. guid : str, optional GUID for the pointcloud. name : str, optional Name for the pointcloud. Returns ------- :class:`PointCloud` Reconstructed pointcloud instance. """ from .encoders import decode_node cloud = cls() cloud.guid = guid cloud.name = name # Reconstruct points from flat array points_flat = data["points"] cloud.points = [ Point(points_flat[i], points_flat[i + 1], points_flat[i + 2]) for i in range(0, len(points_flat), 3) ] # Reconstruct normals from flat array normals_flat = data["normals"] cloud.normals = [ Vector(normals_flat[i], normals_flat[i + 1], normals_flat[i + 2]) for i in range(0, len(normals_flat), 3) ] # Reconstruct colors from flat array (RGB only, alpha always 255) colors_flat = data["colors"] cloud.colors = [ Color(colors_flat[i], colors_flat[i + 1], colors_flat[i + 2], 255) for i in range(0, len(colors_flat), 3) ] cloud.xform = decode_node(data["xform"]) return cloud ########################################################################################### # No-copy Operators ########################################################################################### def __iadd__(self, other): """Translate point cloud by vector (in-place).""" if isinstance(other, Vector): for p in self.points: p.x += other.x p.y += other.y p.z += other.z return self def __isub__(self, other): """Translate point cloud by negative vector (in-place).""" if isinstance(other, Vector): for p in self.points: p.x -= other.x p.y -= other.y p.z -= other.z return self ########################################################################################### # Copy Operators ########################################################################################### def __add__(self, other): """Translate point cloud by vector (copy).""" if isinstance(other, Vector): cloud = PointCloud( [Point(p.x, p.y, p.z) for p in self.points], [Vector(n.x, n.y, n.z) for n in self.normals], [Color(c.r, c.g, c.b, c.a) for c in self.colors], ) cloud.guid = self.guid cloud.name = self.name cloud.xform = self.xform cloud += other return cloud return NotImplemented def __sub__(self, other): """Translate point cloud by negative vector (copy).""" if isinstance(other, Vector): cloud = PointCloud( [Point(p.x, p.y, p.z) for p in self.points], [Vector(n.x, n.y, n.z) for n in self.normals], [Color(c.r, c.g, c.b, c.a) for c in self.colors], ) cloud.guid = self.guid cloud.name = self.name cloud.xform = self.xform cloud -= other return cloud return NotImplemented ########################################################################################### # Details ###########################################################################################
[docs] def size(self) -> int: """Get number of points.""" return len(self.points)
[docs] def is_empty(self) -> bool: """Check if point cloud is empty.""" return len(self.points) == 0