session-py 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. session_py-0.1.3/.github/workflows/publish.yml +71 -0
  2. session_py-0.1.3/.gitignore +27 -0
  3. session_py-0.1.3/.gitmodules +6 -0
  4. session_py-0.1.3/PKG-INFO +59 -0
  5. session_py-0.1.3/README.md +32 -0
  6. session_py-0.1.3/doc.bat +40 -0
  7. session_py-0.1.3/doc.sh +32 -0
  8. session_py-0.1.3/examples/bvh_demo.py +174 -0
  9. session_py-0.1.3/examples/nurbsurface.py +153 -0
  10. session_py-0.1.3/main.py +569 -0
  11. session_py-0.1.3/pyproject.toml +68 -0
  12. session_py-0.1.3/serialization/test_arrow.json +959 -0
  13. session_py-0.1.3/serialization/test_boundingbox.bin +0 -0
  14. session_py-0.1.3/serialization/test_boundingbox.json +78 -0
  15. session_py-0.1.3/serialization/test_color.bin +3 -0
  16. session_py-0.1.3/serialization/test_color.json +9 -0
  17. session_py-0.1.3/serialization/test_edge.json +9 -0
  18. session_py-0.1.3/serialization/test_graph.json +34 -0
  19. session_py-0.1.3/serialization/test_line.bin +0 -0
  20. session_py-0.1.3/serialization/test_line.json +44 -0
  21. session_py-0.1.3/serialization/test_mesh.bin +0 -0
  22. session_py-0.1.3/serialization/test_mesh.json +108 -0
  23. session_py-0.1.3/serialization/test_nurbscurve.bin +0 -0
  24. session_py-0.1.3/serialization/test_nurbscurve.json +71 -0
  25. session_py-0.1.3/serialization/test_nurbssurface.bin +0 -0
  26. session_py-0.1.3/serialization/test_nurbssurface.json +104 -0
  27. session_py-0.1.3/serialization/test_objects.json +98 -0
  28. session_py-0.1.3/serialization/test_plane.bin +0 -0
  29. session_py-0.1.3/serialization/test_plane.json +43 -0
  30. session_py-0.1.3/serialization/test_point.bin +0 -0
  31. session_py-0.1.3/serialization/test_point.json +41 -0
  32. session_py-0.1.3/serialization/test_pointcloud.bin +0 -0
  33. session_py-0.1.3/serialization/test_pointcloud.json +55 -0
  34. session_py-0.1.3/serialization/test_polyline.bin +0 -0
  35. session_py-0.1.3/serialization/test_polyline.json +52 -0
  36. session_py-0.1.3/serialization/test_quaternion.json +9 -0
  37. session_py-0.1.3/serialization/test_session.json +148 -0
  38. session_py-0.1.3/serialization/test_tree.json +11 -0
  39. session_py-0.1.3/serialization/test_treenode.json +13 -0
  40. session_py-0.1.3/serialization/test_trimmedsurface.bin +0 -0
  41. session_py-0.1.3/serialization/test_trimmedsurface.json +169 -0
  42. session_py-0.1.3/serialization/test_vector.bin +1 -0
  43. session_py-0.1.3/serialization/test_vector.json +8 -0
  44. session_py-0.1.3/serialization/test_vertex.json +7 -0
  45. session_py-0.1.3/serialization/test_xform.bin +0 -0
  46. session_py-0.1.3/serialization/test_xform.json +23 -0
  47. session_py-0.1.3/src/session_py/__init__.py +70 -0
  48. session_py-0.1.3/src/session_py/aabb_test.py +106 -0
  49. session_py-0.1.3/src/session_py/boundingbox.py +553 -0
  50. session_py-0.1.3/src/session_py/boundingbox_test.py +154 -0
  51. session_py-0.1.3/src/session_py/brep.py +1069 -0
  52. session_py-0.1.3/src/session_py/brep_test.py +353 -0
  53. session_py-0.1.3/src/session_py/bvh.py +880 -0
  54. session_py-0.1.3/src/session_py/bvh_test.py +306 -0
  55. session_py-0.1.3/src/session_py/closest.py +514 -0
  56. session_py-0.1.3/src/session_py/closest_test.py +159 -0
  57. session_py-0.1.3/src/session_py/color.py +516 -0
  58. session_py-0.1.3/src/session_py/color_test.py +164 -0
  59. session_py-0.1.3/src/session_py/edge.py +64 -0
  60. session_py-0.1.3/src/session_py/edge_test.py +26 -0
  61. session_py-0.1.3/src/session_py/encoders.py +245 -0
  62. session_py-0.1.3/src/session_py/encoders_test.py +256 -0
  63. session_py-0.1.3/src/session_py/graph.py +658 -0
  64. session_py-0.1.3/src/session_py/graph_test.py +29 -0
  65. session_py-0.1.3/src/session_py/intersection.py +1512 -0
  66. session_py-0.1.3/src/session_py/intersection_test.py +588 -0
  67. session_py-0.1.3/src/session_py/knot.py +1126 -0
  68. session_py-0.1.3/src/session_py/knot_test.py +258 -0
  69. session_py-0.1.3/src/session_py/line.py +801 -0
  70. session_py-0.1.3/src/session_py/line_test.py +322 -0
  71. session_py-0.1.3/src/session_py/mesh.py +2016 -0
  72. session_py-0.1.3/src/session_py/mesh_test.py +746 -0
  73. session_py-0.1.3/src/session_py/mini_test.py +432 -0
  74. session_py-0.1.3/src/session_py/nurbscurve.py +3816 -0
  75. session_py-0.1.3/src/session_py/nurbscurve_test.py +744 -0
  76. session_py-0.1.3/src/session_py/nurbssurface.py +2889 -0
  77. session_py-0.1.3/src/session_py/nurbssurface_test.py +911 -0
  78. session_py-0.1.3/src/session_py/obj.py +60 -0
  79. session_py-0.1.3/src/session_py/obj_test.py +49 -0
  80. session_py-0.1.3/src/session_py/objects.py +214 -0
  81. session_py-0.1.3/src/session_py/objects_test.py +27 -0
  82. session_py-0.1.3/src/session_py/plane.py +895 -0
  83. session_py-0.1.3/src/session_py/plane_test.py +294 -0
  84. session_py-0.1.3/src/session_py/point.py +659 -0
  85. session_py-0.1.3/src/session_py/point_test.py +243 -0
  86. session_py-0.1.3/src/session_py/pointcloud.py +447 -0
  87. session_py-0.1.3/src/session_py/pointcloud_test.py +226 -0
  88. session_py-0.1.3/src/session_py/polyline.py +983 -0
  89. session_py-0.1.3/src/session_py/polyline_test.py +435 -0
  90. session_py-0.1.3/src/session_py/primitives.py +2556 -0
  91. session_py-0.1.3/src/session_py/primitives_test.py +1390 -0
  92. session_py-0.1.3/src/session_py/proto/__init__.py +4 -0
  93. session_py-0.1.3/src/session_py/proto/boundingbox_pb2.py +39 -0
  94. session_py-0.1.3/src/session_py/proto/brep_pb2.py +55 -0
  95. session_py-0.1.3/src/session_py/proto/bvh_pb2.py +41 -0
  96. session_py-0.1.3/src/session_py/proto/color_pb2.py +36 -0
  97. session_py-0.1.3/src/session_py/proto/edge_pb2.py +36 -0
  98. session_py-0.1.3/src/session_py/proto/encoders_pb2.py +38 -0
  99. session_py-0.1.3/src/session_py/proto/graph_pb2.py +42 -0
  100. session_py-0.1.3/src/session_py/proto/line_pb2.py +38 -0
  101. session_py-0.1.3/src/session_py/proto/mesh_pb2.py +94 -0
  102. session_py-0.1.3/src/session_py/proto/nurbscurve_pb2.py +38 -0
  103. session_py-0.1.3/src/session_py/proto/nurbssurface_pb2.py +39 -0
  104. session_py-0.1.3/src/session_py/proto/objects_pb2.py +46 -0
  105. session_py-0.1.3/src/session_py/proto/plane_pb2.py +37 -0
  106. session_py-0.1.3/src/session_py/proto/point_pb2.py +38 -0
  107. session_py-0.1.3/src/session_py/proto/pointcloud_pb2.py +37 -0
  108. session_py-0.1.3/src/session_py/proto/polyline_pb2.py +38 -0
  109. session_py-0.1.3/src/session_py/proto/quaternion_pb2.py +36 -0
  110. session_py-0.1.3/src/session_py/proto/session_pb2.py +40 -0
  111. session_py-0.1.3/src/session_py/proto/tolerance_pb2.py +36 -0
  112. session_py-0.1.3/src/session_py/proto/tree_pb2.py +37 -0
  113. session_py-0.1.3/src/session_py/proto/treenode_pb2.py +37 -0
  114. session_py-0.1.3/src/session_py/proto/trimmedsurface_pb2.py +40 -0
  115. session_py-0.1.3/src/session_py/proto/vector_pb2.py +36 -0
  116. session_py-0.1.3/src/session_py/proto/vertex_pb2.py +36 -0
  117. session_py-0.1.3/src/session_py/proto/xform_pb2.py +36 -0
  118. session_py-0.1.3/src/session_py/quaternion.py +119 -0
  119. session_py-0.1.3/src/session_py/quaternion_test.py +26 -0
  120. session_py-0.1.3/src/session_py/ray_box_intersection.py +76 -0
  121. session_py-0.1.3/src/session_py/reload.py +137 -0
  122. session_py-0.1.3/src/session_py/session.py +772 -0
  123. session_py-0.1.3/src/session_py/session_test.py +264 -0
  124. session_py-0.1.3/src/session_py/tolerance.py +377 -0
  125. session_py-0.1.3/src/session_py/tolerance_test.py +78 -0
  126. session_py-0.1.3/src/session_py/tree.py +352 -0
  127. session_py-0.1.3/src/session_py/tree_test.py +30 -0
  128. session_py-0.1.3/src/session_py/treenode.py +186 -0
  129. session_py-0.1.3/src/session_py/treenode_test.py +26 -0
  130. session_py-0.1.3/src/session_py/triangulation_2d.py +321 -0
  131. session_py-0.1.3/src/session_py/triangulation_2d_test.py +114 -0
  132. session_py-0.1.3/src/session_py/trimesh_adaptive.py +429 -0
  133. session_py-0.1.3/src/session_py/trimesh_cdt.py +738 -0
  134. session_py-0.1.3/src/session_py/trimmedsurface.py +461 -0
  135. session_py-0.1.3/src/session_py/trimmedsurface_test.py +392 -0
  136. session_py-0.1.3/src/session_py/vector.py +1139 -0
  137. session_py-0.1.3/src/session_py/vector_test.py +430 -0
  138. session_py-0.1.3/src/session_py/vertex.py +59 -0
  139. session_py-0.1.3/src/session_py/vertex_test.py +25 -0
  140. session_py-0.1.3/src/session_py/xform.py +719 -0
  141. session_py-0.1.3/src/session_py/xform_test.py +365 -0
  142. session_py-0.1.3/test.bat +55 -0
  143. session_py-0.1.3/test.sh +56 -0
  144. session_py-0.1.3/uv.lock +3298 -0
