Skip to content

Commit d7e3168

Browse files
committed
packing fix and docstrings
1 parent 1aca24c commit d7e3168

9 files changed

Lines changed: 216 additions & 65 deletions

File tree

.travis.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,14 @@ script:
7979
- python -c "import trimesh"
8080
- pytest tests/test_inertia.py
8181

82-
# install most deps here
82+
# shapely/rtree are easiest to get from conda
8383
- conda install scikit-image rtree shapely
84-
# eat exit codes for these two packages
84+
8585
# pyembree and python-fcl not available everywhere
86-
- conda install pyembree || true
87-
- pip install python-fcl || true
86+
- if [[ "$TRAVIS_PYTHON_VERSION" == "3.6" ]]; then conda install pyembree; fi;
87+
- if [[ "$TRAVIS_PYTHON_VERSION" == "3.6" ]]; then pip install python-fcl; fi;
88+
89+
# install most deps here
8890
- pip install .[easy]
8991
- pip install triangle xxhash
9092

@@ -94,7 +96,7 @@ script:
9496
# downgrade networkx from 2.x to 1.x to make sure our
9597
# graph operations work on both versions of their API
9698
- pip install -Iv networkx==1.11
97-
- python -c "import networkx; print(networkx.__version__)"
99+
- python -c "import networkx; print('::NX_VERSION::', networkx.__version__)"
98100
- pytest tests/test_graph.py tests/test_scene.py
99101

100102
# make sure examples still work

tests/generic.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585

8686
io_wrap = trimesh.util.wrap_as_stream
8787

88+
8889
def _load_data():
8990
data = {}
9091
for file_name in os.listdir(dir_data):

tests/test_packing.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@ def test_obb(self):
1717
def test_paths(self):
1818
from trimesh.path import packing
1919
paths = [g.trimesh.load_path(i) for i in self.nestable]
20-
r = packing.pack_paths(paths)
2120

21+
r, inserted = packing.pack_paths(paths)
22+
23+
# number of paths inserted
24+
count = len(g.np.unique(inserted))
25+
assert count == len(paths)
26+
assert count == len(r.split())
2227

2328
if __name__ == '__main__':
2429
g.trimesh.util.attach_to_log()

tests/test_paths.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,16 @@ def test_discrete(self):
5757
g.log.error('On file %s First and last vertex distance %f',
5858
d.metadata['file_name'],
5959
circuit_dist)
60-
self.assertTrue(circuit_test)
60+
assert circuit_test
6161

6262
is_ccw = g.trimesh.path.util.is_ccw(verts)
6363
if not is_ccw:
6464
g.log.error('discrete %s not ccw!',
6565
d.metadata['file_name'])
66-
# self.assertTrue(is_ccw)
6766

6867
for i in range(len(d.paths)):
69-
self.assertTrue(d.polygons_closed[i].is_valid)
70-
self.assertTrue(d.polygons_closed[i].area > g.tol_path.zero)
68+
assert d.polygons_closed[i].is_valid
69+
assert d.polygons_closed[i].area > g.tol_path.zero
7170
export_dict = d.export(file_type='dict')
7271
to_dict = d.to_dict()
7372
assert isinstance(to_dict, dict)
@@ -86,6 +85,15 @@ def test_discrete(self):
8685
if len(d.root) == 1:
8786
d.apply_obb()
8887

88+
# store the X values of bounds
89+
ori = d.bounds.copy()
90+
# apply a translation
91+
d.apply_translation([10, 0])
92+
# X should have translated by 10.0
93+
assert g.np.allclose(d.bounds[:, 0] - 10, ori[:, 0])
94+
# Y should not have moved
95+
assert g.np.allclose(d.bounds[:, 1], ori[:, 1])
96+
8997
if len(d.vertices) < 150:
9098
g.log.info('Checking medial axis on %s',
9199
d.metadata['file_name'])
@@ -99,22 +107,22 @@ def test_discrete(self):
99107

100108
def test_poly(self):
101109
p = g.get_mesh('2D/LM2.dxf')
102-
self.assertTrue(p.is_closed)
103-
self.assertTrue(any(len(i.points) > 2 for i in p.entities if
104-
g.trimesh.util.is_instance_named(i, 'Line')))
110+
assert p.is_closed
111+
assert any(len(i.points) > 2 for i in p.entities if
112+
g.trimesh.util.is_instance_named(i, 'Line'))
105113

106114
assert len(p.layers) == len(p.entities)
107115
assert len(g.np.unique(p.layers)) > 1
108116

109117
p.explode()
110-
self.assertTrue(all(len(i.points) == 2 for i in p.entities if
111-
g.trimesh.util.is_instance_named(i, 'Line')))
112-
self.assertTrue(p.is_closed)
118+
assert all(len(i.points) == 2 for i in p.entities if
119+
g.trimesh.util.is_instance_named(i, 'Line'))
120+
assert p.is_closed
113121
p.entities = p.entities[:-1]
114122
self.assertFalse(p.is_closed)
115123

116124
p.fill_gaps()
117-
self.assertTrue(p.is_closed)
125+
assert p.is_closed
118126

