Skip to content

Commit c57f8cb

Browse files
committed
πŸ™†πŸ» Refactor STL handling
1 parent 2cf074a commit c57f8cb

5 files changed

Lines changed: 112 additions & 140 deletions

File tree

β€Žsrc/STLInfo.jlβ€Ž

Lines changed: 0 additions & 25 deletions
This file was deleted.

β€Žsrc/polygon.jlβ€Ž

Lines changed: 22 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,12 @@
1-
#==========================================================================================++
1+
#==========================================================================================+
22
| TABLE OF CONTENTS: |
33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4-
| struct list: |
5-
| - QueryPolygon |
6-
+------------------------------------------------------------------------------------------+
7-
| function list: |
8-
| - get_polygon (from LibGEOS, need to improve) |
4+
| - get_polygon |
95
| - pip_query |
106
+==========================================================================================#
117

12-
struct QueryPolygon
13-
ju_xy::AbstractMatrix
14-
py_xy::Py
15-
function QueryPolygon(ju_xy::AbstractMatrix, py_xy::Py)
16-
n, m = size(ju_xy)
17-
m >= 3 || error("at least 3 points are required")
18-
n == 2 || error("points must be 2D (2Γ—N array)")
19-
new(ju_xy, py_xy)
20-
end
21-
end
22-
238
"""
24-
get_polygon(points::AbstractArray; ratio::Bool=0.1)
9+
get_polygon(points::AbstractMatrix; ratio::Bool=0.1)
2510
2611
Description:
2712
---
@@ -35,7 +20,7 @@ polygon_xy = [0 0; 1 0; 1 1; 0 1]' # 2xN array
3520
polygon = get_polygon(polygon_xy, ratio=1) # polygon.py_xy to visualize
3621
```
3722
"""
38-
function get_polygon(points::AbstractArray; ratio::Real=0.1)
23+
function get_polygon(points::AbstractMatrix; ratio::Real=0.1)
3924
# inputs checking
4025
n, m = size(points)
4126
n == 2 || error("points must be a 2xN array")
@@ -115,117 +100,49 @@ function pip_query(
115100
end
116101

117102
"""
118-
pip_query(stl_file::String, points::AbstractMatrix; edge::Bool=false)
103+
pip_query(stl_model::STLInfo2D, points::AbstractMatrix; edge::Bool=false)
119104
120105
Description:
121106
---
122-
Determine whether a set of points is inside a 3D mesh defined by an STL file. The input
123-
`stl_file` should be a valid file path to an STL file, and `points` should be a 2xN array
124-
where each column represents a point (x, y). If `edge` is set to true, it checks if the
125-
points are on the edge of the mesh as well.
126-
127-
Example:
128-
---
129-
```julia
130-
stl_file = "path/to/your/file.stl"
131-
points = [0 0; 0.5 0.5; 1 1]'
132-
pip_query(stl_file, points, edge=true)
133-
```
134-
"""
135-
function pip_query(
136-
stl_file::String,
137-
points ::AbstractMatrix;
138-
edge ::Bool=false
139-
)
140-
isfile(stl_file) || error("stl_file must be a valid file path")
141-
size(points, 1) == 2 || error("points must be a 2xN array")
142-
py_points = shapely.points(points')
143-
if edge
144-
@pyexec """
145-
def py_pip(stl_file, py_points, trimesh, shapely):
146-
mesh = trimesh.load(stl_file, force="mesh")
147-
tris2d = mesh.triangles[:, :, :2]
148-
region = shapely.unary_union([shapely.Polygon(t) for t in tris2d])
149-
mask = shapely.covers(region, py_points)
150-
return mask
151-
""" => py_pip
152-
else
153-
@pyexec """
154-
def py_pip(stl_file, py_points, trimesh, shapely):
155-
mesh = trimesh.load(stl_file, force="mesh")
156-
tris2d = mesh.triangles[:, :, :2]
157-
region = shapely.unary_union([shapely.Polygon(t) for t in tris2d])
158-
mask = shapely.within(py_points, region)
159-
return mask
160-
""" => py_pip
161-
end
162-
tmp = py_pip(stl_file, py_points, trimesh, shapely)
163-
return pyconvert(Vector{Bool}, tmp)
164-
end
165-
166-
"""
167-
pip_query(mesh::Py, points::AbstractMatrix; edge::Bool=false)
168-
169-
Description:
170-
---
171-
Determine whether a set of points is inside a 3D mesh defined by a Python object. The input
172-
`mesh` should be a Python object representing the mesh (`trimesh`), and `points` should be
107+
Determine whether a set of points is inside a 3D mesh defined by a 'STLInfo'. The input
108+
`stl_model` should be initiated by function `readSTL2D(stl_file)`, and `points` should be
173109
a 2xN array where each column represents a point (x, y). If `edge` is set to true, it checks
174110
if the points are on the edge of the mesh as well.
175111
176112
Example:
177113
---
178114
```julia
179-
mesh = trimesh.load("path/to/your/file.stl", force="mesh")
115+
stl_model = readSTL2D("path/to/your/file.stl")
180116
points = [0 0; 0.5 0.5; 1 1]'
181-
pip_query(mesh, points, edge=true)
117+
pip_query(stl_model, points, edge=true)
182118
```
183119
"""
184120
function pip_query(
185-
mesh ::Py,
186-
points ::AbstractMatrix;
187-
edge ::Bool=false
121+
stl_model::STLInfo2D,
122+
points ::AbstractMatrix;
123+
edge ::Bool=false
188124
)
189125
size(points, 1) == 2 || error("points must be a 2xN array")
190126
py_points = shapely.points(points')
191127
if edge
192128
@pyexec """
193-
def py_pip(mesh, py_points, trimesh, shapely):
194-
tris2d = mesh.triangles[:, :, :2]
195-
region = shapely.unary_union([shapely.Polygon(t) for t in tris2d])
129+
def py_pip(vertices, triangles, py_points, shapely):
130+
triangle_coords_2d = vertices[triangles][:, :, :2]
131+
tris2d = shapely.polygons(triangle_coords_2d)
132+
region = shapely.unary_union(tris2d)
196133
mask = shapely.covers(region, py_points)
197134
return mask
198135
""" => py_pip
199136
else
200137
@pyexec """
201-
def py_pip(mesh, py_points, trimesh, shapely):
202-
tris2d = mesh.triangles[:, :, :2]
203-
region = shapely.unary_union([shapely.Polygon(t) for t in tris2d])
138+
def py_pip(vertices, triangles, py_points, shapely):
139+
triangle_coords_2d = vertices[triangles][:, :, :2]
140+
tris2d = shapely.polygons(triangle_coords_2d)
141+
region = shapely.unary_union(tris2d)
204142
mask = shapely.within(py_points, region)
205143
return mask
206144
""" => py_pip
207145
end
208-
tmp = py_pip(mesh, py_points, trimesh, shapely)
146+
tmp = py_pip(stl_model.py_vertices, stl_model.py_triangles, py_points, shapely)
209147
return pyconvert(Vector{Bool}, tmp)
210-
end
211-
212-
"""
213-
pip_query(stl_model::STLInfo, points::AbstractMatrix; edge::Bool=false)
214-
215-
Description:
216-
---
217-
Determine whether a set of points is inside a 3D mesh defined by a 'STLInfo'. The input
218-
`stl_model` should be initiated by function `loadmesh(stl_file)`, and `points` should be
219-
a 2xN array where each column represents a point (x, y). If `edge` is set to true, it checks
220-
if the points are on the edge of the mesh as well.
221-
222-
Example:
223-
---
224-
```julia
225-
stl_model = loadmesh("path/to/your/file.stl")
226-
points = [0 0; 0.5 0.5; 1 1]'
227-
pip_query(stl_model, points, edge=true)
228-
```
229-
"""
230-
pip_query(stl_model::STLInfo, points::AbstractMatrix; edge::Bool=false) = pip_query(
231-
stl_model.mesh, points; edge=edge)
148+
end

β€Žsrc/polyhedron.jlβ€Ž

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#==========================================================================================+
2+
| TABLE OF CONTENTS: |
3+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4+
| - pip_query |
5+
+==========================================================================================#
6+
7+
function pip_query(
8+
stl_model::STLInfo3D,
9+
points ::AbstractMatrix;
10+
nsamples ::Int=3,
11+
dev ::String="CPU:0"
12+
)
13+
# inputs check for points
14+
n, m = size(points)
15+
n == 3 || error("points must be a 3xN array")
16+
m >= 1 || error("at least 1 points are required")
17+
py_points = np.array(points')
18+
19+
# query by using open3d
20+
vertices = stl_model.py_vertices
21+
faces = stl_model.py_triangles
22+
_dev = o3d.core.Device(dev)
23+
verts_o3d = o3d.core.Tensor(vertices, dtype=o3d.core.Dtype.Float32, device=_dev)
24+
faces_o3d = o3d.core.Tensor(faces, dtype=o3d.core.Dtype.Int32, device=_dev)
25+
mesh_t = o3d.t.geometry.TriangleMesh(_dev)
26+
mesh_t.vertex.positions = verts_o3d
27+
mesh_t.triangle.indices = faces_o3d
28+
scene = o3d.t.geometry.RaycastingScene(device=_dev)
29+
_ = scene.add_triangles(mesh_t)
30+
pts_t = o3d.core.Tensor(py_points.astype(np.float32), device=_dev)
31+
occ = scene.compute_occupancy(pts_t, nsamples=nsamples)
32+
tmp = occ.numpy().astype(pybuiltins.bool)
33+
34+
return pyconvert(Vector{Bool}, tmp)
35+
end

β€Žsrc/utils.jlβ€Ž

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#==========================================================================================+
2+
| TABLE OF CONTENTS: |
3+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4+
| - readSTL2D |
5+
| - readSTL3D |
6+
+==========================================================================================#
7+
8+
"""
9+
readSTL2D(stl_file::String)
10+
11+
Description:
12+
---
13+
Read a STL file as a 2D object (z=0) containing the mesh, bounding box, vertices, and
14+
triangles.
15+
16+
Example:
17+
---
18+
```julia
19+
stl_info = readSTL2D("path/to/your/file.stl")
20+
```
21+
"""
22+
function readSTL2D(stl_file)
23+
isfile(stl_file) || error("stl_file should be a valid file path")
24+
mesh = o3d.io.read_triangle_mesh(stl_file)
25+
vertices = np.asarray(mesh.vertices) # (N, 3)
26+
triangles = np.asarray(mesh.triangles)
27+
aabb = mesh.get_axis_aligned_bounding_box()
28+
vmin = pyconvert(Vector, aabb.get_min_bound())
29+
vmax = pyconvert(Vector, aabb.get_max_bound())
30+
return STLInfo2D(mesh, vmin, vmax, vertices, triangles)
31+
end
32+
33+
"""
34+
readSTL3D(stl_file::String)
35+
36+
Description:
37+
---
38+
Read a STL file as a 3D object containing the mesh, bounding box, vertices, and triangles.
39+
40+
Example:
41+
---
42+
```julia
43+
stl_info = readSTL3D("path/to/your/file.stl")
44+
```
45+
"""
46+
function readSTL3D(stl_file)
47+
isfile(stl_file) || error("stl_file should be a valid file path")
48+
mesh = o3d.io.read_triangle_mesh(stl_file)
49+
vertices = np.asarray(mesh.vertices)
50+
triangles = np.asarray(mesh.triangles)
51+
aabb = mesh.get_axis_aligned_bounding_box()
52+
vmin = pyconvert(Vector, aabb.get_min_bound())
53+
vmax = pyconvert(Vector, aabb.get_max_bound())
54+
return STLInfo3D(mesh, vmin, vmax, vertices, triangles)
55+
end

β€Žtest/1.jlβ€Ž

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
Β (0)