개정판 f155c8ad
issue #1445: transform 적용
Change-Id: Ie4beea559a5ca1d71887b0dff8bca431f9a2dd00
DTI_PID/DTI_PID/DEXPI/Equipment.py | ||
---|---|---|
3 | 3 |
|
4 | 4 |
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse, tostring |
5 | 5 |
from PyQt5.QtWidgets import * |
6 |
from PyQt5.QtGui import * |
|
7 |
from PyQt5.QtCore import * |
|
6 | 8 |
from .Extent import Extent |
7 | 9 |
from .Presentation import Presentation |
8 | 10 |
from .Shape import Point, Line as DEXPI_Line, ConnectionPoints, GenericAttributes, BsplineCurve |
... | ... | |
15 | 17 |
pass |
16 | 18 |
|
17 | 19 |
@staticmethod |
20 |
def to_transform(matrix: str) -> QTransform: |
|
21 |
"""convert given value to transform""" |
|
22 |
import sys |
|
23 |
import re |
|
24 |
|
|
25 |
res = None |
|
26 |
try: |
|
27 |
if 'matrix' in matrix: |
|
28 |
_str = matrix[len('matrix('):-1] |
|
29 |
tokens = _str.split(',') |
|
30 |
|
|
31 |
res = QTransform(float(tokens[0]), float(tokens[1]), |
|
32 |
float(tokens[2]), float(tokens[3]), |
|
33 |
float(tokens[4]), float(tokens[5])) |
|
34 |
else: |
|
35 |
float_re = '[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?' |
|
36 |
|
|
37 |
translate_trans = None |
|
38 |
if 'translate' in matrix: |
|
39 |
match = re.search(f"translate\({float_re},{float_re}\)", matrix) |
|
40 |
if match: |
|
41 |
_str = match.group()[len('translate('):-1] |
|
42 |
tokens = _str.split(',') |
|
43 |
|
|
44 |
translate_trans = QTransform() |
|
45 |
translate_trans.translate(float(tokens[0]), float(tokens[1])) |
|
46 |
|
|
47 |
scale_trans = None |
|
48 |
if 'scale' in matrix: |
|
49 |
match = re.search(f"scale\({float_re},{float_re}\)", matrix) |
|
50 |
if match: |
|
51 |
_str = match.group()[len('scale('):-1] |
|
52 |
tokens = _str.split(',') |
|
53 |
|
|
54 |
scale_trans = QTransform() |
|
55 |
scale_trans.scale(float(tokens[0]), float(tokens[1])) |
|
56 |
|
|
57 |
if translate_trans and scale_trans: |
|
58 |
res = scale_trans * translate_trans |
|
59 |
elif translate_trans: |
|
60 |
res = translate_trans |
|
61 |
elif scale_trans: |
|
62 |
res = scale_trans |
|
63 |
except Exception as ex: |
|
64 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \ |
|
65 |
f"{sys.exc_info()[-1].tb_lineno}" |
|
66 |
print(message) |
|
67 |
|
|
68 |
return res |
|
69 |
|
|
70 |
@staticmethod |
|
71 |
def apply_transform(trans: QTransform, pos: complex) -> complex: |
|
72 |
"""transform given pos and then return the result""" |
|
73 |
res = trans.map(QPointF(pos.real, pos.imag)) |
|
74 |
return complex(res.x(), res.y()) |
|
75 |
|
|
76 |
@staticmethod |
|
18 | 77 |
def to_xml(item) -> Element: |
19 | 78 |
"""return element for equipment""" |
20 | 79 |
import sys |
... | ... | |
31 | 90 |
node.attrib['ComponentType'] = 'Explicit' |
32 | 91 |
node.attrib['Status'] = 'Current' |
33 | 92 |
|
34 |
Presentation.to_xml(node, layer='0', color='0', line_type='0', line_weight=0.1, r=0, g=0, b=0)
|
|
93 |
Presentation.to_xml(node, layer='0', color='0', line_type='0', line_weight=1, r=0, g=0, b=0) |
|
35 | 94 |
Extent.to_xml(node, item=item) |
36 | 95 |
|
37 | 96 |
_node = SubElement(node, 'Position') |
... | ... | |
47 | 106 |
_node.attrib['Context'] = 'ID2' |
48 | 107 |
|
49 | 108 |
svg = item.to_svg(parent=None) |
109 |
matrix_trans = None |
|
110 |
if 'transform' in svg[0].attrib: |
|
111 |
matrix_trans = Equipment.to_transform(svg[0].attrib['transform']) |
|
112 |
|
|
50 | 113 |
paths = svg[0].findall('path') |
51 | 114 |
for path in paths: |
115 |
_trans = Equipment.to_transform(path.attrib['transform']) |
|
116 |
trans = _trans * matrix_trans |
|
52 | 117 |
path_ele = parse_path(path.attrib['d']) |
53 | 118 |
for idx, ele in enumerate(path_ele): |
54 | 119 |
if type(ele) is Move: |
55 | 120 |
continue |
56 | 121 |
elif type(ele) is Line: |
57 |
line = DEXPI_Line(ele.start, ele.end) |
|
122 |
line = DEXPI_Line(Equipment.apply_transform(trans, ele.start), |
|
123 |
Equipment.apply_transform(trans, ele.end)) |
|
58 | 124 |
node.append(line.to_xml()) |
59 | 125 |
elif type(ele) is Arc: |
60 | 126 |
continue |
61 | 127 |
elif type(ele) is CubicBezier: |
62 |
bspline_curve_node = BsplineCurve.to_xml(controls=[ele.start, ele.control1, |
|
63 |
ele.control2, ele.end], |
|
128 |
bspline_curve_node = BsplineCurve.to_xml(controls=[Equipment.apply_transform(trans, ele.start), |
|
129 |
Equipment.apply_transform(trans, ele.control1), |
|
130 |
Equipment.apply_transform(trans, ele.control2), |
|
131 |
Equipment.apply_transform(trans, ele.end)], |
|
64 | 132 |
_type='BsplineCurve', knots=[]) |
65 | 133 |
node.append(bspline_curve_node) |
66 | 134 |
elif type(ele) is QuadraticBezier: |
DTI_PID/DTI_PID/DEXPI/Extent.py | ||
---|---|---|
16 | 16 |
|
17 | 17 |
rect = None |
18 | 18 |
if item: |
19 |
rect = item.boundingRect()
|
|
19 |
rect = item.sceneBoundingRect()
|
|
20 | 20 |
elif scene: |
21 | 21 |
rect = scene.itemsBoundingRect() |
22 | 22 |
|
... | ... | |
25 | 25 |
_min.attrib['Y'] = str(rect.top()) |
26 | 26 |
_min.attrib['Z'] = '0' |
27 | 27 |
_max = SubElement(_node, 'Max') |
28 |
_max.attrib['X'] = str(rect.right())
|
|
28 |
_max.attrib['X'] = str(rect.right()) |
|
29 | 29 |
_max.attrib['Y'] = str(rect.bottom()) |
30 | 30 |
_max.attrib['Z'] = '0' |
31 | 31 |
|
DTI_PID/DTI_PID/DEXPI/Shape.py | ||
---|---|---|
92 | 92 |
knot_node.text = f"{knot}" |
93 | 93 |
|
94 | 94 |
weights_node = SubElement(node, 'WeightsData') |
95 |
for control in controls:
|
|
95 |
for idx, control in enumerate(controls):
|
|
96 | 96 |
weight_node = SubElement(weights_node, 'ControlPointWeight') |
97 |
weight_node.text = '1' |
|
97 |
weight_node.text = '1' if idx == 0 or idx == len(controls) - 1 else '0.5'
|
|
98 | 98 |
|
99 | 99 |
return node |
100 | 100 |
|
내보내기 Unified diff