프로젝트

일반

사용자정보

개정판 2374ffa5

ID2374ffa52cf97a0149cb60478389301d82561e21
상위 4747c73a
하위 e8f57e0a

HUMKYUNG 이(가) 약 4년 전에 추가함

issue #1059: Add to_svg method to all of shape class

Change-Id: I5c3795171ee612779d7f4dbebe6cfb2989dc6e06

차이점 보기:

HYTOS/HYTOS/MainWindow.py
1545 1545
                      f"{sys.exc_info()[-1].tb_lineno}"
1546 1546
            self.addMessage.emit(MessageType.Error, message)
1547 1547

  
1548
    def on_generate_report(self):
1548
    def on_generate_report(self) -> None:
1549 1549
        """generate calculation report"""
1550 1550
        from tempfile import NamedTemporaryFile
1551 1551
        import openpyxl
HYTOS/HYTOS/QtImageViewer.py
570 570
                      f"{sys.exc_info()[-1].tb_lineno}"
571 571
            App.mainWnd().addMessage.emit(MessageType.Error, message)
572 572

  
573
    def save_as_svg(self, file_path):
574
        """ save scene as given file """
575
        from xml.etree.ElementTree import Element, tostring, SubElement, dump, ElementTree, parse
576
        from PyQt5.QtSvg import QSvgGenerator
577
        import cairosvg
578

  
579
        def prettify(elem):
580
            """Return a pretty-printed XML string for the Element."""
581
            from xml.etree import ElementTree
582
            from xml.dom import minidom
583

  
584
            try:
585
                rough_string = ElementTree.tostring(elem, 'utf-8')
586
                reparsed = minidom.parseString(rough_string)
587
                return reparsed.toprettyxml(indent="  ")
588
            except Exception as ex:
589
                from AppDocData import MessageType
590

  
591
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
592
                                                               sys.exc_info()[-1].tb_lineno)
593
                self.display_message.emit(MessageType.Error, message)
594

  
595
        try:
596
            rect = self.scene.itemsBoundingRect()
597

  
598
            svg = Element('svg')
599
            svg.attrib['width'] = f"{rect.width()}"
600
            svg.attrib['height'] = f"{rect.height()}"
601
            svg.attrib['viewBox'] = f"{rect.left()} {rect.top()} {rect.width()} {rect.height()}"
602
            svg.attrib['xmlns'] = 'http://www.w3.org/2000/svg'
603
            svg.attrib['xmlns:xlink'] = "http://www.w3.org/1999/xlink"
604
            svg.attrib['xmlns:inkscape'] = "http://www.inkscape.org/namespaces/inkscape"
605
            svg.attrib['version'] = "1.1"
606
            svg.attrib['baseProfile'] = "tiny"
607

  
608
            for item in self.scene.items():
609
                if hasattr(item, 'to_svg'):
610
                    node = item.to_svg(None)
611
                    if node:
612
                        svg.extend(node)
613

  
614
            with open(file_path, 'w', encoding='utf-8') as output_file:
615
                output_file.write(prettify(svg))
616

  
617
            cairosvg.svg2png(url=file_path, write_to="d:\\temp\\temp.png")
618

  
619

  
620
            """
621
            generator = QSvgGenerator()
622
            generator.setFileName(file_path)
623
            default = QSize(1550, 990)
624
            generator.setSize(default)
625

  
626
            painter = QPainter()
627
            # render the scene
628
            painter.begin(generator)
629
            self.render(painter)
630
            painter.end()
631
            """
632

  
633
            # save the image to a given file
634
            # image.save(file_path)
635
        except Exception as ex:
636
            from App import App
637
            from AppDocData import MessageType
638

  
639
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
640
                      f"{sys.exc_info()[-1].tb_lineno}"
641
            App.mainWnd().addMessage.emit(MessageType.Error, message)
642

  
643

  
573 644
if __name__ == '__main__':
574 645
    import sys
575 646
    try:
HYTOS/HYTOS/Shapes/EngineeringAbstractItem.py
185 185

  
186 186
        return res
187 187

  
188
    def getAttributes(self):
189
        _attrs = {}
190
        try:
191
            from AppDocData import AppDocData
192
            from SymbolSvgItem import SymbolSvgItem
193
            from EngineeringLineItem import QEngineeringLineItem
194

  
195
            """ get attributes of item from database """
196
            docData = AppDocData.instance()
197
            symbolAttrs = docData.getSymbolAttribute(self.type) if type(
198
                self) is not QEngineeringLineItem else docData.getSymbolAttribute('Line')
199
            targetAttrs = []
