BenjiELCA commited on
Commit
642c17f
·
1 Parent(s): 98b1103

add curve for sequence flow

Browse files
Files changed (3) hide show
  1. modules/OCR.py +12 -0
  2. modules/eval.py +0 -5
  3. 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
- BPMN_id[idx] = f'{key}_{enums[key]}'
330
- enums[key] += 1
 
 
 
 
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
- element = ET.SubElement(process, 'bpmn:dataObjectReference', id=dataObject_ref, dataObjectRef=element_id, name=text_mapping[element_id])
537
- ET.SubElement(process, f'bpmn:{element_type}', id=element_id)
 
 
 
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 [(source_x, source_y), (target_x, target_y)]
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
- return [(source_x, source_y), (target_x, target_y)]
 
 
 
 
 
 
 
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]