Repository navigation
Expand file tree
/
Copy pathextrudePlusPyramids2.py
More file actions
167 lines (143 loc) · 5.68 KB
/
Copy pathextrudePlusPyramids2.py
File metadata and controls
167 lines (143 loc) · 5.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import math
def read_obj(path):
vertices = []
faces = []
materials = []
current_material = None
current_object = None
objects = {}
with open(path, 'r') as f:
for line in f:
if line.startswith('v '):
_, x, y, z = line.strip().split()
vertices.append([float(x), float(y), float(z)])
elif line.startswith('vn '):
_, nx, ny, nz = line.strip().split()
normals = (float(nx), float(ny), float(nz))
elif line.startswith('f '):
parts = line.strip().split()[1:]
face = []
for part in parts:
indices = part.split('/')
v_idx = int(indices[0]) - 1
t_idx = int(indices[1]) - 1 if len(indices) > 1 and indices[1] else None
n_idx = int(indices[2]) - 1 if len(indices) > 2 and indices[2] else None
face.append((v_idx, t_idx, n_idx))
faces.append((face, current_material, current_object))
elif line.startswith('usemtl '):
parts = line.strip().split()
if len(parts) > 1:
current_material = parts[1]
else:
current_material = None
elif line.startswith('mtllib '):
materials.append(line.strip().split()[1])
elif line.startswith('o '):
current_object = line.strip().split()[1]
if current_object not in objects:
objects[current_object] = []
elif line.startswith('g '):
current_group = line.strip().split()[1]
return vertices, faces, materials, objects
def write_obj(path, vertices, faces, materials=None, objects=None):
with open(path, 'w') as f:
f.write('# Generated by extrusion script\n')
for v in vertices:
f.write(f'v {v[0]} {v[1]} {v[2]}\n')
if materials:
for mat in materials:
f.write(f'mtllib {mat}\n')
for obj_name, obj_faces in objects.items():
f.write(f'o {obj_name}\n')
for face in obj_faces:
face_indices, mat_name = face
if mat_name:
f.write(f'usemtl {mat_name}\n')
face_str = ' '.join([
f'{v+1}/{t+1 if t is not None else ""}/{n+1 if n is not None else ""}'
for v, t, n in face_indices
])
f.write(f'f {face_str}\n')
def cross(a, b):
return [
a[1]*b[2] - a[2]*b[1],
a[2]*b[0] - a[0]*b[2],
a[0]*b[1] - a[1]*b[0]
]
def normalize(v):
length = math.sqrt(sum(x*x for x in v))
if length == 0:
return [0, 0, 0]
return [x / length for x in v]
def vec_add(a, b):
return [a[i] + b[i] for i in range(len(a))]
def vec_sub(a, b):
return [a[i] - b[i] for i in range(len(a))]
def compute_face_normal(v1, v2, v3):
edge1 = vec_sub(v2, v1)
edge2 = vec_sub(v3, v1)
normal = cross(edge1, edge2)
return normalize(normal)
def compute_centroid(vertices, face_indices):
num_verts = len(face_indices)
centroid = [0.0, 0.0, 0.0]
for idx, _, _ in face_indices:
v = vertices[idx]
centroid = vec_add(centroid, v)
centroid = [c / num_verts for c in centroid]
return centroid
def extrude_face_to_pyramid(vertices, face_indices, height=3.0):
# Compute face centroid
centroid = compute_centroid(vertices, face_indices)
# Compute face normal
v0, _, _ = face_indices[0]
v1, _, _ = face_indices[1]
v2, _, _ = face_indices[2]
normal = compute_face_normal(vertices[v0], vertices[v1], vertices[v2])
# Ensure the normal points outward
if normal[1] < 0: # Assuming Y-axis is up
normal = [-n for n in normal]
# Scale normal by extrusion height
extrusion_vector = [n * height for n in normal]
# Extrude centroid
apex = vec_add(centroid, extrusion_vector)
return apex
def extrude_mesh_to_pyramids(vertices, faces, height=3.0):
new_vertices = []
new_faces = []
objects = {}
for face in faces:
face_indices, mat_name, obj_name = face
if mat_name == 'roof':
# Compute apex of the pyramid
apex = extrude_face_to_pyramid(vertices, face_indices, height)
apex_index = len(vertices) + len(new_vertices)
new_vertices.append(apex)
# Create triangular faces from original vertices to apex
num_verts = len(face_indices)
for i in range(num_verts):
v1, t1, n1 = face_indices[i]
v2, t2, n2 = face_indices[(i+1) % num_verts]
new_faces.append(([(v1, t1, n1), (v2, t2, n2), (apex_index, None, None)], mat_name, obj_name))
else:
new_faces.append((face_indices, mat_name, obj_name))
# Organize faces by object
if obj_name not in objects:
objects[obj_name] = []
objects[obj_name].append((face_indices, mat_name))
return new_vertices, new_faces, objects
# Main process
input_path = 'scuolaColorata.obj.txt'
output_path = 'scuolaColorata_pyramids.obj'
vertices, faces, materials, objects = read_obj(input_path)
new_vertices, new_faces, objects = extrude_mesh_to_pyramids(vertices, faces, height=8.0)
# Combine everything
final_vertices = vertices + new_vertices
# Update objects dictionary with new faces
for face in new_faces:
face_indices, mat_name, obj_name = face
if obj_name not in objects:
objects[obj_name] = []
objects[obj_name].append((face_indices, mat_name))
write_obj(output_path, final_vertices, new_faces, materials, objects)
print(f"Saved extruded mesh to '{output_path}'")