Nighty3912 commited on
Commit
5a578b7
·
verified ·
1 Parent(s): b992c8f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +2 -392
app.py CHANGED
@@ -286,292 +286,6 @@ def polygon_to_exterior_coords(poly: Polygon):
286
  return []
287
  return list(poly.exterior.coords)
288
 
289
- # def place_finger_cut_adjusted(
290
- # tool_polygon,
291
- # points_inch,
292
- # existing_centers,
293
- # all_polygons,
294
- # circle_diameter=1, # Finger cut circle diameter in inches.
295
- # min_gap=0.25, # Minimum clearance (in inches) between the finger cut and adjacent contours.
296
- # max_attempts=50 # Maximum candidate attempts.
297
- # ):
298
- # """
299
- # Attempts to place a finger-cut circle along the tool polygon's contour, biased toward one side
300
- # (the boundary side) by shifting the candidate center away from the polygon centroid.
301
- # The candidate circle is merged with the tool polygon via union_tool_and_circle().
302
- # Debug information is printed to help trace candidate evaluation.
303
-
304
- # :param tool_polygon: Shapely Polygon representing the tool contour.
305
- # :param points_inch: List of (x, y) points (in inches) along the contour.
306
- # :param existing_centers: List of already accepted finger cut centers.
307
- # :param all_polygons: List of all polygons (for overlap checking).
308
- # :param circle_diameter: Diameter of the finger cut (in inches).
309
- # :param min_gap: Clearance (in inches) required between the finger cut and any adjacent contour.
310
- # :param max_attempts: Maximum number of candidate attempts.
311
- # :return: (updated_polygon, candidate_center) if successful; otherwise, (None, None).
312
- # """
313
- # import random
314
- # from shapely.geometry import Point
315
- # import numpy as np
316
-
317
- # needed_center_distance = circle_diameter + min_gap
318
- # radius = circle_diameter / 2.0
319
- # attempts = 0
320
-
321
- # # Parameter: how far to push the candidate center outward.
322
- # # Here we set it to half the circle radius, but you can adjust this as needed.
323
- # outward_offset = radius * 0.1
324
-
325
- # # Compute the centroid of the tool polygon once.
326
- # polygon_centroid = tool_polygon.centroid
327
-
328
- # # Create a safe version of the polygon via an inward buffer.
329
- # safe_tool_polygon = tool_polygon.buffer(-min_gap)
330
- # if safe_tool_polygon.is_empty:
331
- # safe_tool_polygon = tool_polygon
332
-
333
- # # Shuffle the contour indices for randomness.
334
- # indices = list(range(len(points_inch)))
335
- # random.shuffle(indices)
336
-
337
- # for i in indices:
338
- # if attempts >= max_attempts:
339
- # break
340
-
341
- # # Base candidate point from the resampled contour:
342
- # base_x, base_y = points_inch[i]
343
-
344
- # # Try a grid of offsets from this candidate base point.
345
- # for dx in np.linspace(-0.3, 0.3, 15):
346
- # for dy in np.linspace(-0.3, 0.3, 15):
347
- # # Compute an initial candidate point.
348
- # candidate_unshifted = (base_x + dx, base_y + dy)
349
-
350
- # # Compute the outward direction based on the vector from the centroid to candidate.
351
- # vec_x = candidate_unshifted[0] - polygon_centroid.x
352
- # vec_y = candidate_unshifted[1] - polygon_centroid.y
353
- # norm = np.hypot(vec_x, vec_y)
354
- # if norm == 0:
355
- # continue # Skip degenerate case.
356
- # # Normalize the outward vector.
357
- # unit_vec = (vec_x / norm, vec_y / norm)
358
- # # Push the candidate center further out so it lies along the boundary.
359
- # candidate_center = (candidate_unshifted[0] + unit_vec[0] * outward_offset,
360
- # candidate_unshifted[1] + unit_vec[1] * outward_offset)
361
-
362
- # # Check that candidate center is not too close to previously accepted centers.
363
- # if any(np.hypot(candidate_center[0] - ex, candidate_center[1] - ey) < needed_center_distance
364
- # for ex, ey in existing_centers):
365
- # continue
366
-
367
- # # Create the candidate circle.
368
- # candidate_circle = Point(candidate_center).buffer(radius, resolution=64)
369
-
370
- # # Check if the candidate circle is mostly on the boundary:
371
- # area_ratio = candidate_circle.intersection(tool_polygon).area / candidate_circle.area
372
- # # Debug: Show candidate center and its area ratio.
373
- # #print(f"Candidate center: {candidate_center}, area_ratio: {area_ratio:.2f}")
374
- # # Accept if at least 70% of the circle's area lies within the tool polygon.
375
- # if area_ratio < 0.6:
376
- # continue
377
-
378
- # # Merge candidate circle with tool polygon using the existing union function.
379
- # candidate_union = union_tool_and_circle(tool_polygon, candidate_center, circle_diameter)
380
-
381
- # # Overlap check: ensure this candidate does not intrude on any other object.
382
- # overlap = False
383
- # for other_poly in all_polygons:
384
- # if other_poly.equals(tool_polygon):
385
- # continue
386
- # if candidate_union.intersects(other_poly) or candidate_circle.buffer(min_gap).intersects(other_poly):
387
- # overlap = True
388
- # #print(f"Candidate at {candidate_center} rejected due to overlap.")
389
- # break
390
- # if overlap:
391
- # continue
392
-
393
- # # Candidate accepted.
394
- # print(f"Accepted candidate center: {candidate_center} with area_ratio: {area_ratio:.2f}")
395
- # existing_centers.append(candidate_center)
396
- # return candidate_union, candidate_center
397
-
398
- # attempts += 1
399
-
400
- # print("Warning: Could not place a finger cut circle meeting all spacing requirements.")
401
- # return None, None
402
-
403
-
404
- # def place_finger_cut_adjusted(
405
- # tool_polygon,
406
- # points_inch,
407
- # existing_centers,
408
- # all_polygons,
409
- # circle_diameter=1.0, # Finger cut circle diameter in inches.
410
- # min_gap=0.25, # Minimum clearance (in inches) between the finger cut and adjacent contours.
411
- # max_attempts=50 # Maximum candidate attempts.
412
- # ):
413
- # """
414
- # Attempts to place a finger-cut circle along the tool polygon's contour, biased toward one side
415
- # (the boundary side) by shifting the candidate center away from the polygon centroid.
416
- # Simplified version that maintains core functionality while using a more streamlined approach.
417
-
418
- # :param tool_polygon: Shapely Polygon representing the tool contour.
419
- # :param points_inch: List of (x, y) points (in inches) along the contour.
420
- # :param existing_centers: List of already accepted finger cut centers.
421
- # :param all_polygons: List of all polygons (for overlap checking).
422
- # :param circle_diameter: Diameter of the finger cut (in inches).
423
- # :param min_gap: Clearance (in inches) required between the finger cut and any adjacent contour.
424
- # :param max_attempts: Maximum number of candidate attempts.
425
- # :return: (updated_polygon, candidate_center) if successful; otherwise, (None, None).
426
- # """
427
- # import random
428
- # import numpy as np
429
- # from shapely.geometry import Point
430
-
431
- # needed_center_distance = circle_diameter + min_gap
432
- # radius = circle_diameter / 2.0
433
-
434
- # # Compute the centroid of the tool polygon once.
435
- # polygon_centroid = tool_polygon.centroid
436
-
437
- # # Parameter: how far to push the candidate center outward.
438
- # outward_offset = radius * 0.5
439
-
440
- # # Try random points along the contour
441
- # indices = list(range(len(points_inch)))
442
- # random.shuffle(indices)
443
-
444
- # for idx in indices[:max_attempts]:
445
- # # Get base point from contour
446
- # base_x, base_y = points_inch[idx]
447
-
448
- # # Calculate the outward vector from centroid to point
449
- # vec_x = base_x - polygon_centroid.x
450
- # vec_y = base_y - polygon_centroid.y
451
- # norm = np.hypot(vec_x, vec_y)
452
-
453
- # if norm == 0:
454
- # continue # Skip if point is at centroid
455
-
456
- # # Normalize and calculate shifted candidate center
457
- # unit_vec = (vec_x / norm, vec_y / norm)
458
- # candidate_center = (base_x + unit_vec[0] * outward_offset,
459
- # base_y + unit_vec[1] * outward_offset)
460
-
461
- # # Check distance from existing centers
462
- # too_close = False
463
- # for (ex_x, ex_y) in existing_centers:
464
- # if np.hypot(candidate_center[0] - ex_x, candidate_center[1] - ex_y) < needed_center_distance:
465
- # too_close = True
466
- # break
467
-
468
- # if too_close:
469
- # continue
470
-
471
- # # Create the candidate circle
472
- # candidate_circle = Point(candidate_center).buffer(radius, resolution=64)
473
-
474
- # # Check if circle is mostly on the boundary (at least 60% inside)
475
- # area_ratio = candidate_circle.intersection(tool_polygon).area / candidate_circle.area
476
- # if area_ratio < 0.6:
477
- # continue
478
-
479
- # # Merge candidate with tool polygon
480
- # union_poly = union_tool_and_circle(tool_polygon, candidate_center, circle_diameter)
481
-
482
- # # Check for overlaps with other polygons
483
- # overlap = False
484
- # for other_poly in all_polygons:
485
- # if other_poly.equals(tool_polygon):
486
- # continue
487
- # if union_poly.intersects(other_poly) or candidate_circle.buffer(min_gap).intersects(other_poly):
488
- # overlap = True
489
- # break
490
-
491
- # if overlap:
492
- # continue
493
-
494
- # # Candidate accepted
495
- # print(f"Accepted candidate center: {candidate_center} with area_ratio: {area_ratio:.2f}")
496
- # existing_centers.append(candidate_center)
497
- # return union_poly, candidate_center
498
-
499
- # print("Warning: Could not place a finger cut circle meeting all spacing requirements.")
500
- # return None, None
501
-
502
-
503
- # def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_polygons, circle_diameter=1.0, min_gap=0.25, max_attempts=100):
504
- # import random
505
- # needed_center_distance = circle_diameter + min_gap
506
- # radius = circle_diameter / 2.0
507
- # for _ in range(max_attempts):
508
- # idx = random.randint(0, len(points_inch) - 1)
509
- # cx, cy = points_inch[idx]
510
- # too_close = False
511
- # for (ex_x, ex_y) in existing_centers:
512
- # if np.hypot(cx - ex_x, cy - ex_y) < needed_center_distance:
513
- # too_close = True
514
- # break
515
- # if too_close:
516
- # continue
517
- # circle_poly = Point((cx, cy)).buffer(radius, resolution=64)
518
- # union_poly = tool_polygon.union(circle_poly)
519
- # overlap_with_others = False
520
- # too_close_to_others = False
521
- # for poly in all_polygons:
522
- # if union_poly.intersects(poly):
523
- # overlap_with_others = True
524
- # break
525
- # if circle_poly.buffer(min_gap).intersects(poly):
526
- # too_close_to_others = True
527
- # break
528
- # if overlap_with_others or too_close_to_others:
529
- # continue
530
- # existing_centers.append((cx, cy))
531
- # return union_poly, (cx, cy)
532
- # print("Warning: Could not place a finger cut circle meeting all spacing requirements.")
533
- # return None, None
534
-
535
- # def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_polygons, 2nd best
536
- # circle_diameter=1.0, min_gap=0.25, max_attempts=30):
537
- # import random
538
- # from shapely.geometry import Point
539
-
540
- # # Analyze bounding box
541
- # bounds = tool_polygon.bounds # (minx, miny, maxx, maxy)
542
- # width = bounds[2] - bounds[0]
543
- # height = bounds[3] - bounds[1]
544
- # min_dim = min(width, height)
545
-
546
- # # Adjust circle diameter based on tool size
547
- # scale_factor = min(1.0, min_dim / 2.0) # Adjust this factor to control size sensitivity
548
- # adjusted_diameter = circle_diameter * scale_factor
549
- # radius = adjusted_diameter / 2.0
550
- # needed_center_distance = adjusted_diameter + min_gap
551
-
552
- # for _ in range(max_attempts):
553
- # idx = random.randint(0, len(points_inch) - 1)
554
- # cx, cy = points_inch[idx]
555
-
556
- # # Check distance from existing centers
557
- # if any(np.hypot(cx - ex_x, cy - ex_y) < needed_center_distance for ex_x, ex_y in existing_centers):
558
- # continue
559
-
560
- # circle_poly = Point((cx, cy)).buffer(radius, resolution=64)
561
- # union_poly = tool_polygon.union(circle_poly)
562
-
563
- # overlap_with_others = any(union_poly.intersects(poly) for poly in all_polygons)
564
- # too_close_to_others = any(circle_poly.buffer(min_gap).intersects(poly) for poly in all_polygons)
565
-
566
- # if overlap_with_others or too_close_to_others:
567
- # continue
568
-
569
- # existing_centers.append((cx, cy))
570
- # return union_poly, (cx, cy)
571
-
572
- # print("Warning: Could not place a finger cut circle meeting all spacing requirements.")
573
- # return None, None
574
-
575
 
