Skip to content
Path.py 31.5 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
from .Conic import Circle2D, AngularDomain
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...