From 6a8dc8de472c4d5a000c148638e054d1b8644005 Mon Sep 17 00:00:00 2001 From: Fen Dweller Date: Sat, 15 Jan 2022 16:16:24 -0500 Subject: [PATCH] Add sugar cubes Also update the scripts to support tagging entities with masses and volumes. --- macrovision.js | 1 + media/attribution.js | 7 +++ media/food/Sugar Cubes/Sugar Cube-Angled.svg | 55 +++++++++++++++++++ media/food/Sugar Cubes/Sugar Cube-Corner.svg | 55 +++++++++++++++++++ media/food/Sugar Cubes/Sugar Cube-Front.svg | 52 ++++++++++++++++++ presets/food.js | 1 + .../blender/addons/macrovision/__init__.py | 2 + scripts/blender/addons/macrovision/ops.py | 46 +++++++++++++--- scripts/blender/addons/macrovision/props.py | 53 +++++++++++++++++- scripts/blender/addons/macrovision/ui.py | 47 +++++++++++++++- 10 files changed, 307 insertions(+), 12 deletions(-) create mode 100644 media/food/Sugar Cubes/Sugar Cube-Angled.svg create mode 100644 media/food/Sugar Cubes/Sugar Cube-Corner.svg create mode 100644 media/food/Sugar Cubes/Sugar Cube-Front.svg diff --git a/macrovision.js b/macrovision.js index 3eed5006..0549c37f 100644 --- a/macrovision.js +++ b/macrovision.js @@ -458,6 +458,7 @@ const unitChoices = { "m^3", ], "customary": [ + "in^3", "floz", "cups", "pints", diff --git a/media/attribution.js b/media/attribution.js index 49c10d82..39d56f43 100644 --- a/media/attribution.js +++ b/media/attribution.js @@ -20172,6 +20172,13 @@ const attributionData = { "chemicalcrux" ] }, + { + prefix: "./media/food/Sugar Cubes/", + all: null, + authors: [ + "chemicalcrux" + ] + }, { prefix: "./media/furniture/Sofas/", files: [ diff --git a/media/food/Sugar Cubes/Sugar Cube-Angled.svg b/media/food/Sugar Cubes/Sugar Cube-Angled.svg new file mode 100644 index 00000000..50d763f4 --- /dev/null +++ b/media/food/Sugar Cubes/Sugar Cube-Angled.svg @@ -0,0 +1,55 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/media/food/Sugar Cubes/Sugar Cube-Corner.svg b/media/food/Sugar Cubes/Sugar Cube-Corner.svg new file mode 100644 index 00000000..d33b5e13 --- /dev/null +++ b/media/food/Sugar Cubes/Sugar Cube-Corner.svg @@ -0,0 +1,55 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/media/food/Sugar Cubes/Sugar Cube-Front.svg b/media/food/Sugar Cubes/Sugar Cube-Front.svg new file mode 100644 index 00000000..fa64a576 --- /dev/null +++ b/media/food/Sugar Cubes/Sugar Cube-Front.svg @@ -0,0 +1,52 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + image/svg+xml + + + + + + + + + + + + + diff --git a/presets/food.js b/presets/food.js index 5b79fdff..96235abd 100644 --- a/presets/food.js +++ b/presets/food.js @@ -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) => { diff --git a/scripts/blender/addons/macrovision/__init__.py b/scripts/blender/addons/macrovision/__init__.py index c6b1d60b..6fe98128 100644 --- a/scripts/blender/addons/macrovision/__init__.py +++ b/scripts/blender/addons/macrovision/__init__.py @@ -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(): diff --git a/scripts/blender/addons/macrovision/ops.py b/scripts/blender/addons/macrovision/ops.py index c94bdbe4..b5c01ca1 100644 --- a/scripts/blender/addons/macrovision/ops.py +++ b/scripts/blender/addons/macrovision/ops.py @@ -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" diff --git a/scripts/blender/addons/macrovision/props.py b/scripts/blender/addons/macrovision/props.py index b12d8466..2de9672d 100644 --- a/scripts/blender/addons/macrovision/props.py +++ b/scripts/blender/addons/macrovision/props.py @@ -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 ] \ No newline at end of file diff --git a/scripts/blender/addons/macrovision/ui.py b/scripts/blender/addons/macrovision/ui.py index c7b57d67..53daf9e1 100644 --- a/scripts/blender/addons/macrovision/ui.py +++ b/scripts/blender/addons/macrovision/ui.py @@ -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 ]