diff --git a/media/attribution.js b/media/attribution.js index cbe0c794..45392693 100644 --- a/media/attribution.js +++ b/media/attribution.js @@ -1263,6 +1263,18 @@ const attributionData = { "dimensions-guide" ] }, + { + prefix: "./media/buildings/Houses/", + files: [ + { name: "Two-Story House-Front.svg", source: "http://www.sweethome3d.com/gallery.jsp" }, + { name: "Two-Story House-Angled.svg", source: "http://www.sweethome3d.com/gallery.jsp" }, + { name: "Two-Story House-Side.svg", source: "http://www.sweethome3d.com/gallery.jsp" }, + { name: "Two-Story House-Top.svg", source: "http://www.sweethome3d.com/gallery.jsp" }, + ], + authors: [ + "eteks" + ] + }, { prefix: "./media/buildings/Houses", all: null, diff --git a/media/buildings/Houses/Shotgun House-Angled.svg b/media/buildings/Houses/Shotgun House-Angled.svg index 7086a1b1..2c138d4b 100644 --- a/media/buildings/Houses/Shotgun House-Angled.svg +++ b/media/buildings/Houses/Shotgun House-Angled.svg @@ -1,559 +1 @@ - - - - -Created by potrace 1.16, written by Peter Selinger 2001-2019 - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/media/buildings/Houses/Shotgun House-Front.svg b/media/buildings/Houses/Shotgun House-Front.svg index 3b45a4f0..55ae066f 100644 --- a/media/buildings/Houses/Shotgun House-Front.svg +++ b/media/buildings/Houses/Shotgun House-Front.svg @@ -1,367 +1 @@ - - - - -Created by potrace 1.16, written by Peter Selinger 2001-2019 - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/media/buildings/Houses/Shotgun House-Side.svg b/media/buildings/Houses/Shotgun House-Side.svg index b2b78202..1eeddf3e 100644 --- a/media/buildings/Houses/Shotgun House-Side.svg +++ b/media/buildings/Houses/Shotgun House-Side.svg @@ -1,607 +1 @@ - - - - -Created by potrace 1.16, written by Peter Selinger 2001-2019 - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/media/buildings/Houses/Shotgun House-Top.svg b/media/buildings/Houses/Shotgun House-Top.svg index 40e61f71..80f61916 100644 --- a/media/buildings/Houses/Shotgun House-Top.svg +++ b/media/buildings/Houses/Shotgun House-Top.svg @@ -1,83 +1 @@ - - - - -Created by potrace 1.16, written by Peter Selinger 2001-2019 - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/media/buildings/Houses/Two-Story House-Angled.svg b/media/buildings/Houses/Two-Story House-Angled.svg new file mode 100644 index 00000000..4e5d9ad3 --- /dev/null +++ b/media/buildings/Houses/Two-Story House-Angled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/buildings/Houses/Two-Story House-Front.svg b/media/buildings/Houses/Two-Story House-Front.svg new file mode 100644 index 00000000..bbfa5577 --- /dev/null +++ b/media/buildings/Houses/Two-Story House-Front.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/buildings/Houses/Two-Story House-Side.svg b/media/buildings/Houses/Two-Story House-Side.svg new file mode 100644 index 00000000..d3e6f756 --- /dev/null +++ b/media/buildings/Houses/Two-Story House-Side.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/buildings/Houses/Two-Story House-Top.svg b/media/buildings/Houses/Two-Story House-Top.svg new file mode 100644 index 00000000..ff5224ca --- /dev/null +++ b/media/buildings/Houses/Two-Story House-Top.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/presets/buildings.js b/presets/buildings.js index 724dfb78..f5244052 100644 --- a/presets/buildings.js +++ b/presets/buildings.js @@ -286,11 +286,21 @@ function makeBuildings() { name: "Shotgun House", sides: { "Front": { height: math.unit(3.968526840209961, "meters") }, + "Angled": { height: math.unit(3.968526840209961, "meters") }, "Side": { height: math.unit(3.968526840209961, "meters") }, "Top": { height: math.unit(9.709759712219238, "meters") }, - "Angled": { height: math.unit(3.968526840209961, "meters") } + } + }, + { + name: "Two-Story House", + sides: { + "Front": { height: math.unit(8.241991996765137, "meters") }, + "Angled": { height: math.unit(8.241991996765137, "meters") }, + "Side": { height: math.unit(8.241991996765137, "meters") }, + "Top": { height: math.unit(6.589994430541992, "meters") }, } } + ] const dataRooms = [ diff --git a/scripts/blender-svg b/scripts/blender-svg new file mode 100644 index 00000000..4a0dc3e4 --- /dev/null +++ b/scripts/blender-svg @@ -0,0 +1,157 @@ +import bpy +from mathutils import Vector, Euler +from math import pi +import json +import os +import bpy_extras +import bmesh +import time + +class ModalTimerOperator(bpy.types.Operator): + """Operator which runs its self from a timer""" + bl_idname = "wm.modal_timer_operator" + bl_label = "Modal Timer Operator" + + _timer = None + index = 0 + + def menu_func(self, context): + self.layout.operator(ModalTimerOperator.bl_idname) + + def modal(self, context, event): + scene = context.scene + if self.index >= len(self.sides): + self.cancel(context) + return {'CANCELLED'} + + if event.type == 'TIMER': + print("HOLY COW!!!") + self.capture(self.sides[self.index]) + self.index += 1 + if self.index < len(self.sides): + self.position_camera(self.sides[self.index]) + else: + self.export_data() + + return {'PASS_THROUGH'} + + def execute(self, context): + print("execute!") + self.c = bpy.data.objects["cam"] + self.scene = bpy.context.scene + selected = bpy.context.selected_objects[0] + + bpy.ops.object.mode_set(mode="OBJECT") + bpy.ops.object.transform_apply( rotation = True ) + + self.data = {} + + self.b = selected + + FRONT = [0, 1, 2, "Front"] + SIDE = [1, 1, 2, "Side"] + TOP = [0, 0, 1, "Top"] + ANGLED = [0.5, 1, 2, "Angled"] + + self.sides = [FRONT, SIDE, TOP, ANGLED] + + path = "/tmp/macrovision/" + + media_path = "/home/crux/furry/macrovision/media/" + media_folder = "buildings/Houses/" + + os.makedirs(path, exist_ok=True) + os.makedirs(os.path.join(media_path, media_folder), exist_ok=True) + wm = context.window_manager + self._timer = wm.event_timer_add(0.25, window=context.window) + wm.modal_handler_add(self) + self.position_camera(self.sides[self.index]) + return {'RUNNING_MODAL'} + + def cancel(self, context): + wm = context.window_manager + wm.event_timer_remove(self._timer) + + + def getView3dAreaAndRegion(self, context): + for area in context.screen.areas: + if area.type == "VIEW_3D": + for region in area.regions: + if region.type == "WINDOW": + print("Found WINDOW") + return area, region + + def select_border(self, context, view3dAreaAndRegion=None, extend=True): + if not view3dAreaAndRegion: + view3dAreaAndRegion = self.getView3dAreaAndRegion(context) + print(view3dAreaAndRegion) + view3dArea, view3dRegion = view3dAreaAndRegion + override = context.copy() + override['area'] = view3dArea + override['region'] = view3dRegion + bpy.ops.view3d.select_box(override,xmin=0,xmax=view3dArea.width,ymin=0,ymax=view3dArea.height,mode='SET') + + def position_camera(self, angles): + bpy.ops.object.mode_set(mode="OBJECT") + local_bbox_center = 0.125 * sum((Vector(box) for box in self.b.bound_box), Vector()) + global_bbox_center = self.b.matrix_world @ local_bbox_center + self.c.data.ortho_scale = max(self.b.dimensions) * 1.3 + self.c.location = global_bbox_center + self.c.rotation_euler = Euler([angles[1] * pi / 2, 0, angles[0] * pi / 2]) + rot = self.c.rotation_euler.to_matrix() + rot.invert() + self.c.location = self.c.location + Vector([0, 0, 100]) @ rot + self.data[angles[3]] = self.b.dimensions[angles[2]] + + def capture(self, angles): + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_all(action="SELECT") + bpy.ops.mesh.sort_elements(type='VIEW_ZAXIS', elements={'FACE'}, reverse=False) + bm = bmesh.from_edit_mesh(bpy.context.active_object.data) + polygons = [] + edges = [] + + self.select_border(bpy.context) + bm.faces.ensure_lookup_table() + bm.verts.ensure_lookup_table() + bm.edges.ensure_lookup_table() + for face in bm.faces: + if not face.select: + continue + verts = [] + for vert in face.verts: + co = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, vert.co) + verts.append([co[0], co[1]]) + verts.append(verts[0]) + polygons.append({"verts": verts, "type": "bright" if face.material_index == 1 else "dark"}) + for edge in face.edges: + if not edge.select: + continue + co1 = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, edge.verts[0].co) + co2 = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, edge.verts[1].co) + polygons.append({"type": "edge", "verts": [ + [co1[0], co1[1]], + [co2[0], co2[1]] + ]}) + bm.free() + bpy.ops.object.mode_set(mode="OBJECT") + + + with open(f"/tmp/polygons-{angles[3]}.json", "w", encoding="utf-8") as file: + json.dump({"polygons": polygons}, file) + + + def export_data(self): + with open(f"/tmp/data-{self.b.name}.json", "w", encoding="utf-8") as file: + json.dump({"name": self.b.name, "views": self.data}, file) + + +def register(): + bpy.utils.register_class(ModalTimerOperator) + bpy.types.VIEW3D_MT_object.append(ModalTimerOperator.menu_func) + +def unregister(): + bpy.utils.unregister_class(ModalTimerOperator) + + +register() \ No newline at end of file