576
  def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_polygons, circle_diameter=1.0, min_gap=0.25, max_attempts=30): #1st best
577
  needed_center_distance = circle_diameter + min_gap
@@ -616,110 +330,6 @@ def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_p
616
  return None, None
617
 
618
 
619
- # def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_polygons,
620
- # circle_diameter=1.0, min_gap=0.25, max_attempts=30):
621
- # fallback_diameters = [circle_diameter, 0.75, 0.5, 0.4] # Try these in order
622
-
623
- # for fallback_d in fallback_diameters:
624
- # radius = fallback_d / 2.0
625
- # needed_center_distance = fallback_d + min_gap
626
-
627
- # for _ in range(max_attempts):
628
- # idx = random.randint(0, len(points_inch) - 1)
629
- # cx, cy = points_inch[idx]
630
-
631
- # # Check distance from existing centers
632
- # too_close = any(np.hypot(cx - ex_x, cy - ex_y) < needed_center_distance
633
- # for ex_x, ex_y in existing_centers)
634
- # if too_close:
635
- # continue
636
-
637
- # # Create and check the finger cut circle
638
- # circle_poly = Point((cx, cy)).buffer(radius, resolution=64)
639
- # union_poly = tool_polygon.union(circle_poly)
640
-
641
- # if not union_poly.is_valid:
642
- # continue # Skip invalid geometry
643
-
644
- # # Check against all other polygons strictly
645
- # overlap = False
646
- # for poly in all_polygons:
647
- # if poly.equals(tool_polygon):
648
- # continue
649
-
650
- # # Shrink slightly to avoid even edge contact
651
- # if union_poly.intersects(poly.buffer(-1e-3)):
652
- # overlap = True
653
- # break
654
- # if circle_poly.buffer(min_gap).intersects(poly):
655
- # overlap = True
656
- # break
657
-
658
- # if overlap:
659
- # continue
660
-
661
- # # Final sanity check
662
- # for poly in all_polygons:
663
- # if poly.equals(tool_polygon):
664
- # continue
665
- # if union_poly.intersects(poly):
666
- # print("Overlap slipped through. Rejecting.")
667
- # overlap = True
668
- # break
669
-
670
- # if overlap:
671
- # continue
672
-
673
- # existing_centers.append((cx, cy))
674
- # return union_poly, (cx, cy)
675
-
676
- # # If we get here, all attempts failed — still try placing smallest fallback
677
- # print("Warning: Could not place cleanly. Forcing smallest fallback.")
678
- # smallest_radius = fallback_diameters[-1] / 2.0
679
- # for _ in range(100):
680
- # idx = random.randint(0, len(points_inch) - 1)
681
- # cx, cy = points_inch[idx]
682
- # circle_poly = Point((cx, cy)).buffer(smallest_radius, resolution=64)
683
- # union_poly = tool_polygon.union(circle_poly)
684
- # if union_poly.is_valid:
685
- # existing_centers.append((cx, cy))
686
- # return union_poly, (cx, cy)
687
-
688
- # # Absolute fallback — return original tool without finger cut
689
- # print("Failed to place even smallest fallback. No cutout added.")
690
- # return tool_polygon, None
691
-
692
-
693
- # def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_polygons, circle_diameter=1.0, min_gap=0.25, max_attempts=30):
694
- # import random
695
- # import numpy as np
696
- # from shapely.geometry import Point, Polygon
697
-
698
- # needed_center_distance = circle_diameter + min_gap
699
- # radius = circle_diameter / 2.0
700
- # for _ in range(max_attempts):
701
- # idx = random.randint(0, len(points_inch) - 1)
702
- # cx, cy = points_inch[idx]
703
- # # Check against existing centers
704
- # too_close = any(np.hypot(cx - ex_x, cy - ex_y) < needed_center_distance for (ex_x, ex_y) in existing_centers)
705
- # if too_close:
706
- # continue
707
- # circle_poly = Point((cx, cy)).buffer(radius, resolution=64)
708
- # # Ensure circle intersects the tool to form a valid cut
709
- # if not circle_poly.intersects(tool_polygon):
710
- # continue
711
- # # Check proximity to other polygons
712
- # if any(circle_poly.buffer(min_gap).intersects(poly) for poly in all_polygons):
713
- # continue
714
- # # Subtract circle from tool and check for overlaps
715
- # difference_poly = tool_polygon.difference(circle_poly)
716
- # if any(difference_poly.intersects(poly) for poly in all_polygons):
717
- # continue
718
- # existing_centers.append((cx, cy))
719
- # return difference_poly, (cx, cy)
720
- # print("Warning: Could not place a finger cut circle meeting all spacing requirements.")
721
- # return None, None
722
-
723
 
