개정판 7ac0f479
issue #480: 라인 인식
- 라인과 심볼의 연결점의 방향이 맞을때 라인과 심볼을 연결한다
Change-Id: I922479b730517bbb1a35efe2aeba961de45f466c
DTI_PID/DTI_PID/LineDetector.py | ||
---|---|---|
81 | 81 |
qy = origin[1] + math.sin(angle) * dx + math.cos(angle) * dy |
82 | 82 |
return [qx, qy] |
83 | 83 |
|
84 |
def is_connected(self, lhs, rhs, toler=20, gap=None): |
|
84 |
@staticmethod |
|
85 |
def is_connected(lhs, rhs, toler=20, gap=None): |
|
85 | 86 |
"""check if given two lines are connected""" |
86 | 87 |
|
87 | 88 |
try: |
88 | 89 |
if gap: |
89 |
l_v = self.is_vertical([lhs[0][0], lhs[0][1], lhs[1][0], lhs[1][1]])
|
|
90 |
r_v = self.is_vertical([rhs[0][0], rhs[0][1], rhs[1][0], rhs[1][1]])
|
|
90 |
l_v = LineDetector.is_vertical([lhs[0][0], lhs[0][1], lhs[1][0], lhs[1][1]])
|
|
91 |
r_v = LineDetector.is_vertical([rhs[0][0], rhs[0][1], rhs[1][0], rhs[1][1]])
|
|
91 | 92 |
# return False if not same angle |
92 | 93 |
if l_v ^ r_v: |
93 | 94 |
return False |
... | ... | |
169 | 170 |
|
170 | 171 |
return False |
171 | 172 |
|
172 |
def is_vertical(self, line): |
|
173 |
@staticmethod |
|
174 |
def is_vertical(line): |
|
173 | 175 |
from HoughBundler import HoughBundler |
174 | 176 |
|
175 | 177 |
diagonal = HoughBundler() |
... | ... | |
179 | 181 |
return False |
180 | 182 |
else: |
181 | 183 |
return True |
182 |
|
|
183 |
def is_collinear(self, lhs, rhs, toler, gap=None): |
|
184 |
|
|
185 |
@staticmethod |
|
186 |
def is_collinear(lhs, rhs, toler, gap=None): |
|
184 | 187 |
"""check if given two lines are connected and collinear""" |
185 | 188 |
try: |
186 |
if self.is_connected(lhs, rhs, toler, gap=gap):
|
|
189 |
if LineDetector.is_connected(lhs, rhs, toler, gap=gap):
|
|
187 | 190 |
dx = lhs[1][0] - lhs[0][0] |
188 | 191 |
dy = lhs[1][1] - lhs[0][1] |
189 | 192 |
length = math.sqrt(dx * dx + dy * dy) |
... | ... | |
326 | 329 |
dx = connector.center()[0] - symbol.origin[0] |
327 | 330 |
dy = connector.center()[1] - symbol.origin[1] |
328 | 331 |
else: |
329 |
dx, dy = direction[0], direction[1]
|
|
332 |
dx, dy = direction.x(), direction.y()
|
|
330 | 333 |
# up to here |
331 | 334 |
|
332 | 335 |
length = math.sqrt(dx * dx + dy * dy) |
... | ... | |
388 | 391 |
# merge near line |
389 | 392 |
for line in connectedLines: |
390 | 393 |
matches = [param for param in connectedLines |
391 |
if (line != param) and self.is_collinear(line, param, toler)]
|
|
394 |
if (line != param) and LineDetector.is_collinear(line, param, toler)]
|
|
392 | 395 |
if len(matches) > 0: |
393 | 396 |
matches.append(line) |
394 | 397 |
mergedLine = self.connect_lines(matches, toler) |
... | ... | |
401 | 404 |
# merge gap |
402 | 405 |
for line in connectedLines: |
403 | 406 |
matches = [param for param in connectedLines |
404 |
if (line != param) and self.is_collinear(line, param, toler, gap=symbol_areas)]
|
|
407 |
if (line != param) and LineDetector.is_collinear(line, param, toler, gap=symbol_areas)]
|
|
405 | 408 |
if len(matches) > 0: |
406 | 409 |
matches.append(line) |
407 | 410 |
mergedLine = self.connect_lines(matches, toler) |
... | ... | |
425 | 428 |
''' |
426 | 429 |
|
427 | 430 |
def connectLineToSymbol(self, line, symbol, toler): |
428 |
startPt = list(line.startPoint()) |
|
429 |
distStart = [(self.distanceTo(startPt, (connector.center()[0], connector.center()[1])), |
|
430 |
(connector.center()[0], connector.center()[1])) for connector in |
|
431 |
symbol.connectors] |
|
432 |
distStart.sort() |
|
433 |
|
|
434 |
endPt = list(line.endPoint()) |
|
435 |
distEnd = [(self.distanceTo(endPt, (connector.center()[0], connector.center()[1])), |
|
436 |
(connector.center()[0], connector.center()[1])) for connector in |
|
437 |
symbol.connectors] |
|
438 |
distEnd.sort() |
|
439 |
|
|
440 |
if distStart[0][0] < distEnd[0][0]: |
|
441 |
dx = distStart[0][1][0] - startPt[0] |
|
442 |
dy = distStart[0][1][1] - startPt[1] |
|
443 |
dir = (endPt[0] - startPt[0], endPt[1] - startPt[1]) |
|
444 |
if abs(dir[0]) > abs(dir[1]): |
|
445 |
endPt[1] += dy |
|
446 |
else: |
|
447 |
endPt[0] += dx |
|
431 |
try: |
|
432 |
start_pt = list(line.startPoint()) |
|
433 |
distStart = [(self.distanceTo(start_pt, (connector.center()[0], connector.center()[1])), |
|
434 |
(connector.center()[0], connector.center()[1])) for connector in |
|
435 |
symbol.connectors] |
|
436 |
distStart.sort() |
|
437 |
|
|
438 |
end_pt = list(line.endPoint()) |
|
439 |
distEnd = [(self.distanceTo(end_pt, (connector.center()[0], connector.center()[1])), |
|
440 |
(connector.center()[0], connector.center()[1])) for connector in |
|
441 |
symbol.connectors] |
|
442 |
distEnd.sort() |
|
443 |
|
|
444 |
# there is no connectors |
|
445 |
if not (distStart and distEnd): |
|
446 |
return |
|
448 | 447 |
|
449 | 448 |
res = line.connect_if_possible(symbol, toler) |
450 | 449 |
if res: |
451 | 450 |
line.set_line([res[1], res[2]]) |
452 |
else: |
|
453 |
dx = distEnd[0][1][0] - endPt[0] |
|
454 |
dy = distEnd[0][1][1] - endPt[1] |
|
455 |
dir = (endPt[0] - startPt[0], endPt[1] - startPt[1]) |
|
456 |
if abs(dir[0]) > abs(dir[1]): |
|
457 |
startPt[1] += dy |
|
451 |
|
|
452 |
""" |
|
453 |
if distStart[0][0] < distEnd[0][0]: |
|
454 |
dx = distStart[0][1][0] - start_pt[0] |
|
455 |
dy = distStart[0][1][1] - start_pt[1] |
|
456 |
dir = (end_pt[0] - start_pt[0], end_pt[1] - start_pt[1]) |
|
457 |
if abs(dir[0]) > abs(dir[1]): |
|
458 |
end_pt[1] += dy |
|
459 |
else: |
|
460 |
end_pt[0] += dx |
|
461 |
|
|
462 |
res = line.connect_if_possible(symbol, toler) |
|
463 |
if res: |
|
464 |
line.set_line([res[1], res[2]]) |
|
458 | 465 |
else: |
459 |
startPt[0] += dx |
|
466 |
dx = distEnd[0][1][0] - end_pt[0] |
|
467 |
dy = distEnd[0][1][1] - end_pt[1] |
|
468 |
dir = (end_pt[0] - start_pt[0], end_pt[1] - start_pt[1]) |
|
469 |
if abs(dir[0]) > abs(dir[1]): |
|
470 |
start_pt[1] += dy |
|
471 |
else: |
|
472 |
start_pt[0] += dx |
|
460 | 473 |
|
461 |
res = line.connect_if_possible(symbol, toler) |
|
462 |
if res: |
|
463 |
line.set_line([res[1], res[2]]) |
|
474 |
res = line.connect_if_possible(symbol, toler) |
|
475 |
if res: |
|
476 |
line.set_line([res[1], res[2]]) |
|
477 |
""" |
|
478 |
except Exception as ex: |
|
479 |
from App import App |
|
480 |
from AppDocData import MessageType |
|
481 |
|
|
482 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
483 |
sys.exc_info()[-1].tb_lineno) |
|
484 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
464 | 485 |
|
465 | 486 |
''' |
466 | 487 |
@brief extend line to intersection point |
DTI_PID/DTI_PID/MainWindow.py | ||
---|---|---|
3344 | 3344 |
|
3345 | 3345 |
""" update scene """ |
3346 | 3346 |
_items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')] |
3347 |
items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items)) |
|
3348 |
with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool: |
|
3349 |
future_items = {pool.submit(update_items, _items): _items for _items in items} |
|
3350 |
for future in futures.as_completed(future_items): |
|
3351 |
_items = future.result() |
|
3352 |
self.progress.setValue(self.progress.value() + len(_items)) |
|
3347 |
if _items: |
|
3348 |
items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items)) |
|
3349 |
with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool: |
|
3350 |
future_items = {pool.submit(update_items, _items): _items for _items in items} |
|
3351 |
for future in futures.as_completed(future_items): |
|
3352 |
_items = future.result() |
|
3353 |
self.progress.setValue(self.progress.value() + len(_items)) |
|
3353 | 3354 |
|
3354 | 3355 |
""" |
3355 | 3356 |
for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]: |
DTI_PID/DTI_PID/RecognitionDialog.py | ||
---|---|---|
216 | 216 |
Jeongwoo 2018.05.30 Remove return value |
217 | 217 |
humkyung 2018.06.08 add signal for progressbar to parameter |
218 | 218 |
humkyung 2018.06.11 get difference between original and recognized image |
219 |
Jeongwoo 2018.06.21 If noteTextInfoList is None, change from None to empty list
|
|
219 |
Jeongwoo 2018.06.21 If noteTextInfoList is None, change from None to empty list |
|
220 | 220 |
humkyung 2018.08.20 remove alreay existing symbol and text item before recognizing |
221 | 221 |
block until drawing reconized objects |
222 | 222 |
euisung 2018.11.12 add title block properties |
... | ... | |
242 | 242 |
# remove already existing symbol and text |
243 | 243 |
if not batch: |
244 | 244 |
listWidget.addItem('Deleting existing items...') |
245 |
items = [item for item in worker.graphicsView.scene().items() if
|
|
245 |
items = [item for item in worker.scene.items() if
|
|
246 | 246 |
type(item) is QEngineeringUnknownItem or type(item) is QEngineeringEndBreakItem or |
247 | 247 |
type(item) is QEngineeringErrorItem or type(item) is QGraphicsBoundingBoxItem] |
248 | 248 |
|
249 | 249 |
if worker.isSymbolChecked: |
250 | 250 |
items.extend( |
251 |
[item for item in worker.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)])
|
|
251 |
[item for item in worker.scene.items() if issubclass(type(item), SymbolSvgItem)])
|
|
252 | 252 |
if worker.isTextChecked: |
253 |
items.extend([item for item in worker.graphicsView.scene().items() if
|
|
253 |
items.extend([item for item in worker.scene.items() if
|
|
254 | 254 |
issubclass(type(item), QEngineeringTextItem)]) |
255 | 255 |
for item in items: |
256 | 256 |
item.transfer.onRemoved.emit(item) |
... | ... | |
376 | 376 |
''' |
377 | 377 |
import math |
378 | 378 |
|
379 |
symbolItems = [item for item in worker.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
|
|
379 |
symbolItems = [item for item in worker.scene.items() if issubclass(type(item), SymbolSvgItem)]
|
|
380 | 380 |
|
381 | 381 |
for symbolItem in symbolItems: |
382 | 382 |
symbolName = symbolItem.name |
... | ... | |
423 | 423 |
[], |
424 | 424 |
baseSymbol, additionalSymbol, isExceptDetect, detectFlip)) |
425 | 425 |
|
426 |
worker.graphicsView.scene().removeItem(symbolItem)
|
|
426 |
worker.scene.removeItem(symbolItem)
|
|
427 | 427 |
|
428 | 428 |
pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER) |
429 | 429 |
''' |
430 |
# symbolItems = [item for item in worker.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
|
|
430 |
# symbolItems = [item for item in worker.scene.items() if issubclass(type(item), SymbolSvgItem)]
|
|
431 | 431 |
# appDocData.symbols.extend(symbolItems) |
432 | 432 |
# appDocData.allItems.extend(symbolItems) |
433 | 433 |
|
... | ... | |
505 | 505 |
import math |
506 | 506 |
from TextInfo import TextInfo |
507 | 507 |
|
508 |
textItems = [item for item in worker.graphicsView.scene().items() if
|
|
508 |
textItems = [item for item in worker.scene.items() if
|
|
509 | 509 |
issubclass(type(item), QEngineeringTextItem)] |
510 | 510 |
app_doc_data.texts.extend(textItems) |
511 | 511 |
app_doc_data.allItems.extend(textItems) |
... | ... | |
523 | 523 |
round(math.degrees(textItem.angle)))) |
524 | 524 |
|
525 | 525 |
textItem.owner = None |
526 |
worker.graphicsView.scene().removeItem(textItem)
|
|
526 |
worker.scene.removeItem(textItem)
|
|
527 | 527 |
|
528 | 528 |
worker.updateBatchProgress.emit(len(srcList), 2) |
529 | 529 |
|
... | ... | |
585 | 585 |
titleBlockTextInfoList if titleBlockTextInfoList is not None else []) |
586 | 586 |
|
587 | 587 |
if isLineChecked: |
588 |
Worker.recognizeLine(mainRes, listWidget, worker.graphicsView, worker, batch)
|
|
588 |
Worker.recognizeLine(mainRes, listWidget, worker.scene, worker, batch)
|
|
589 | 589 |
else: |
590 |
lineItems = [item for item in worker.graphicsView.scene().items()
|
|
590 |
lineItems = [item for item in worker.scene.items()
|
|
591 | 591 |
if issubclass(type(item), QEngineeringLineItem)] |
592 | 592 |
app_doc_data.lines.extend(lineItems) |
593 | 593 |
app_doc_data.allItems.extend(lineItems) |
... | ... | |
596 | 596 |
lineItem.owner = None |
597 | 597 |
for conn in lineItem.connectors: |
598 | 598 |
conn.connectedItem = None |
599 |
worker.graphicsView.scene().removeItem(lineItem)
|
|
599 |
worker.scene.removeItem(lineItem)
|
|
600 | 600 |
|
601 | 601 |
# connect symbol to symbol |
602 | 602 |
try: |
... | ... | |
623 | 623 |
# connect line to symbol |
624 | 624 |
try: |
625 | 625 |
for line in app_doc_data.lines: |
626 |
matches = [symbol for symbol in symbols if symbol.is_connectable(line, toler=toler)]
|
|
627 |
for symbol in matches: |
|
628 |
detector.connectLineToSymbol(line, symbol, toler=toler) |
|
626 |
matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
|
|
627 |
for _symbol in matches:
|
|
628 |
detector.connectLineToSymbol(line, _symbol, toler=toler)
|
|
629 | 629 |
except Exception as ex: |
630 | 630 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[ |
631 | 631 |
-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
... | ... | |
727 | 727 |
project = app_doc_data.getCurrentProject() |
728 | 728 |
# remove already existing line and flow arrow item |
729 | 729 |
if not batch: |
730 |
items = [item for item in worker.graphicsView.scene().items() if (type(item) is QEngineeringLineItem)]
|
|
730 |
items = [item for item in worker.scene.items() if (type(item) is QEngineeringLineItem)]
|
|
731 | 731 |
for item in items: |
732 | 732 |
item.transfer.onRemoved.emit(item) |
733 | 733 |
# up to here |
... | ... | |
1893 | 1893 |
QDialog.__init__(self, parent) |
1894 | 1894 |
|
1895 | 1895 |
self.parent = parent |
1896 |
self.graphicsView = parent.graphicsView
|
|
1896 |
self._scene = parent.graphicsView.scene()
|
|
1897 | 1897 |
self.path = path |
1898 | 1898 |
self.xmlPath = None |
1899 | 1899 |
self.ui = Recognition_UI.Ui_Recognition() |
... | ... | |
2063 | 2063 |
self.obj = Worker() # no parent! |
2064 | 2064 |
self.obj.path = self.path |
2065 | 2065 |
self.obj.listWidget = self.ui.listWidget |
2066 |
self.obj.graphicsView = self.graphicsView
|
|
2066 |
self.obj.scene = self._scene
|
|
2067 | 2067 |
self.obj.isSymbolChecked = self.ui.checkBoxSymbol.isChecked() |
2068 | 2068 |
self.obj.isTextChecked = self.ui.checkBoxText.isChecked() |
2069 | 2069 |
self.obj.isLineChecked = self.ui.lineCheckBox.isChecked() |
DTI_PID/DTI_PID/Shapes/EngineeringConnectorItem.py | ||
---|---|---|
57 | 57 |
self._sceneConnectPoint = None |
58 | 58 |
self.connectPoint = None |
59 | 59 |
self._hoverItem = None |
60 |
self._dir = None |
|
60 | 61 |
|
61 | 62 |
self.setAcceptHoverEvents(True) |
62 | 63 |
self.transfer = Transfer() |
... | ... | |
159 | 160 |
|
160 | 161 |
def dir(self): |
161 | 162 |
"""return direction vector""" |
162 |
|
|
163 |
if self._direction == 'LEFT': |
|
164 |
return -1, 0 |
|
165 |
elif self._direction == 'RIGHT': |
|
166 |
return 1, 0 |
|
167 |
elif self._direction == 'UP': |
|
168 |
return 0, -1 |
|
169 |
elif self._direction == 'DOWN': |
|
170 |
return 0, 1 |
|
171 |
elif self._direction == 'AUTO': |
|
172 |
import math |
|
173 |
from SymbolSvgItem import SymbolSvgItem |
|
174 |
|
|
175 |
if issubclass(type(self.parentItem()), SymbolSvgItem): |
|
176 |
dx = self.center()[0] - self.parentItem().origin[0] |
|
177 |
dy = self.center()[1] - self.parentItem().origin[1] |
|
178 |
length = math.sqrt(dx*dx + dy*dy) |
|
179 |
if length - 0 < 0.01: |
|
180 |
return 0, 1 |
|
181 |
return dx/length, dy/length |
|
182 |
|
|
183 |
return None |
|
163 |
DIRECTION_MAP = {'LEFT': QPointF(-1, 0), 'RIGHT': QPointF(1, 0), 'UP': QPointF(0, -1), 'DOWN': QPointF(0, 1)} |
|
164 |
|
|
165 |
if not self._dir: |
|
166 |
if self._direction in DIRECTION_MAP: |
|
167 |
self._dir = DIRECTION_MAP[self._direction] |
|
168 |
elif self._direction == 'AUTO': |
|
169 |
import math |
|
170 |
from SymbolSvgItem import SymbolSvgItem |
|
171 |
|
|
172 |
if issubclass(type(self.parentItem()), SymbolSvgItem): |
|
173 |
dx = self.center()[0] - self.parentItem().origin[0] |
|
174 |
dy = self.center()[1] - self.parentItem().origin[1] |
|
175 |
length = math.sqrt(dx * dx + dy * dy) |
|
176 |
if length - 0 < 0.01: |
|
177 |
return 0, 1 |
|
178 |
pt = QPointF(dx / length, dy / length) |
|
179 |
|
|
180 |
trans = QTransform() |
|
181 |
trans.rotateRadians(-self.parentItem().angle) |
|
182 |
self._dir = trans.map(pt) |
|
183 |
|
|
184 |
pt = None |
|
185 |
if self._dir: |
|
186 |
trans = QTransform() |
|
187 |
trans.rotateRadians(self.parentItem().angle) |
|
188 |
pt = trans.map(self._dir) |
|
189 |
|
|
190 |
return pt |
|
184 | 191 |
|
185 | 192 |
def __repr__(self): |
186 | 193 |
return '{},{},{},{}'.format(self._direction, self.center()[0], self.center()[1], self._symbol_idx) |
... | ... | |
502 | 509 |
rect = self.rect() |
503 | 510 |
size = rect.width() |
504 | 511 |
painter.drawLine(rect.center().x(), rect.center().y(), |
505 |
rect.center().x() + direction[0]*size, rect.center().y() + direction[1]*size)
|
|
512 |
rect.center().x() + self._dir.x()*size, rect.center().y() + self._dir.y()*size)
|
|
506 | 513 |
|
507 | 514 |
''' |
508 | 515 |
@brief check Overlap |
DTI_PID/DTI_PID/Shapes/EngineeringLineItem.py | ||
---|---|---|
303 | 303 |
@author humkyung |
304 | 304 |
@date 2018.04.14 |
305 | 305 |
''' |
306 |
|
|
307 | 306 |
def dotProduct(self, lhs, rhs): |
308 | 307 |
return sum([lhs[i] * rhs[i] for i in range(len(lhs))]) |
309 | 308 |
|
... | ... | |
461 | 460 |
Jeongwoo 18.05.16 Add length == 0 check |
462 | 461 |
''' |
463 | 462 |
|
464 |
def is_connectable(self, line, toler=20):
|
|
463 |
def is_connectable(self, item, toler=20):
|
|
465 | 464 |
import math |
465 |
from EngineeringConnectorItem import QEngineeringConnectorItem |
|
466 | 466 |
|
467 |
startPt = line.startPoint() |
|
468 |
endPt = line.endPoint() |
|
467 |
if type(item) is QEngineeringLineItem: |
|
468 |
startPt = item.startPoint() |
|
469 |
endPt = item.endPoint() |
|
470 |
|
|
471 |
dx = endPt[0] - startPt[0] |
|
472 |
dy = endPt[1] - startPt[1] |
|
473 |
length = math.sqrt(dx * dx + dy * dy) |
|
474 |
if length == 0: |
|
475 |
return False |
|
476 |
dx /= length |
|
477 |
dy /= length |
|
478 |
extendedLine = [(startPt[0] - dx * toler, startPt[1] - dy * toler), |
|
479 |
(endPt[0] + dx * toler, endPt[1] + dy * toler)] |
|
480 |
pt = self.intersection(extendedLine) |
|
481 |
|
|
482 |
return (pt is not None) and (type(pt) == shapely.geometry.point.Point) |
|
483 |
elif type(item) is QEngineeringConnectorItem: |
|
484 |
start_pt = self.startPoint() |
|
485 |
end_pt = self.endPoint() |
|
486 |
|
|
487 |
lhs = [end_pt[0] - start_pt[0], end_pt[1] - start_pt[1]] |
|
488 |
length = math.sqrt(lhs[0] * lhs[0] + lhs[1] * lhs[1]) |
|
489 |
if length == 0: |
|
490 |
return False |
|
491 |
|
|
492 |
rhs = [item.dir().x(), item.dir().y()] |
|
493 |
dot = sum([lhs[i] * rhs[i] for i in range(len(lhs))]) |
|
494 |
angle = math.degrees(math.acos(dot / length)) |
|
495 |
if (abs(angle) < 5) or (abs(angle - 180) < 5): |
|
496 |
_center = item.center() |
|
497 |
dx = [start_pt[0] - _center[0], end_pt[0] - _center[0]] |
|
498 |
dy = [start_pt[1] - _center[1], end_pt[1] - _center[1]] |
|
499 |
length = [math.sqrt(dx[0] * dx[0] + dy[0] * dy[0]), math.sqrt(dx[1] * dx[1] + dy[1] * dy[1])] |
|
500 |
return length[0] < toler or length[1] < toler |
|
469 | 501 |
|
470 |
dx = endPt[0] - startPt[0] |
|
471 |
dy = endPt[1] - startPt[1] |
|
472 |
length = math.sqrt(dx * dx + dy * dy) |
|
473 |
if length == 0: |
|
474 | 502 |
return False |
475 |
dx /= length |
|
476 |
dy /= length |
|
477 |
extendedLine = [(startPt[0] - dx * toler, startPt[1] - dy * toler), |
|
478 |
(endPt[0] + dx * toler, endPt[1] + dy * toler)] |
|
479 |
pt = self.intersection(extendedLine) |
|
480 | 503 |
|
481 |
return (pt is not None) and (type(pt) == shapely.geometry.point.Point)
|
|
504 |
return False
|
|
482 | 505 |
|
483 | 506 |
''' |
484 | 507 |
@author humkyung |
... | ... | |
639 | 662 |
''' |
640 | 663 |
|
641 | 664 |
def connect_if_possible(self, obj, toler=20): |
642 |
""" connect line or symbol is able to be connected and return symbol or line connected to connectors """ |
|
643 |
""" this method not update item's position """ |
|
665 |
"""connect line or symbol is able to be connected and return symbol or line connected to connectors |
|
666 |
this method not update item's position' \ |
|
667 |
""" |
|
644 | 668 |
|
645 | 669 |
from shapely.geometry import Point |
646 | 670 |
from SymbolSvgItem import SymbolSvgItem |
... | ... | |
648 | 672 |
|
649 | 673 |
res = [] |
650 | 674 |
|
651 |
startPt = self.startPoint()
|
|
652 |
endPt = self.endPoint()
|
|
675 |
start_pt = self.startPoint()
|
|
676 |
end_pt = self.endPoint()
|
|
653 | 677 |
|
654 | 678 |
try: |
655 | 679 |
if issubclass(type(obj), SymbolSvgItem): |
656 | 680 |
for i in range(len(obj.connectors)): |
681 |
if not self.is_connectable(obj.connectors[i]): |
|
682 |
continue |
|
683 |
|
|
657 | 684 |
pt = obj.connectors[i].center() |
658 |
if Point(startPt[0], startPt[1]).distance(Point(pt[0], pt[1])) < toler: |
|
685 |
""" |
|
686 |
dist = [(self.connectors[0], Point(start_pt[0], start_pt[1]).distance(Point(pt[0], pt[1])), start_pt), |
|
687 |
(self.connectors[1], Point(end_pt[0], end_pt[1]).distance(Point(pt[0], pt[1])), end_pt)] |
|
688 |
|
|
689 |
dist.sort(key=lambda x: x[1]) |
|
690 |
|
|
691 |
if dist[0][0].connectedItem is None and obj.connectors[i].connectedItem is None: |
|
692 |
dist[0][0].connect(obj) |
|
693 |
obj.connectors[i].connect(self) |
|
694 |
# line, start, end |
|
695 |
res.append(obj) |
|
696 |
res.append(obj.connectors[i].center()) |
|
697 |
res.append(dist[0][2]) |
|
698 |
""" |
|
699 |
if Point(start_pt[0], start_pt[1]).distance(Point(pt[0], pt[1])) < toler: |
|
659 | 700 |
if self.connectors[0].connectedItem is None and obj.connectors[i].connectedItem is None: |
660 | 701 |
self.connectors[0].connect(obj) |
661 | 702 |
obj.connectors[i].connect(self) |
662 | 703 |
# line, start, end |
663 | 704 |
res.append(obj) |
664 | 705 |
res.append(obj.connectors[i].center()) |
665 |
res.append(endPt)
|
|
666 |
elif Point(endPt[0], endPt[1]).distance(Point(pt[0], pt[1])) < toler:
|
|
706 |
res.append(end_pt)
|
|
707 |
elif Point(end_pt[0], end_pt[1]).distance(Point(pt[0], pt[1])) < toler:
|
|
667 | 708 |
if self.connectors[1].connectedItem is None and obj.connectors[i].connectedItem is None: |
668 | 709 |
self.connectors[1].connect(obj) |
669 | 710 |
obj.connectors[i].connect(self) |
670 | 711 |
# line, start, end |
671 | 712 |
res.append(obj) |
672 |
res.append(startPt)
|
|
713 |
res.append(start_pt)
|
|
673 | 714 |
res.append(obj.connectors[i].center()) |
674 | 715 |
elif type(obj) is QEngineeringLineItem: |
675 | 716 |
_startPt = obj.startPoint() |
676 | 717 |
_endPt = obj.endPoint() |
677 | 718 |
if obj.connectors[0].connectedItem is None and self.distanceTo(_startPt) < toler: |
678 |
if self.connectors[0].connectedItem is None and ((Point(startPt[0], startPt[1]).distance(Point(_startPt[0], _startPt[1])) < toler)): |
|
719 |
if self.connectors[0].connectedItem is None and \ |
|
720 |
(Point(start_pt[0], start_pt[1]).distance(Point(_startPt[0], _startPt[1])) < toler): |
|
679 | 721 |
self.connectors[0].connect(obj) |
680 | 722 |
obj.connectors[0].connect(self) |
681 | 723 |
res.append(obj) |
682 |
elif self.connectors[1].connectedItem is None and ((Point(endPt[0], endPt[1]).distance(Point(_startPt[0], _startPt[1])) < toler)): |
|
724 |
elif self.connectors[1].connectedItem is None and \ |
|
725 |
(Point(end_pt[0], end_pt[1]).distance(Point(_startPt[0], _startPt[1])) < toler): |
|
683 | 726 |
self.connectors[1].connect(obj) |
684 | 727 |
obj.connectors[0].connect(self) |
685 | 728 |
res.append(obj) |
... | ... | |
689 | 732 |
|
690 | 733 |
elif obj.connectors[1].connectedItem is None and self.distanceTo(_endPt) < toler: |
691 | 734 |
if self.connectors[0].connectedItem is None and \ |
692 |
((Point(startPt[0], startPt[1]).distance(Point(_endPt[0], _endPt[1])) < toler)):
|
|
735 |
(Point(start_pt[0], start_pt[1]).distance(Point(_endPt[0], _endPt[1])) < toler):
|
|
693 | 736 |
self.connectors[0].connect(obj) |
694 | 737 |
obj.connectors[1].connect(self) |
695 | 738 |
res.append(obj) |
696 | 739 |
elif self.connectors[1].connectedItem is None and \ |
697 |
((Point(endPt[0], endPt[1]).distance(Point(_endPt[0], _endPt[1])) < toler)):
|
|
740 |
(Point(end_pt[0], end_pt[1]).distance(Point(_endPt[0], _endPt[1])) < toler):
|
|
698 | 741 |
self.connectors[1].connect(obj) |
699 | 742 |
obj.connectors[1].connect(self) |
700 | 743 |
res.append(obj) |
DTI_PID/DTI_PID/Shapes/SymbolSvgItem.py | ||
---|---|---|
694 | 694 |
def rect(self): |
695 | 695 |
return self.sceneBoundingRect() |
696 | 696 |
|
697 |
''' |
|
698 |
@brief return true if line is able to connect symbol |
|
699 |
@author humkyung |
|
700 |
@date 2018.04.13 |
|
701 |
''' |
|
702 |
|
|
703 | 697 |
def is_connectable(self, item, toler=10): |
704 |
# from EngineeringLineItem import QEngineeringLineItem
|
|
698 |
"""return true if line is able to connect symbol"""
|
|
705 | 699 |
|
706 |
''' |
|
707 |
if False:#type(item) is QEngineeringLineItem: |
|
708 |
line = item |
|
709 |
start_pt = line.startPoint() |
|
710 |
end_pt = line.endPoint() |
|
711 |
for connector in self.connectors: |
|
712 |
dx = connector.sceneConnectPoint[0] - (start_pt[0]) |
|
713 |
dy = connector.sceneConnectPoint[1] - (start_pt[1]) |
|
714 |
if (math.sqrt(dx*dx + dy*dy) < toler): return True |
|
715 |
dx = connector.sceneConnectPoint[0] - (end_pt[0]) |
|
716 |
dy = connector.sceneConnectPoint[1] - (end_pt[1]) |
|
717 |
if (math.sqrt(dx*dx + dy*dy) < toler): return True |
|
718 |
elif True:#issubclass(type(item), SymbolSvgItem): |
|
719 |
''' |
|
720 | 700 |
for connector in self.connectors: |
721 | 701 |
for iConnector in item.connectors: |
722 | 702 |
dx = connector.center()[0] - iConnector.center()[0] |
723 | 703 |
dy = connector.center()[1] - iConnector.center()[1] |
724 |
if (math.sqrt(dx * dx + dy * dy) < toler): return True |
|
704 |
if math.sqrt(dx * dx + dy * dy) < toler: |
|
705 |
return True |
|
725 | 706 |
|
726 | 707 |
return False |
727 | 708 |
|
내보내기 Unified diff