Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2014-07-28 19:10:10 +0400
committerBastien Montagne <montagne29@wanadoo.fr>2014-07-28 19:10:10 +0400
commita3d8d01b0e24fc8ba3d31498b16f581c9968b80a (patch)
treefb9090df04d4b041538cf0e953f7d685f841fdd7 /io_mesh_stl
parentb21415fca89f71a1a4db69c3fd1a156d644347e7 (diff)
Fix T40949: Importing STL file fails and produces a python error - Mac.
Replace usage of mmap by mere open(). It's not significatively slower (perhaps 2% or 3%), and seems more reliable. Based on patch by paddy10663 (Patrick Taylor), with own edits and optimizations.
Diffstat (limited to 'io_mesh_stl')
-rw-r--r--io_mesh_stl/stl_utils.py77
1 files changed, 36 insertions, 41 deletions
diff --git a/io_mesh_stl/stl_utils.py b/io_mesh_stl/stl_utils.py
index 67478ba8..d1dea5e9 100644
--- a/io_mesh_stl/stl_utils.py
+++ b/io_mesh_stl/stl_utils.py
@@ -26,35 +26,14 @@ Used as a blender script, it load all the stl files in the scene:
blender --python stl_utils.py -- file1.stl file2.stl file3.stl ...
"""
+import os
import struct
-import mmap
import contextlib
import itertools
from mathutils.geometry import normal
# TODO: endien
-
-@contextlib.contextmanager
-def mmap_file(filepath):
- """
- Context manager over the data of an mmap'ed file (Read ONLY).
-
-
- Example:
-
- with mmap_file(filepath) as m:
- m.read()
- print m[10:50]
- """
- with open(filepath, 'rb') as file:
- # check http://bugs.python.org/issue8046 to have mmap context
- # manager fixed in python
- mem_map = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ)
- yield mem_map
- mem_map.close()
-
-
class ListDict(dict):
"""
Set struct with order.
@@ -100,9 +79,16 @@ def _is_ascii_file(data):
represents a binary file. It can be a (very *RARE* in real life, but
can easily be forged) ascii file.
"""
- size = struct.unpack_from('<I', data, BINARY_HEADER)[0]
+ # Skip header...
+ data.seek(BINARY_HEADER)
+ size = struct.unpack('<I', data.read(4))[0]
+ # Use seek() method to get size of the file.
+ data.seek(0, os.SEEK_END)
+ file_size = data.tell()
+ # Reset to the start of the file.
+ data.seek(0)
- return not data.size() == BINARY_HEADER + 4 + BINARY_STRIDE * size
+ return (file_size != BINARY_HEADER + 4 + BINARY_STRIDE * size)
def _binary_read(data):
@@ -115,18 +101,28 @@ def _binary_read(data):
# - 9 * 4 bytes of coordinate (3*3 floats)
# - 2 bytes of garbage (usually 0)
- # OFFSET for the first byte of coordinate (headers + first normal bytes)
+ # OFFSET is to skip normal bytes
# STRIDE between each triangle (first normal + coordinates + garbage)
- OFFSET = BINARY_HEADER + 4 + 12
+ OFFSET = 12
- # read header size, ignore description
- size = struct.unpack_from('<I', data, BINARY_HEADER)[0]
- unpack = struct.Struct('<9f').unpack_from
+ # Skip header...
+ data.seek(BINARY_HEADER)
+ size = struct.unpack('<I', data.read(4))[0]
+
+ # We read 4096 elements at once, avoids too much calls to read()!
+ CHUNK_LEN = 4096
+ chunks = [CHUNK_LEN] * (size // CHUNK_LEN)
+ chunks.append(size % CHUNK_LEN)
- for i in range(size):
- # read the points coordinates of each triangle
- pt = unpack(data, OFFSET + BINARY_STRIDE * i)
- yield pt[:3], pt[3:6], pt[6:]
+ unpack = struct.Struct('<9f').unpack_from
+ for chunk_len in chunks:
+ if chunk_len == 0:
+ continue
+ buf = data.read(BINARY_STRIDE * chunk_len)
+ for i in range(chunk_len):
+ # read the points coordinates of each triangle
+ pt = unpack(buf, OFFSET + BINARY_STRIDE * i)
+ yield pt[:3], pt[3:6], pt[6:]
def _ascii_read(data):
@@ -145,16 +141,11 @@ def _ascii_read(data):
# strip header
data.readline()
- while True:
- l = data.readline()
- if not l:
- break
-
+ for l in data:
# if we encounter a vertex, read next 2
l = l.lstrip()
if l.startswith(b'vertex'):
- yield [tuple(map(float, l_item.split()[1:]))
- for l_item in (l, data.readline(), data.readline())]
+ yield [tuple(map(float, l_item.split()[1:])) for l_item in (l, data.readline(), data.readline())]
def _binary_write(filepath, faces):
@@ -244,10 +235,12 @@ def read_stl(filepath):
>>> # print the coordinate of the triangle n
>>> print(pts[i] for i in tris[n])
"""
+ import time
+ start_time = time.process_time()
tris, pts = [], ListDict()
- with mmap_file(filepath) as data:
+ with open(filepath, 'rb') as data:
# check for ascii or binary
gen = _ascii_read if _is_ascii_file(data) else _binary_read
@@ -258,6 +251,8 @@ def read_stl(filepath):
# first equal point inserted.
tris.append([pts.add(p) for p in pt])
+ print('Import finished in %.4f sec.' % (time.process_time() - start_time))
+
return tris, pts.list