200
            if type(self) is not QEngineeringLineItem:
201
                for attr in symbolAttrs:
202
                    if attr.Target is None or attr.Target == 'ALL' or [target for target in attr.Target.split(',') if
203
                                                                       self.dbUid is int(target)]:
204
                        targetAttrs.append(attr)
205

  
206
            _texts = self.texts()
207
            _symbols = self.symbols()
208
            for attr in targetAttrs:
209
                matches = [_attr for _attr, _ in self.attrs.items() if _attr.UID == attr.UID]
210
                if matches:
211
                    attr.Freeze = matches[0].Freeze  ### update freeze value
212
                    attr.AssocItem = matches[0].AssocItem
213
                    _attrs[attr] = self.attrs[matches[0]]  ### copy attribute value
214
                else:
215
                    _attrs[attr] = ''
216

  
217
                if attr.Freeze: continue  ### do not evalulate value if attribute is frozen
218
                if attr.AttributeType == 'Text Item' or attr.AttributeType == 'Valve Oper Code':
219
                    at = int(attr.AttrAt)
220
                    items = [text for text in _texts if QEngineeringAbstractItem.assoc_type(text) == attr.AttributeType]
221
                    if not attr.AssocItem and len(items) > at:
222
                        attr.AssocItem = items[at]
223
                        item = attr.AssocItem
224
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
225
                    elif attr.AssocItem:
226
                        item = attr.AssocItem
227
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
228
                    else:
229
                        _attrs[attr] = ''
230
                if attr.AttributeType == 'Size Text Item':
231
                    at = int(attr.AttrAt)
232
                    items = [text for text in _texts if QEngineeringAbstractItem.assoc_type(text) == attr.AttributeType]
233
                    if not attr.AssocItem and len(items) > at:
234
                        attr.AssocItem = items[at]
235
                        item = attr.AssocItem
236
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
237
                    else:
238
                        item = attr.AssocItem
239
                        _attrs[attr] = eval(attr.Expression) if attr.Expression and (
240
                                    (item and 'item' in attr.Expression) or 'self' in attr.Expression) else ''
241
                elif attr.AttributeType == 'Symbol Item':
242
                    at = int(attr.AttrAt)
243
                    if not attr.AssocItem and len(_symbols) > at:
244
                        attr.AssocItem = _symbols[at]
245
                        item = attr.AssocItem
246
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
247
                    elif attr.AssocItem:
248
                        item = attr.AssocItem
249
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
250
                    else:
251
                        _attrs[attr] = ''
252

  
253
            for _attr, _value in _attrs.items():
254
                if _value is None or _value == '':
255
                    _attr.AssocItem = None
256

  
257
            self.attrs = _attrs  ### assign self.attrs
258
        except Exception as ex:
259
            from App import App
260
            from AppDocData import MessageType
261

  
262
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
263
                                                           sys.exc_info()[-1].tb_lineno)
264
            App.mainWnd().addMessage.emit(MessageType.Error, message)
265

  
266
        return self.attrs
267

  
268 188
    def attrib(self, name):
269 189
        """ return the value of given attribute with name """
270 190
        matches = [(attr, value) for attr, value in self.getAttributes().items() if attr.Attribute == name]
HYTOS/HYTOS/Shapes/EngineeringArrowItem.py
32 32

  
33 33
        self.setFlag(QGraphicsItem.ItemIsSelectable, False) 
34 34
        self.setFlag(QGraphicsItem.ItemIsFocusable, False) 
35
        self.setFlag(QGraphicsItem.ItemStacksBehindParent, True)
35
        self.setFlag(QGraphicsItem.ItemStacksBehindParent, True)
36

  
37
    def to_svg(self, parent) -> list:
38
        """convert arrow item to svg"""
39
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
40

  
41
        res = []
42

  
43
        scene_pos = self.scenePos()
44

  
45
        node = Element('g')
46
        node.attrib['stroke'] = self.pen().color().name()
47
        node.attrib['stroke-width'] = str(self.pen().widthF())
48

  
49
        polyline = SubElement(node, 'polyline')
50
        polyline.attrib['fill'] = self.pen().color().name()
51

  
52
        points = []
53
        polygon = self.polygon()
54
        for at in range(polygon.count()):
55
            ele = polygon.at(at)
56
            points.append(f"{scene_pos.x() + ele.x()},{scene_pos.y() + ele.y()}")
57
        polyline.attrib['points'] = ' '.join(points)
58

  
59
        res.append(node)
60
        return res
