Skip to content

Commit 05ebd72

Browse files
committed
GeoCode initial commit
1 parent 3e17a83 commit 05ebd72

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+4667
-0
lines changed

.gitignore

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# Distribution / packaging
7+
.Python
8+
build/
9+
develop-eggs/
10+
dist/
11+
downloads/
12+
eggs/
13+
.eggs/
14+
lib/
15+
lib64/
16+
parts/
17+
sdist/
18+
var/
19+
wheels/
20+
share/python-wheels/
21+
*.egg-info/
22+
.installed.cfg
23+
*.egg
24+
MANIFEST
25+
26+
27+
.DS_Store
28+
datasets/
29+
*.zip.
30+
.idea/
31+
Models/
32+
Logs/
33+
cls/
34+
slurm-*.out
35+
node_modules/
36+
neptune_config.yml
37+
neptune_session.json
38+
.neptune/
39+
.vscode/
40+
*.egg_inf
41+
lightning_logs/
42+
stability_results.json
43+
dataset_processing/model-converter-python/

__init__.py

Whitespace-only changes.

common/__init__.py

Whitespace-only changes.

common/bpy_util.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import bpy
2+
import math
3+
from mathutils import Vector
4+
from typing import Union
5+
from pathlib import Path
6+
7+
8+
def save_obj(target_obj_file_path: Union[Path, str], additional_objs_to_save=None, simplification_ratio=None):
9+
"""
10+
save the object and returns a mesh duplicate version of it
11+
"""
12+
obj = select_shape()
13+
refresh_obj_in_viewport(obj)
14+
dup_obj = copy(obj)
15+
# set active
16+
bpy.ops.object.select_all(action='DESELECT')
17+
dup_obj.select_set(True)
18+
bpy.context.view_layer.objects.active = dup_obj
19+
# apply the modifier to turn the geometry node to a mesh
20+
bpy.ops.object.modifier_apply(modifier="GeometryNodes")
21+
if simplification_ratio and simplification_ratio < 1.0:
22+
bpy.ops.object.modifier_add(type='DECIMATE')
23+
dup_obj.modifiers["Decimate"].decimate_type = 'COLLAPSE'
24+
dup_obj.modifiers["Decimate"].ratio = simplification_ratio
25+
bpy.ops.object.modifier_apply(modifier="Decimate")
26+
assert dup_obj.type == 'MESH'
27+
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
28+
# set origin to center of bounding box
29+
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
30+
dup_obj.location.x = dup_obj.location.y = dup_obj.location.z = 0
31+
normalize_scale(dup_obj)
32+
if additional_objs_to_save:
33+
for additional_obj in additional_objs_to_save:
34+
additional_obj.select_set(True)
35+
# save
36+
bpy.ops.export_scene.obj(filepath=str(target_obj_file_path), use_selection=True, use_materials=False, use_triangles=True)
37+
return dup_obj
38+
39+
40+
def get_geometric_nodes_modifier(obj):
41+
# loop through all modifiers of the given object
42+
gnodes_mod = None
43+
for modifier in obj.modifiers:
44+
# check if current modifier is the geometry nodes modifier
45+
if modifier.type == "NODES":
46+
gnodes_mod = modifier
47+
break
48+
return gnodes_mod
49+
50+
51+
def normalize_scale(obj):
52+
obj.select_set(True)
53+
bpy.context.view_layer.objects.active = obj
54+
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
55+
# set origin to the center of the bounding box
56+
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
57+
58+
obj.location.x = 0
59+
obj.location.y = 0
60+
obj.location.z = 0
61+
62+
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
63+
max_vert_dist = math.sqrt(max([v.co.dot(v.co) for v in obj.data.vertices]))
64+
65+
for v in obj.data.vertices:
66+
v.co /= max_vert_dist
67+
68+
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
69+
70+
# verify that the shape is normalized
71+
# max_vert_dist = math.sqrt(max([v.co.dot(v.co) for v in obj.data.vertices]))
72+
# assert abs(max_vert_dist - 1.0) < 0.01
73+
74+
75+
def setup_lights():
76+
"""
77+
setup lights for rendering
78+
used for visualization of 3D objects as images
79+
"""
80+
scene = bpy.context.scene
81+
# light 1
82+
light_data_1 = bpy.data.lights.new(name="light_data_1", type='POINT')
83+
light_data_1.energy = 300
84+
light_object_1 = bpy.data.objects.new(name="Light_1", object_data=light_data_1)
85+
light_object_1.location = Vector((10, -10, 10))
86+
scene.collection.objects.link(light_object_1)
87+
# light 2
88+
light_data_2 = bpy.data.lights.new(name="light_data_2", type='POINT')
89+
light_data_2.energy = 300
90+
light_object_2 = bpy.data.objects.new(name="Light_2", object_data=light_data_2)
91+
light_object_2.location = Vector((-10, -10, 10))
92+
scene.collection.objects.link(light_object_2)
93+
# light 3
94+
light_data_3 = bpy.data.lights.new(name="light_data_3", type='POINT')
95+
light_data_3.energy = 300
96+
light_object_3 = bpy.data.objects.new(name="Light_3", object_data=light_data_3)
97+
light_object_3.location = Vector((10, 0, 10))
98+
scene.collection.objects.link(light_object_3)
99+
100+
101+
def look_at(obj_camera, point):
102+
"""
103+
orient the given camera with a fixed position to loot at a given point in space
104+
"""
105+
loc_camera = obj_camera.matrix_world.to_translation()
106+
direction = point - loc_camera
107+
# point the cameras '-Z' and use its 'Y' as up
108+
rot_quat = direction.to_track_quat('-Z', 'Y')
109+
obj_camera.rotation_euler = rot_quat.to_euler()
110+
111+
112+
def clean_scene(start_with_strings=["Camera", "procedural", "Light"]):
113+
"""
114+
delete all object of which the name's prefix is matching any of the given strings
115+
"""
116+
scene = bpy.context.scene
117+
bpy.ops.object.select_all(action='DESELECT')
118+
for obj in scene.objects:
119+
if any([obj.name.startswith(starts_with_string) for starts_with_string in start_with_strings]):
120+
# select the object
121+
if obj.visible_get():
122+
obj.select_set(True)
123+
bpy.ops.object.delete()
124+
125+
126+
def del_obj(obj):
127+
bpy.ops.object.select_all(action='DESELECT')
128+
obj.select_set(True)
129+
bpy.ops.object.delete()
130+
131+
132+
def refresh_obj_in_viewport(obj):
133+
# the following two line cause the object to update according to the new geometric nodes input
134+
obj.show_bounds = not obj.show_bounds
135+
obj.show_bounds = not obj.show_bounds
136+
137+
138+
def select_objs(*objs):
139+
bpy.ops.object.select_all(action='DESELECT')
140+
for i, obj in enumerate(objs):
141+
if i == 0:
142+
bpy.context.view_layer.objects.active = obj
143+
obj.select_set(True)
144+
145+
146+
def select_obj(obj):
147+
select_objs(obj)
148+
149+
150+
def select_shape():
151+
"""
152+
select the procedural shape in the blend file
153+
note that in all our domains, the procedural shape is named "procedural shape" within the blend file
154+
"""
155+
obj = bpy.data.objects["procedural shape"]
156+
select_obj(obj)
157+
return obj
158+
159+
160+
def copy(obj):
161+
dup_obj = obj.copy()
162+
dup_obj.data = obj.data.copy()
163+
dup_obj.animation_data_clear()
164+
bpy.context.collection.objects.link(dup_obj)
165+
return dup_obj

