source: orange/orange/OrangeWidgets/plot/primitives/owprimitives3d.py @ 8962:7b2526198a2a

Revision 8962:7b2526198a2a, 5.3 KB checked in by matejd <matejd@…>, 3 years ago (diff)

Fixed a bug in obj parsing

Line 
1import os
2import re
3from plot.owplot3d import Symbol, enum
4import numpy
5
6GeometryType = enum('SOLID_3D', 'SOLID_2D', 'EDGE_3D', 'EDGE_2D')
7
8def normalize(vec):
9    return vec / numpy.sqrt(numpy.sum(vec**2))
10
11def clamp(value, min, max):
12    if value < min:
13        return min
14    if value > max:
15        return max
16    return value
17
18def normal_from_points(p1, p2, p3):
19    if isinstance(p1, (list, tuple)):
20        v1 = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]]
21        v2 = [p3[0]-p1[0], p3[1]-p1[1], p3[2]-p1[2]]
22    else:
23        v1 = p2 - p1
24        v2 = p3 - p1
25    return normalize(numpy.cross(v1, v2))
26
27symbol_map = {
28    Symbol.RECT:      'cube.obj',
29    Symbol.TRIANGLE:  'pyramid.obj',
30    Symbol.DTRIANGLE: 'dpyramid.obj',
31    Symbol.CIRCLE:    'sphere.obj',
32    Symbol.LTRIANGLE: 'lpyramid.obj',
33    Symbol.DIAMOND:   'octahedron.obj',
34    Symbol.WEDGE:     'wedge.obj',
35    Symbol.LWEDGE:    'lwedge.obj',
36    Symbol.CROSS:     'cross.obj',
37    Symbol.XCROSS:    'xcross.obj'
38}
39
40symbol_map_2d = {
41    Symbol.RECT:      'rect.obj',
42    Symbol.TRIANGLE:  'triangle.obj',
43    Symbol.DTRIANGLE: 'dtriangle.obj',
44    Symbol.CIRCLE:    'circle.obj',
45    Symbol.LTRIANGLE: 'ltriangle.obj',
46    Symbol.DIAMOND:   'diamond.obj',
47    Symbol.WEDGE:     'wedge_2d.obj',
48    Symbol.LWEDGE:    'lwedge_2d.obj',
49    Symbol.CROSS:     'cross_2d.obj',
50    Symbol.XCROSS:    'xcross_2d.obj'
51}
52
53symbol_edge_map = {
54    Symbol.RECT:      'cube_edges.obj',
55    Symbol.TRIANGLE:  'pyramid_edges.obj',
56    Symbol.DTRIANGLE: 'dpyramid_edges.obj',
57    Symbol.CIRCLE:    'sphere_edges.obj',
58    Symbol.LTRIANGLE: 'lpyramid_edges.obj',
59    Symbol.DIAMOND:   'octahedron_edges.obj',
60    Symbol.WEDGE:     'wedge_edges.obj',
61    Symbol.LWEDGE:    'lwedge_edges.obj',
62    Symbol.CROSS:     'cross_edges.obj',
63    Symbol.XCROSS:    'xcross_edges.obj'
64}
65
66symbol_edge_map_2d = {
67    Symbol.RECT:      'rect_edges.obj',
68    Symbol.TRIANGLE:  'triangle_edges.obj',
69    Symbol.DTRIANGLE: 'dtriangle_edges.obj',
70    Symbol.CIRCLE:    'circle_edges.obj',
71    Symbol.LTRIANGLE: 'ltriangle_edges.obj',
72    Symbol.DIAMOND:   'diamond_edges.obj',
73    Symbol.WEDGE:     'wedge_2d_edges.obj',
74    Symbol.LWEDGE:    'lwedge_2d_edges.obj',
75    Symbol.CROSS:     'cross_2d_edges.obj',
76    Symbol.XCROSS:    'xcross_2d_edges.obj'
77}
78
79_symbol_data = {} # Cache: contains triangles + vertices normals for each needed symbol.
80_symbol_data_2d = {}
81_symbol_edges = {}
82_symbol_edges_2d = {}
83
84def parse_obj(file_name):
85    if not os.path.exists(file_name):
86        # Try to load the file from primitives/ folder if given only name (path missing).
87        file_name = os.path.join(os.path.dirname(__file__), file_name)
88    lines = open(file_name).readlines()
89    normals_lines =  filter(lambda line: line.startswith('vn '), lines)
90    vertices_lines = filter(lambda line: line.startswith('v '), lines)
91    faces_lines =    filter(lambda line: line.startswith('f '), lines)
92    normals =  [map(float, line.split()[1:]) for line in normals_lines]
93    vertices = [map(float, line.split()[1:]) for line in vertices_lines]
94    if len(normals) > 0:
95        pattern = r'f (\d+)//(\d+) (\d+)//(\d+) (\d+)//(\d+)'
96        faces = [map(int, re.match(pattern, line).groups()) for line in faces_lines]
97        triangles = [[vertices[face[0]-1],
98                      vertices[face[2]-1],
99                      vertices[face[4]-1],
100                      normals[face[1]-1],
101                      normals[face[3]-1],
102                      normals[face[5]-1]] for face in faces]
103    else:
104        faces = [map(int, line.split()[1:]) for line in faces_lines]
105        triangles = []
106        for face in faces:
107            v0 = vertices[face[0]-1]
108            v1 = vertices[face[1]-1]
109            v2 = vertices[face[2]-1]
110            normal = normal_from_points(v0, v1, v2)
111            triangles.append([v0, v1, v2, normal, normal, normal])
112    return triangles
113
114def get_symbol_geometry(symbol, geometry_type):
115    if not Symbol.is_valid(symbol):
116        print('Invalid symbol!')
117        return []
118
119    if geometry_type == GeometryType.SOLID_3D:
120        cache = _symbol_data
121        name_map = symbol_map
122    elif geometry_type == GeometryType.SOLID_2D:
123        cache = _symbol_data_2d
124        name_map = symbol_map_2d
125    elif geometry_type == GeometryType.EDGE_3D:
126        cache = _symbol_edges
127        name_map = symbol_edge_map
128    elif geometry_type == GeometryType.EDGE_2D:
129        cache = _symbol_edges_2d
130        name_map = symbol_edge_map_2d
131    else:
132        print('Wrong geometry type!')
133        return []
134
135    if symbol in cache:
136        return cache[symbol]
137
138    file_name = name_map[symbol]
139    file_name = os.path.join(os.path.dirname(__file__), file_name)
140    if geometry_type in [GeometryType.SOLID_3D, GeometryType.SOLID_2D]:
141        triangles = parse_obj(file_name)
142        cache[symbol] = triangles
143        return triangles
144
145    lines = open(file_name).readlines()
146    vertices_lines = filter(lambda line: line.startswith('v '), lines)
147    edges_lines =    filter(lambda line: line.startswith('f '), lines)
148    vertices = [map(float, line.split()[1:]) for line in vertices_lines]
149    edges_indices = [map(int, line.split()[1:]) for line in edges_lines]
150    edges = []
151    for i0, i1 in edges_indices:
152        v0 = vertices[i0-1]
153        v1 = vertices[i1-1]
154        edges.append([v0, v1])
155    cache[symbol] = edges
156    return edges
Note: See TracBrowser for help on using the repository browser.