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 @@
+
+
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 @@
+
+
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 @@
+
+
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
]