Also update the scripts to support tagging entities with masses and volumes.master
| @@ -458,6 +458,7 @@ const unitChoices = { | |||
| "m^3", | |||
| ], | |||
| "customary": [ | |||
| "in^3", | |||
| "floz", | |||
| "cups", | |||
| "pints", | |||
| @@ -20172,6 +20172,13 @@ const attributionData = { | |||
| "chemicalcrux" | |||
| ] | |||
| }, | |||
| { | |||
| prefix: "./media/food/Sugar Cubes/", | |||
| all: null, | |||
| authors: [ | |||
| "chemicalcrux" | |||
| ] | |||
| }, | |||
| { | |||
| prefix: "./media/furniture/Sofas/", | |||
| files: [ | |||
| @@ -0,0 +1,55 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
| <svg | |||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
| xmlns:cc="http://creativecommons.org/ns#" | |||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
| xmlns:svg="http://www.w3.org/2000/svg" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| id="svg18" | |||
| preserveAspectRatio="xMidYMid meet" | |||
| viewBox="0 0 1692 1300" | |||
| height="1300pt" | |||
| width="1692pt" | |||
| version="1.0"> | |||
| <defs | |||
| id="defs22" /> | |||
| <metadata | |||
| id="metadata2"> | |||
| Created by potrace 1.16, written by Peter Selinger 2001-2019 | |||
| <rdf:RDF> | |||
| <cc:Work | |||
| rdf:about=""> | |||
| <dc:format>image/svg+xml</dc:format> | |||
| <dc:type | |||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
| </cc:Work> | |||
| </rdf:RDF> | |||
| </metadata> | |||
| <g | |||
| style="fill:#000000;stroke:none" | |||
| id="g6" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1650)"> | |||
| <path | |||
| id="path4" | |||
| d="m 1581,16455 -41,-45 V 10000 3590 l 41,-45 42,-45 h 8377 8377 l 27,21 c 14,11 33,34 41,49 13,26 15,798 15,6430 0,5632 -2,6404 -15,6430 -8,15 -27,38 -41,49 l -27,21 H 10000 1623 Z" /> | |||
| </g> | |||
| <g | |||
| style="fill:#1a1a1a;stroke:none" | |||
| id="g12" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1650)"> | |||
| <path | |||
| id="path8" | |||
| d="M 1790,10000 V 3750 h 5770 5770 v 6250 6250 H 7560 1790 Z" /> | |||
| <path | |||
| id="path10" | |||
| d="M 13580,10000 V 3750 h 2315 2315 v 6250 6250 h -2315 -2315 z" /> | |||
| </g> | |||
| <g | |||
| style="fill:#333333;stroke:none" | |||
| id="g14" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1650)" /> | |||
| <g | |||
| style="fill:#4d4d4d;stroke:none" | |||
| id="g16" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1650)" /> | |||
| </svg> | |||
| @@ -0,0 +1,55 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
| <svg | |||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
| xmlns:cc="http://creativecommons.org/ns#" | |||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
| xmlns:svg="http://www.w3.org/2000/svg" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| id="svg18" | |||
| preserveAspectRatio="xMidYMid meet" | |||
| viewBox="0 0 1692 1204" | |||
| height="1204pt" | |||
| width="1692pt" | |||
| version="1.0"> | |||
| <defs | |||
| id="defs22" /> | |||
| <metadata | |||
| id="metadata2"> | |||
| Created by potrace 1.16, written by Peter Selinger 2001-2019 | |||
| <rdf:RDF> | |||
| <cc:Work | |||
| rdf:about=""> | |||
| <dc:format>image/svg+xml</dc:format> | |||
| <dc:type | |||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
| </cc:Work> | |||
| </rdf:RDF> | |||
| </metadata> | |||
| <g | |||
| style="fill:#000000;stroke:none" | |||
| id="g6" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1602)"> | |||
| <path | |||
| id="path4" | |||
| d="m 1610,16002 c -19,-10 -43,-34 -52,-53 -17,-32 -18,-337 -18,-5949 0,-5612 1,-5917 18,-5949 9,-19 33,-43 52,-53 34,-17 305,-18 8390,-18 8085,0 8356,1 8390,18 19,10 43,34 52,53 17,32 18,337 18,5949 0,5612 -1,5917 -18,5949 -9,19 -33,43 -52,53 -34,17 -305,18 -8390,18 -8085,0 -8356,-1 -8390,-18 z" /> | |||
| </g> | |||
| <g | |||
| style="fill:#1a1a1a;stroke:none" | |||
| id="g12" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1602)"> | |||
| <path | |||
| id="path8" | |||
| d="M 1790,10000 V 4230 h 4045 4045 v 5770 5770 H 5835 1790 Z" /> | |||
| <path | |||
| id="path10" | |||
| d="M 10120,10000 V 4230 h 4045 4045 v 5770 5770 h -4045 -4045 z" /> | |||
| </g> | |||
| <g | |||
| style="fill:#333333;stroke:none" | |||
| id="g14" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1602)" /> | |||
| <g | |||
| style="fill:#4d4d4d;stroke:none" | |||
| id="g16" | |||
| transform="matrix(0.1,0,0,-0.1,-154,1602)" /> | |||
| </svg> | |||
| @@ -0,0 +1,52 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
| <svg | |||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
| xmlns:cc="http://creativecommons.org/ns#" | |||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
| xmlns:svg="http://www.w3.org/2000/svg" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| id="svg16" | |||
| preserveAspectRatio="xMidYMid meet" | |||
| viewBox="0 0 1691.5 1691.7589" | |||
| height="1691.7589pt" | |||
| width="1691.5pt" | |||
| version="1.0"> | |||
| <defs | |||
| id="defs20" /> | |||
| <metadata | |||
| id="metadata2"> | |||
| Created by potrace 1.16, written by Peter Selinger 2001-2019 | |||
| <rdf:RDF> | |||
| <cc:Work | |||
| rdf:about=""> | |||
| <dc:format>image/svg+xml</dc:format> | |||
| <dc:type | |||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
| </cc:Work> | |||
| </rdf:RDF> | |||
| </metadata> | |||
| <g | |||
| style="fill:#000000;stroke:none" | |||
| id="g6" | |||
| transform="matrix(0.1,0,0,-0.1,-154.5,1845.9269)"> | |||
| <path | |||
| id="path4" | |||
| d="m 1625,18450 c -11,-4 -33,-22 -50,-40 l -30,-31 V 10000 1620 l 38,-37 37,-38 8368,-2 c 7950,-3 8369,-2 8402,15 20,10 42,32 52,52 17,33 18,456 18,8390 0,7934 -1,8357 -18,8390 -10,20 -32,42 -52,52 -33,17 -455,18 -8390,17 -4595,0 -8364,-4 -8375,-9 z" /> | |||
| </g> | |||
| <g | |||
| style="fill:#1a1a1a;stroke:none" | |||
| id="g10" | |||
| transform="matrix(0.1,0,0,-0.1,-154.5,1845.9269)"> | |||
| <path | |||
| id="path8" | |||
| d="M 1790,10000 V 1790 h 8210 8210 v 8210 8210 H 10000 1790 Z" /> | |||
| </g> | |||
| <g | |||
| style="fill:#333333;stroke:none" | |||
| id="g12" | |||
| transform="matrix(0.1,0,0,-0.1,-154.5,1845.9269)" /> | |||
| <g | |||
| style="fill:#4d4d4d;stroke:none" | |||
| id="g14" | |||
| transform="matrix(0.1,0,0,-0.1,-154.5,1845.9269)" /> | |||
| </svg> | |||
| @@ -127,6 +127,7 @@ function makeFood() { | |||
| /* ***Cereal Grains*** */ results.push(makeModel({"name": "Cereal Grains", "kind": "food", "forms": [{"name": "Jasmine Rice", "views": [{"name": "Top", "height": 0.007500000298023224, "mass": 1.5666666513425298e-05}, {"name": "Front", "height": 0.0014000001829117537, "mass": 1.5666666513425298e-05}, {"name": "Angled", "height": 0.0014000001829117537, "mass": 1.5666666513425298e-05}, {"name": "Side", "height": 0.0014000001829117537, "mass": 1.5666666513425298e-05}]}]})); | |||
| /* ***Noodles*** */ results.push(makeModel({"name": "Noodles", "kind": "food", "forms": [{"name": "Egg Noodle", "views": [{"name": "Top", "height": 0.032999999821186066, "mass": 0.000699999975040555, "extra": 1.0016954381752703, "bottom": 0.0016897085823988345}, {"name": "Front", "height": 0.011669180355966091, "mass": 0.000699999975040555, "extra": 1.001628943629906, "bottom": 0.0016236539483931555}, {"name": "Angled", "height": 0.011669180355966091, "mass": 0.000699999975040555, "extra": 1.0039921006053496, "bottom": 0.003960479341396986}, {"name": "Side", "height": 0.011669180355966091, "mass": 0.000699999975040555, "extra": 1.0040804752644092, "bottom": 0.004047444271937919}]}]})); | |||
| /* ***Seeds*** */ results.push(makeModel({"name": "Seeds", "kind": "food", "forms": [{"name": "Corn Kernel", "views": [{"name": "Top", "height": 0.013000001199543476, "mass": 0.00044133333722129464, "extra": 1.002910640340875, "bottom": 0.002893794749403287}, {"name": "Front", "height": 0.005000000353902578, "mass": 0.00044133333722129464, "extra": 1.0054957130415634, "bottom": 0.005435964044576862}, {"name": "Side", "height": 0.005000000353902578, "mass": 0.00044133333722129464, "extra": 1.0069798441153546, "bottom": 0.006883749123728984}]}]})); | |||
| /* ***Sugar Cubes*** */ results.push(makeModel({"name": "Sugar Cubes", "kind": "food", "forms": [{"name": "Sugar Cube", "views": [{"name": "Front", "height": 0.015239999629557133, "volume": 3.5396055658854918e-06, "mass": 0.004, "extra": 1.007730762304922, "bottom": 0.0076130529001503305}, {"name": "Angled", "height": 0.015239999629557133, "volume": 3.5396055658854918e-06, "mass": 0.004, "extra": 1.0094043887147335, "bottom": 0.009230769230769232}, {"name": "Corner", "height": 0.015239999629557133, "volume": 3.5396055658854918e-06, "mass": 0.004, "extra": 1.0110356536502547, "bottom": 0.01079734219269103}]}]})); | |||
| /* ***INSERT HERE*** */ | |||
| results.sort((b1, b2) => { | |||
| @@ -20,6 +20,8 @@ def register(): | |||
| for id, prop in props.scene_props.items(): | |||
| setattr(bpy.types.Scene, id, prop) | |||
| for id, prop in props.collection_props.items(): | |||
| setattr(bpy.types.Collection, id, prop) | |||
| def unregister(): | |||
| @@ -20,6 +20,9 @@ VIEW_DATA = { | |||
| "BOTTOM_FLIPPED": [2, 2, 1, "Bottom Flipped"], | |||
| } | |||
| def read_sci(property): | |||
| return property.base * pow(10, property.power) | |||
| def get_bounds(objects): | |||
| xl = [] | |||
| yl = [] | |||
| @@ -216,7 +219,7 @@ class MVExport(bpy.types.Operator): | |||
| bl_idname = "mv.export" | |||
| bl_label = "Export objects" | |||
| def execute(self, context: bpy.types.Context): | |||
| def execute(self, context: bpy.context): | |||
| path_info = pathlib.Path(bpy.data.filepath).parent.joinpath("macrovision-directory.txt") | |||
| config_path = pathlib.Path(open(path_info).read().strip()) | |||
| @@ -267,6 +270,8 @@ class MVExport(bpy.types.Operator): | |||
| os.makedirs(workdir, exist_ok=True) | |||
| coll: bpy.types.Collection | |||
| for coll in collections: | |||
| coll.hide_render = True | |||
| @@ -322,15 +327,42 @@ class MVExport(bpy.types.Operator): | |||
| scale_factor = (10 ** context.scene.mv_scale_factor) | |||
| height = dimensions[angles[2]] * scale_factor | |||
| data["views"].append({ | |||
| view_data = { | |||
| "name": angles[3], | |||
| "height": height | |||
| }) | |||
| } | |||
| volume_mode = context.scene.mv_entity_volume_mode | |||
| mass_mode = context.scene.mv_entity_mass_mode | |||
| volume = None | |||
| if volume_mode == "MANUAL": | |||
| volume = read_sci(coll.mv_entity_volume) | |||
| elif volume_mode == "AUTO": | |||
| # this over-estimates, since overlapping objects will count the same space | |||
| volume = 0 | |||
| for object in coll.objects: | |||
| if object.type == "MESH": | |||
| bm = bmesh.new() | |||
| bm.from_object(object, context.evaluated_depsgraph_get()) | |||
| volume += bm.calc_volume() | |||
| bm.free() | |||
| mass = None | |||
| if mass_mode == "MANUAL": | |||
| mass = read_sci(coll.mv_entity_mass) | |||
| elif mass_mode == "DENSITY": | |||
| mass = volume * read_sci(coll.mv_entity_mass) * 1000 | |||
| if volume is not None: | |||
| view_data["volume"] = volume * (scale_factor ** 3) | |||
| if mass is not None: | |||
| view_data["mass"] = mass * (scale_factor ** 3) | |||
| if "Volume" in coll: | |||
| data["views"][-1]["volume"] = coll["Volume"] * (scale_factor ** 3) | |||
| if "Mass" in coll: | |||
| data["views"][-1]["mass"] = coll["Mass"] * (scale_factor ** 3) | |||
| data["views"].append(view_data) | |||
| lineart.hide_render = False | |||
| filename = f"{coll.name}-{angles[3]}.png" | |||
| @@ -1,6 +1,7 @@ | |||
| import bpy | |||
| scene_props = {} | |||
| collection_props = {} | |||
| scene_props["mv_name"] = bpy.props.StringProperty( | |||
| name = "Name", | |||
| @@ -31,6 +32,19 @@ class MVView(bpy.types.PropertyGroup): | |||
| ) | |||
| name: bpy.props.StringProperty(name = "Name", description="What to call this view") | |||
| class MVScientificNumber(bpy.types.PropertyGroup): | |||
| base: bpy.props.FloatProperty( | |||
| name = "Base", | |||
| description = "The base of the number", | |||
| default = 0, | |||
| precision = 7 | |||
| ) | |||
| power: bpy.props.IntProperty( | |||
| name = "Power", | |||
| description = "The power of ten to multiply the base by", | |||
| default = 0 | |||
| ) | |||
| scene_props["mv_views"] = bpy.props.CollectionProperty( | |||
| name = "Views", | |||
| description = "The views to view the object from", | |||
| @@ -49,7 +63,7 @@ scene_props["mv_scale_factor"] = bpy.props.IntProperty( | |||
| max = 20, | |||
| soft_min = -20, | |||
| soft_max = 20, | |||
| default = 5 | |||
| default = 0 | |||
| ) | |||
| scene_props["mv_material_mode"] = bpy.props.EnumProperty( | |||
| @@ -74,6 +88,41 @@ scene_props["mv_material_names_medium"] = bpy.props.StringProperty( | |||
| default = "" | |||
| ) | |||
| scene_props["mv_entity_mass_mode"] = bpy.props.EnumProperty( | |||
| name = "Mass", | |||
| description = "How to compute the mass of entities", | |||
| items = ( | |||
| ("OFF", "Off", "Do not include mass",), | |||
| ("MANUAL", "Manual", "Use manually-specified mass",), | |||
| ("DENSITY", "Density", "Use volume and manually-specified density") | |||
| ), | |||
| default = "OFF" | |||
| ) | |||
| scene_props["mv_entity_volume_mode"] = bpy.props.EnumProperty( | |||
| name = "Volume", | |||
| description = "How to compute the volume of entities", | |||
| items = ( | |||
| ("OFF", "Off", "Do not include volume",), | |||
| ("MANUAL", "Manual", "Use manually-specified volume",), | |||
| ("AUTO", "Auto", "Use auto-computed volume") | |||
| ), | |||
| default = "OFF" | |||
| ) | |||
| collection_props["mv_entity_volume"] = bpy.props.PointerProperty( | |||
| type = MVScientificNumber, | |||
| ) | |||
| collection_props["mv_entity_mass"] = bpy.props.PointerProperty( | |||
| type = MVScientificNumber, | |||
| ) | |||
| collection_props["mv_entity_density"] = bpy.props.PointerProperty( | |||
| type = MVScientificNumber, | |||
| ) | |||
| clses = [ | |||
| MVView | |||
| MVView, | |||
| MVScientificNumber | |||
| ] | |||
| @@ -38,8 +38,9 @@ class MV_Views_List_Delete(bpy.types.Operator): | |||
| context.scene.mv_views_index = index | |||
| return {'FINISHED'} | |||
| class MVPanel(bpy.types.Panel): | |||
| bl_idname="OBJECT_PT_MV_menu" | |||
| class MVScenePanel(bpy.types.Panel): | |||
| bl_idname="OBJECT_PT_MV_scene_menu" | |||
| bl_label="Macrovision" | |||
| bl_space_type="VIEW_3D" | |||
| bl_region_type="UI" | |||
| @@ -55,6 +56,9 @@ class MVPanel(bpy.types.Panel): | |||
| box = layout.box() | |||
| box.label(text="Setup") | |||
| box.prop(context.scene, "mv_entity_mass_mode") | |||
| box.prop(context.scene, "mv_entity_volume_mode") | |||
| op_props = box.operator("mv.config_collection") | |||
| op_props = box.operator("mv.assign_materials") | |||
| @@ -84,9 +88,46 @@ class MVPanel(bpy.types.Panel): | |||
| row.operator("mv.views_list_add", text="+") | |||
| row.operator("mv.views_list_delete", text="-") | |||
| box.prop(context.scene, 'mv_scale_factor') | |||
| class MVCollectionPanel(bpy.types.Panel): | |||
| bl_idname="OBJECT_PT_MV_collection_menu" | |||
| bl_label="Entity" | |||
| bl_space_type="VIEW_3D" | |||
| bl_region_type="UI" | |||
| bl_category = "Macrovision" | |||
| @classmethod | |||
| def poll(cls, context: bpy.context): | |||
| return context.collection.name in bpy.data.collections['Macrovision'].children | |||
| def draw(self, context): | |||
| layout = self.layout | |||
| box = layout.box() | |||
| box.label(text="Entity") | |||
| if context.scene.mv_entity_mass_mode == "MANUAL": | |||
| row = box.row() | |||
| row.label(text="Mass") | |||
| row.prop(context.collection.mv_entity_mass, "base") | |||
| row.prop(context.collection.mv_entity_mass, "power") | |||
| if context.scene.mv_entity_mass_mode == "DENSITY": | |||
| row = box.row() | |||
| row.label(text="Density") | |||
| row.prop(context.collection.mv_entity_density, "base") | |||
| row.prop(context.collection.mv_entity_density, "power") | |||
| if context.scene.mv_entity_volume_mode == "MANUAL": | |||
| row = box.row() | |||
| row.label(text="Volume") | |||
| row.prop(context.collection.mv_entity_volume, "base") | |||
| row.prop(context.collection.mv_entity_volume, "power") | |||
| clses = [ | |||
| MV_UL_ViewList, | |||
| MV_Views_List_Add, | |||
| MV_Views_List_Delete, | |||
| MVPanel | |||
| MVScenePanel, | |||
| MVCollectionPanel | |||
| ] | |||