Skip to content

Commit 4b480fc

Browse files
committed
allow empty headers in DXF files
1 parent 25bc3b3 commit 4b480fc

10 files changed

Lines changed: 88 additions & 74 deletions

File tree

models/fuze.zip

111 KB
Binary file not shown.

trimesh/base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from . import transformations
4040

4141
from .io.export import export_mesh
42-
from .constants import log, _log_time, tol
42+
from .constants import log, log_time, tol
4343

4444
from .scene import Scene
4545
from .parent import Geometry
@@ -1113,7 +1113,7 @@ def rezero(self):
11131113
"""
11141114
self.apply_translation(self.bounds[0] * -1.0)
11151115

1116-
@_log_time
1116+
@log_time
11171117
def split(self, only_watertight=True, adjacency=None, **kwargs):
11181118
"""
11191119
Returns a list of Trimesh objects, based on face connectivity.
@@ -1579,7 +1579,7 @@ def facets_on_hull(self):
15791579

15801580
return on_hull
15811581

1582-
@_log_time
1582+
@log_time
15831583
def fix_normals(self, multibody=None):
15841584
"""
15851585
Find and fix problems with self.face_normals and self.faces
@@ -1716,7 +1716,7 @@ def subdivide(self, face_index=None):
17161716
face_index=face_index)
17171717
return Trimesh(vertices=vertices, faces=faces)
17181718

1719-
@_log_time
1719+
@log_time
17201720
def smoothed(self, angle=.4):
17211721
"""
17221722
Return a version of the current mesh which will render nicely.

trimesh/constants.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,13 @@ def __init__(self, **kwargs):
116116
log.addHandler(_NullHandler())
117117

118118

119-
def _log_time(method):
119+
def log_time(method):
120120
"""
121121
A decorator for methods which will time the method
122122
and then emit a log.debug message with the method name
123123
and how long it took to execute.
124124
"""
125+
125126
def timed(*args, **kwargs):
126127
tic = time_function()
127128
result = method(*args, **kwargs)

trimesh/io/load.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ..base import Trimesh
88
from ..points import PointCloud
99
from ..scene.scene import Scene, append_scenes
10-
from ..constants import _log_time, log
10+
from ..constants import log_time, log
1111

1212
from . import misc
1313
from .ply import _ply_loaders
@@ -147,7 +147,7 @@ def load(file_obj, file_type=None, **kwargs):
147147
return loaded
148148

149149

