From 33dc00cb6a4a25d801a09f82054c9cc4a6f7a539 Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 4 Mar 2026 20:35:24 -0800 Subject: [PATCH] progress --- SetPiece_.gd | 2 +- TransitionPiece.gd | 1 + label.gd | 9 +- .../kq4_003_fountain_pool/columns.png.import | 40 ++++++ scenes/kq4_003_fountain_pool/columns_0.tres | 8 ++ scenes/kq4_003_fountain_pool/columns_1.tres | 8 ++ scenes/kq4_003_fountain_pool/columns_2.tres | 8 ++ scenes/kq4_003_fountain_pool/columns_3.tres | 8 ++ .../kq4_003_fountain_pool/columns_preview.png | 3 + .../columns_preview.png.import | 40 ++++++ .../kq4_003_fountain_pool.tscn | 52 +++++--- template_scene.gd | 8 +- tools/mask_to_polygon.py | 117 +++++++++++++++--- 13 files changed, 257 insertions(+), 47 deletions(-) create mode 100644 scenes/kq4_003_fountain_pool/columns.png.import create mode 100644 scenes/kq4_003_fountain_pool/columns_0.tres create mode 100644 scenes/kq4_003_fountain_pool/columns_1.tres create mode 100644 scenes/kq4_003_fountain_pool/columns_2.tres create mode 100644 scenes/kq4_003_fountain_pool/columns_3.tres create mode 100644 scenes/kq4_003_fountain_pool/columns_preview.png create mode 100644 scenes/kq4_003_fountain_pool/columns_preview.png.import diff --git a/SetPiece_.gd b/SetPiece_.gd index 74c9c51..0b1b501 100644 --- a/SetPiece_.gd +++ b/SetPiece_.gd @@ -1,6 +1,6 @@ @tool extends Polygon2D -#class_name SetPiece +class_name SetPiece # Declare member variables here. Examples: diff --git a/TransitionPiece.gd b/TransitionPiece.gd index 60710ee..10eeb58 100644 --- a/TransitionPiece.gd +++ b/TransitionPiece.gd @@ -1,4 +1,5 @@ extends "res://SetPiece_.gd" +class_name TransitionPiece @export var appear_at_node: String @export_file("*.tscn") var target diff --git a/label.gd b/label.gd index e04868b..960187c 100644 --- a/label.gd +++ b/label.gd @@ -7,13 +7,14 @@ extends Node2D @onready var label : Label = $"label" func _ready(): - for n in get_tree().get_nodes_in_group("set-piece"): - n.connect("entered", Callable(self, "_on_setpiece_entered")) - n.connect("exited", Callable(self, "_on_setpiece_exited")) + _connect_setpieces(get_parent()) func _on_transitioned(s): $label.hide() - for n in get_tree().get_nodes_in_group("set-piece"): + _connect_setpieces(get_parent()) + +func _connect_setpieces(scene: Node) -> void: + for n in scene.find_children("*", "SetPiece"): n.connect("entered", Callable(self, "_on_setpiece_entered")) n.connect("exited", Callable(self, "_on_setpiece_exited")) diff --git a/scenes/kq4_003_fountain_pool/columns.png.import b/scenes/kq4_003_fountain_pool/columns.png.import new file mode 100644 index 0000000..7639185 --- /dev/null +++ b/scenes/kq4_003_fountain_pool/columns.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dnh18cufk5m1e" +path="res://.godot/imported/columns.png-e0ca8e379675199b0c5c1f2210768c25.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://scenes/kq4_003_fountain_pool/columns.png" +dest_files=["res://.godot/imported/columns.png-e0ca8e379675199b0c5c1f2210768c25.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/scenes/kq4_003_fountain_pool/columns_0.tres b/scenes/kq4_003_fountain_pool/columns_0.tres new file mode 100644 index 0000000..4364f58 --- /dev/null +++ b/scenes/kq4_003_fountain_pool/columns_0.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="PolygonPointsResource" format=3 uid="uid://bu8vcjwarqsym"] + +[ext_resource type="Script" uid="uid://dtemboas3bi8y" path="res://PolygonPointsResource.gd" id="1_ppr"] + +[resource] +script = ExtResource("1_ppr") +points = PackedVector2Array(2453, 307, 2406, 529, 2417, 926, 2495, 1018, 2456, 1197, 2223, 1148, 2205, 980, 2279, 917, 2303, 522, 2266, 322, 2324, 290) +metadata/_custom_type_script = "uid://dtemboas3bi8y" diff --git a/scenes/kq4_003_fountain_pool/columns_1.tres b/scenes/kq4_003_fountain_pool/columns_1.tres new file mode 100644 index 0000000..d153f99 --- /dev/null +++ b/scenes/kq4_003_fountain_pool/columns_1.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="PolygonPointsResource" format=3 uid="uid://byjfu6q8wx5vn"] + +[ext_resource type="Script" uid="uid://dtemboas3bi8y" path="res://PolygonPointsResource.gd" id="1_ppr"] + +[resource] +script = ExtResource("1_ppr") +points = PackedVector2Array(173, 317, 212, 357, 216, 935, 284, 988, 259, 1125, 94, 1111, 24, 1040, 95, 931, 100, 457, 65, 322) +metadata/_custom_type_script = "uid://dtemboas3bi8y" diff --git a/scenes/kq4_003_fountain_pool/columns_2.tres b/scenes/kq4_003_fountain_pool/columns_2.tres new file mode 100644 index 0000000..16eccf8 --- /dev/null +++ b/scenes/kq4_003_fountain_pool/columns_2.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="PolygonPointsResource" format=3 uid="uid://dv2fngjcedsrt"] + +[ext_resource type="Script" uid="uid://dtemboas3bi8y" path="res://PolygonPointsResource.gd" id="1_ppr"] + +[resource] +script = ExtResource("1_ppr") +points = PackedVector2Array(496, 356, 489, 680, 523, 735, 531, 856, 490, 888, 386, 875, 386, 749, 419, 700, 405, 344) +metadata/_custom_type_script = "uid://dtemboas3bi8y" diff --git a/scenes/kq4_003_fountain_pool/columns_3.tres b/scenes/kq4_003_fountain_pool/columns_3.tres new file mode 100644 index 0000000..b18ce6a --- /dev/null +++ b/scenes/kq4_003_fountain_pool/columns_3.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="PolygonPointsResource" format=3 uid="uid://ufmqd22by6sj"] + +[ext_resource type="Script" uid="uid://dtemboas3bi8y" path="res://PolygonPointsResource.gd" id="1_ppr"] + +[resource] +script = ExtResource("1_ppr") +points = PackedVector2Array(2109, 359, 2089, 414, 2094, 663, 2126, 871, 2103, 879, 1995, 856, 2003, 734, 2029, 674, 2035, 427, 2016, 356) +metadata/_custom_type_script = "uid://dtemboas3bi8y" diff --git a/scenes/kq4_003_fountain_pool/columns_preview.png b/scenes/kq4_003_fountain_pool/columns_preview.png new file mode 100644 index 0000000..e4fc053 --- /dev/null +++ b/scenes/kq4_003_fountain_pool/columns_preview.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d1ced040c1a658e6cb0e77948a8a56213d3a6268aefa0bb50583ee7103252ff +size 92682 diff --git a/scenes/kq4_003_fountain_pool/columns_preview.png.import b/scenes/kq4_003_fountain_pool/columns_preview.png.import new file mode 100644 index 0000000..0bfc54d --- /dev/null +++ b/scenes/kq4_003_fountain_pool/columns_preview.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cu02obiykro70" +path="res://.godot/imported/columns_preview.png-4f93bff54ad2e8d1a27a3e45abd460bf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://scenes/kq4_003_fountain_pool/columns_preview.png" +dest_files=["res://.godot/imported/columns_preview.png-4f93bff54ad2e8d1a27a3e45abd460bf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn b/scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn index d1fe2d8..3d29744 100644 --- a/scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn +++ b/scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn @@ -4,9 +4,13 @@ [ext_resource type="Texture2D" uid="uid://nb7ybebcy6ok" path="res://scenes/kq4_003_fountain_pool/caption_1_2884713022_generated.png" id="2_ev2w4"] [ext_resource type="Script" uid="uid://xmphq3i0wbg3" path="res://ScalePoint_.gd" id="3_1g2ot"] [ext_resource type="PackedScene" uid="uid://c4vc1wx7k6cw" path="res://TransitionPiece.tscn" id="4_6r684"] -[ext_resource type="Resource" uid="uid://biiu4g5skgjun" path="res://scenes/kq4_003_fountain_pool/pool_shap2.tres" id="4_nuxlg"] +[ext_resource type="Resource" path="res://scenes/kq4_003_fountain_pool/pool_shap2.tres" id="4_nuxlg"] [ext_resource type="Texture2D" uid="uid://bmvcn5pl2qble" path="res://scenes/kq4_003_fountain_pool/fg.png" id="5_cu368"] +[ext_resource type="Resource" path="res://scenes/kq4_003_fountain_pool/columns_0.tres" id="6_7gmu8"] [ext_resource type="Script" uid="uid://bounwnqg34t5k" path="res://SetPiece_.gd" id="6_n67q9"] +[ext_resource type="Resource" path="res://scenes/kq4_003_fountain_pool/columns_1.tres" id="7_hj5s8"] +[ext_resource type="Resource" path="res://scenes/kq4_003_fountain_pool/columns_2.tres" id="8_1m5ii"] +[ext_resource type="Resource" path="res://scenes/kq4_003_fountain_pool/columns_3.tres" id="9_s7130"] [sub_resource type="NavigationPolygon" id="NavigationPolygon_heq0u"] vertices = PackedVector2Array(2047.41, 716.57, 2016.32, 718.031, 2012.05, 588.461, 2016.21, 588.297, -24.7109, 554.789, -30.1563, 678.656, -32.4922, 678.719, -26.5, 554.672, 1549.08, 973.094, 1600.39, 892.133, 1664.59, 879.789, 1849.6, 912.438, 2010.65, 1152.71, 1938.66, 866.219, 1997.01, 738.961, 1913.5, 767.961, 1652.01, 755.148, 1694.65, 795.859, 1548.2, 566.008, 1990.35, 536.656, 1991.42, 569.242, 1521.82, 587.352, -3.86719, 536.156, -3.4375, 526.25, 1322.68, 566.07, 572.727, 554.938, -28.5625, 1097.27, -11.0078, 698.188, 363.648, 688.758, 233.078, 917.219, 522.023, 998.82, 544.961, 937, 1256.86, 937, 1356.66, 1006.56, 1515.53, 657.82, 368.352, 561.688, 319.969, 1004.11) @@ -15,10 +19,10 @@ outlines = Array[PackedVector2Array]([PackedVector2Array(-13, 516, 1548, 556, 20 [node name="background" type="Node2D" unique_id=47039231] y_sort_enabled = true +scale = Vector2(0.77, 0.77) script = ExtResource("1_heq0u") [node name="bg" type="Sprite2D" parent="." unique_id=56586945] -scale = Vector2(0.78, 0.777) texture = ExtResource("2_ev2w4") centered = false @@ -45,7 +49,6 @@ position = Vector2(-150, 100) polygon = PackedVector2Array(-108, 454, -87, 649, 376, 658, 348, 381) appear_at_node = "kq4_003_fountain_pool" target = "uid://1489d4oh9twtu" -label = "Meadow" [node name="entrance" parent="kq4_002_meadow" index="0"] position = Vector2(350, 500) @@ -59,7 +62,6 @@ color = Color(1, 1, 1, 1) polygon = PackedVector2Array(-235, -142, -147, 252, 155, 148, 102, -85) appear_at_node = "kq4_003_fountain_pool" target = "uid://1nxmm3b1kcdm1" -label = "Ogre's House" [node name="entrance" parent="kq4_004_ogres_cottage" index="0"] position = Vector2(-79, 65) @@ -72,7 +74,6 @@ position = Vector2(910, 542) polygon = PackedVector2Array(-108, 454, -87, 649, 376, 658, 348, 381) appear_at_node = "kq4_003_fountain_pool" target = "uid://1hkplw2a78b1y" -label = "Shady Wooded Area" [node name="entrance" parent="kq4_009_shady_wooded_area" index="0"] position = Vector2(118, 514) @@ -85,7 +86,6 @@ position = Vector2(500, 100) polygon = PackedVector2Array(122, 279, -87, 649, 688, 583, 650, 277) appear_at_node = "kq4_003_fountain_pool" target = "uid://1fpyosj18xls7" -label = "Forest Path" [node name="entrance" parent="kq4_027_forest_path" index="0"] position = Vector2(207, 489) @@ -94,11 +94,36 @@ position = Vector2(207, 489) position = Vector2(396, 438) [node name="columns" type="Polygon2D" parent="." unique_id=896145355] -position = Vector2(-43, 689) +scale = Vector2(0.785, 0.785) color = Color(0.7, 0.7, 0.7, 0.25) -polygon = PackedVector2Array(398, -10, 402, -118, -4, -128, 0, -19) +polygon = PackedVector2Array(2453, 307, 2406, 529, 2417, 926, 2495, 1018, 2456, 1197, 2223, 1148, 2205, 980, 2279, 917, 2303, 522, 2266, 322, 2324, 290) script = ExtResource("6_n67q9") label = "Columns" +points_resource = ExtResource("6_7gmu8") + +[node name="columns2" type="Polygon2D" parent="." unique_id=1059125744] +scale = Vector2(0.785, 0.785) +color = Color(0.7, 0.7, 0.7, 0.25) +polygon = PackedVector2Array(173, 317, 212, 357, 216, 935, 284, 988, 259, 1125, 94, 1111, 24, 1040, 95, 931, 100, 457, 65, 322) +script = ExtResource("6_n67q9") +label = "Columns" +points_resource = ExtResource("7_hj5s8") + +[node name="columns3" type="Polygon2D" parent="." unique_id=1419038383] +scale = Vector2(0.785, 0.785) +color = Color(0.7, 0.7, 0.7, 0.25) +polygon = PackedVector2Array(496, 356, 489, 680, 523, 735, 531, 856, 490, 888, 386, 875, 386, 749, 419, 700, 405, 344) +script = ExtResource("6_n67q9") +label = "Columns" +points_resource = ExtResource("8_1m5ii") + +[node name="columns4" type="Polygon2D" parent="." unique_id=1962195047] +scale = Vector2(0.785, 0.785) +color = Color(0.7, 0.7, 0.7, 0.25) +polygon = PackedVector2Array(2109, 359, 2089, 414, 2094, 663, 2126, 871, 2103, 879, 1995, 856, 2003, 734, 2029, 674, 2035, 427, 2016, 356) +script = ExtResource("6_n67q9") +label = "Columns" +points_resource = ExtResource("9_s7130") [node name="stairs" type="Polygon2D" parent="." unique_id=737804296] position = Vector2(1526, 653) @@ -107,13 +132,6 @@ polygon = PackedVector2Array(129, 92, 534, 73, 498, -75, 5, -56) script = ExtResource("6_n67q9") label = "Stairs" -[node name="ground" type="Polygon2D" parent="." unique_id=1868664008] -position = Vector2(-28.5625, 1097.27) -color = Color(0.4, 0.27, 0.13, 0.25) -polygon = PackedVector2Array(17.5625, -399.27, 392.211, -408.512, 261.641, -180.051, 550.586, -98.4498, 573.523, -160.27, 1285.42, -160.27, 1385.22, -90.7104, 1544.09, -439.453, 396.914, -535.582, 17.5547, -1051.08) -script = ExtResource("6_n67q9") -label = "Ground" - [node name="Fg" type="Sprite2D" parent="." unique_id=1431047880] scale = Vector2(1.163, 1.179) texture = ExtResource("5_cu368") @@ -132,8 +150,10 @@ points_resource = ExtResource("4_nuxlg") [connection signal="interacted" from="kq4_009_shady_wooded_area" to="." method="_on_shady_wooded_area_interacted"] [connection signal="interacted" from="kq4_027_forest_path" to="." method="_on_forest_path_27_interacted"] [connection signal="looked" from="columns" to="." method="_on_columns_looked"] +[connection signal="looked" from="columns2" to="." method="_on_columns_looked"] +[connection signal="looked" from="columns3" to="." method="_on_columns_looked"] +[connection signal="looked" from="columns4" to="." method="_on_columns_looked"] [connection signal="looked" from="stairs" to="." method="_on_stairs_looked"] -[connection signal="looked" from="ground" to="." method="_on_ground_looked"] [connection signal="looked" from="pool" to="." method="_on_pool_looked"] [editable path="kq4_002_meadow"] diff --git a/template_scene.gd b/template_scene.gd index a721b73..fcf5172 100644 --- a/template_scene.gd +++ b/template_scene.gd @@ -5,10 +5,6 @@ func _ready() -> void: super._ready() func _register_setpiece_defaults() -> void: - for sp in get_tree().get_nodes_in_group("transition-set-piece"): - print("SET PIECE", sp) - sp.interacted.connect(func(): - print("HELE") - sp.default_script(self) - ) + for sp in find_children("*", "TransitionPiece"): + sp.interacted.connect(func(): sp.default_script(self)) diff --git a/tools/mask_to_polygon.py b/tools/mask_to_polygon.py index 164757a..4e8b9bd 100755 --- a/tools/mask_to_polygon.py +++ b/tools/mask_to_polygon.py @@ -41,16 +41,16 @@ def find_largest_contour(contours: list) -> np.ndarray: return max(contours, key=cv2.contourArea) -def contours_to_polygon(contours: list, mode: str) -> np.ndarray: +def contours_to_polygon(contours: list, mode: str) -> np.ndarray | None: """ Convert contours to a single polygon. Args: contours: List of contours from cv2.findContours - mode: "convex_hull" or "largest_only" + mode: "convex_hull", "largest_only", or "multiple" Returns: - Single contour as numpy array + Single contour as numpy array (or None for "multiple" mode) """ if not contours: return None @@ -62,9 +62,23 @@ def contours_to_polygon(contours: list, mode: str) -> np.ndarray: all_points = np.vstack(contours) return cv2.convexHull(all_points) + if mode == "multiple": + return None + raise ValueError(f"Unknown mode: {mode}") +def process_contour( + contour: np.ndarray, padding: float, target_points: int +) -> np.ndarray: + """ + Process a single contour: pad, simplify, and ensure clockwise. + """ + padded = pad_polygon(contour, padding) + simplified = simplify_to_target_points(padded, target_points) + return ensure_clockwise(simplified) + + def simplify_to_target_points(contour: np.ndarray, target_points: int) -> np.ndarray: """ Simplify a contour to approximately target number of points. @@ -230,9 +244,9 @@ def main(): ) parser.add_argument( "--mode", - choices=["convex_hull", "largest_only"], + choices=["convex_hull", "largest_only", "multiple"], default="convex_hull", - help="How to handle multiple regions (default: convex_hull)", + help="How to handle multiple regions: convex_hull, largest_only, or multiple (default: convex_hull)", ) parser.add_argument( "--preview", @@ -240,6 +254,12 @@ def main(): default=None, help="Output preview PNG showing polygon on mask", ) + parser.add_argument( + "--min-area", + type=int, + default=100, + help="Minimum contour area to include in multiple mode (default: 100)", + ) args = parser.parse_args() @@ -259,25 +279,82 @@ def main(): print("Error: No contours found in mask", file=sys.stderr) sys.exit(1) - polygon = contours_to_polygon(contours, args.mode) - padded = pad_polygon(polygon, args.padding) - simplified = simplify_to_target_points(padded, args.target_points) - clockwise = ensure_clockwise(simplified) + if args.mode == "multiple": + contours = sorted(contours, key=cv2.contourArea, reverse=True) + contours = [c for c in contours if cv2.contourArea(c) >= args.min_area] - output_path = args.output - if output_path is None: - output_path = args.image.with_suffix(".tres") + if not contours: + print("Error: No contours meet minimum area requirement", file=sys.stderr) + sys.exit(1) - uid = generate_godot_uid() - write_tres(clockwise, output_path, uid) + output_base = args.output if args.output else args.image.with_suffix("") + output_dir = output_base.parent + output_stem = output_base.stem - if args.preview: - write_preview(image, clockwise, args.preview) - print(f"Preview: {args.preview}") + all_points = [] + for i, contour in enumerate(contours): + processed = process_contour(contour, args.padding, args.target_points) + all_points.append(processed) - print(f"Created: {output_path}") - print(f"Points: {len(clockwise.squeeze())}") - print(f"UID: uid://{uid}") + output_path = output_dir / f"{output_stem}_{i}.tres" + uid = generate_godot_uid() + write_tres(processed, output_path, uid) + print(f"Created: {output_path}") + print(f" Points: {len(processed.squeeze())}") + print(f" UID: uid://{uid}") + + if args.preview: + preview = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) + colors = [ + (0, 255, 0), + (255, 0, 0), + (0, 0, 255), + (255, 255, 0), + (255, 0, 255), + (0, 255, 255), + ] + for i, points in enumerate(all_points): + color = colors[i % len(colors)] + pts = points.squeeze().astype(np.int32).reshape(-1, 1, 2) + cv2.polylines(preview, [pts], True, color, 2) + for j, pt in enumerate(pts): + cv2.circle(preview, tuple(pt[0]), 4, (0, 0, 255), -1) + cv2.putText( + preview, + f"{i}.{j}", + (pt[0][0] + 5, pt[0][1] - 5), + cv2.FONT_HERSHEY_SIMPLEX, + 0.4, + (255, 255, 0), + 1, + ) + cv2.imwrite(str(args.preview), preview) + print(f"Preview: {args.preview}") + + print(f"Total polygons: {len(all_points)}") + else: + polygon = contours_to_polygon(contours, args.mode) + if polygon is None: + print("Error: No polygon generated", file=sys.stderr) + sys.exit(1) + padded = pad_polygon(polygon, args.padding) + simplified = simplify_to_target_points(padded, args.target_points) + clockwise = ensure_clockwise(simplified) + + output_path = args.output + if output_path is None: + output_path = args.image.with_suffix(".tres") + + uid = generate_godot_uid() + write_tres(clockwise, output_path, uid) + + if args.preview: + write_preview(image, clockwise, args.preview) + print(f"Preview: {args.preview}") + + print(f"Created: {output_path}") + print(f"Points: {len(clockwise.squeeze())}") + print(f"UID: uid://{uid}") if __name__ == "__main__":