724
  # ---------------------
725
  # DXF Spline and Boundary Functions
@@ -1171,8 +781,8 @@ if __name__ == "__main__":
1171
  gr.Textbox(label="Scaling Factor (inches/pixel)")
1172
  ],
1173
  examples=[
1174
- ["./Test20.jpg", 0.075, "inches", "No", "No", 300.0, 200.0, "MyTool"],
1175
- ["./Test21.jpg", 0.075, "inches", "Yes", "Yes", 300.0, 200.0, "Tool2"]
1176
  ]
1177
  )
1178
  iface.launch(share=True)
 
286
  return []
287
  return list(poly.exterior.coords)
288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
 
290
  def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_polygons, circle_diameter=1.0, min_gap=0.25, max_attempts=30): #1st best
291
  needed_center_distance = circle_diameter + min_gap
 
330
  return None, None
331
 
332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
 
334
  # ---------------------
335
  # DXF Spline and Boundary Functions
 
781
  gr.Textbox(label="Scaling Factor (inches/pixel)")
782
  ],
783
  examples=[
784
+ ["./Test20.jpg", 0.075, "inches", "No", "No", 30.0, 20.0, "MyTool"],
785
+ ["./Test21.jpg", 0.075, "inches", "Yes", "Yes", 30.0, 20.0, "Tool2"]
786
  ]
787
  )
788
  iface.launch(share=True)