150-
@_log_time
150+
@log_time
151151
def load_mesh(file_obj, file_type=None, **kwargs):
152152
"""
153153
Load a mesh file into a Trimesh object

trimesh/path/io/dxf.py

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -319,45 +319,56 @@ def convert_bspline(e):
319319

320320
# get the section which contains the header in the DXF file
321321
endsec = np.nonzero(blob[:, 1] == 'ENDSEC')[0]
322-
header_start = np.nonzero(blob[:, 1] == 'HEADER')[0][0]
323-
header_end = endsec[np.searchsorted(endsec, header_start)]
324-
header_blob = blob[header_start:header_end]
325322

326323
# get the section which contains entities in the DXF file
327324
entity_start = np.nonzero(blob[:, 1] == 'ENTITIES')[0][0]
328325
entity_end = endsec[np.searchsorted(endsec, entity_start)]
329326
entity_blob = blob[entity_start:entity_end]
330327

331-
# store some properties from the DXF header
332-
metadata = {'DXF_HEADER': {}}
333-
334-
for key in ['$DIMSCALE', '$DIMUNIT', '$INSUNITS', '$LUNITS']:
335-
value = get_key(header_blob,
336-
key,
337-
'70')
338-
if value is not None:
339-
metadata['DXF_HEADER'][key] = value
340-
341-
# store unit data pulled from the header of the DXF
342-
# prefer LUNITS over INSUNITS
343-
# I couldn't find a table for LUNITS values but they
344-
# look like they are 0- indexed versions of
345-
# the INSUNITS keys, so for now offset the key value
346-
for offset, key in [(-1, '$LUNITS'),
347-
(0, '$INSUNITS')]:
348-
# get the key from the header blob
349-
units = get_key(header_blob, key, '70')
350-
# if it exists add the offset
351-
if units is None:
352-
continue
353-
metadata[key] = units
354-
units += offset
355-
# if the key is in our list of units store it
356-
if units in _DXF_UNITS:
357-
metadata['units'] = _DXF_UNITS[units]
358-
# warn on drawings with no units
359-
if 'units' not in metadata:
360-
log.warning('DXF doesn\'t have units specified!')
328+
# store metadata
329+
metadata = {}
330+
331+
# try reading the header, which may be malformed
332+
header_start = np.nonzero(blob[:, 1] == 'HEADER')[0]
333+
if len(header_start) > 0:
334+
header_end = endsec[np.searchsorted(endsec, header_start[0])]
335+
header_blob = blob[header_start[0]:header_end]
336+
337+
# store some properties from the DXF header
338+
metadata['DXF_HEADER'] = {}
339+
for key, group in [('$ACADVER', '1'),
340+
('$DIMSCALE', '40'),
341+
('$DIMALT', '70'),
342+
('$DIMALTF', '40'),
343+
('$DIMUNIT', '70'),
344+
('$INSUNITS', '70'),
345+
('$LUNITS', '70')]:
346+
value = get_key(header_blob,
347+
key,
348+
group)
349+
if value is not None:
350+
metadata['DXF_HEADER'][key] = value
351+
352+
# store unit data pulled from the header of the DXF
353+
# prefer LUNITS over INSUNITS
354+
# I couldn't find a table for LUNITS values but they
355+
# look like they are 0- indexed versions of
356+
# the INSUNITS keys, so for now offset the key value
357+
for offset, key in [(-1, '$LUNITS'),
358+
(0, '$INSUNITS')]:
359+
# get the key from the header blob
360+
units = get_key(header_blob, key, '70')
361+
# if it exists add the offset
362+
if units is None:
363+
continue
364+
metadata[key] = units
365+
units += offset
366+
# if the key is in our list of units store it
367+
if units in _DXF_UNITS:
368+
metadata['units'] = _DXF_UNITS[units]
369+
# warn on drawings with no units
370+
if 'units' not in metadata:
371+
log.warning('DXF doesn\'t have units specified!')
361372

362373
# find the start points of entities
363374
group_check = entity_blob[:, 0] == '0'

trimesh/proximity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from . import util
1010

1111
from .grouping import group_min
12-
from .constants import tol, _log_time
12+
from .constants import tol, log_time
1313
from .triangles import closest_point as closest_point_corresponding
1414

1515
from collections import deque
@@ -241,7 +241,7 @@ class ProximityQuery(object):
241241
def __init__(self, mesh):
242242
self._mesh = mesh
243243

244-
@_log_time
244+
@log_time
245245
def on_surface(self, points):
246246
"""
247247
Given list of points, for each point find the closest point

trimesh/ray/ray_util.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .. import constants
66

77