HYTOS/HYTOS/Shapes/EngineeringCalloutTextItem.py
78 78

  
79 79
    '''
80 80
        @brief      hover event
81
        @authro     humkyung
81
        @author     humkyung
82 82
        @date       
83 83
    '''
84 84

  
......
238 238

  
239 239
        return res
240 240

  
241
    def contextMenuEvent(self, event: 'QGraphicsSceneContextMenuEvent') -> None:
242
        """ignore context menu"""
243
        event.ignore()
241
    def to_svg(self, parent) -> list:
242
        """convert text item to svg"""
243
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
244
        from App import App
245

  
246
        res = []
247
        try:
248
            node = None
249
            if parent is None or str(self.owner) == str(parent):
250
                app_doc_data = AppDocData.instance()
251

  
252
                node = Element('g')
253
                node.attrib['id'] = str(self.uid)
254
                node.attrib['font-family'] = self.font().family()
255
                node.attrib['font-size'] = str(self.font().pointSizeF())
256
                node.attrib['font-weight'] = str(self.font().weight())
257

  
258
                inverted = QTransform()
259
                if parent:
260
                    trans = parent.sceneTransform()
261
                    inverted, _ = trans.inverted()
262

  
263
                trans = self.sceneTransform()
264

  
265
                trans = trans * inverted
266
                node.attrib['transform'] = f"matrix(" \
267
                                           f"{trans.m11()},{trans.m12()}," \
268
                                           f"{trans.m21()},{trans.m22()}," \
269
                                           f"{trans.m31()},{trans.m32()}" \
270
                                           f")"
271
                text = Element('text')
272
                text.attrib['textLength'] = str(self.boundingRect().width())
273
                text.attrib['lengthAdjust'] = 'spacingAndGlyphs'
274
                text.attrib['xml:space'] = 'preserve'
275
                tokens = self.toPlainText().split('\n')
276
                if len(tokens) > 1:
277
                    for token in tokens:
278
                        tspan = SubElement(text, 'tspan')
279
                        tspan.attrib['x'] = "0"
280
                        tspan.attrib['dy'] = str(self.font().pointSizeF() + 1)
281
                        tspan.text = token
282
                else:
283
                    text.text = self.toPlainText()
284

  
285
                text.attrib['alignment-baseline'] = 'hanging'  # align left-top corner
286
                node.append(text)
287

  
288
                bounding = self.boundingRect()
289
                rect = SubElement(node, 'rect')
290
                rect.attrib['x'] = str(bounding.x())
291
                rect.attrib['y'] = str(bounding.y())
292
                rect.attrib['width'] = str(bounding.width())
293
                rect.attrib['height'] = str(bounding.height())
294
                rect.attrib['stroke'] = "#000000"
295
                rect.attrib['style'] = "fill:none"
296

  
297
                res.append(node)
298
        except Exception as ex:
299
            from App import App
300
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
301
                                                           sys.exc_info()[-1].tb_lineno)
302
            App.mainWnd().addMessage.emit(MessageType.Error, message)
303

  
304
        return res
