Skip to content
Importer.py 4.97 KiB
Newer Older
Fabrice Salvaire's avatar
Fabrice Salvaire committed
####################################################################################################
#
# Patro - A Python library to make patterns for fashion design
# Copyright (C) 2017 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 handle the DXF file format.

"""

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

__all__ = ['DxfImporter']

Fabrice Salvaire's avatar
Fabrice Salvaire committed
####################################################################################################

Fabrice Salvaire's avatar
Fabrice Salvaire committed
import ezdxf # Python packahe to read/write DXF
Fabrice Salvaire's avatar
Fabrice Salvaire committed
from Patro.GeometryEngine.Conic import Circle2D, Ellipse2D, AngularDomain
Fabrice Salvaire's avatar
Fabrice Salvaire committed
from Patro.GeometryEngine.Segment import Segment2D
from Patro.GeometryEngine.Spline import BSpline2D
Fabrice Salvaire's avatar
Fabrice Salvaire committed
from Patro.GeometryEngine.Vector import Vector2D

from .Polyline import Polyline

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

class DxfImporter:

Fabrice Salvaire's avatar
Fabrice Salvaire committed
    """Class to implement a DXF importer.
    """

Fabrice Salvaire's avatar
Fabrice Salvaire committed
    ##############################################

    def __init__(self, path):

        path = str(path)
        self._drawing = ezdxf.readfile(path)
        self._model_space = self._drawing.modelspace()
        self._items = []
        self._read()

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

Fabrice Salvaire's avatar
Fabrice Salvaire committed
    def __len__(self):
        return len(self._items)

    def __iter__(self):
        return iter(self._items)

    def __getitem__(self, slice_):
        return self._items[slice_]

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

Fabrice Salvaire's avatar
Fabrice Salvaire committed
    @staticmethod
    def _to_vector(point):
        return Vector2D(point[:2])

    @classmethod
    def _to_vectors(cls, points):
        return [cls._to_vector(x) for x in points]

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

    def _add(self, item):
        self._items.append(item)

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

    def _read(self):

        for item in self._model_space:
            dxf_type = item.dxftype()
            if dxf_type == 'LINE':
                self._on_line(item)
            elif dxf_type in ('CIRCLE', 'ARC'):
                self._on_circle(item, dxf_type == 'ARC')
            elif dxf_type == 'ELLIPSE':
                self._on_ellipse(item)
            elif dxf_type == 'LWPOLYLINE':
                self._on_polyline(item)
            elif dxf_type == 'SPLINE':
                self._on_spline(item)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
            # else skip
Fabrice Salvaire's avatar
Fabrice Salvaire committed

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

    def _on_line(self, item):
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        item_dxf = item.dxf
        segment = Segment2D(*self._to_vectors((item_dxf.start, item_dxf.end)))
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        self._add(segment)

Fabrice Salvaire's avatar
Fabrice Salvaire committed

Fabrice Salvaire's avatar
Fabrice Salvaire committed
    ##############################################

    def _on_circle(self, item, is_arc):

Fabrice Salvaire's avatar
Fabrice Salvaire committed
        item_dxf = item.dxf
        center = self._to_vector(item_dxf.center)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        if is_arc:
Fabrice Salvaire's avatar
Fabrice Salvaire committed
            domain = AngularDomain(item_dxf.start_angle, item_dxf.end_angle)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        else:
            domain = None
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        circle = Circle2D(center, item_dxf.radius, domain=domain)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        self._add(circle)

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

Fabrice Salvaire's avatar
Fabrice Salvaire committed
    def _on_ellipse(self, item):
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        item_dxf = item.dxf
        center = self._to_vector(item_dxf.center)
        major_axis = self._to_vector(item_dxf.major_axis)
        minor_axis = major_axis * item_dxf.ratio
        domain = AngularDomain(item_dxf.start_param, item_dxf.end_param, degrees=False)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        radius_x, radius_y = major_axis.magnitude, minor_axis.magnitude
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        angle = major_axis.orientation
        if angle == 90:
Fabrice Salvaire's avatar
Fabrice Salvaire committed
            radius_x, radius_y = radius_y, radius_x
Fabrice Salvaire's avatar
Fabrice Salvaire committed
            angle = 0
        # Fixme: ...
        ellipse = Ellipse2D(
            center,
Fabrice Salvaire's avatar
Fabrice Salvaire committed
            radius_x, radius_y,
Fabrice Salvaire's avatar
Fabrice Salvaire committed
            angle,
            domain=domain,
        )
        self._add(ellipse)
Fabrice Salvaire's avatar
Fabrice Salvaire committed

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

    def _on_polyline(self, item):

        polyline = Polyline(item.closed)
        for x, y, s, e, b in item.get_points():
            polyline.add(Vector2D(x, y), b)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        geometry = polyline.geometry()
        self._add(geometry)
Fabrice Salvaire's avatar
Fabrice Salvaire committed

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

    def _on_spline(self, item):

        with item.edit_data() as data:
            points = self._to_vectors(data.control_points)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        item_dxf = item.dxf
        spline = BSpline2D(points, item_dxf.degree, item.closed)
Fabrice Salvaire's avatar
Fabrice Salvaire committed
        self._add(spline)