Skip to content

Commit

Permalink
fix DXF loading on AutoCAD
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedh committed Oct 19, 2018
1 parent a476427 commit 3326247
Show file tree
Hide file tree
Showing 17 changed files with 105 additions and 76 deletions.
33 changes: 14 additions & 19 deletions examples/scan_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
scan_register.py
-------------
Create some simulated 3D scan data and register
Create some simulated 3D scan data and register
it to a "truth" mesh.
"""

Expand Down Expand Up @@ -30,7 +30,7 @@ def simulated_brick(face_count, extents, noise, max_iter=10):

# add some systematic error pre- tesselation
mesh.vertices[0] += mesh.vertex_normals[0] + (noise * 2)

# subdivide until we have more faces than we want
for i in range(max_iter):
if len(mesh.vertices) > face_count:
Expand All @@ -43,19 +43,19 @@ def simulated_brick(face_count, extents, noise, max_iter=10):
# randomly rotation with translation
transform = trimesh.transformations.random_rotation_matrix()
transform[:3, 3] = (np.random.random(3) - .5) * 1000

mesh.apply_transform(transform)

return mesh


if __name__ == '__main__':
# print log messages to terminal
trimesh.util.attach_to_log()

# the size of our boxes
extents = [6, 12, 2]

# create a simulated brick with noise and random transform
scan = simulated_brick(face_count=5000,
extents=extents,
Expand All @@ -65,39 +65,34 @@ def simulated_brick(face_count, extents, noise, max_iter=10):
truth = trimesh.creation.box(extents=extents)

# (4, 4) float homogenous transform from truth to scan
# this will do an ICP refinement with initial transforms
# seeded by the principal components of inertia
truth_to_scan, cost = truth.register(scan)

print("centroid distance pre-registration:",
np.linalg.norm(truth.centroid - scan.centroid))

# apply the registration transform
truth.apply_transform(truth_to_scan)

print("centroid distance post-registration:",
np.linalg.norm(truth.centroid - scan.centroid))

# find the distance from the truth mesh to each scan vertex
distance = truth.nearest.on_surface(scan.vertices)[1]
# 0.0 - 1.0 distance fraction
fraction = distance / distance.max()

# color the mesh by distance from truth with
# color the mesh by distance from truth
# linear interpolation between two colors
colors = ([255,0,0,255] * fraction.reshape((-1,1)) +
[0,255,0,255] * (1 - fraction).reshape((-1,1)))
# apply the vertex colors to the scan mesh
scan.visual.vertex_colors = colors.astype(np.uint8)
# scaled between distance.min() and distance.max()
scan.visual.vertex_colors = trimesh.visual.interpolate(distance)

# print some quick statistics about the mesh
print('distance max:', distance.max())
print('distance mean:', distance.mean())
print('distance STD:', distance.std())

# export result with vertex colors for meshlab
scan.export('scan_new.ply')

# show in a pyglet window
scan.show()




8 changes: 5 additions & 3 deletions tests/test_visual.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ def test_concatenate(self):

def test_data_model(self):
"""
Test the probably too- magical color caching and storage system.
Test the probably too- magical color caching and storage
system.
"""
m = g.get_mesh('featuretype.STL')
test_color = [255, 0, 0, 255]
test_color_2 = [0, 255, 0, 255]
test_color_transparent = [25, 33, 0, 146]

# there should be nothing in the cache or DataStore when starting
# there should be nothing in the cache or DataStore when
# starting
assert len(m.visual._cache) == 0
assert len(m.visual._data) == 0
# no visuals have been defined so this should be None
Expand Down Expand Up @@ -174,7 +176,7 @@ def test_interpolate(self):
"""
values = g.np.array([-1.0, 0.0, 1.0, 2.0])
# should clamp
colors = g.trimesh.visual._default_cmap(values)
colors = g.trimesh.visual.linear_color_map(values)
print(colors)
assert g.np.allclose(colors[0], [255, 0, 0, 255])
assert g.np.allclose(colors[1], [255, 0, 0, 255])
Expand Down
2 changes: 1 addition & 1 deletion trimesh/collision.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ def _get_BVH(self, mesh):
Returns
--------------
bvh : fcl.BVHModel
BVH object of souce mesh
BVH object of source mesh
"""
bvh = mesh_to_BVH(mesh)
return bvh
Expand Down
3 changes: 2 additions & 1 deletion trimesh/comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ def identifier_simple(mesh):
# cylinder height
h = np.dot(vertices, mesh.symmetry_axis).ptp()
# section radius
R2 = (np.dot(vertices, mesh.symmetry_section.T)**2).sum(axis=1).max()
R2 = (np.dot(vertices, mesh.symmetry_section.T)
** 2).sum(axis=1).max()
# area of a cylinder primitive
area = (2 * np.pi * (R2**.5) * h) + (2 * np.pi * R2)
# replace area in this case with area ratio
Expand Down
3 changes: 2 additions & 1 deletion trimesh/intersections.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ def slice_mesh_plane(mesh,
# Extract the single vertex for each triangle inside the plane and get the
# inside vertices (CCW order)
tri_int_inds = np.where(cut_signs_tri == -1)[1]
tri_int_verts = cut_faces_tri[range(num_tris), tri_int_inds].reshape(num_tris, 1)
tri_int_verts = cut_faces_tri[range(
num_tris), tri_int_inds].reshape(num_tris, 1)

# Fill out new triangles with the intersection points as vertices
new_tri_faces = np.append(
Expand Down
2 changes: 1 addition & 1 deletion trimesh/io/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ In [16]: %timeit ('{}/{}/{}\n' * len(array))[:-1].format(*array.flatten())
The highest priority is making sure `pip install trimesh` basically always works. If someone just wants an STL loader they shouldn't need to compile 8 million things and install half of pypi. Also in general all dependencies should be running unit tests in CI on Python 2.7 and 3.4-3.7 on Windows and Linux (OSX as a bonus).

#### `pip install trimesh[easy]`
Install things that install cleanly on all major platforms / Python versions without compiling (they have working wheels). Unfortunatly two packages (`rtree` and `shapely`) currently required additional shared libraries to function rather than including them in the wheels.
Install things that install cleanly on all major platforms / Python versions without compiling (they have working wheels). Unfortunately two packages (`rtree` and `shapely`) currently required additional shared libraries to function rather than including them in the wheels.

#### `pip install trimesh[all]`
Includes libraries that need compiling. Should be able to install through some means on all platforms.
11 changes: 8 additions & 3 deletions trimesh/io/gltf.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,9 @@ def _append_mesh(mesh,
tree['meshes'][-1]['primitives'][0]['attributes']['COLOR_0'] = len(
tree['accessors'])

color_data = _byte_pad(mesh.visual.vertex_colors.astype(np.uint8).tobytes())
color_data = _byte_pad(
mesh.visual.vertex_colors.astype(
np.uint8).tobytes())

# the vertex color accessor data
tree['accessors'].append({
Expand All @@ -407,7 +409,8 @@ def _append_mesh(mesh,
buffer_items.append(color_data)
else:
# if no colors, set a material
tree['meshes'][-1]['primitives'][0]['material'] = len(tree['materials'])
tree['meshes'][-1]['primitives'][0]['material'] = len(
tree['materials'])
# add a default- ish material
tree['materials'].append(_mesh_to_material(mesh))

Expand All @@ -416,7 +419,9 @@ def _append_mesh(mesh,
tree['meshes'][-1]['primitives'][0]['attributes']['NORMAL'] = len(
tree['accessors'])

normal_data = _byte_pad(mesh.vertex_normals.astype(np.float32).tobytes())
normal_data = _byte_pad(
mesh.vertex_normals.astype(
np.float32).tobytes())
# the vertex color accessor data
tree['accessors'].append({
"bufferView": len(buffer_items),
Expand Down
2 changes: 1 addition & 1 deletion trimesh/path/curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def binomial(n):
Returns
---------------
binom : (n + 1,) int
Binomial coefficents of a given order
Binomial coefficients of a given order
"""
if n == 1:
return [1, 1]
Expand Down
4 changes: 2 additions & 2 deletions trimesh/path/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ def discrete(self, vertices, scale=1.0, count=None):
scale : float
Scale of overall drawings (for precision)
count : int
Number of segments to reurn
Number of segments to return
Returns
-------------
Expand Down Expand Up @@ -411,7 +411,7 @@ def discrete(self, vertices, count=None, scale=1.0):
scale : float
Scale of overall drawings (for precision)
count : int
Number of segments to reurn
Number of segments to return
Returns
-------------
Expand Down
11 changes: 8 additions & 3 deletions trimesh/path/io/dxf.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,9 +725,14 @@ def convert_metadata():
objects,
footer]
if len(i) > 0]
# append them all into one DXF file
export = '\n'.join(sections)
return export