244 305

  
245 306
'''
246 307
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
HYTOS/HYTOS/Shapes/EngineeringEqpDescTextItem.py
85 85

  
86 86
        return res
87 87

  
88
    def to_svg(self, parent) -> list:
89
        """convert text item to svg"""
90
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
91
        from App import App
92

  
93
        res = []
94
        try:
95
            node = None
96
            if parent is None or str(self.owner) == str(parent):
97
                rect = self.boundingRect()
98

  
99
                node = Element('g')
100
                node.attrib['font-family'] = self.font().family()
101
                node.attrib['font-size'] = str(self.font().pointSizeF())
102
                node.attrib['font-weight'] = str(self.font().weight())
103

  
104
                text = Element('text')
105
                # text.attrib['textLength'] = str(self.boundingRect().width())
106
                text.attrib['x'] = str(self.scenePos().x())
107
                text.attrib['y'] = str(self.scenePos().y() + self.font().pointSizeF() * 0.5)
108
                text.attrib['lengthAdjust'] = 'spacingAndGlyphs'
109
                tokens = self.toPlainText().split('\n')
110
                if len(tokens) > 1:
111
                    for token in tokens:
112
                        tspan = SubElement(text, 'tspan')
113
                        tspan.attrib['x'] = str(self.scenePos().x())
114
                        tspan.attrib['dy'] = node.attrib['font-size']
115
                        tspan.text = token
116
                else:
117
                    text.text = self.toPlainText()
118

  
119
                # text.attrib['alignment-baseline'] = 'middle'
120
                # text.attrib['text-anchor'] = 'middle'  # align left-top corner
121
                node.append(text)
122

  
123
                res.append(node)
124
        except Exception as ex:
125
            from App import App
126
            from AppDocData import MessageType
127

  
128
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
129
                                                           sys.exc_info()[-1].tb_lineno)
130
            App.mainWnd().addMessage.emit(MessageType.Error, message)
131

  
132
        return res
133

  
88 134
    """
89 135
    def paint(self, painter, options=None, widget=None):
90 136
        painter.drawText(QRectF(self.pos(), QSizeF(self.boundingRect().width(), self.boundingRect().height())),
HYTOS/HYTOS/Shapes/EngineeringStreamNoTextItem.py
59 59
        """call parent's mouseDoubleClickEvent"""
60 60
        self.parentItem().mouseDoubleClickEvent(event)
61 61

  
62
    def to_svg(self, parent) -> list:
63
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
64

  
65
        res = []
66

  
67
        scene_pos = self.scenePos()
68

  
69
        node = Element('g')
70
        node.attrib['stroke'] = self.pen().color().name()
71
        node.attrib['stroke-width'] = str(self.pen().widthF())
72

  
73
        polyline = SubElement(node, 'polyline')
74
        polyline.attrib['fill'] = 'none'
75

  
76
        points = []
77
        painter_path = self.path()
78
        for at in range(painter_path.elementCount()):
79
            ele = painter_path.elementAt(at)
80
            if ele.isMoveTo() or ele.isLineTo():
81
                points.append(f"{scene_pos.x() + ele.x},{scene_pos.y() + ele.y}")
82
        polyline.attrib['points'] = ' '.join(points)
83

  
84
        res.append(node)
85
        return res
86

  
62 87

  
63 88
class QEngineeringStreamNoTextItem(QGraphicsTextItem):
64 89
    """ This is engineering stream no text item class """
......
136 161
    def mouseDoubleClickEvent(self, event):
137 162
        """call parent's mouseDoubleClickEvent"""
138 163
        self.parentItem().mouseDoubleClickEvent(event)
164

  
165
    def to_svg(self, parent) -> list:
166
        """convert text item to svg"""
167
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
168
        from App import App
169

  
170
        res = []
171
        try:
172
            node = None
173
            if parent is None or str(self.owner) == str(parent):
174
                app_doc_data = AppDocData.instance()
175

  
176
                node = Element('g')
177
                node.attrib['font-family'] = self.font().family()
178
                node.attrib['font-size'] = str(self.font().pointSizeF())
179
                node.attrib['font-weight'] = str(self.font().weight())
180

  
181
                """
182
                inverted = QTransform()
183
                if parent:
184
                    trans = parent.sceneTransform()
185
                    inverted, _ = trans.inverted()
186

  
187
                trans = self.sceneTransform()
188
                trans = trans * inverted
189
                node.attrib['transform'] = f"matrix(" \
190
                                           f"{trans.m11()},{trans.m12()}," \
191
                                           f"{trans.m21()},{trans.m22()}," \
192
                                           f"{trans.m31()},{trans.m32()}" \
193
                                           f")"
194
                """
195
                rect = self.boundingRect()
196
                text = Element('text')
197
                text.attrib['x'] = str(self.scenePos().x() + rect.width() * 0.5)
198
                text.attrib['y'] = str(self.scenePos().y() + rect.height() * 0.5)
199
                text.attrib['lengthAdjust'] = 'spacingAndGlyphs'
200
                text.text = self.toPlainText()
201
                text.attrib['alignment-baseline'] = 'middle'
202
                text.attrib['text-anchor'] = 'middle'  # align left-top corner
203
                node.append(text)
204

  
205
                res.append(node)
206
        except Exception as ex:
207
            from App import App
208
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
209
                                                           sys.exc_info()[-1].tb_lineno)
210
            App.mainWnd().addMessage.emit(MessageType.Error, message)
211

  
212
        return res
HYTOS/HYTOS/Shapes/EngineeringStreamlineItem.py
1150 1150

  
1151 1151
        return item
1152 1152

  
1153
    def to_svg(self, parent) -> list:
1154
        """convert line item to svg"""
1155
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
1156
        from App import App
1157
        from AppDocData import AppDocData
1158

  
1159
        res = []
1160
        try:
1161
            app_doc_data = AppDocData.instance()
1162

  
1163
            node = Element('g')
1164
            node.attrib['id'] = str(self.uid)
1165
            node.attrib['stroke'] = self.pen().color().name()
1166
            node.attrib['stroke-width'] = str(self.pen().widthF())
1167
            if not parent:
1168
                trans = QTransform()
1169
            else:
1170
                trans, _ = parent.sceneTransform().inverted()
1171

  
1172
            node.attrib['transform'] = f"matrix(" \
1173
                                       f"{trans.m11()},{trans.m12()}," \
1174
                                       f"{trans.m21()},{trans.m22()}," \
1175
                                       f"{trans.m31()},{trans.m32()}" \
1176
                                       f")"
1177

  
1178
            polyline = Element('polyline')
1179
            polyline.attrib['fill'] = 'none'
1180

  
1181
            points = []
1182
            for vertex in self._vertices:
1183
                points.append(f"{vertex[0]},{vertex[1]}")
1184
            polyline.attrib['points'] = ' '.join(points)
1185

  
1186
            node.append(polyline)
1187

  
1188
            res.append(node)
1189
        except Exception as ex:
1190
            from App import App
1191
            from AppDocData import MessageType
1192
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1193
                                                           sys.exc_info()[-1].tb_lineno)
1194
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1195

  
1196
        return res
1153 1197

  
1154 1198
'''
1155 1199
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
HYTOS/HYTOS/Shapes/SymbolSvgItem.py
2074 2074
        anim.setDuration(10000)
