import bpy from mathutils import Vector, Euler from math import pi import json import os import subprocess import xml.etree.ElementTree as ET c = bpy.data.objects["cam"] selected = bpy.context.selected_objects[0] bpy.ops.object.transform_apply( rotation = True ) data = {} b = selected FRONT = [0, 1, 2, "Front"] FRONT_CORNER = [0.5, 1, 2, "Front Corner"] SIDE = [1, 1, 2, "Side"] BACK_CORNER = [1.5, 1, 2, "Back Corner"] BACK = [2, 1, 2, "Back"] BOTTOM = [0, 2, 1, "Bottom"] TOP = [0, 0, 1, "Top"] sides = [FRONT, FRONT_CORNER, SIDE, BACK_CORNER, BACK, BOTTOM, TOP] path = "/tmp/macrovision/" media_path = "/home/crux/furry/macrovision/media/" media_folder = "clothing/Boots/" os.makedirs(path, exist_ok=True) os.makedirs(os.path.join(media_path, media_folder), exist_ok=True) ns = {"svg": "http://www.w3.org/2000/svg"} ET.register_namespace("", ns["svg"]) TEMPLATE = """ {{ name: "{0}", sides: {{ {1} }} }}""" VIEW_TEMPLATE = ' "{0}": {{ height: math.unit({1}, "meters") }}' for angles in sides: local_bbox_center = 0.125 * sum((Vector(box) for box in b.bound_box), Vector()) global_bbox_center = b.matrix_world @ local_bbox_center c.location = global_bbox_center c.data.ortho_scale = max(b.dimensions) * 1.1 c.rotation_euler = Euler([angles[1] * pi / 2, 0, angles[0] * pi / 2]) rot = c.rotation_euler.to_matrix() rot.invert() c.location = c.location + Vector([0, 0, 100]) @ rot data[angles[3]] = b.dimensions[angles[2]] output_path = os.path.join(path, f"{b.name}-{angles[3]}") bpy.context.scene.render.filepath = output_path svg_path = output_path + "0001.svg" bpy.ops.render.render(write_still = True) os.rename(svg_path, output_path + ".svg") subprocess.check_output([ "potrace", "-b", "svg", output_path + ".bmp", "-o", output_path + "-fill.svg" ]) line_xml = ET.parse(output_path + ".svg") fill_xml = ET.parse(output_path + "-fill.svg") style = None for elem in line_xml.findall(".//svg:path", namespaces=ns): if style is None: style = {} for key in elem.attrib: if not key == "d": style[key] = elem.attrib[key] for key in style: del elem.attrib[key] parts = elem.attrib["d"].strip().split(" ") if len(parts) > 6 and parts[1] == parts[3] == parts[5] and parts[2] == parts[4] == parts[6]: elem.attrib["DELETEME"] = True while True: child = line_xml.find(".//svg:path[@DELETEME]", namespaces=ns) parent = line_xml.find(".//svg:path[@DELETEME]...", namespaces=ns) print(parent, child) if parent is None: break parent.remove(child) for key in style: line_xml.find("./svg:g", namespaces=ns).attrib[key] = style[key] line_xml.write(output_path + "-cleaned.svg") subprocess.check_output([ "inkscape", output_path + "-cleaned.svg", "--batch-process", "--actions=EditSelectAll;SelectionSimplify;FileSave", ]) optimized = ET.parse(output_path + "-cleaned.svg") lines = optimized.find("./svg:g", namespaces=ns) fill_xml.find("svg:g[@fill='#000000']", namespaces=ns).attrib["fill"] = "#1a1a1a" fill_xml.iter().__next__().append(lines) fill_xml.write(output_path + "-combined.svg") subprocess.check_output([ "inkscape", "--batch-process", "--export-plain-svg=" + output_path + "-prepared.svg", "--export-area-drawing", output_path + "-combined.svg" ]) subprocess.check_output([ "svgo", output_path + "-prepared.svg", "-o", os.path.join(media_path, media_folder, f"{b.name}-{angles[3]}.svg") ]) lines = [] for key, value in data.items(): lines.append(VIEW_TEMPLATE.format(key, value)) print(TEMPLATE.format(b.name, ",\n".join(lines)))