Spaces:
Running
Running
add curve for sequence flow
Browse files- modules/OCR.py +12 -0
- modules/eval.py +0 -5
- modules/toXML.py +99 -20
modules/OCR.py
CHANGED
@@ -352,6 +352,18 @@ def mapping_text(full_pred, text_pred, print_sentences=False,percentage_thresh=0
|
|
352 |
text_mapping[full_pred['BPMN_id'][j]]=grouped_sentences[i]
|
353 |
|
354 |
# Map the grouped sentences to the corresponding pool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
355 |
for i in range(len(info_boxes)):
|
356 |
if is_vertical(info_boxes[i]):
|
357 |
for j in range(len(boxes)):
|
|
|
352 |
text_mapping[full_pred['BPMN_id'][j]]=grouped_sentences[i]
|
353 |
|
354 |
# Map the grouped sentences to the corresponding pool
|
355 |
+
for key, elements in full_pred['pool_dict'].items():
|
356 |
+
if len(elements) > 0:
|
357 |
+
continue
|
358 |
+
else:
|
359 |
+
for i in range(len(info_boxes)):
|
360 |
+
#find the position of the key in BPMN_id
|
361 |
+
position = list(full_pred['BPMN_id']).index(key)
|
362 |
+
if proportion_inside(info_boxes[i], boxes[position])>iou_threshold:
|
363 |
+
text_mapping[key] = info_texts[i]
|
364 |
+
info_texts[i] = '' # Clear the text to avoid re-use
|
365 |
+
|
366 |
+
|
367 |
for i in range(len(info_boxes)):
|
368 |
if is_vertical(info_boxes[i]):
|
369 |
for j in range(len(boxes)):
|
modules/eval.py
CHANGED
@@ -427,11 +427,6 @@ def develop_prediction(boxes, labels, scores, keypoints, class_dict, correction=
|
|
427 |
|
428 |
#give a link to event to allow the creation of the BPMN id with start, indermediate and end event
|
429 |
flow_links = give_link_to_element(flow_links, labels)
|
430 |
-
|
431 |
-
#change every datastore to dataobject [TO DO: change it to make the dataStore work]
|
432 |
-
for i in range(len(labels)):
|
433 |
-
if labels[i] == list(class_dict.values()).index('dataStore'):
|
434 |
-
labels[i] = list(class_dict.values()).index('dataObject')
|
435 |
|
436 |
boxes,labels,scores,keypoints,bpmn_id, flow_links,best_points,pool_dict = last_correction(boxes,labels,scores,keypoints,bpmn_id,flow_links,best_points, pool_dict)
|
437 |
|
|
|
427 |
|
428 |
#give a link to event to allow the creation of the BPMN id with start, indermediate and end event
|
429 |
flow_links = give_link_to_element(flow_links, labels)
|
|
|
|
|
|
|
|
|
|
|
430 |
|
431 |
boxes,labels,scores,keypoints,bpmn_id, flow_links,best_points,pool_dict = last_correction(boxes,labels,scores,keypoints,bpmn_id,flow_links,best_points, pool_dict)
|
432 |
|
modules/toXML.py
CHANGED
@@ -248,6 +248,7 @@ def create_XML(full_pred, text_mapping, size_scale, scale):
|
|
248 |
|
249 |
return pretty_xml_as_string
|
250 |
|
|
|
251 |
def create_big_pool(full_pred, text_mapping):
|
252 |
# If no pools or lanes are detected, create a single pool with all elements
|
253 |
new_pool_index = 'pool_1'
|
@@ -262,6 +263,7 @@ def create_big_pool(full_pred, text_mapping):
|
|
262 |
print(f"Created a big pool index {new_pool_index} with elements: {elements_pool}")
|
263 |
return full_pred, text_mapping
|
264 |
|
|
|
265 |
def get_size_elements(size_scale):
|
266 |
size_elements = {
|
267 |
'event': (size_scale*43.2, size_scale*43.2),
|
@@ -286,10 +288,13 @@ def rescale(scale, boxes):
|
|
286 |
boxes[i][3]*scale]
|
287 |
return boxes
|
288 |
|
|
|
289 |
def create_BPMN_id(labels,pool_dict):
|
290 |
|
291 |
BPMN_id = [class_dict[labels[i]] for i in range(len(labels))]
|
292 |
|
|
|
|
|
293 |
enums = {
|
294 |
'event': 1,
|
295 |
'task': 1,
|
@@ -300,8 +305,6 @@ def create_BPMN_id(labels,pool_dict):
|
|
300 |
'parallelGateway': 1,
|
301 |
'dataAssociation': 1,
|
302 |
'pool': 1,
|
303 |
-
'dataObject': 1,
|
304 |
-
'dataStore': 1,
|
305 |
'timerEvent': 1,
|
306 |
'eventBasedGateway': 1
|
307 |
}
|
@@ -326,8 +329,12 @@ def create_BPMN_id(labels,pool_dict):
|
|
326 |
}.get(Bpmn_id, None)
|
327 |
|
328 |
if key:
|
329 |
-
|
330 |
-
|
|
|
|
|
|
|
|
|
331 |
|
332 |
# Update the pool_dict keys with their corresponding BPMN_id values
|
333 |
updated_pool_dict = {}
|
@@ -450,8 +457,10 @@ def create_bpmn_object(process, bpmnplane, text_mapping, definitions, size, data
|
|
450 |
dataObject_idx = links[dataAssociation_idx][0]
|
451 |
dataObject_name = elements[dataObject_idx]
|
452 |
dataObject_ref = f'DataObjectReference_{dataObject_name.split("_")[1]}'
|
|
|
453 |
sub_element = ET.SubElement(element, 'bpmn:dataInputAssociation', id=f'dataInAsso_{dataAssociation_idx}_{dataObject_ref.split("_")[1]}')
|
454 |
ET.SubElement(sub_element, 'bpmn:sourceRef').text = dataObject_ref
|
|
|
455 |
create_data_Association(bpmnplane, data, size, sub_element.attrib['id'], dataAssociation_idx, dataObject_name, element_id)
|
456 |
|
457 |
# Handle Data Output Association
|
@@ -533,8 +542,11 @@ def create_bpmn_object(process, bpmnplane, text_mapping, definitions, size, data
|
|
533 |
#print('ici dataObject', element_id)
|
534 |
dataObject_idx = element_id.split('_')[1]
|
535 |
dataObject_ref = f'DataObjectReference_{dataObject_idx}'
|
536 |
-
|
537 |
-
|
|
|
|
|
|
|
538 |
add_diagram_elements(bpmnplane, dataObject_ref, x, y, size[element_type][0], size[element_type][1])
|
539 |
|
540 |
# Timer Event
|
@@ -610,6 +622,68 @@ def calculate_pool_waypoints(idx, data, size, source_idx, target_idx, source_ele
|
|
610 |
|
611 |
return waypoints
|
612 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
613 |
def calculate_waypoints(data, size, current_idx, source_id, target_id):
|
614 |
best_points = data['best_points'][current_idx]
|
615 |
pos_source = best_points[0]
|
@@ -618,20 +692,18 @@ def calculate_waypoints(data, size, current_idx, source_id, target_id):
|
|
618 |
source_idx = data['BPMN_id'].index(source_id)
|
619 |
target_idx = data['BPMN_id'].index(target_id)
|
620 |
|
621 |
-
if source_idx==target_idx:
|
622 |
warning()
|
623 |
-
#return [data['keypoints'][current_idx][0][:2], data['keypoints'][current_idx][1][:2]]
|
624 |
return None
|
625 |
|
626 |
if source_idx is None or target_idx is None:
|
627 |
warning()
|
628 |
-
return
|
629 |
-
|
630 |
|
631 |
name_source = source_id.split('_')[0]
|
632 |
name_target = target_id.split('_')[0]
|
633 |
|
634 |
-
#Get the position of the source and target
|
635 |
source_x, source_y = data['boxes'][source_idx][:2]
|
636 |
target_x, target_y = data['boxes'][target_idx][:2]
|
637 |
|
@@ -641,31 +713,38 @@ def calculate_waypoints(data, size, current_idx, source_id, target_id):
|
|
641 |
|
642 |
if pos_source == 'left':
|
643 |
source_x = source_x
|
644 |
-
source_y += size[name_source][1]/2
|
645 |
elif pos_source == 'right':
|
646 |
source_x += size[name_source][0]
|
647 |
-
source_y += size[name_source][1]/2
|
648 |
elif pos_source == 'top':
|
649 |
-
source_x += size[name_source][0]/2
|
650 |
source_y = source_y
|
651 |
elif pos_source == 'bottom':
|
652 |
-
source_x += size[name_source][0]/2
|
653 |
source_y += size[name_source][1]
|
654 |
|
655 |
if pos_target == 'left':
|
656 |
target_x = target_x
|
657 |
-
target_y += size[name_target][1]/2
|
658 |
elif pos_target == 'right':
|
659 |
target_x += size[name_target][0]
|
660 |
-
target_y += size[name_target][1]/2
|
661 |
elif pos_target == 'top':
|
662 |
-
target_x += size[name_target][0]/2
|
663 |
target_y = target_y
|
664 |
elif pos_target == 'bottom':
|
665 |
-
target_x += size[name_target][0]/2
|
666 |
target_y += size[name_target][1]
|
667 |
|
668 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
669 |
|
670 |
def create_flow_element(bpmn, text_mapping, idx, size, data, parent, message=False):
|
671 |
source_idx, target_idx = data['links'][idx]
|
|
|
248 |
|
249 |
return pretty_xml_as_string
|
250 |
|
251 |
+
# Function that creates a single pool with all elements
|
252 |
def create_big_pool(full_pred, text_mapping):
|
253 |
# If no pools or lanes are detected, create a single pool with all elements
|
254 |
new_pool_index = 'pool_1'
|
|
|
263 |
print(f"Created a big pool index {new_pool_index} with elements: {elements_pool}")
|
264 |
return full_pred, text_mapping
|
265 |
|
266 |
+
# Function that gives the size of the elements
|
267 |
def get_size_elements(size_scale):
|
268 |
size_elements = {
|
269 |
'event': (size_scale*43.2, size_scale*43.2),
|
|
|
288 |
boxes[i][3]*scale]
|
289 |
return boxes
|
290 |
|
291 |
+
#Function to create the unique BPMN_id
|
292 |
def create_BPMN_id(labels,pool_dict):
|
293 |
|
294 |
BPMN_id = [class_dict[labels[i]] for i in range(len(labels))]
|
295 |
|
296 |
+
data_counter = 1
|
297 |
+
|
298 |
enums = {
|
299 |
'event': 1,
|
300 |
'task': 1,
|
|
|
305 |
'parallelGateway': 1,
|
306 |
'dataAssociation': 1,
|
307 |
'pool': 1,
|
|
|
|
|
308 |
'timerEvent': 1,
|
309 |
'eventBasedGateway': 1
|
310 |
}
|
|
|
329 |
}.get(Bpmn_id, None)
|
330 |
|
331 |
if key:
|
332 |
+
if key in ['dataObject', 'dataStore']:
|
333 |
+
BPMN_id[idx] = f'{key}_{data_counter}'
|
334 |
+
data_counter += 1
|
335 |
+
else:
|
336 |
+
BPMN_id[idx] = f'{key}_{enums[key]}'
|
337 |
+
enums[key] += 1
|
338 |
|
339 |
# Update the pool_dict keys with their corresponding BPMN_id values
|
340 |
updated_pool_dict = {}
|
|
|
457 |
dataObject_idx = links[dataAssociation_idx][0]
|
458 |
dataObject_name = elements[dataObject_idx]
|
459 |
dataObject_ref = f'DataObjectReference_{dataObject_name.split("_")[1]}'
|
460 |
+
ET.SubElement(element, 'bpmn:property', id=f'Property_{dataAssociation_idx}_{dataObject_ref.split("_")[1]}', name='__targetRef_placeholder')
|
461 |
sub_element = ET.SubElement(element, 'bpmn:dataInputAssociation', id=f'dataInAsso_{dataAssociation_idx}_{dataObject_ref.split("_")[1]}')
|
462 |
ET.SubElement(sub_element, 'bpmn:sourceRef').text = dataObject_ref
|
463 |
+
ET.SubElement(sub_element, 'bpmn:targetRef').text = f"Property_{dataAssociation_idx}_{dataObject_ref.split('_')[1]}"
|
464 |
create_data_Association(bpmnplane, data, size, sub_element.attrib['id'], dataAssociation_idx, dataObject_name, element_id)
|
465 |
|
466 |
# Handle Data Output Association
|
|
|
542 |
#print('ici dataObject', element_id)
|
543 |
dataObject_idx = element_id.split('_')[1]
|
544 |
dataObject_ref = f'DataObjectReference_{dataObject_idx}'
|
545 |
+
if element_type == 'dataObject':
|
546 |
+
ET.SubElement(process, 'bpmn:dataObjectReference', id=dataObject_ref, dataObjectRef=element_id, name=text_mapping[element_id])
|
547 |
+
ET.SubElement(process, f'bpmn:{element_type}', id=element_id)
|
548 |
+
elif element_type == 'dataStore':
|
549 |
+
ET.SubElement(process, 'bpmn:dataStoreReference', id=dataObject_ref, name=text_mapping[element_id])
|
550 |
add_diagram_elements(bpmnplane, dataObject_ref, x, y, size[element_type][0], size[element_type][1])
|
551 |
|
552 |
# Timer Event
|
|
|
622 |
|
623 |
return waypoints
|
624 |
|
625 |
+
def add_curve(waypoints, pos_source, pos_target, threshold=30):
|
626 |
+
"""
|
627 |
+
Add a single curve to the sequence flow by introducing a control point.
|
628 |
+
The control point is added at an offset from the midpoint of the original waypoints.
|
629 |
+
"""
|
630 |
+
if len(waypoints) < 2:
|
631 |
+
return waypoints
|
632 |
+
|
633 |
+
# Extract start and end points
|
634 |
+
start_point = waypoints[0]
|
635 |
+
end_point = waypoints[1]
|
636 |
+
|
637 |
+
start_x, start_y = start_point
|
638 |
+
end_x, end_y = end_point
|
639 |
+
|
640 |
+
pos_horizontal = ['left', 'right']
|
641 |
+
pos_vertical = ['top', 'bottom']
|
642 |
+
|
643 |
+
if abs(start_x - end_x) < threshold or abs(start_y - end_y) < threshold:
|
644 |
+
return waypoints
|
645 |
+
|
646 |
+
# Calculate the control point
|
647 |
+
if pos_source in pos_horizontal and pos_target in pos_horizontal:
|
648 |
+
control_point = None
|
649 |
+
elif pos_source in pos_vertical and pos_target in pos_vertical:
|
650 |
+
control_point = None
|
651 |
+
elif pos_source in pos_horizontal and pos_target in pos_vertical:
|
652 |
+
control_point = (end_x, start_y)
|
653 |
+
elif pos_source in pos_vertical and pos_target in pos_horizontal:
|
654 |
+
control_point = (start_x, end_y)
|
655 |
+
else:
|
656 |
+
control_point = None
|
657 |
+
|
658 |
+
|
659 |
+
# Create the curved path
|
660 |
+
if control_point is not None:
|
661 |
+
curved_waypoints = [start_point, control_point, end_point]
|
662 |
+
else:
|
663 |
+
curved_waypoints = [start_point, end_point]
|
664 |
+
|
665 |
+
return curved_waypoints
|
666 |
+
|
667 |
+
|
668 |
+
def check_for_obstacles(waypoints, data, margin=10):
|
669 |
+
"""
|
670 |
+
Check if the curved path intersects with any existing elements.
|
671 |
+
"""
|
672 |
+
object_boxes = []
|
673 |
+
for idx, element in enumerate(data['boxes']):
|
674 |
+
if idx >= len(data['labels']):
|
675 |
+
continue
|
676 |
+
if data['labels'][idx] <= 12 and data['labels'][idx] != 7 and data['labels'][idx] != 6:
|
677 |
+
object_boxes.append(element)
|
678 |
+
|
679 |
+
for box in object_boxes:
|
680 |
+
x1, y1, x2, y2 = box
|
681 |
+
for point in waypoints:
|
682 |
+
x, y = point
|
683 |
+
if (x1 - margin < x < x2 + margin) and (y1 - margin < y < y2 + margin):
|
684 |
+
return True
|
685 |
+
return False
|
686 |
+
|
687 |
def calculate_waypoints(data, size, current_idx, source_id, target_id):
|
688 |
best_points = data['best_points'][current_idx]
|
689 |
pos_source = best_points[0]
|
|
|
692 |
source_idx = data['BPMN_id'].index(source_id)
|
693 |
target_idx = data['BPMN_id'].index(target_id)
|
694 |
|
695 |
+
if source_idx == target_idx:
|
696 |
warning()
|
|
|
697 |
return None
|
698 |
|
699 |
if source_idx is None or target_idx is None:
|
700 |
warning()
|
701 |
+
return None
|
|
|
702 |
|
703 |
name_source = source_id.split('_')[0]
|
704 |
name_target = target_id.split('_')[0]
|
705 |
|
706 |
+
# Get the position of the source and target
|
707 |
source_x, source_y = data['boxes'][source_idx][:2]
|
708 |
target_x, target_y = data['boxes'][target_idx][:2]
|
709 |
|
|
|
713 |
|
714 |
if pos_source == 'left':
|
715 |
source_x = source_x
|
716 |
+
source_y += size[name_source][1] / 2
|
717 |
elif pos_source == 'right':
|
718 |
source_x += size[name_source][0]
|
719 |
+
source_y += size[name_source][1] / 2
|
720 |
elif pos_source == 'top':
|
721 |
+
source_x += size[name_source][0] / 2
|
722 |
source_y = source_y
|
723 |
elif pos_source == 'bottom':
|
724 |
+
source_x += size[name_source][0] / 2
|
725 |
source_y += size[name_source][1]
|
726 |
|
727 |
if pos_target == 'left':
|
728 |
target_x = target_x
|
729 |
+
target_y += size[name_target][1] / 2
|
730 |
elif pos_target == 'right':
|
731 |
target_x += size[name_target][0]
|
732 |
+
target_y += size[name_target][1] / 2
|
733 |
elif pos_target == 'top':
|
734 |
+
target_x += size[name_target][0] / 2
|
735 |
target_y = target_y
|
736 |
elif pos_target == 'bottom':
|
737 |
+
target_x += size[name_target][0] / 2
|
738 |
target_y += size[name_target][1]
|
739 |
|
740 |
+
waypoints = [(source_x, source_y), (target_x, target_y)]
|
741 |
+
|
742 |
+
# Add curve if no obstacles are in the path
|
743 |
+
if data['labels'][current_idx] == list(class_dict.values()).index('sequenceFlow'):
|
744 |
+
waypoints = add_curve(waypoints, pos_source, pos_target)
|
745 |
+
|
746 |
+
return waypoints
|
747 |
+
|
748 |
|
749 |
def create_flow_element(bpmn, text_mapping, idx, size, data, parent, message=False):
|
750 |
source_idx, target_idx = data['links'][idx]
|