119127
def test_edges(self):
120128
"""
@@ -187,8 +195,8 @@ def test_sample(self):
187195
# test sampling with multiple bodies
188196
for i in range(3):
189197
assert g.np.isclose(path.area, p.area * (i + 1))
190-
path = path + \
191-
g.trimesh.load_path(g.Point([(i + 2) * 2, 0]).buffer(1.0))
198+
path = path + g.trimesh.load_path(
199+
g.Point([(i + 2) * 2, 0]).buffer(1.0))
192200
s = path.sample(count=count)
193201
assert s.shape[1] == 2
194202

@@ -207,9 +215,8 @@ def test_center(self):
207215
center_info['normal'],
208216
center_info['span'])
209217

210-
self.assertTrue(abs(R - res_radius) < g.tol_path.zero)
211-
self.assertTrue(g.trimesh.util.euclidean(
212-
C, res_center) < g.tol_path.zero)
218+
assert abs(R - res_radius) < g.tol_path.zero
219+
assert g.trimesh.util.euclidean(C, res_center) < g.tol_path.zero
213220

214221
def test_center_random(self):
215222

trimesh/path/entities.py

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ def end_points(self):
9494
def is_valid(self):
9595
"""
9696
Is the current entity valid.
97+
98+
Returns
99+
-----------
100+
valid : bool
101+
Is the current entity well formed
97102
"""
98103
return True
99104

@@ -183,25 +188,36 @@ def discrete(self, vertices, scale=1.0):
183188
184189
Parameters
185190
------------
186-
vertices: (n, dimension) float, points in space
187-
scale: float, size of overall scene for numerical comparisons
191+
vertices: (n, dimension) float
192+
Points in space
193+
scale : float
194+
Size of overall scene for numerical comparisons
188195
189196
Returns
190197
-------------
191-
discrete: (m, dimension) float, linear path in space
198+
discrete: (m, dimension) float
199+
Path in space composed of line segments
192200
"""
193201
discrete = self._orient(vertices[self.points])
194202
return discrete
195203

196204
@property
197205
def is_valid(self):
206+
"""
207+
Is the current entity valid.
208+
209+
Returns
210+
-----------
211+
valid : bool
212+
Is the current entity well formed
213+
"""
198214
valid = np.any((self.points - self.points[0]) != 0)
199215
return valid
200216

201217
def explode(self):
202218
"""
203-
If the current Line entity consists of multiple lines, break it
204-
up into n Line entities.
219+
If the current Line entity consists of multiple line
220+
break it up into n Line entities.
205221
206222
Returns
207223
----------
@@ -223,16 +239,38 @@ def closed(self):
223239
224240
Returns
225241
----------
226-
closed: bool, if true arc will be a closed circle in space
242+
closed : bool
243+
If set True, Arc will be a closed circle
227244
"""
228245
if hasattr(self, '_closed'):
229246
return self._closed
230247
return False
231248

232249
@closed.setter
233250
def closed(self, value):
251+
"""
252+
Set the Arc to be closed or not, without
253+
changing the control points
254+
255+
Parameters
256+
------------
257+
value : bool
258+
Should this Arc be a closed circle or not
259+
"""
234260
self._closed = bool(value)
235261

262+
@property
263+
def is_valid(self):
264+
"""
265+
Is the current Arc entity valid.
266+
267+
Returns
268+
-----------
269+
valid : bool
270+
Does the current Arc have exactly 3 control points
271+
"""
272+
return len(np.unique(self.points)) == 3
273+
236274
def _bytes(self):
237275
hashable = (self.__class__.__name__.encode('utf-8') +
238276
bytes(bool(self.closed)) +
@@ -307,7 +345,9 @@ def bounds(self, vertices):
307345

308346

309347
class Curve(Entity):
310-
348+
"""
349+
The parent class for all wild curves in space.
350+
"""
311351
@property
312352
def nodes(self):
313353
return [[self.points[0],
@@ -317,15 +357,38 @@ def nodes(self):
317357

318358

319359
class Bezier(Curve):
360+
"""
361+
An open or closed Bezier curve
362+
"""
320363

321364
def discrete(self, vertices, scale=1.0, count=None):
365+
"""
366+
Discretize the Bezier curve.
367+
368+
Parameters
369+
-------------
370+
vertices : (n, 2) or (n, 3) float
371+
Points in space
372+
scale : float
373+
Scale of overall drawings (for precision)
374+
count : int
375+
Number of segments to reurn
376+
377+
Returns
378+
-------------
379+
discrete : (m, 2) or (m, 3) float
380+
Curve as line segments
381+
"""
322382
discrete = discretize_bezier(vertices[self.points],
323383
count=count,
324384
scale=scale)
325385
return self._orient(discrete)
326386

327387

328388
class BSpline(Curve):
389+
"""
390+
An open or closed B- Spline.
391+
"""
329392

330393
def __init__(self, points,
331394
knots,
@@ -338,6 +401,23 @@ def __init__(self, points,
338401
self.kwargs = kwargs
339402

340403
def discrete(self, vertices, count=None, scale=1.0):
404+
"""
405+
Discretize the B-Spline curve.
406+
407+
Parameters
408+
-------------
409+
vertices : (n, 2) or (n, 3) float
410+
Points in space
411+
scale : float
412+
Scale of overall drawings (for precision)
413+
count : int
414+
Number of segments to reurn
415+
416+
Returns
417+
-------------
418+
discrete : (m, 2) or (m, 3) float
419+
Curve as line segments
420+
"""
341421
discrete = discretize_bspline(
342422
control=vertices[self.points],
343423
knots=self.knots,

0 commit comments

Comments
 (0)