hytos / DTI_PID / DTI_PID / LineNoTracer.py @ 8a48a60b
이력 | 보기 | 이력해설 | 다운로드 (20.8 KB)
1 |
# coding: utf-8
|
---|---|
2 |
"""
|
3 |
This is line no tracer module
|
4 |
"""
|
5 | |
6 |
import sys |
7 |
import math |
8 |
import shapely |
9 |
from AppDocData import AppDocData, MessageType |
10 |
from EngineeringLineItem import QEngineeringLineItem |
11 |
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem |
12 |
from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem |
13 |
from SymbolSvgItem import SymbolSvgItem |
14 |
from EngineeringTextItem import QEngineeringTextItem |
15 |
from EngineeringUnknownItem import QEngineeringUnknownItem |
16 |
try:
|
17 |
from PyQt5.QtCore import * |
18 |
from PyQt5.QtGui import * |
19 |
from PyQt5.QtWidgets import * |
20 |
except ImportError: |
21 |
try:
|
22 |
from PyQt4.QtCore import * |
23 |
from PyQt4.QtGui import * |
24 |
except ImportError: |
25 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
26 | |
27 |
class LineNoTracer: |
28 |
'''
|
29 |
@history 2018.04.26 Jeongwoo Variable name changed (texts → lineNos)
|
30 |
'''
|
31 |
def __init__(self, symbols, lines, lineNos, specBreak, lineIndicator): |
32 |
try:
|
33 |
self._symbols = symbols
|
34 |
#for symbol in self._symbols: symbol.owner = None
|
35 |
self._lines = lines
|
36 |
#for line in self._lines: line.owner = None
|
37 |
self._lineNos = lineNos
|
38 |
self._specBreak = specBreak
|
39 |
self._specBreakUID = []
|
40 |
self._lineIndicator = lineIndicator
|
41 |
|
42 |
for spec in self._specBreak: |
43 |
for attr in spec.attrs: |
44 |
if type(attr) is tuple and attr[1] != '': |
45 |
self._specBreakUID.append(attr[1]) |
46 | |
47 |
except Exception as ex: |
48 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
49 | |
50 |
'''
|
51 |
@brief find primary lines connected to given line no
|
52 |
@author humkyung
|
53 |
'''
|
54 |
def findPrimaryLines(self, lineno): |
55 |
from EngineeringLineItem import QEngineeringLineItem |
56 |
from EngineeringRunItem import QEngineeringRunItem |
57 | |
58 |
connectedItems = [] |
59 |
if 1 == len(lineno.conns): |
60 |
connectedItems = self.findConnectedObjects(lineno.conns[0], toler=10) |
61 |
for item in connectedItems: |
62 |
item.owner = lineno # set item's owner
|
63 |
item.linkedItem = lineno |
64 |
|
65 |
pipeRun = QEngineeringRunItem() |
66 |
pipeRun.items = connectedItems |
67 |
lineno.runs.append(pipeRun) |
68 | |
69 |
return connectedItems
|
70 | |
71 |
'''
|
72 |
@brief find secondary lines
|
73 |
@author humkyung
|
74 |
'''
|
75 |
def findSecondaryLines(self, lines): |
76 |
from EngineeringLineItem import QEngineeringLineItem |
77 |
from EngineeringRunItem import QEngineeringRunItem |
78 | |
79 |
try:
|
80 |
foundCount = 1
|
81 |
while foundCount:
|
82 |
foundCount = 0
|
83 |
notMatches = [] |
84 |
for line in lines: |
85 |
if line.linkedItem is not None: continue |
86 | |
87 |
matches = [x for x in self._lines if x.linkedItem is not None and x.isConnectable(line)] |
88 |
if matches:
|
89 |
foundCount += 1
|
90 |
connectedItems = self.findConnectedObjects(line, toler=10) |
91 |
# set connection object
|
92 |
for idx in range(len(line.connectors)): |
93 |
if line.connectors[idx].connectedItem is None: line.connectors[idx].connectedItem = matches[0] |
94 |
# up to here
|
95 |
for item in connectedItems: |
96 |
item.owner = matches[0].owner # set item's owner |
97 |
item.linkedItem = matches[0].owner
|
98 | |
99 |
pipeRun = QEngineeringRunItem() |
100 |
pipeRun.items = connectedItems |
101 |
if pipeRun.items is not None and len(pipeRun.items) > 0: |
102 |
matches[0].owner.runs.append(pipeRun)
|
103 |
else:
|
104 |
notMatches.append(line) |
105 |
lines = notMatches |
106 |
except Exception as ex: |
107 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
108 | |
109 |
|
110 | |
111 |
'''
|
112 |
@brief trace line no
|
113 |
@author humkyung
|
114 |
@date 2018.04.16
|
115 |
@history 2018.04.26 Jeongwoo docDatalineNos = self.lineNos, Not For loop
|
116 |
humkyung 2018.05.08 add flow arrow
|
117 |
Jeongwoo 2018.05.14 Add [runs] on Primary/Secondary Line - Need to modify Secondary Line
|
118 |
Jeongwoo 2018.05.15 Make Comments [lineno.conns[0].owner = lineno]
|
119 |
Jeongwoo 2018.05.17 Modify find secondary lines with 'while'
|
120 |
Modify find secondary lines with 'while' used sublist for unconnected line
|
121 |
humkyung 2018.05.18 set start line's owner before tracing
|
122 |
'''
|
123 |
def execute(self, displayMessage, updateProgress, toler=50): |
124 |
from EngineeringLineItem import QEngineeringLineItem |
125 |
from SymbolSvgItem import SymbolSvgItem |
126 |
from EngineeringRunItem import QEngineeringRunItem |
127 |
from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem |
128 | |
129 |
try:
|
130 |
docData = AppDocData.instance() |
131 | |
132 |
configs = docData.getConfigs('Line No', 'Delimiter') |
133 |
if 1 == len(configs): |
134 |
delimiter = configs[0].value
|
135 |
configs = docData.getConfigs('Line No', 'Configuration') |
136 | |
137 |
docData.tracerLineNos.clear() |
138 |
|
139 |
## 기존에 찾은 것 유지
|
140 |
#for lineNo in self._lineNos:
|
141 |
# lineNo.conns.clear()
|
142 | |
143 |
docData.tracerLineNos = self._lineNos
|
144 |
remainLineNos = [] |
145 |
remainLines = [] |
146 |
for lineno in docData.tracerLineNos: |
147 |
## CONN은 유지
|
148 |
if lineno.conns:
|
149 |
continue
|
150 | |
151 |
minDist = None
|
152 |
startLine = None
|
153 |
for line in self._lines: |
154 |
dist = line.distanceTo((lineno.center().x(), lineno.center().y())) |
155 |
if (minDist is None) or (dist < minDist): |
156 |
minDist = dist |
157 |
startLine = line |
158 |
if (startLine is not None) and (minDist < toler): |
159 |
lineno.conns.append(startLine) |
160 |
else:
|
161 |
remainLineNos.append(lineno) |
162 |
|
163 |
## lineIndicator
|
164 |
extendPixel = 10
|
165 |
for lineIndicator in self._lineIndicator: |
166 |
maxOverLap = 0
|
167 |
matchLineNo = None
|
168 |
liInRect = [round(lineIndicator.boundingRect().x()), round(lineIndicator.boundingRect().y()), round(lineIndicator.boundingRect().x() + lineIndicator.boundingRect().width()), round(lineIndicator.boundingRect().y() + lineIndicator.boundingRect().height())] |
169 |
for remainLineNo in remainLineNos: |
170 |
xOverlap = False
|
171 |
yOverlap = False
|
172 |
extendDx = remainLineNo.size[0] if lineIndicator.isVH == 'V' else remainLineNo.size[1] |
173 |
reNoRect = [round(remainLineNo.loc[0] - extendDx), round(remainLineNo.loc[1] - extendDx), round(remainLineNo.loc[0] + remainLineNo.size[0] + extendDx), round(remainLineNo.loc[1] + remainLineNo.size[1] + extendDx)] |
174 |
w, h = 0, 0 |
175 |
for x1 in range(reNoRect[0], reNoRect[2] + 1): |
176 |
for x2 in range(liInRect[0], liInRect[2] + 1): |
177 |
if x1 - x2 is 0: |
178 |
xOverlap = True
|
179 |
w += 1
|
180 |
if not xOverlap: |
181 |
continue
|
182 |
for y1 in range(reNoRect[1], reNoRect[3] + 1): |
183 |
for y2 in range(liInRect[1], liInRect[3] + 1): |
184 |
if y1 - y2 is 0: |
185 |
yOverlap = True
|
186 |
h += 1
|
187 | |
188 |
if not xOverlap or not yOverlap: |
189 |
continue
|
190 |
overLapRate = (w / lineIndicator.boundingRect().width() * 100) if lineIndicator.boundingRect().width() > lineIndicator.boundingRect().height() else (h / lineIndicator.boundingRect().height() * 100) |
191 |
#print(overLapRate)
|
192 |
if maxOverLap < overLapRate:
|
193 |
maxOverLap = overLapRate |
194 |
matchLineNo = remainLineNo |
195 |
#lineIndicator.setBrush(QBrush(QColor(255, 0, 0, 127)))
|
196 | |
197 |
if matchLineNo is not None: |
198 |
#print(matchLineNo.text() + ' indicator : ' + str(lineIndicator.boundingRect().x()) + ', ' + str(lineIndicator.boundingRect().y()))
|
199 |
matchLine = None
|
200 |
x1, y1, x2, y2 = round(lineIndicator.boundingRect().x() + lineIndicator.otherLine[0]), round(lineIndicator.boundingRect().y() + lineIndicator.otherLine[1]), round(lineIndicator.boundingRect().x() + lineIndicator.otherLine[2]), round(lineIndicator.boundingRect().y() + lineIndicator.otherLine[3]) |
201 |
startXorY = (min(liInRect[0], liInRect[2]) - extendPixel) if lineIndicator.isVH == 'V' else (min(liInRect[1], liInRect[3]) - extendPixel) |
202 |
endXorY = (max(liInRect[0], liInRect[2]) + extendPixel) if lineIndicator.isVH == 'V' else (max(liInRect[1], liInRect[3]) + extendPixel) |
203 |
fXorY = [] |
204 |
for dXOrdY in range(startXorY, endXorY + 1): # if horizontal -> Y, if vertical -> X |
205 |
if lineIndicator.isVH == 'V': |
206 |
fXorY.append(round(((y2-y1)/(x2-x1))*dXOrdY + y1 - ((y2-y1)/(x2-x1))*x1)) # f(x) |
207 |
else:
|
208 |
fXorY.append(round(((x2-x1)/(y2-y1))*dXOrdY + x1 - ((x2-x1)/(y2-y1))*y1)) # f(y) |
209 | |
210 |
for line in self._lines: |
211 |
axis1Overlap = False
|
212 |
axis2Overlap = False
|
213 |
lX1, lY1, lX2, lY2 = int(line.startPoint()[0]), int(line.startPoint()[1]), int(line.endPoint()[0]), int(line.endPoint()[1]) |
214 | |
215 |
if lineIndicator.isVH == 'V': |
216 |
range11 = range(startXorY, endXorY + 1) |
217 |
range12 = range(min(lX1, lX2), max(lX1, lX2)+ 1) |
218 |
range21 = fXorY |
219 |
range22 = range(min(lY1, lY2), max(lY1, lY2) + 1) |
220 |
else:
|
221 |
range11 = range(startXorY, endXorY + 1) |
222 |
range12 = range(min(lY1, lY2), max(lY1, lY2) + 1) |
223 |
range21 = fXorY |
224 |
range22 = range(min(lX1, lX2), max(lX1, lX2) + 1) |
225 | |
226 |
for axis11 in range11: |
227 |
for axis12 in range12: |
228 |
if axis11 - axis12 is 0: |
229 |
axis1Overlap = True
|
230 |
break
|
231 |
if axis1Overlap: break |
232 |
if not axis1Overlap: |
233 |
continue
|
234 |
for axis21 in range21: |
235 |
for axis22 in range22: |
236 |
if axis21 - axis22 is 0: |
237 |
axis2Overlap = True
|
238 |
break
|
239 |
if axis2Overlap: break |
240 |
|
241 |
if axis1Overlap and axis2Overlap: |
242 |
matchLine = line |
243 |
break
|
244 |
if matchLine is not None: |
245 |
matchLineNo.conns.append(matchLine) |
246 |
lineIndicator.lineIndicator = 'Match'
|
247 |
lineIndicator.setBrush(QBrush(QColor(0, 0, 255, 127))) |
248 |
#print('connected ' + matchLineNo.text() + ' and ' + matchLine.uid)
|
249 |
## up to here
|
250 |
|
251 |
# set start line's owner
|
252 |
for lineno in docData.tracerLineNos: |
253 |
if lineno.conns:
|
254 |
lineno.conns[0].owner = lineno
|
255 |
lineno.conns[0].linkedItem = lineno
|
256 |
|
257 |
maxValue = len(self._lineNos) + 1 ## line no's count + secondary line |
258 | |
259 |
# find primary lines
|
260 |
for lineno in docData.tracerLineNos: |
261 |
displayMessage.emit('{} {}'.format(lineno.text(), 'Topology Construction')) |
262 |
self.findPrimaryLines(lineno)
|
263 |
updateProgress.emit(maxValue) |
264 | |
265 |
# find secondary lines
|
266 |
lines = self._lines
|
267 |
self.findSecondaryLines(lines)
|
268 |
updateProgress.emit(maxValue) |
269 | |
270 |
### make trim lines
|
271 |
updateProgress.emit(-1) # reset progressbar |
272 |
displayMessage.emit('TrimLine Topology Construction')
|
273 |
orphanLines = [line for line in self._lines if line.linkedItem is None] |
274 |
if orphanLines:
|
275 |
maxValue = len(orphanLines)
|
276 |
orphanLines = sorted(orphanLines, key=lambda param:param.length(), reverse=True) |
277 |
while len(orphanLines) > 0: |
278 |
trimLineNo = QEngineeringTrimLineNoTextItem() |
279 |
trimLineNo.conns.append(orphanLines[0])
|
280 |
orphanLines[0].owner = trimLineNo
|
281 |
orphanLines[0].linkedItem = trimLineNo
|
282 | |
283 |
connectedItems = self.findPrimaryLines(trimLineNo)
|
284 |
for item in connectedItems: |
285 |
if item in orphanLines: |
286 |
orphanLines.remove(item) |
287 |
updateProgress.emit(maxValue) |
288 | |
289 |
self.findSecondaryLines(orphanLines)
|
290 |
for item in orphanLines[:]: |
291 |
if item.linkedItem is not None: |
292 |
orphanLines.remove(item) |
293 |
updateProgress.emit(maxValue) |
294 | |
295 |
docData.tracerLineNos.append(trimLineNo) |
296 |
|
297 |
updateProgress.emit(maxValue) |
298 |
except Exception as ex: |
299 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
300 | |
301 |
'''
|
302 |
@brief find objects connected to given line while loop
|
303 |
@author humkyung
|
304 |
@date 2018.04.16
|
305 |
@history humkyung 2018.05.08 find symbol or line connected to given object
|
306 |
humkyung 2018.05.10 set found object's owner
|
307 |
humkyung 2018.05.17 try to connect both symbol and line
|
308 |
humkyung 2018.06.22 order connected objects
|
309 |
'''
|
310 |
def findConnectedObjects(self, startLine, toler): |
311 |
from EngineeringLineItem import QEngineeringLineItem |
312 |
from EngineeringEquipmentItem import QEngineeringEquipmentItem |
313 |
from SymbolSvgItem import SymbolSvgItem |
314 | |
315 |
visited = [startLine] |
316 | |
317 |
try:
|
318 |
pool = [] |
319 |
pool.append((0, startLine))
|
320 |
|
321 |
while len(pool) > 0: |
322 |
sign, obj = pool.pop() |
323 |
if type(obj) is QEngineeringLineItem: |
324 |
symbolMatches = [x for x in self._symbols if (x.linkedItem is None) and (x not in visited) and len(obj.connectIfPossible(x, toler)) > 0] |
325 |
lineMatches = [x for x in self._lines if (x.linkedItem is None) and (x is not obj) and (x not in visited) and (len(obj.connectIfPossible(x, toler)) > 0)] |
326 | |
327 |
elif issubclass(type(obj), SymbolSvgItem): |
328 |
lineMatches = [x for x in self._lines if (x.linkedItem is None) and (x not in visited) and len(obj.connectIfPossible(x, toler)) > 0] |
329 |
symbolMatches = [x for x in self._symbols if (x.linkedItem is None) and (x is not obj) and (x not in visited) and (len(obj.connectIfPossible(x, toler)) > 0)] |
330 | |
331 |
# order connected objects
|
332 |
matches = [] |
333 |
matches.extend([x for x in symbolMatches if not issubclass(type(x), QEngineeringEquipmentItem)]) # except equipment |
334 |
matches.extend(lineMatches) |
335 | |
336 |
# specBreak 확인
|
337 |
isContainSpecBreak = False
|
338 |
for uid in self._specBreakUID: |
339 |
if obj.uid == uid:
|
340 |
isContainSpecBreak = True
|
341 |
for item in matches: |
342 |
if item.uid == uid:
|
343 |
isContainSpecBreak = True
|
344 |
|
345 |
if isContainSpecBreak:
|
346 |
break
|
347 | |
348 |
# specBreak 포함시
|
349 |
if isContainSpecBreak:
|
350 |
isConnSpecBreak = obj.isConnectSpecBreak(self._specBreak)
|
351 |
if isConnSpecBreak[0]: |
352 |
connector = isConnSpecBreak[1]
|
353 |
removeList = [] |
354 |
if connector.connectedItem is not None: |
355 |
for item in matches: |
356 |
if item == connector.connectedItem:
|
357 |
removeList.append(connector.connectedItem) |
358 |
|
359 |
# connectedItem 제거
|
360 |
if connector.connectedItem is not None: |
361 |
connector.connectedItem.disconnectedItemAtConnector(connector) |
362 |
obj.disconnectedItemAtConnector(connector) |
363 |
|
364 |
for item in removeList: |
365 |
matches.remove(item) |
366 |
|
367 |
|
368 |
if sign == 0 and len(matches) > 1: |
369 |
mid = int(len(matches)*0.5) |
370 |
lhs = matches[0:mid]
|
371 |
rhs = matches[mid:] |
372 |
elif sign == -1: |
373 |
lhs = matches |
374 |
rhs = [] |
375 |
else:
|
376 |
lhs = [] |
377 |
rhs = matches |
378 | |
379 |
for match in lhs: |
380 |
pool.append((-1, match))
|
381 |
visited.insert(0, match)
|
382 | |
383 |
for match in rhs: |
384 |
pool.append((1, match))
|
385 |
visited.append(match) |
386 |
# up to here
|
387 | |
388 |
except Exception as ex: |
389 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
390 | |
391 |
return visited
|
392 | |
393 |
'''
|
394 |
@brief connect attributes
|
395 |
@author humkyung
|
396 |
@date 2018.06.17
|
397 |
@history humkyung 2018.06.21 paste connect attributes codes from recognizeLine function
|
398 |
kyouho 2018.09.14 clear Item's owner
|
399 |
'''
|
400 |
def connectAttrImpl(worker): |
401 |
from LineNoTracer import LineNoTracer |
402 |
from AppDocData import AppDocData |
403 |
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem |
404 | |
405 |
try:
|
406 |
symbols = [] |
407 |
lines = [] |
408 |
lineNos = [] |
409 |
specBreak = [] |
410 |
lineIndicator = [] |
411 |
for item in worker.graphicsView.scene.items(): |
412 |
if type(item) is QEngineeringSpecBreakItem: |
413 |
specBreak.append(item) |
414 |
elif issubclass(type(item), SymbolSvgItem): |
415 |
#item.owner = None
|
416 |
item.linkedItem = None
|
417 |
symbols.append(item) |
418 |
elif type(item) is QEngineeringLineNoTextItem: |
419 |
#item.owner = None
|
420 |
item.linkedItem = None
|
421 |
item.runs.clear() |
422 |
lineNos.append(item) |
423 |
elif type(item) is QEngineeringLineItem: |
424 |
#item.owner = None
|
425 |
item.linkedItem = None
|
426 |
lines.append(item) |
427 |
elif type(item) is QEngineeringUnknownItem and item.lineIndicator != 'False': |
428 |
lineIndicator.append(item) |
429 | |
430 |
# trace line no
|
431 |
tracer = LineNoTracer(symbols, lines, lineNos, specBreak, lineIndicator) |
432 |
tracer.execute(worker.displayMessage, worker.updateProgress) |
433 |
# up to here
|
434 | |
435 |
# connect attribut
|
436 |
texts = [item for item in worker.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)] |
437 |
for symbol in symbols: |
438 |
try:
|
439 |
symbol.connectAttribute(texts) |
440 |
except Exception as ex: |
441 |
from App import App |
442 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
443 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
444 | |
445 |
# up to here
|
446 |
except Exception as ex: |
447 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
448 |
finally:
|
449 |
worker.finished.emit() |