@@ -0,0 +1,71 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ matrix:
12
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ submodules: true
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+
22
+ - name: Install and test
23
+ run: |
24
+ pip install -e ".[dev]"
25
+ pytest
26
+
27
+ publish:
28
+ needs: test
29
+ runs-on: ubuntu-latest
30
+ environment:
31
+ name: pypi
32
+ url: https://pypi.org/p/session_py
33
+ permissions:
34
+ id-token: write # PyPI trusted publisher
35
+ contents: write # create GitHub releases + tags
36
+
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - uses: actions/setup-python@v5
41
+ with:
42
+ python-version: "3.11"
43
+
44
+ - name: Set version
45
+ run: echo "VERSION=0.1.${{ github.run_number }}" >> $GITHUB_ENV
46
+
47
+ - name: Patch pyproject.toml version
48
+ run: sed -i "s/^version = .*/version = \"$VERSION\"/" pyproject.toml
49
+
50
+ - name: Commit version bump
51
+ run: |
52
+ git config user.name "github-actions[bot]"
53
+ git config user.email "github-actions[bot]@users.noreply.github.com"
54
+ git add pyproject.toml
55
+ git commit -m "chore: bump version to $VERSION [skip ci]"
56
+ git push
57
+
58
+ - name: Build
59
+ run: |
60
+ pip install build
61
+ python -m build
62
+
63
+ - name: Create GitHub Release
64
+ uses: softprops/action-gh-release@v2
65
+ with:
66
+ tag_name: v${{ env.VERSION }}
67
+ name: v${{ env.VERSION }}
68
+ files: dist/*
69
+
70
+ - name: Publish to PyPI
71
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,27 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.so
5
+ .Python
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+
10
+ # Virtual environments
11
+ venv/
12
+ env/
13
+ ENV/
14
+ uvsession/
15
+ session/
16
+
17
+ # Documentation
18
+ docs_output/
19
+ _build/
20
+
21
+ # IDE
22
+ .vscode/
23
+ .idea/
24
+ *.swp
25
+
26
+ # OS
27
+ .DS_Store
@@ -0,0 +1,6 @@
1
+ [submodule "session_proto"]
2
+ path = session_proto
3
+ url = https://github.com/petrasvestartas/session_proto.git
4
+ [submodule "session_data"]
5
+ path = session_data
6
+ url = https://github.com/petrasvestartas/session_data.git
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: session_py
3
+ Version: 0.1.3
4
+ Summary: A minimal Python geometry library
5
+ Project-URL: Homepage, https://github.com/petrasvestartas/session_py
6
+ Project-URL: Repository, https://github.com/petrasvestartas/session_py
7
+ Author-email: Petras Vestartas <petrasvestartas@gmail.com>
8
+ License: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Requires-Python: >=3.8
18
+ Requires-Dist: grpcio-tools>=1.60.0
19
+ Requires-Dist: numpy>=1.20.0
20
+ Requires-Dist: protobuf>=5.0.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
23
+ Requires-Dist: pytest>=7.0; extra == 'dev'
24
+ Provides-Extra: performance
25
+ Requires-Dist: numba>=0.56.0; extra == 'performance'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # session_py
29
+
30
+ Python NURBS geometry library.
31
+
32
+ ## Setup
33
+
34
+ ```bash
35
+ # Create environment
36
+ uv venv uvsession --python 3.11
37
+ source uvsession/bin/activate
38
+
39
+ # Install
40
+ uv pip install -e .
41
+ ```
42
+
43
+ ## Test
44
+
45
+ ```bash
46
+ source uvsession/bin/activate
47
+ pytest -v
48
+ ```
49
+
50
+ ## Publish
51
+
52
+ ```bash
53
+ Edit pyproject.toml version: "0.1.0" → "0.1.1"
54
+ cd session_py
55
+ git add pyproject.toml .github/
56
+ git commit -m "setup PyPI publish workflow"
57
+ git tag v0.1.0
58
+ git push && git push --tags
59
+ ```
@@ -0,0 +1,32 @@
1
+ # session_py
2
+
3
+ Python NURBS geometry library.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ # Create environment
9
+ uv venv uvsession --python 3.11
10
+ source uvsession/bin/activate
11
+
12
+ # Install
13
+ uv pip install -e .
14
+ ```
15
+
16
+ ## Test
17
+
18
+ ```bash
19
+ source uvsession/bin/activate
20
+ pytest -v
21
+ ```
22
+
23
+ ## Publish
24
+
25
+ ```bash
26
+ Edit pyproject.toml version: "0.1.0" → "0.1.1"
27
+ cd session_py
28
+ git add pyproject.toml .github/
29
+ git commit -m "setup PyPI publish workflow"
30
+ git tag v0.1.0
31
+ git push && git push --tags
32
+ ```
@@ -0,0 +1,40 @@
1
+ @echo off
2
+ REM Script to build session_py documentation using Sphinx
3
+
4
+ echo Building session_py documentation...
5
+
6
+ REM Change to docs directory
7
+ cd docs
8
+
9
+ REM Clean previous build
10
+ echo Cleaning previous build...
11
+ if exist _build rmdir /s /q _build
12
+ if exist Makefile.bat (
13
+ call make.bat clean
14
+ ) else (
15
+ sphinx-build -M clean . _build
16
+ )
17
+
18
+ REM Build HTML documentation
19
+ echo Building HTML documentation...
20
+ if exist Makefile.bat (
21
+ call make.bat html
22
+ ) else (
23
+ sphinx-build -M html . _build
24
+ )
25
+
26
+ if %errorlevel% equ 0 (
27
+ REM Copy built HTML to a stable output directory used by CI deployment
28
+ if exist ..\docs_output\html rmdir /s /q ..\docs_output\html
29
+ if not exist ..\docs_output mkdir ..\docs_output
30
+ xcopy /e /i _build\html ..\docs_output\html
31
+ echo.
32
+ echo Documentation built successfully!
33
+ echo Open docs_output\html\index.html in your browser to view the documentation.
34
+ echo.
35
+ echo To serve locally, run:
36
+ echo cd docs_output\html ^&^& python -m http.server 8000
37
+ ) else (
38
+ echo Build failed!
39
+ exit /b 1
40
+ )
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+
3
+ # Script to build session_py documentation using Sphinx
4
+
5
+ echo "Building session_py documentation..."
6
+
7
+ # Change to docs directory
8
+ cd docs
9
+
10
+ # Clean previous build
11
+ echo "Cleaning previous build..."
12
+ make clean
13
+
14
+ # Build HTML documentation
15
+ echo "Building HTML documentation..."
16
+ make html
17
+
18
+ if [ $? -eq 0 ]; then
19
+ # Copy built HTML to a stable output directory used by CI deployment
20
+ rm -rf ../docs_output/html
21
+ mkdir -p ../docs_output
22
+ cp -r _build/html ../docs_output/
23
+ echo ""
24
+ echo "Documentation built successfully!"
25
+ echo "Open docs_output/html/index.html in your browser to view the documentation."
26
+ echo ""
27
+ echo "To serve locally, run:"
28
+ echo " cd docs_output/html && python -m http.server 8000"
29
+ else
30
+ echo "Build failed!"
31
+ exit 1
32
+ fi
@@ -0,0 +1,174 @@
1
+ """BVH Collision Detection Demo
2
+
3
+ This example demonstrates how to use the BVH (Boundary Volume Hierarchy)
4
+ for efficient collision detection among many objects.
5
+ """
6
+
7
+ import random
8
+ import time
9
+ from session_py import BVH, BoundingBox, Point, Vector
10
+
11
+
12
+ def create_random_boxes(count, world_size=100.0, min_size=0.5, max_size=3.0):
13
+ """Create random bounding boxes in 3D space.
14
+
15
+ Parameters
16
+ ----------
17
+ count : int
18
+ Number of boxes to create.
19
+ world_size : float
20
+ Size of the world bounds.
21
+ min_size : float
22
+ Minimum box dimension.
23
+ max_size : float
24
+ Maximum box dimension.
25
+
26
+ Returns
27
+ -------
28
+ list of BoundingBox
29
+ List of randomly positioned and sized bounding boxes.
30
+ """
31
+ boxes = []
32
+ for i in range(count):
33
+ # Random center position
34
+ center = Point(
35
+ random.uniform(-world_size / 2, world_size / 2),
36
+ random.uniform(-world_size / 2, world_size / 2),
37
+ random.uniform(-world_size / 2, world_size / 2),
38
+ )
39
+
40
+ # Random half-size (dimensions)
41
+ half_size = Vector(
42
+ random.uniform(min_size, max_size) / 2,
43
+ random.uniform(min_size, max_size) / 2,
44
+ random.uniform(min_size, max_size) / 2,
45
+ )
46
+
47
+ # Create axis-aligned bounding box
48
+ bbox = BoundingBox(
49
+ center,
50
+ Vector(1, 0, 0), # X axis
51
+ Vector(0, 1, 0), # Y axis
52
+ Vector(0, 0, 1), # Z axis
53
+ half_size,
54
+ )
55
+ boxes.append(bbox)
56
+
57
+ return boxes
58
+
59
+
60
+ def naive_collision_detection(boxes):
61
+ """Naive O(n²) collision detection for comparison.
62
+
63
+ Parameters
64
+ ----------
65
+ boxes : list of BoundingBox
66
+ List of bounding boxes to check.
67
+
68
+ Returns
69
+ -------
70
+ tuple
71
+ (collisions, check_count) where collisions is a list of (i, j) pairs.
72
+ """
73
+ collisions = []
74
+ check_count = 0
75
+
76
+ for i in range(len(boxes)):
77
+ for j in range(i + 1, len(boxes)):
78
+ check_count += 1
79
+ # Simple AABB intersection test
80
+ box1 = boxes[i]
81
+ box2 = boxes[j]
82
+
83
+ min1_x = box1.center.x - box1.half_size.x
84
+ max1_x = box1.center.x + box1.half_size.x
85
+ min2_x = box2.center.x - box2.half_size.x
86
+ max2_x = box2.center.x + box2.half_size.x
87
+
88
+ min1_y = box1.center.y - box1.half_size.y
89
+ max1_y = box1.center.y + box1.half_size.y
90
+ min2_y = box2.center.y - box2.half_size.y
91
+ max2_y = box2.center.y + box2.half_size.y
92
+
93
+ min1_z = box1.center.z - box1.half_size.z
94
+ max1_z = box1.center.z + box1.half_size.z
95
+ min2_z = box2.center.z - box2.half_size.z
96
+ max2_z = box2.center.z + box2.half_size.z
97
+
98
+ if (
99
+ min1_x <= max2_x
100
+ and max1_x >= min2_x
101
+ and min1_y <= max2_y
102
+ and max1_y >= min2_y
103
+ and min1_z <= max2_z
104
+ and max1_z >= min2_z
105
+ ):
106
+ collisions.append((i, j))
107
+
108
+ return collisions, check_count
109
+
110
+
111
+ def main():
112
+ """Run BVH collision detection demo."""
113
+ print("=" * 60)
114
+ print("BVH Collision Detection Demo")
115
+ print("=" * 60)
116
+
117
+ # Set random seed for reproducibility
118
+ random.seed(42)
119
+
120
+ # Test with different box counts
121
+ box_counts = [10, 50, 100, 500, 1000]
122
+
123
+ for count in box_counts:
124
+ print(f"\n--- Testing with {count} boxes ---")
125
+
126
+ # Create random boxes
127
+ boxes = create_random_boxes(count, world_size=100.0)
128
+
129
+ # Build BVH
130
+ bvh = BVH(world_size=100.0)
131
+ start_time = time.time()
132
+ bvh.build(boxes)
133
+ build_time = (time.time() - start_time) * 1000 # Convert to ms
134
+
135
+ # BVH collision detection
136
+ start_time = time.time()
137
+ bvh_collisions, bvh_checks = bvh.check_all_collisions(boxes)
138
+ bvh_time = (time.time() - start_time) * 1000 # Convert to ms
139
+
140
+ # Naive collision detection (only for smaller counts)
141
+ if count <= 100:
142
+ start_time = time.time()
143
+ naive_collisions, naive_checks = naive_collision_detection(boxes)
144
+ naive_time = (time.time() - start_time) * 1000
145
+
146
+ # Verify results match
147
+ assert len(bvh_collisions) == len(
148
+ naive_collisions
149
+ ), f"Collision count mismatch: BVH={len(bvh_collisions)}, Naive={len(naive_collisions)}"
150
+
151
+ speedup = naive_time / bvh_time if bvh_time > 0 else float("inf")
152
+ check_reduction = (
153
+ (1 - bvh_checks / naive_checks) * 100 if naive_checks > 0 else 0
154
+ )
155
+
156
+ print(f" Collisions found: {len(bvh_collisions)}")
157
+ print(f" BVH build time: {build_time:.2f} ms")
158
+ print(f" BVH check time: {bvh_time:.2f} ms ({bvh_checks:,} checks)")
159
+ print(f" Naive check time: {naive_time:.2f} ms ({naive_checks:,} checks)")
160
+ print(f" Speedup: {speedup:.1f}x")
161
+ print(f" Check reduction: {check_reduction:.1f}%")
162
+ else:
163
+ print(f" Collisions found: {len(bvh_collisions)}")
164
+ print(f" BVH build time: {build_time:.2f} ms")
165
+ print(f" BVH check time: {bvh_time:.2f} ms ({bvh_checks:,} checks)")
166
+ print(f" (Naive method skipped for performance)")
167
+
168
+ print("\n" + "=" * 60)
169
+ print("Demo complete!")
170
+ print("=" * 60)
171
+
172
+
173
+ if __name__ == "__main__":
174
+ main()
@@ -0,0 +1,153 @@
1
+ from session_py import NurbsSurface, Point
2
+ from compas_viewer import Viewer
3
+ from compas.datastructures import Mesh
4
+ from compas.geometry import Point as CompasPoint, Polyline
5
+
6
+ # Create a NURBS surface (3D, order 4, 5x5 control points)
7
+ srf = NurbsSurface(3, False, 4, 4, 5, 5)
8
+
9
+ # Setup knot vectors
10
+ srf.make_clamped_uniform_knot_vector(0, 1.0)
11
+ srf.make_clamped_uniform_knot_vector(1, 1.0)
12
+
13
+ # Set control points (hardcoded 5x5 grid)
14
+ srf.set_cv(0, 0, Point(0.0, 0.0, 2.5*-1))
15
+ srf.set_cv(0, 1, Point(0.0, 1.0, 0.0))
16
+ srf.set_cv(0, 2, Point(0.0, 2.0, 0.0))
17
+ srf.set_cv(0, 3, Point(0.0, 3.0, 0.0))
18
+ srf.set_cv(0, 4, Point(0.0, 4.0, 2.5*-1))
19
+
20
+ srf.set_cv(1, 0, Point(1.0, 0.0, 0.0))
21
+ srf.set_cv(1, 1, Point(1.0, 1.0, 0.0))
22
+ srf.set_cv(1, 2, Point(1.0, 2.0, 5.0))
23
+ srf.set_cv(1, 3, Point(1.0, 3.0, 0.0))
24
+ srf.set_cv(1, 4, Point(1.0, 4.0, 0.0))
25
+
26
+ srf.set_cv(2, 0, Point(2.0, 0.0, 0.0))
27
+ srf.set_cv(2, 1, Point(2.0, 1.0, 0.0))
28
+ srf.set_cv(2, 2, Point(2.0, 2.0, 0.0))
29
+ srf.set_cv(2, 3, Point(2.0, 3.0, 0.0))
30
+ srf.set_cv(2, 4, Point(2.0, 4.0, 0.0))
31
+
32
+ srf.set_cv(3, 0, Point(3.0, 0.0, 0.0))
33
+ srf.set_cv(3, 1, Point(3.0, 1.0, 0.0))
34
+ srf.set_cv(3, 2, Point(3.0, 2.0, 0.0))
35
+ srf.set_cv(3, 3, Point(3.0, 3.0, 0.0))
36
+ srf.set_cv(3, 4, Point(3.0, 4.0, 0.0))
37
+
38
+ srf.set_cv(4, 0, Point(4.0, 0.0, 2.5*-1))
39
+ srf.set_cv(4, 1, Point(4.0, 1.0, 0.0))
40
+ srf.set_cv(4, 2, Point(4.0, 2.0, 0.0))
41
+ srf.set_cv(4, 3, Point(4.0, 3.0, 0.0))
42
+ srf.set_cv(4, 4, Point(4.0, 4.0, 2.5*-1))
43
+
44
+ print("NURBS Surface Grid Evaluation\n")
45
+
46
+ # Evaluate surface at subdivided grid points
47
+ grid_size = 10 # Increase for finer mesh
48
+ u_min, u_max = srf.domain(0)
49
+ v_min, v_max = srf.domain(1)
50
+
51
+ # Store evaluated points in 2D grid
52
+ points_grid = []
53
+ for i in range(grid_size):
54
+ row = []
55
+ for j in range(grid_size):
56
+ # Calculate parameters
57
+ u = u_min + (u_max - u_min) * i / (grid_size - 1)
58
+ v = v_min + (v_max - v_min) * j / (grid_size - 1)
59
+
60
+ # Evaluate point
61
+ pt = srf.point_at(u, v)
62
+ row.append(CompasPoint(pt.x, pt.y, pt.z))
63
+ points_grid.append(row)
64
+
65
+ print(f"Evaluated {grid_size}x{grid_size} = {grid_size*grid_size} points")
66
+
67
+ # Create COMPAS Mesh
68
+ mesh = Mesh()
69
+
70
+ # Add vertices and store their keys in a 2D array
71
+ vertex_keys = []
72
+ for i in range(grid_size):
73
+ row_keys = []
74
+ for j in range(grid_size):
75
+ pt = points_grid[i][j]
76
+ key = mesh.add_vertex(x=pt.x, y=pt.y, z=pt.z)
77
+ row_keys.append(key)
78
+ vertex_keys.append(row_keys)
79
+
80
+ print(f"Added {mesh.number_of_vertices()} vertices")
81
+
82
+ # Create quad faces
83
+ face_count = 0
84
+ for i in range(grid_size - 1):
85
+ for j in range(grid_size - 1):
86
+ # Create quad face from 4 adjacent vertices
87
+ v0 = vertex_keys[i][j]
88
+ v1 = vertex_keys[i+1][j]
89
+ v2 = vertex_keys[i+1][j+1]
90
+ v3 = vertex_keys[i][j+1]
91
+ mesh.add_face([v0, v1, v2, v3])
92
+ face_count += 1
93
+
94
+ print(f"Added {face_count} quad faces")
95
+ print(f"Mesh: {mesh.number_of_vertices()} vertices, {mesh.number_of_faces()} faces, {mesh.number_of_edges()} edges")
96
+
97
+ # Extract isocurves and convert to polylines
98
+ print("\nExtracting Isocurves...")
99
+ iso_polylines = []
100
+ num_iso_curves = 5 # Number of isocurves in each direction
101
+ curve_divisions = 10 # Points per curve
102
+
103
+ # Extract iso-u curves (v varies, u constant)
104
+ print(f"Extracting {num_iso_curves} iso-u curves...")
105
+ for i in range(num_iso_curves):
106
+ u_param = u_min + (u_max - u_min) * i / (num_iso_curves - 1)
107
+ iso_curve = srf.iso_curve(0, u_param)
108
+
109
+ if iso_curve:
110
+ curve_points = []
111
+ t_min, t_max = iso_curve.domain()
112
+
113
+ for j in range(curve_divisions):
114
+ t = t_min + (t_max - t_min) * j / (curve_divisions - 1)
115
+ pt = iso_curve.point_at(t)
116
+ curve_points.append(CompasPoint(pt.x, pt.y, pt.z))
117
+
118
+ polyline = Polyline(curve_points)
119
+ iso_polylines.append(polyline)
120
+ print(f" Iso-u at u={u_param:.2f}: {len(curve_points)} points")
121
+
122
+ # Extract iso-v curves (u varies, v constant)
123
+ print(f"Extracting {num_iso_curves} iso-v curves...")
124
+ for i in range(num_iso_curves):
125
+ v_param = v_min + (v_max - v_min) * i / (num_iso_curves - 1)
126
+ iso_curve = srf.iso_curve(1, v_param)
127
+
128
+ if iso_curve:
129
+ curve_points = []
130
+ t_min, t_max = iso_curve.domain()
131
+
132
+ for j in range(curve_divisions):
133
+ t = t_min + (t_max - t_min) * j / (curve_divisions - 1)
134
+ pt = iso_curve.point_at(t)
135
+ curve_points.append(CompasPoint(pt.x, pt.y, pt.z))
136
+
137
+ polyline = Polyline(curve_points)
138
+ iso_polylines.append(polyline)
139
+ print(f" Iso-v at v={v_param:.2f}: {len(curve_points)} points")
140
+
141
+ print(f"\nTotal isocurve polylines: {len(iso_polylines)}")
142
+
143
+ # Visualize with COMPAS Viewer
144
+ viewer = Viewer()
145
+ viewer.scene.add(mesh, show_vertices=False, show_edges=True, show_faces=True, opacity=0.7)
146
+
147
+ # Add isocurve polylines with different color
148
+ for polyline in iso_polylines:
149
+ viewer.scene.add(polyline, linewidth=2, linecolor=(1, 0, 0)) # Red isocurves
150
+
151
+ viewer.show()
152
+
153
+ print("\n✅ Done!")