Skip to content

Commit 4310a02

Browse files
committed
adding inner and outer offsets
1 parent fc60f46 commit 4310a02

File tree

5 files changed

+139
-2
lines changed

5 files changed

+139
-2
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from compas.datastructures import Graph
2+
from compas.geometry import Polygon
3+
from compas_cgal.straight_skeleton_2 import create_offset_polygons_2
4+
from compas_viewer import Viewer
5+
6+
points = [
7+
(-1.91, 3.59, 0.0),
8+
(-5.53, -5.22, 0.0),
9+
(-0.39, -1.98, 0.0),
10+
(2.98, -5.51, 0.0),
11+
(4.83, -2.02, 0.0),
12+
(9.70, -3.63, 0.0),
13+
(12.23, 1.25, 0.0),
14+
(3.42, 0.66, 0.0),
15+
(2.92, 4.03, 0.0),
16+
(-1.91, 3.59, 0.0),
17+
]
18+
polygon = Polygon(points)
19+
offset = 1.5
20+
21+
offset_polygons_inner = create_offset_polygons_2(points, offset)
22+
offset_polygons_outer = create_offset_polygons_2(points, -offset)
23+
24+
# ==============================================================================
25+
# Viz
26+
# ==============================================================================
27+
28+
viewer = Viewer(width=1600, height=900)
29+
viewer.scene.add(polygon)
30+
31+
for opolygon in offset_polygons_inner:
32+
viewer.scene.add(opolygon, linecolor=(1.0, 0.0, 0.0))
33+
for opolygon in offset_polygons_outer:
34+
viewer.scene.add(opolygon, linecolor=(0.0, 0.0, 1.0))
35+
36+
viewer.show()

src/compas_cgal/straight_skeleton_2.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
from compas.geometry import normal_polygon
3+
from compas.geometry import Polygon
34
from compas.tolerance import TOL
45

56
from compas_cgal._cgal import straight_skeleton_2
@@ -66,3 +67,17 @@ def create_interior_straight_skeleton_with_holes(points, holes) -> PolylinesNump
6667
hole = np.asarray(points, dtype=np.float64)
6768
H.append(hole)
6869
return straight_skeleton_2.create_interior_straight_skeleton_with_holes(V, H)
70+
71+
72+
def create_offset_polygons_2(points, offset) -> PolylinesNumpy:
73+
points = list(points)
74+
if not TOL.is_allclose(normal_polygon(points, True), [0, 0, 1]):
75+
raise ValueError("Please pass a polygon with a normal vector of [0, 0, 1].")
76+
V = np.asarray(points, dtype=np.float64)
77+
offset = float(offset)
78+
if offset < 0: # outside
79+
offset_polygons = straight_skeleton_2.create_offset_polygons_2_outer(V, abs(offset))[1:] # first one is box
80+
else: # inside
81+
offset_polygons = straight_skeleton_2.create_offset_polygons_2_inner(V, offset)
82+
return [Polygon(points.tolist()) for points in offset_polygons]
83+

src/straight_skeleton_2.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <CGAL/Polygon_2.h>
44
#include <CGAL/create_straight_skeleton_2.h>
55
#include <CGAL/create_straight_skeleton_from_polygon_with_holes_2.h>
6+
#include <CGAL/create_offset_polygons_2.h>
67

78
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
89
typedef K::Point_2 Point;
@@ -12,6 +13,8 @@ typedef CGAL::Straight_skeleton_2<K> Ss;
1213
typedef boost::shared_ptr<Ss> SsPtr;
1314
typedef CGAL::Straight_skeleton_2<K>::Halfedge_const_handle Halfedge_const_handle;
1415
typedef CGAL::Straight_skeleton_2<K>::Vertex_const_handle Vertex_const_handle;
16+
typedef boost::shared_ptr<Polygon_2> PolygonPtr;
17+
typedef std::vector<PolygonPtr> PolygonPtrVector;
1518

1619
compas::Edges pmp_create_interior_straight_skeleton(
1720
Eigen::Ref<const compas::RowMatrixXd> &V)
@@ -86,6 +89,52 @@ compas::Edges pmp_create_interior_straight_skeleton_with_holes(
8689

8790
}
8891