common/domain.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from enum import Enum
2+
3+
class Domain(Enum):
4+
chair = 'chair'
5+
vase = 'vase'
6+
table = 'table'
7+
8+
def __str__(self):
9+
return self.value

common/file_util.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import yaml
2+
import hashlib
3+
import numpy as np
4+
from pathlib import Path
5+
from typing import Union
6+
7+
8+
def save_yml(yml_obj, target_yml_file_path):
9+
with open(target_yml_file_path, 'w') as target_yml_file:
10+
yaml.dump(yml_obj, target_yml_file, sort_keys=False, width=1000)
11+
12+
13+
def get_source_recipe_file_path(domain):
14+
"""
15+
get the path to the recipe file path that is found in the source code under the directory "recipe_files"
16+
"""
17+
return Path(__file__).parent.joinpath('..', 'dataset_generator', 'recipe_files', f'recipe_{domain}.yml').resolve()
18+
19+
20+
def hash_file_name(file_name):
21+
return int(hashlib.sha1(file_name.encode("utf-8")).hexdigest(), 16) % (10 ** 8)
22+
23+
24+
def get_recipe_yml_obj(recipe_file_path: Union[str, Path]):
25+
with open(recipe_file_path, 'r') as recipe_file:
26+
recipe_yml_obj = yaml.load(recipe_file, Loader=yaml.FullLoader)
27+
return recipe_yml_obj
28+
29+
30+
def load_obj(file: str):
31+
vs, faces = [], []
32+
f = open(file)
33+
for line in f:
34+
line = line.strip()
35+
split_line = line.split()
36+
if not split_line:
37+
continue
38+
elif split_line[0] == 'v':
39+
vs.append([float(v) for v in split_line[1:4]])
40+
elif split_line[0] == 'f':
41+
face_vertex_ids = [int(c.split('/')[0]) for c in split_line[1:]]
42+
assert len(face_vertex_ids) == 3
43+
face_vertex_ids = [(ind - 1) if (ind >= 0) else (len(vs) + ind)
44+
for ind in face_vertex_ids]
45+
faces.append(face_vertex_ids)
46+
f.close()
47+
vs = np.asarray(vs)
48+
faces = np.asarray(faces, dtype=np.int64)
49+
assert np.logical_and(faces >= 0, faces < len(vs)).all()
50+
return vs, faces

0 commit comments

Comments
 (0)