diff --git a/media/attribution.js b/media/attribution.js index 730a8650..0b1c9e18 100644 --- a/media/attribution.js +++ b/media/attribution.js @@ -19870,8 +19870,6 @@ const attributionData = { { name: "circle.svg", source: null }, { name: "pencil.svg", source: null }, { name: "pebble.svg", source: null }, - { name: "credit-card.svg", source: null }, - { name: "credit-card-vertical.svg", source: null }, { name: "flagpole.svg", source: null }, { name: "strand.svg", source: null }, { name: "sine-wave.svg", source: null }, @@ -20356,6 +20354,16 @@ const attributionData = { "https://www.homedepot.com/p/L-I-F-Industries-36-in-x-80-in-Gray-Flush-Exit-Left-Hand-Fire-Proof-Steel-Prehung-Commercial-Door-with-Welded-Frame-UWX3680L/202510508" ] }, + { + prefix: "./media/objects/Cards/", + all: null, + authors: [ + "chemicalcrux" + ], + citations: [ + "https://en.wikipedia.org/wiki/ISO/IEC_7810" + ] + }, { prefix: "./media/real-buildings/", all: "https://wiki.openstreetmap.org/wiki/Blender", diff --git a/media/objects/Cards/Credit Card-Back.svg b/media/objects/Cards/Credit Card-Back.svg new file mode 100644 index 00000000..c2eb204f --- /dev/null +++ b/media/objects/Cards/Credit Card-Back.svg @@ -0,0 +1,51 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + image/svg+xml + + + + + + + + + + + + + diff --git a/media/objects/Cards/Credit Card-Edge.svg b/media/objects/Cards/Credit Card-Edge.svg new file mode 100644 index 00000000..41127d49 --- /dev/null +++ b/media/objects/Cards/Credit Card-Edge.svg @@ -0,0 +1,199 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/media/objects/Cards/Credit Card-Front.svg b/media/objects/Cards/Credit Card-Front.svg new file mode 100644 index 00000000..b0e26c19 --- /dev/null +++ b/media/objects/Cards/Credit Card-Front.svg @@ -0,0 +1,229 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presets/objects.js b/presets/objects.js index 90e94522..f2eb31eb 100644 --- a/presets/objects.js +++ b/presets/objects.js @@ -203,6 +203,12 @@ function makeModel(data) { source: "./media/" + data.kind + "/" + data.name + "/" + form.name + "-" + view.name + ".svg" } } + + if (view.bottom) + views[viewId].image.bottom = view.bottom + + if (view.extra) + views[viewId].image.extra = view.extra }) }); @@ -415,25 +421,6 @@ function makeObjects() { ) }); - results.push({ - name: "Credit Card", - constructor: () => makeObject( - "Credit Card", - { - creditCard: { - height: math.unit(53.98, "mm"), - image: { source: "./media/objects/credit-card.svg" }, - name: "Credit card", - }, - creditCardVertical: { - height: math.unit(85.60, "mm"), - image: { source: "./media/objects/credit-card-vertical.svg" }, - name: "Credit card (vertical)", - }, - } - ) - }); - results.push({ name: "Molecular", constructor: () => makeObject( @@ -919,6 +906,7 @@ function makeObjects() { /* ***Straws*** */ results.push(makeModel({"name": "Straws", "kind": "objects", "forms": [{"name": "Normal", "views": [{"name": "Front", "height": 0.2159000039100647}, {"name": "Top", "height": 0.006095999851822853}]}, {"name": "Wide", "views": [{"name": "Front", "height": 0.2159000039100647}, {"name": "Top", "height": 0.008127997629344463}]}, {"name": "Smoothie", "views": [{"name": "Front", "height": 0.2159000039100647}, {"name": "Top", "height": 0.00914399977773428}]}, {"name": "Boba", "views": [{"name": "Front", "height": 0.2159000039100647}, {"name": "Top", "height": 0.012191999703645706}]}]})); /* ***Coins*** */ results.push(makeModel({"name": "Coins", "kind": "objects", "forms": [{"name": "U.S. Dollar", "views": [{"name": "Top", "height": 0.026492198929190636, "mass": 0.008100000210106373}, {"name": "Side", "height": 0.0020000000949949026, "mass": 0.008100000210106373}]}, {"name": "U.S. Half Dollar", "views": [{"name": "Top", "height": 0.03060699999332428, "mass": 0.011339999735355377}, {"name": "Side", "height": 0.00215000007301569, "mass": 0.011339999735355377}]}, {"name": "U.S. Quarter", "views": [{"name": "Top", "height": 0.024257000535726547, "mass": 0.005669999867677689}, {"name": "Side", "height": 0.0017500000540167093, "mass": 0.005669999867677689}]}, {"name": "U.S. Dime", "views": [{"name": "Top", "height": 0.017906999215483665, "mass": 0.002268000040203333}, {"name": "Side", "height": 0.0013500000350177288, "mass": 0.002268000040203333}]}, {"name": "U.S. Nickel", "views": [{"name": "Top", "height": 0.021208999678492546, "mass": 0.004999999888241291}, {"name": "Side", "height": 0.0019500000635161996, "mass": 0.004999999888241291}]}, {"name": "U.S. Penny", "views": [{"name": "Top", "height": 0.019050000235438347, "mass": 0.0024999999441206455}, {"name": "Side", "height": 0.0015200000489130616, "mass": 0.0024999999441206455}]}, {"name": "UK \u00a35", "views": [{"name": "Top", "height": 0.028400002047419548, "mass": 0.028279999271035194}, {"name": "Side", "height": 0.0028900043107569218, "mass": 0.028279999271035194}]}, {"name": "UK \u00a32", "views": [{"name": "Top", "height": 0.028400002047419548, "mass": 0.012000000104308128}, {"name": "Side", "height": 0.0025000039022415876, "mass": 0.012000000104308128}]}, {"name": "UK \u00a31", "views": [{"name": "Top", "height": 0.023430000990629196, "mass": 0.008750000037252903}, {"name": "Side", "height": 0.0028000001329928637, "mass": 0.008750000037252903}]}, {"name": "UK 50p", "views": [{"name": "Top", "height": 0.027300003916025162, "mass": 0.00800000037997961}, {"name": "Side", "height": 0.0017800000496208668, "mass": 0.00800000037997961}]}, {"name": "UK 20p", "views": [{"name": "Top", "height": 0.021400000900030136, "mass": 0.004999999888241291}, {"name": "Side", "height": 0.0017000001389533281, "mass": 0.004999999888241291}]}, {"name": "UK 10p", "views": [{"name": "Top", "height": 0.024500001221895218, "mass": 0.006500000134110451}, {"name": "Side", "height": 0.0018500001169741154, "mass": 0.006500000134110451}]}, {"name": "UK 5p", "views": [{"name": "Top", "height": 0.018000001087784767, "mass": 0.0032500000670552254}, {"name": "Side", "height": 0.0017000001389533281, "mass": 0.0032500000670552254}]}, {"name": "UK 2p", "views": [{"name": "Top", "height": 0.02590000070631504, "mass": 0.007120000198483467}, {"name": "Side", "height": 0.00203000009059906, "mass": 0.007120000198483467}]}, {"name": "UK 1p", "views": [{"name": "Top", "height": 0.0203000009059906, "mass": 0.0035600000992417336}, {"name": "Side", "height": 0.0016500001074746251, "mass": 0.0035600000992417336}]}, {"name": "Canadian Two Dollar", "views": [{"name": "Top", "height": 0.02800000086426735, "mass": 0.007300000172108412}, {"name": "Side", "height": 0.0018000000854954123, "mass": 0.007300000172108412}]}, {"name": "Canadian Dollar", "views": [{"name": "Top", "height": 0.026500001549720764, "mass": 0.0062699997797608376}, {"name": "Side", "height": 0.0019500007620081306, "mass": 0.0062699997797608376}]}, {"name": "2 Euro", "views": [{"name": "Top", "height": 0.02575000189244747, "mass": 0.008500000461935997}, {"name": "Side", "height": 0.0022000002209097147, "mass": 0.008500000461935997}]}, {"name": "1 Euro", "views": [{"name": "Top", "height": 0.023250000551342964, "mass": 0.007499999832361937}, {"name": "Side", "height": 0.0023300000466406345, "mass": 0.007499999832361937}]}, {"name": "500 Yen", "views": [{"name": "Top", "height": 0.026500001549720764, "mass": 0.0071000000461936}, {"name": "Side", "height": 0.0018100000452250242, "mass": 0.0071000000461936}]}, {"name": "50 Yen", "views": [{"name": "Top", "height": 0.021000003442168236, "mass": 0.004000000189989805}, {"name": "Side", "height": 0.0015100002055987716, "mass": 0.004000000189989805}]}, {"name": "5 Yen", "views": [{"name": "Top", "height": 0.02200000174343586, "mass": 0.0037499999161809683}, {"name": "Side", "height": 0.0015100002055987716, "mass": 0.0037499999161809683}]}]})); /* ***Doors*** */ results.push(makeModel({"name": "Doors", "kind": "objects", "forms": [{"name": "6 Panel Door", "views": [{"name": "Front", "height": 2.0320000648498535, "mass": 11.793399810791016}, {"name": "Angled", "height": 2.0320000648498535, "mass": 11.793399810791016}, {"name": "Side", "height": 2.0320000648498535, "mass": 11.793399810791016}, {"name": "Top", "height": 0.03492499887943268, "mass": 11.793399810791016}]}, {"name": "French Door", "views": [{"name": "Front", "height": 2.0320000648498535, "mass": 31.75149917602539}, {"name": "Angled", "height": 2.0320000648498535, "mass": 31.75149917602539}, {"name": "Side", "height": 2.0320000648498535, "mass": 31.75149917602539}, {"name": "Top", "height": 0.03492499887943268, "mass": 31.75149917602539}]}, {"name": "Fire Door", "views": [{"name": "Front", "height": 2.0320000648498535, "mass": 54.54545593261719}, {"name": "Angled", "height": 2.0320000648498535, "mass": 54.54545593261719}, {"name": "Side", "height": 2.0320000648498535, "mass": 54.54545593261719}, {"name": "Top", "height": 0.10518216341733932, "mass": 54.54545593261719}]}]})); + /* ***Cards*** */ results.push(makeModel({"name": "Cards", "kind": "objects", "forms": [{"name": "Credit Card", "views": [{"name": "Front", "height": 0.053975000977516174, "mass": 11.793399810791016, "extra": 1.0047993079868203, "bottom": 0.00475367924528303}, {"name": "Back", "height": 0.053975000977516174, "mass": 11.793399810791016, "extra": 1.0047993079868203, "bottom": 0.00475367924528303}, {"name": "Edge", "height": 0.0015578659949824214, "mass": 11.793399810791016, "extra": 1.1704167, "bottom": 0.127097594675073}]}]})); /* ***INSERT HERE*** */ return results; } diff --git a/scripts/blender-model.py b/scripts/blender-model.py index d8e52985..d3251fac 100644 --- a/scripts/blender-model.py +++ b/scripts/blender-model.py @@ -12,7 +12,8 @@ VIEW_DATA = { "Back Angled": [1.5, 1, 2, "Back Angled"], "Back": [2, 1, 2, "Back"], "Top": [0, 0, 1, "Top"], - "Bottom": [0, 2, 1, "Bottom"] + "Bottom": [0, 2, 1, "Bottom"], + "Bottom Flipped": [2, 2, 1, "Bottom Flipped"], } def get_bounds(objects): @@ -42,6 +43,7 @@ config = json.load(open(json_path.resolve(), encoding="utf-8")) parent_workdir = config["work-directory"] c = bpy.data.objects["cam"] +lineart = bpy.data.objects["lineart"] c.data.type = "ORTHO" bpy.data.scenes["Scene"].render.resolution_x = 2000 @@ -65,6 +67,12 @@ default_views = [] for view in mv["MVViews"].split(","): default_views.append(VIEW_DATA[view.strip()]) +if "MVViewLabels" in mv: + for pair in mv["MVViewLabels"].split(","): + key, val = pair.split(":") + VIEW_DATA[key.strip()][3] = val.strip() + + workdir = pathlib.Path(parent_workdir).joinpath(all_data["name"]) os.makedirs(workdir, exist_ok=True) @@ -120,9 +128,14 @@ for coll in collections: if "Mass" in coll: data["views"][-1]["mass"] = coll["Mass"] + lineart.hide_render = False filename = f"{coll.name}-{angles[3]}.png" bpy.context.scene.render.filepath = workdir.joinpath(filename).resolve().__str__() bpy.ops.render.render(write_still = True) + lineart.hide_render = True + filename = f"{coll.name}-{angles[3]}-noline.png" + bpy.context.scene.render.filepath = workdir.joinpath(filename).resolve().__str__() + bpy.ops.render.render(write_still = True) all_data["forms"].append(data) coll.hide_render = True diff --git a/scripts/process-model.py b/scripts/process-model.py index 04998cf2..d4b93549 100644 --- a/scripts/process-model.py +++ b/scripts/process-model.py @@ -1,11 +1,12 @@ import sys import re import json -import glob import os import subprocess import pathlib +from xml.dom import minidom + # an affront to god def combine(base_path, highlight_path, vivid_path, output_path): base = open(base_path, "r", encoding="utf-8").read() @@ -57,6 +58,7 @@ for data in all_data["forms"]: for view in data["views"]: view_name = view["name"] input = sourcedir.joinpath(name + "-" + view_name + ".png").__str__() + input_noline_raw = sourcedir.joinpath(name + "-" + view_name + "-" + "noline.png").__str__() result = outputdir.joinpath(name + "-" + view_name + ".svg").__str__() print(result) if os.path.exists(result) and os.path.getmtime(input) < os.path.getmtime(result): @@ -66,19 +68,47 @@ for data in all_data["forms"]: input_base = sourcedir.joinpath(name + "-" + view_name + "-base.bmp").__str__() input_highlight = sourcedir.joinpath(name + "-" + view_name + "-highlight.bmp").__str__() input_vivid = sourcedir.joinpath(name + "-" + view_name + "-vivid.bmp").__str__() + input_noline = sourcedir.joinpath(name + "-" + view_name + "-noline.bmp").__str__() subprocess.run(["magick", "convert", input, base_lut, "-channel", "RGB", "-clut", "-background", "#FFFFFF", "-flatten", input_base], shell=False) subprocess.run(["magick", "convert", input, highlight_lut, "-channel", "RGB", "-clut", "-background", "#FFFFFF", "-flatten", input_highlight], shell=False) subprocess.run(["magick", "convert", input, vivid_lut, "-channel", "RGB", "-clut", "-background", "#FFFFFF", "-flatten", input_vivid], shell=False) + + # to correct for extra height from lines + subprocess.run(["magick", "convert", input_noline_raw, base_lut, "-channel", "RGB", "-clut", "-background", "#FFFFFF", "-flatten", input_noline], shell=False) output_base = sourcedir.joinpath(name + "-" + view_name + "-base.svg").__str__() output_highlight = sourcedir.joinpath(name + "-" + view_name + "-highlight.svg").__str__() output_vivid = sourcedir.joinpath(name + "-" + view_name + "-vivid.svg").__str__() + output_noline = sourcedir.joinpath(name + "-" + view_name + "-noline.svg").__str__() subprocess.run([POTRACE, input_base, "-b", "svg", "-o", output_base], shell=False) subprocess.run([POTRACE, input_highlight, "-b", "svg", "-C", "#1a1a1a", "-o", output_highlight], shell=False) subprocess.run([POTRACE, input_vivid, "-b", "svg", "-C", "#333333", "-o", output_vivid], shell=False) + subprocess.run([POTRACE, input_noline, "-b", "svg", "-C", "#333333", "-o", output_noline], shell=False) + combine(output_base, output_highlight, output_vivid, result) + + noline_result = sourcedir.joinpath(name + "-" + view_name + "-noline_processed.svg").__str__() + + # we now learn how much height was added by the lineart! + + original_xml = minidom.parse(open(result)) + noline_xml = minidom.parse(open(noline_result)) + + original_height = float(original_xml.childNodes[0].attributes["height"].value[:-2]) + noline_height = float(noline_xml.childNodes[0].attributes["height"].value[:-2]) + + delta = original_height - noline_height + + height = original_height + bottom = height - (height - delta / 2) + top = height - delta / 2 + + view["extra"] = (height - bottom) / (top - bottom) + view["bottom"] = bottom / height + + combine(output_noline, output_noline, output_noline, noline_result) # os.unlink(input_base) # os.unlink(input_highlight)