Newer
Older
####################################################################################################
#
# 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/>.
#
####################################################################################################
####################################################################################################
import logging
from Patro.GeometryEngine.Vector import Vector2D
from Patro.GraphicEngine.GraphicScene.GraphicItem import GraphicStyle, Font
from Patro.GraphicEngine.GraphicScene.Scene import GraphicScene
from . import Calculation
####################################################################################################
_module_logger = logging.getLogger(__name__)
####################################################################################################
class Pattern:
_logger = _module_logger.getChild('Pattern')
self._measurements = measurements
self._calculations = []
self._calculation_dict = {}
@property
def measurements(self):
return self._measurements
@property
def calculator(self):
return self._calculator
@property
def unit(self):
return self._unit
##############################################
def calculations(self):
return self._calculations
self._calculation_dict[calculation.id] = calculation
if hasattr(calculation, 'name'):
self._calculation_dict[calculation.name] = calculation
##############################################
return len(self._calculations) + 1 # id > 0
def has_calculation_id(self, id):
return id in self._calculation_dict
##############################################
def get_calculation(self, id):
return self._calculation_dict[id]
##############################################
def eval(self):
self._logger.info('Eval all calculations')
for calculation in self._calculations:
if isinstance(calculation, Calculation.Point):
self._calculator.add_point(calculation)
calculation.eval()
elif isinstance(calculation, Calculation.SimpleInteractiveSpline):
calculation.eval() # for control points
##############################################
def dump(self):
print("\nDump calculations:")
for calculation in self._calculations:
if isinstance(calculation, Calculation.Point):
print(calculation, calculation.vector)
for dependency in calculation.dependencies:
print(' ->', dependency)
##############################################
def bounding_box(self):
for calculation in self._calculations:
interval = calculation.geometry().bounding_box
if bounding_box is None:
bounding_box = interval
else:
bounding_box |= interval
return bounding_box
##############################################
def _calculation_to_path_style(self, calculation, **kwargs):
"""Generate a :class:`GraphicStyle` instance for a calculation"""
stroke_style=calculation.line_style,
stroke_color=calculation.line_color,
**kwargs
)
##############################################
def detail_scene(self, scene_cls=GraphicScene):
"""Generate a graphic scene for the detail mode
Scene class can be customised using the *scene_cls* parameter.
# Fixme: implement a transformer class to prevent if ... ?
for calculation in self._calculations:
if isinstance(calculation, Calculation.Point):
scene.add_coordinate(calculation.name, calculation.vector)
# Draw point and label
scene.circle(calculation.name, '1pt',
GraphicStyle(fill_color='black'),
user_data=calculation,
)
label_offset = calculation.label_offset
offset = Vector2D(label_offset.x, -label_offset.y) # Fixme: ???
label_position = calculation.vector + offset
if offset:
# arrow must point to the label center and be clipped
scene.segment(calculation.vector, label_position,
GraphicStyle(line_width='.5pt'),
user_data=calculation,
)
scene.text(label_position, calculation.name, font, user_data=calculation)
if isinstance(calculation, Calculation.LinePropertiesMixin):
path_style = self._calculation_to_path_style(calculation, line_width='2pt')
if isinstance(calculation, Calculation.AlongLinePoint):
scene.segment(calculation.first_point.name, calculation.name,
path_style,
user_data=calculation,
)
elif isinstance(calculation, Calculation.EndLinePoint):
scene.segment(calculation.base_point.name, calculation.name,
path_style,
user_data=calculation,
)
# elif isinstance(calculation, LineIntersectPoint):
# scene.segment(calculation.point1_line1.name, calculation.name, path_style)
# source += r'\draw[{0}] ({1.point1_line1.name}) -- ({1.name});'.format(style, calculation) + '\n'
elif isinstance(calculation, Calculation.NormalPoint):
scene.segment(calculation.first_point.name, calculation.name,
path_style,
user_data=calculation,
)
# Draw path item like segments and Bézier curves
elif isinstance(calculation, Calculation.Line):
path_style = self._calculation_to_path_style(calculation, line_width='4pt')
scene.segment(calculation.first_point.name, calculation.second_point.name,
path_style,
user_data=calculation,
)
elif isinstance(calculation, Calculation.SimpleInteractiveSpline):
path_style = self._calculation_to_path_style(calculation, line_width='4pt')
scene.cubic_bezier(calculation.first_point.name,
calculation.control_point1, calculation.control_point2,
calculation.second_point.name,
path_style,
user_data=calculation,
)