8+
@constants.log_time
89
def contains_points(intersector,
910
points,
1011
check_direction=None):
@@ -105,18 +106,20 @@ def contains_points(intersector,
105106
broken = np.logical_and(np.logical_not(agree),
106107
np.logical_not(one_freespace))
107108

109+
# if all rays agree return
110+
if not broken.any():
111+
return contains
112+
108113
# try to run again with a new random vector
109114
# only do it if check_direction isn't specified
110115
# to avoid infinite recursion
111-
if broken.any() and check_direction is None:
116+
if check_direction is None:
112117
# we're going to run the check again in a random direction
113118
new_direction = util.unitize(np.random.random(3) - .5)
114119
# do the mask trick again to be able to assign results
115120
mask = inside_aabb.copy()
116121
mask[mask] = broken
117122

118-
# run a contains check again on the broken points with a
119-
# new random direction but only once and assign it to our results
120123
contains[mask] = contains_points(
121124
intersector,
122125
points[inside_aabb][broken],
@@ -126,11 +129,4 @@ def contains_points(intersector,
126129
'detected %d broken contains test, attempted to fix',
127130
broken.sum())
128131

129-
# we had unrecoverable points
130-
if broken.any() and check_direction is not None:
131-
constants.log.error(
132-
'ray contains tests had %d unrecoverable!' +
133-
'try loading mesh with use_embree=False!',
134-
broken.sum())
135-
136132
return contains

trimesh/util.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,23 +1309,25 @@ def submesh(mesh,
13091309
if append:
13101310
visuals = np.array(visuals)
13111311
vertices, faces = append_faces(vertices, faces)
1312-
appended = trimesh_type(vertices=vertices,
1313-
faces=faces,
1314-
face_normals=np.vstack(normals),
1315-
visual=visuals[0].concatenate(visuals[1:]),
1316-
process=False)
1312+
appended = trimesh_type(
1313+
vertices=vertices,
1314+
faces=faces,
1315+
face_normals=np.vstack(normals),
1316+
visual=visuals[0].concatenate(visuals[1:]),
1317+
process=False)
13171318
return appended
13181319

13191320
# generate a list of Trimesh objects
1320-
result = [trimesh_type(vertices=v,
1321-
faces=f,
1322-
face_normals=n,
1323-
visual=c,
1324-
metadata=copy.deepcopy(mesh.metadata),
1325-
process=False) for v, f, n, c in zip(vertices,
1326-
faces,
1327-
normals,
1328-
visuals)]
1321+
result = [trimesh_type(
1322+
vertices=v,
1323+
faces=f,
1324+
face_normals=n,
1325+
visual=c,
1326+
metadata=copy.deepcopy(mesh.metadata),
1327+
process=False) for v, f, n, c in zip(vertices,
1328+
faces,
1329+
normals,
1330+
visuals)]
13291331
result = np.array(result)
13301332
if len(result) > 0 and only_watertight:
13311333
# fill_holes will attempt a repair and returns the
@@ -1342,12 +1344,15 @@ def zero_pad(data, count, right=True):
13421344
"""
13431345
Parameters
13441346
--------
1345-
data: (n) length 1D array
1346-
count: int
1347+
data : (n,)
1348+
1D array
1349+
count : int
1350+
Minimum length of result array
13471351
13481352
Returns
13491353
--------
1350-
padded: (count) length 1D array if (n < count), otherwise length (n)
1354+
padded : (m,)
1355+
1D array where m >= count
13511356
"""
13521357
if len(data) == 0:
13531358
return np.zeros(count)
@@ -1375,7 +1380,8 @@ def jsonify(obj, **kwargs):
13751380
13761381
Returns
13771382
--------------
1378-
dumped: str, JSON dump of obj
1383+
dumped : str
1384+
JSON dump of obj
13791385
"""
13801386
class NumpyEncoder(json.JSONEncoder):
13811387

trimesh/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '2.35.21'
1+
__version__ = '2.35.23'

trimesh/voxel.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from . import caching
1212
from . import grouping
1313

14-
from .constants import log, _log_time
14+
from .constants import log, log_time
1515

1616

1717
class Voxel(object):
@@ -287,7 +287,7 @@ def show(self, solid=False):
287287
self.as_boxes(solid=solid).show()
288288

289289

290-
@_log_time
290+
@log_time
291291
def voxelize_subdivide(mesh,
292292
pitch,
293293
max_iter=10,
@@ -436,7 +436,7 @@ def local_voxelize(mesh, point, pitch, radius, fill=True, **kwargs):
436436
return voxels, local_origin
437437

438438

439-
@_log_time
439+
@log_time
440440
def voxelize_ray(mesh,
441441
pitch,
442442
per_cell=[2, 2],

0 commit comments

Comments
 (0)