Newer
Older
####################################################################################################
#
# PyValentina - A Python implementation of Valentina Pattern Drafting Software
# 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 lxml import etree
from .Geometry.Vector2D import Vector2D
from .Geometry.Line2D import Line2D
from .Measurement import VitParser
####################################################################################################
_module_logger = logging.getLogger(__name__)
####################################################################################################
# Point
# trueDarts {'type': 'trueDarts', 'name1': 'A34', 'dartP2': '139', 'dartP1': '141', 'my2': '-3.87275', 'point2': '146', 'dartP3': '140', 'id': '144', 'mx2': '0.794387', 'my1': '-2.44561', 'name2': 'A35', 'point1': '145', 'baseLineP2': '63', 'mx1': '-3.64071', 'baseLineP1': '68'}
####################################################################################################
class Operation:
_logger = _module_logger.getChild('Operation')
##############################################
@staticmethod
def from_xml(element, pattern):
if element.tag == 'point':
return Point.from_xml(element, pattern)
elif element.tag == 'line':
return Line.from_xml(element, pattern)
elif element.tag == 'spline':
return Curve.from_xml(element, pattern)
else:
return Operation(pattern, element.attrib['id'])
##############################################
@staticmethod
def xml_attributes(element, pattern, attributes, keys):
attrib = element.attrib
kwargs = {key:attrib.get(attribute, None) for key, attribute in zip(keys, attributes)}
kwargs['pattern'] = pattern
return kwargs
##############################################
@property
def id(self):
return self._id
@property
def pattern(self):
return self._pattern
return self.__class__.__name__ + ' {0._id}'.format(self)
self._logger.info('Eval {}'.format(self))
self.eval_internal()
##############################################
def eval_internal(self):
pass
####################################################################################################
class Pattern:
_logger = _module_logger.getChild('Pattern')
def __init__(self, measurements):
self._measurements = measurements
self._evaluator = measurements.evaluator
@property
def measurements(self):
return self._measurements
##############################################
@property
def evaluator(self):
return self._evaluator
##############################################
@property
def operations(self):
return self._operations
##############################################
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
if operation is not None:
self._operations.append(operation)
self._operation_dict[operation.id] = operation
##############################################
def get_operation(self, id_):
return self._operation_dict[id_]
##############################################
def get_point(self, name):
return self._points[name]
##############################################
def eval(self):
for operation in self._operations:
if isinstance(operation, Point):
self._evaluator.add_point(operation)
operation.eval()
else:
pass
##############################################
def dump(self):
for operation in self._operations:
if isinstance(operation, Point):
print(operation, operation.vector)
else:
print(operation)
####################################################################################################
class LineProperties:
##############################################
def __init__(self, line_type=None, line_color=None):
self._line_type = line_type
self._line_color = line_color
##############################################
@property
def line_color(self):
return self._line_color
@property
def line_type(self):
return self._line_type
####################################################################################################
class Point(Operation):
##############################################
self._vector = None
##############################################
@property
def name(self):
return self._name
@property
def mx(self):
return self._mx
@property
def my(self):
return self._my
@property
def vector(self):
return self._vector
##############################################
@staticmethod
if element.tag != 'point':
raise ValueError
type_ = element.attrib['type']
if type_ == 'single':
return SinglePoint.from_xml(element, pattern)
return AlongLinePoint.from_xml(element, pattern)
return EndLinePoint.from_xml(element, pattern)
return LineIntersectPoint.from_xml(element, pattern)
return NormalPoint.from_xml(element, pattern)
return PointOfIntersectionPoint.from_xml(element, pattern)
##############################################
def _post_eval_internal(self):
self._logger.info('{0._name} {0._vector}'.format(self))
####################################################################################################
class SinglePoint(Point):
##############################################
# super(SinglePoint, self).__init__(id_, name, mx, my, line_type, line_color)
Point.__init__(self, pattern, id_, name, mx, my)
self._x = Expression(x, pattern.evaluator)
self._y = Expression(y, pattern.evaluator)
##############################################
@property
def x(self):
return self._x
@property
def y(self):
return self._y
##############################################
@staticmethod
# {'y': '1.05833', 'mx': '0.132292', 'type': 'single', 'my': '0.264583', 'id': '1', 'name': 'A0', 'x': '0.79375'}
kwargs = Operation.xml_attributes(element, pattern,
('id', 'name', 'x', 'y', 'mx', 'my'),
('id_', 'name', 'x', 'y', 'mx', 'my'))
return SinglePoint(**kwargs)
##############################################
def __repr__(self):
return self.__class__.__name__ + ' {0._name} = ({0._x}, {0._y})'.format(self)
##############################################
def eval_internal(self):
self._vector = Vector2D(self._x.value, self._y.value)
self._post_eval_internal()
####################################################################################################
class AlongLinePoint(Point, LineProperties):
##############################################
first_point, second_point, length,
mx=0, my=0,
line_type=None, line_color=None,
# super(AlongLinePoint, self).__init__(id_, name, mx, my, line_type, line_color)
Point.__init__(self, pattern, id_, name, mx, my)
self._first_point = pattern.get_operation(first_point)
self._second_point = pattern.get_operation(second_point)
self._length = Expression(length, pattern.evaluator)
##############################################
@property
def first_point(self):
return self._first_point
@property
def second_point(self):
return self._second_point
@property
def length(self):
return self._length
##############################################
@staticmethod
# {'lineColor': 'black', 'firstPoint': '138', 'id': '141', 'mx': '-4.2484', 'typeLine': 'none',
# 'my': '1.01162', 'name': 'A33', 'length': 'Line_A30_A32', 'type': 'alongLine', 'secondPoint': '68'}
kwargs = Operation.xml_attributes(element, pattern,
('id', 'name', 'firstPoint', 'secondPoint', 'length', 'mx', 'my', 'lineType', 'lineType'),
('id_', 'name', 'first_point', 'second_point', 'length', 'mx', 'my', 'line_type', 'line_type'))
return AlongLinePoint(**kwargs)
##############################################
def __repr__(self):
return self.__class__.__name__ + ' {0._name} = ({0._first_point.name}, {0._second_point.name}, {0._length})'.format(self)
##############################################
def eval_internal(self):
vector = self._second_point.vector - self._first_point.vector
self._pattern.evaluator.set_current_segment(vector)
self._vector = self._first_point.vector + vector.to_normalised()*self._length.value
self._pattern.evaluator.unset_current_segment()
self._post_eval_internal()
####################################################################################################
class EndLinePoint(Point, LineProperties):
##############################################
base_point, angle, length,
mx=0, my=0,
line_type=None, line_color=None,
# super(EndLinePoint, self).__init__(id_, name, mx, my, line_type, line_color)
Point.__init__(self, pattern, id_, name, mx, my)
self._base_point = pattern.get_operation(base_point)
self._angle = Expression(angle, pattern.evaluator)
self._length = Expression(length, pattern.evaluator)
##############################################
@property
def base_point(self):
return self._base_point
@property
def length(self):
return self._length
@property
def angle(self):
return self._angle
##############################################
@staticmethod
# {'basePoint': '1', 'name': 'A1', 'id': '2', 'angle': '0', 'length': 'waist_circ/2+10',
# 'typeLine': 'dashDotLine', 'my': '0.264583', 'type': 'endLine', 'mx': '0.132292', 'lineColor': 'black'}
kwargs = Operation.xml_attributes(element, pattern,
('id', 'name', 'basePoint', 'angle', 'length', 'mx', 'my', 'lineType', 'lineType'),
('id_', 'name', 'base_point', 'angle', 'length', 'mx', 'my', 'line_type', 'line_type'))
return EndLinePoint(**kwargs)
##############################################
def __repr__(self):
return self.__class__.__name__ + ' {0._name} = ({0._base_point.name}, {0._angle}, {0._length})'.format(self)
##############################################
def eval_internal(self):
self._vector = self._base_point._vector + Vector2D.from_angle(self._angle.value)*self._length.value
self._post_eval_internal()
####################################################################################################
class LineIntersectPoint(Point, LineProperties):
##############################################
point1_line1, point2_line1, point1_line2, point2_line2,
mx=0, my=0,
line_type=None, line_color=None,
# super(LineIntersectPoint, self).__init__(id_, name, mx, my, line_type, line_color)
Point.__init__(self, pattern, id_, name, mx, my)
self._point1_line1 = pattern.get_operation(point1_line1)
self._point2_line1 = pattern.get_operation(point2_line1)
self._point1_line2 = pattern.get_operation(point1_line2)
self._point2_line2 = pattern.get_operation(point2_line2)
##############################################
@property
def point1_line1(self):
return self._point1_line1
@property
def point2_line1(self):
return self._point2_line1
@property
def point1_line2(self):
return self._point1_line2
@property
def point2_line2(self):
return self._point2_line2
##############################################
@staticmethod
# {'type': 'lineIntersect', 'p2Line1': '32', 'mx': '0.132292', 'p1Line2': '10',
# 'p2Line2': '11', 'p1Line1': '27', 'id': '39', 'my': '0.264583', 'name': 'Cp'}
kwargs = Operation.xml_attributes(element, pattern,
('id', 'name', 'p1Line1', 'p2Line1', 'p1Line2', 'p2Line2', 'mx', 'my', 'lineType', 'lineType'),
('id_', 'name', 'point1_line1', 'point2_line1', 'point1_line2', 'point2_line2', 'mx', 'my', 'line_type', 'line_type'))
##############################################
def __repr__(self):
return self.__class__.__name__ + ' {0._name} = ({0._point1_line1.name}, {0._point2_line1.name}, {0._point1_line2.name}, {0._point2_line2.name})'.format(self)
##############################################
def eval_internal(self):
line1 = Line2D(self._point1_line1.vector, self._point2_line1.vector)
line2 = Line2D(self._point1_line2.vector, self._point2_line2.vector)
print(self._point1_line1.vector, self._point2_line1.vector)
print(self._point1_line2.vector, self._point2_line2.vector)
self._vector = line1.intersection(line2)
self._post_eval_internal()
####################################################################################################
class NormalPoint(Point, LineProperties):
##############################################
first_point, second_point, angle, length,
mx=0, my=0,
line_type=None, line_color=None,
# super(NormalPoint, self).__init__(id_, name, mx, my, line_type, line_color)
Point.__init__(self, pattern, id_, name, mx, my)
self._first_point = pattern.get_operation(first_point)
self._second_point = pattern.get_operation(second_point)
self._angle = Expression(angle, pattern.evaluator)
self._length = Expression(length, pattern.evaluator)
##############################################
@property
def first_point(self):
return self._first_point
@property
def second_point(self):
return self._second_point
@property
def angle(self):
return self._angle
@property
def length(self):
return self._length
##############################################
@staticmethod
# {'my': '-4.18524', 'secondPoint': '63', 'name': 'A36', 'angle': '0', 'length': '0.5',
# 'firstPoint': '138', 'typeLine': 'hair', 'type': 'normal', 'mx': '-1.57131', 'id': '147', 'lineColor': 'black'}
kwargs = Operation.xml_attributes(element, pattern,
('id', 'name', 'firstPoint', 'secondPoint', 'angle', 'length', 'lineType', 'lineType'),
('id_', 'name', 'first_point', 'second_point', 'angle', 'length', 'line_type', 'line_type'))
return NormalPoint(**kwargs)
##############################################
def __repr__(self):
return self.__class__.__name__ + ' {0._name} = ({0._first_point.name}, {0._second_point.name}, {0._angle}, {0._length})'.format(self)
##############################################
def eval_internal(self):
vector = self._second_point.vector - self._first_point.vector
self._pattern.evaluator.set_current_segment(vector)
direction = vector.to_normalised()
direction = direction.rotate_counter_clockwise_90()
angle = self._angle.value
if angle:
direction = direction.rotate_counter_clockwise(angle)
self._vector = self._first_point.vector + direction*self._length.value
self._pattern.evaluator.unset_current_segment()
self._post_eval_internal()
####################################################################################################
class PointOfIntersectionPoint(Point):
##############################################
def __init__(self, pattern, id_, name,
first_point, second_point,
# super(PointOfIntersectionPoint, self).__init__(id_, name, mx, my)
Point.__init__(self, pattern, id_, name, mx, my)
self._first_point = pattern.get_operation(first_point)
self._second_point = pattern.get_operation(second_point)
##############################################
@property
def first_point(self):
return self._first_point
@property
def second_point(self):
return self._second_point
##############################################
@staticmethod
# {'id': '71', 'secondPoint': '56', 'type': 'pointOfIntersection', 'firstPoint': '59', 'name': 'Nc', 'mx': '0.132292', 'my': '0.264583'}
kwargs = Operation.xml_attributes(element, pattern,
('id', 'name', 'firstPoint', 'secondPoint', 'mx', 'my'),
('id_', 'name', 'first_point', 'second_point', 'mx', 'my'))
##############################################
def __repr__(self):
return self.__class__.__name__ + ' {0._name} = ({0._first_point.name}, {0._second_point.name})'.format(self)
##############################################
def eval_internal(self):
self._vector = Vector2D(self._first_point.vector.x, self._second_point.vector.y)
self._post_eval_internal()
####################################################################################################
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
class Line(Operation, LineProperties):
##############################################
def __init__(self, pattern, id_,
first_point, second_point,
line_type=None, line_color=None,
):
Operation.__init__(self, pattern, id_)
LineProperties.__init__(self, line_type, line_color)
self._first_point = pattern.get_operation(first_point)
self._second_point = pattern.get_operation(second_point)
##############################################
@property
def first_point(self):
return self._first_point
@property
def second_point(self):
return self._second_point
##############################################
@staticmethod
def from_xml(element, pattern):
# {'typeLine': 'hair', 'lineColor': 'black', 'firstPoint': '74', 'secondPoint': '72', 'id': '76'}
kwargs = Operation.xml_attributes(element, pattern,
('id', 'firstPoint', 'secondPoint', 'lineType', 'lineType'),
('id_', 'first_point', 'second_point', 'line_type', 'line_type'))
return Line(**kwargs)
##############################################
def __repr__(self):
return self.__class__.__name__ + ' ({0._first_point.name}, {0._second_point.name})'.format(self)
##############################################
def eval_internal(self):
pass
####################################################################################################
class Curve(Operation, LineProperties):
##############################################
def __init__(self, pattern, id_,
first_point, second_point,
angle1, length1,
angle2, length2,
line_type=None, line_color=None,
):
Operation.__init__(self, pattern, id_)
LineProperties.__init__(self, line_type, line_color)
self._first_point = pattern.get_operation(first_point)
self._second_point = pattern.get_operation(second_point)
self._angle1 = Expression(angle1, pattern.evaluator)
self._length1 = Expression(length1, pattern.evaluator)
self._angle2 = Expression(angle2, pattern.evaluator)
self._length2 = Expression(length2, pattern.evaluator)
##############################################
@property
def first_point(self):
return self._first_point
@property
def second_point(self):
return self._second_point
@property
def angle1(self):
return self._angle1
@property
def length1(self):
return self._length1
@property
def angle2(self):
return self._angle2
@property
def length2(self):
return self._length2
##############################################
@staticmethod
def from_xml(element, pattern):
# 'type': 'simpleInteractive',
# 'length2': '8.65783', 'angle2': '85.3921',
# 'point4': '31',
# 'color': 'black',
# 'length1': '8.85757', 'angle1': '251.913',
# 'point1': '20',
# 'id': '97'
# }
kwargs = Operation.xml_attributes(element, pattern,
('id', 'point1', 'point4', 'angle1', 'length1', 'angle2', 'length2', 'lineType', 'lineType'),
('id_', 'first_point', 'second_point', 'angle1', 'length1', 'angle2', 'length2', 'line_type', 'line_type'))
return Curve(**kwargs)
##############################################
def __repr__(self):
return self.__class__.__name__ + ' ({0._first_point.name}, {0._second_point.name}, {0._angle1}, {0._length1}, {0._angle2}, {0._length2})'.format(self)
##############################################
def eval_internal(self):
pass
####################################################################################################
_logger = _module_logger.getChild('ValParser')
##############################################
def parse(self, val_path):
with open(val_path, 'rb') as f:
source = f.read()
tree = etree.fromstring(source)
measurements_path = self._get_xpath_element(tree, 'measurements').text
self._logger.info('Measurements loaded from ' + measurements_path)
measurements = VitParser().parse(measurements_path)
measurements.eval()
pattern = Pattern(measurements)
elements = self._get_xpath_element(tree, 'draw/calculation')
for element in elements:
operation = Operation.from_xml(element, pattern)