# People's Video Editor: high quality, GPU accelerated mp4 editor # Copyright (C) 2025 Roz K # # This file is part of People's Video Editor. # # People's Video Editor is free software: you can redistribute it and/or modify it under the terms of the # GNU General Public License as published by the Free Software Foundation, either version 3 of the License, # or (at your option) any later version. # # People's Video Editor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with People's Video Editor. # If not, see . from array import array from .node import Node from .vector import Vector2 class Point: __slots__ = 'position', 'mapping' def __init__(self, xy = Vector2(), uv = Vector2()): assert isinstance(xy, Vector2) and isinstance(uv, Vector2) self.position = xy self.mapping = uv class Polygon(Node): __slots__ = '_positions', '_mappings', '_len' @classmethod def rectangle(cls, geometry): tl = Vector2(0.0, 0.0) tr = Vector2(geometry._width, 0.0) br = Vector2(geometry._width, geometry._height) bl = Vector2(0.0, geometry._height) return cls(points = ( Point(tl, tl), Point(tr, tr), Point(br, br), Point(bl, bl))) def __init__(self, parent = None, children = None, size = 0, points = None): Node.__init__(self, parent, children) self.clear_points() self.add_points(size, points) def __len__(self): return self._len def __getitem__(self, index): begin = index * 2 end = begin + 2 return Point( Vector2(*self._positions[begin:end]), Vector2(*self._mappings[begin:end])) def __setitem__(self, index, point): begin = index * 2 end = begin + 2 self._positions[begin:end] = array(Vector2.TYPE, point.position) self._mappings[begin:end] = array(Vector2.TYPE, point.mapping) def add_child(self, child): assert isinstance(child, Polygon) Node.add_child(self, child) def add_points(self, count = 0, points = None): assert (count > 0) ^ len(points) if count: initializer = bytes(count * Vector2.SIZE) self._positions.frombytes(initializer) self._mappings.frombytes(initializer) self._len += count else: for point in points: self._positions.extend(point.position) self._mappings.extend(point.mapping) self._len += len(points) def insert_points(self, index, count = 0, points = None): assert (count == 0) ^ (points is None) index *= 2 if count: initializer = array(Vector2.TYPE, bytes(count * Vector2.SIZE)) self._positions[index:index] = initializer self._mappings[index:index] = initializer self._len += count else: polygon = Polygon(points = points) self._positions[index:index] = polygon._positions self._mappings[index:index] = polygon._mappings self._len += polygon._len def remove_points(self, index, count = 1): begin = index * 2 end = begin + count * 2 del self._positions[begin:end] del self._mappings[begin:end] self._len -= count def clear_points(self): self._positions = array(Vector2.TYPE) self._mappings = array(Vector2.TYPE) self._len = 0