# random whitespace causes AutoCAD to fail to load
# although Draftsight, LibreCAD, and Inkscape don't care
# what a giant legacy piece of shit
# strip out all leading and trailing whitespace
blob = '\n'.join(sections).replace(' ', '')

return blob


def load_dwg(file_obj, **kwargs):
Expand Down
2 changes: 1 addition & 1 deletion trimesh/points.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ def tsp(points, start=0):

# in the loop we want to call distances.sum(axis=1)
# a lot and it's actually kind of slow for "reasons"
# dot products with ones is equivilant and ~2x faster
# dot products with ones is equivalent and ~2x faster
sum_ones = np.ones(points.shape[1])

# loop through all points
Expand Down
6 changes: 3 additions & 3 deletions trimesh/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ def mesh_other(mesh,
Allow scaling in transform
icp_first : int
How many ICP iterations for the 9 possible
combinations of
combinations of sign flippage
icp_final : int
How many ICP itertations for the closest
How many ICP iterations for the closest
candidate from the wider search
Returns
Expand All @@ -55,7 +55,7 @@ def mesh_other(mesh,
def key_points(m, count):
"""
Return a combination of mesh vertices and surface samples
with vertices chosen by likelyhood to be important
with vertices chosen by likelihood to be important
to registation.
"""
if len(m.vertices) < (count / 2):
Expand Down
Loading

0 comments on commit 3326247

Please sign in to comment.