Skip to content
Path.py 31.9 KiB
Newer Older
####################################################################################################
#
# Patro - A Python library to make patterns for fashion design
# Copyright (C) 2019 Fabrice Salvaire
#
# This program 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.
#
# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################

Fabrice Salvaire's avatar
Fabrice Salvaire committed
"""Module to implement path.

For resources on path see :ref:`this section <path-geometry-ressources-page>`.

Fabrice Salvaire's avatar
Fabrice Salvaire committed
"""

####################################################################################################

__all__ = [
    'LinearSegment',
    'QuadraticBezierSegment',
    'CubicBezierSegment',
    'Path2D',
    ]

####################################################################################################

from Patro.Common.Math.Functions import sign
from .Primitive import Primitive1P, Primitive2DMixin
from .Bezier import QuadraticBezier2D, CubicBezier2D
Fabrice Salvaire's avatar
Fabrice Salvaire committed
from .Conic import AngularDomain, Circle2D, Ellipse2D
from .Segment import Segment2D
from .Vector import Vector2D

####################################################################################################

_module_logger = logging.getLogger(__name__)

####################################################################################################

class PathPart:

    ##############################################

    def __init__(self, path, index):

        self._path = path

    ##############################################

    def _init_absolute(self, absolute):
        self._absolute = bool(absolute)

    ##############################################

    def clone(self, path):
        raise NotImplementedError

    ##############################################

    def __repr__(self):
        return '{0}(@{1._index})'.format(self.__class__.__name__, self)

    ##############################################

    @property
    def path(self):
        return self._path

    @property
    def index(self):
        return self._index
    @index.setter
    def index(self, value):
        self._index = int(value)

    ##############################################

    @property
    def prev_part(self):
        return self._path[self._index -1]

    @property
    def next_part(self):
        return self._path[self._index +1]

    ##############################################

    @property
    def start_point(self):
        prev_part = self.prev_part
        if prev_part is not None:
            return prev_part.stop_point
        else:
            return self._path.p0

    ##############################################

    @property
    def stop_point(self):
        raise NotImplementedError

    ##############################################

    def to_absolute_point(self, point):
        # Fixme: cache ???
        if self._absolute:
            return point
        else:
            return point + self.start_point

    ##############################################

    @property
    def geometry(self):
        raise NotImplementedError

    ##############################################

    @property
    def bounding_box(self):
        return self.geometry.bounding_box

####################################################################################################

class OnePointMixin:

    ##############################################

    @property
    def point(self):
        return self._point

    @point.setter
    def point(self, value):
        self._point = Vector2D(value) # self._path.__vector_cls__

    ##############################################

    @property
    def stop_point(self):
        return self.to_absolute_point(self._point)

    ##############################################

    def apply_transformation(self, transformation):
        # Fixme: right for relative ???
        self._point = transformation * self._point

####################################################################################################

class TwoPointMixin:

    ##############################################

        return self.to_absolute_point(self._point1)

    @point1.setter
    def point1(self, value):
        self._point1 = Vector2D(value) # self._path.__vector_cls__

    ##############################################

        return self.to_absolute_point(self._point2)

    @point2.setter
    def point2(self, value):
        self._point2 = Vector2D(value)

    ##############################################

    def apply_transformation(self, transformation):
        # Fixme: right for relative ???
        self._point1 = transformation * self._point1
        self._point2 = transformation * self._point2

####################################################################################################

class ThreePointMixin(TwoPointMixin):
Loading full blame...