2075 2075
        anim.start()
2076 2076

  
2077
    def to_svg(self, parent) -> list:
2078
        """convert symbol svg item to svg"""
2079
        import re
2080
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
2081
        from App import App
2082

  
2083
        res = []
2084
        try:
2085
            app_doc_data = AppDocData.instance()
2086

  
2087
            node = Element('g')
2088
            node.attrib['id'] = str(self.uid)
2089
            node.attrib['stroke'] = "#000000"
2090
            node.attrib['stroke-width'] = "1.0"
2091

  
2092
            trans = self.sceneTransform()
2093
            node.attrib['transform'] = f"matrix(" \
2094
                                       f"{trans.m11()},{trans.m12()}," \
2095
                                       f"{trans.m21()},{trans.m22()}," \
2096
                                       f"{trans.m31()},{trans.m32()}" \
2097
                                       f")"
2098

  
2099
            node_list = self._document.elementsByTagName('path')
2100
            for at in range(node_list.count()):
2101
                path = Element('path')
2102
                path.attrib['style'] = 'fill:none'
2103
                path.attrib['d'] = node_list.item(at).attributes().namedItem('d').nodeValue()
2104
                item = node_list.item(at).attributes().namedItem('transform')
2105
                if item:
2106
                    path.attrib['transform'] = item.nodeValue()
2107
                node.append(path)
2108

  
2109
            rect_list = self._document.elementsByTagName('rect')
2110
            for at in range(rect_list.count()):
2111
                rect = Element('rect')
2112
                rect.attrib['style'] = 'fill:none'
2113
                rect.attrib['x'] = rect_list.item(at).attributes().namedItem('x').nodeValue()
2114
                rect.attrib['y'] = rect_list.item(at).attributes().namedItem('y').nodeValue()
2115
                rect.attrib['width'] = rect_list.item(at).attributes().namedItem('width').nodeValue()
2116
                rect.attrib['height'] = rect_list.item(at).attributes().namedItem('height').nodeValue()
2117
                node.append(rect)
2118

  
2119
            ellipse_list = self._document.elementsByTagName('ellipse')
2120
            for at in range(ellipse_list.count()):
2121
                ellipse = Element('ellipse')
2122
                ellipse.attrib['style'] = 'fill:none'
2123
                item = ellipse_list.item(at).attributes().namedItem('transform')
2124
                if item:
2125
                    ellipse.attrib['transform'] = item.nodeValue()
2126
                ellipse.attrib['cx'] = ellipse_list.item(at).attributes().namedItem('cx').nodeValue()
2127
                ellipse.attrib['cy'] = ellipse_list.item(at).attributes().namedItem('cy').nodeValue()
2128
                ellipse.attrib['rx'] = ellipse_list.item(at).attributes().namedItem('rx').nodeValue()
2129
                ellipse.attrib['ry'] = ellipse_list.item(at).attributes().namedItem('ry').nodeValue()
2130
                node.append(ellipse)
2131

  
2132
            res.append(node)
2133
        except Exception as ex:
2134
            from App import App
2135
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2136
                                                           sys.exc_info()[-1].tb_lineno)
2137
            App.mainWnd().addMessage.emit(MessageType.Error, message)
2138

  
2139
        return res
2140

  
2077 2141

  
2078 2142
def recursiveChangeAttributes(node, attName, attValue):
2079 2143
    while not node.isNull():

내보내기 Unified diff

클립보드 이미지 추가 (최대 크기: 500 MB)