92+
std::vector<compas::RowMatrixXd> pmp_create_offset_polygons_2_inner(Eigen::Ref<const compas::RowMatrixXd> &V, double &offset){
93+
Polygon_2 poly;
94+
for (int i = 0; i < V.rows(); i++){
95+
poly.push_back(Point(V(i, 0), V(i, 1)));
96+
}
97+
PolygonPtrVector offset_polygons = CGAL::create_interior_skeleton_and_offset_polygons_2(offset, poly);
98+
99+
std::vector<compas::RowMatrixXd> result;
100+
for(auto pi = offset_polygons.begin(); pi != offset_polygons.end(); ++pi){
101+
std::size_t n = (*pi)->size();
102+
compas::RowMatrixXd points(n, 3);
103+
int j = 0;
104+
for (auto vi = (*pi)->vertices_begin(); vi != (*pi)->vertices_end(); ++vi){
105+
points(j, 0) = (double)(*vi).x();
106+
points(j, 1) = (double)(*vi).y();
107+
points(j, 2) = 0;
108+
j++;
109+
}
110+
result.push_back(points);
111+
}
112+
return result;
113+
}
114+
115+
std::vector<compas::RowMatrixXd> pmp_create_offset_polygons_2_outer(Eigen::Ref<const compas::RowMatrixXd> &V, double &offset){
116+
Polygon_2 poly;
117+
for (int i = 0; i < V.rows(); i++){
118+
poly.push_back(Point(V(i, 0), V(i, 1)));
119+
}
120+
PolygonPtrVector offset_polygons = CGAL::create_exterior_skeleton_and_offset_polygons_2(offset, poly);
121+
122+
std::vector<compas::RowMatrixXd> result;
123+
for(auto pi = offset_polygons.begin(); pi != offset_polygons.end(); ++pi){
124+
std::size_t n = (*pi)->size();
125+
compas::RowMatrixXd points(n, 3);
126+
int j = 0;
127+
for (auto vi = (*pi)->vertices_begin(); vi != (*pi)->vertices_end(); ++vi){
128+
points(j, 0) = (double)(*vi).x();
129+
points(j, 1) = (double)(*vi).y();
130+
points(j, 2) = 0;
131+
j++;
132+
}
133+
result.push_back(points);
134+
}
135+
return result;
136+
}
137+
89138
// ===========================================================================
90139
// PyBind11
91140
// ===========================================================================
@@ -104,4 +153,16 @@ void init_straight_skeleton_2(pybind11::module &m)
104153
&pmp_create_interior_straight_skeleton_with_holes,
105154
pybind11::arg("V").noconvert(),
106155
pybind11::arg("holes").noconvert());
156+
157+
submodule.def(
158+
"create_offset_polygons_2_inner",
159+
&pmp_create_offset_polygons_2_inner,
160+
pybind11::arg("V").noconvert(),
161+
pybind11::arg("offset").noconvert());
162+
163+
submodule.def(
164+
"create_offset_polygons_2_outer",
165+
&pmp_create_offset_polygons_2_outer,
166+
pybind11::arg("V").noconvert(),
167+
pybind11::arg("offset").noconvert());
107168
};

src/straight_skeleton_2.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@
77
compas::Edges pmp_create_interior_straight_skeleton(
88
Eigen::Ref<const compas::RowMatrixXd> &V);
99

10-
1110
compas::Edges pmp_create_interior_straight_skeleton_with_holes(
1211
Eigen::Ref<const compas::RowMatrixXd> &V,
1312
std::vector<Eigen::Ref<const compas::RowMatrixXd>> &holes);
1413

14+
std::vector<compas::RowMatrixXd> pmp_create_offset_polygons_2_inner(
15+
Eigen::Ref<const compas::RowMatrixXd> &V,
16+
double &offset);
17+
18+
std::vector<compas::RowMatrixXd> pmp_create_offset_polygons_2_outer(
19+
Eigen::Ref<const compas::RowMatrixXd> &V,
20+
double &offset);
21+
1522
#endif /* COMPAS_STRAIGHT_SKELETON_2_H */

tests/test_straight_skeleton_2.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from compas_cgal.straight_skeleton_2 import create_interior_straight_skeleton
44
from compas_cgal.straight_skeleton_2 import create_interior_straight_skeleton_with_holes
5-
5+
from compas_cgal.straight_skeleton_2 import create_offset_polygons_2
66

77
def test_straight_polygon():
88
points = [
@@ -73,3 +73,21 @@ def test_straight_polygon_2_compare():
7373
# the line direction sometimes changes ...
7474
assert TOL.is_allclose(sa, se) or TOL.is_allclose(sa, ee)
7575
assert TOL.is_allclose(ea, ee) or TOL.is_allclose(ea, se)
76+
77+
78+
def test_offset():
79+
points = [
80+
(-1, -1, 0),
81+
(0, -12, 0),
82+
(1, -1, 0),
83+
(12, 0, 0),
84+
(1, 1, 0),
85+
(0, 12, 0),
86+
(-1, 1, 0),
87+
(-12, 0, 0),
88+
]
89+
offset = 0.5
90+
polygons = create_offset_polygons_2(points, offset)
91+
assert len(polygons) == 1, len(polygons)
92+
polygons = create_offset_polygons_2(points, -offset)
93+
assert len(polygons) == 1, len(polygons)

0 commit comments

Comments
 (0)