[Bf-extensions-cvs] [fc96993a] master: move export paper model to release: T51199 T50357
meta-androcto
noreply at git.blender.org
Sat Apr 15 06:05:46 CEST 2017
Commit: fc96993a2392808e22176bc9aecc9ecc26216bd2
Author: meta-androcto
Date: Sat Apr 15 14:05:20 2017 +1000
Branches: master
https://developer.blender.org/rBACfc96993a2392808e22176bc9aecc9ecc26216bd2
move export paper model to release: T51199 T50357
===================================================================
D io_export_paper_model.py
===================================================================
diff --git a/io_export_paper_model.py b/io_export_paper_model.py
deleted file mode 100644
index 508b953f..00000000
--- a/io_export_paper_model.py
+++ /dev/null
@@ -1,2520 +0,0 @@
-# -*- coding: utf-8 -*-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but without any warranty; without even the implied warranty of
-# merchantability or fitness for a particular purpose. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-bl_info = {
- "name": "Export Paper Model",
- "author": "Addam Dominec",
- "version": (0, 9),
- "blender": (2, 70, 0),
- "location": "File > Export > Paper Model",
- "warning": "",
- "description": "Export printable net of the active mesh",
- "category": "Import-Export",
- "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
- "Scripts/Import-Export/Paper_Model",
- "tracker_url": "https://developer.blender.org/T38441"
-}
-
-#### TODO:
-# sanitize the constructors so that they don't edit their parent object
-# rename verts -> vertices, edge.vect -> edge.vector
-# SVG object doesn't need a 'pure_net' argument in constructor
-# remember selected objects before baking, except selected to active
-# islands with default names should be excluded while matching
-# add 'estimated number of pages' to the export UI
-# profile QuickSweepline vs. BruteSweepline with/without blist: for which nets is it faster?
-# rotate islands to minimize area -- and change that only if necessary to fill the page size
-# Sticker.vertices should be of type Vector
-
-# check conflicts in island naming and either:
-# * append a number to the conflicting names or
-# * enumerate faces uniquely within all islands of the same name (requires a check that both label and abbr. equals)
-
-
-"""
-
-Additional links:
- e-mail: adominec {at} gmail {dot} com
-
-"""
-import bpy
-import bl_operators
-import bgl
-import mathutils as M
-from re import compile as re_compile
-from itertools import chain, repeat
-from math import pi, ceil
-
-try:
- import os.path as os_path
-except ImportError:
- os_path = None
-
-try:
- from blist import blist
-except ImportError:
- blist = list
-
-default_priority_effect = {
- 'CONVEX': 0.5,
- 'CONCAVE': 1,
- 'LENGTH': -0.05
-}
-
-
-def first_letters(text):
- """Iterator over the first letter of each word"""
- for match in first_letters.pattern.finditer(text):
- yield text[match.start()]
-first_letters.pattern = re_compile("((?<!\w)\w)|\d")
-
-
-def is_upsidedown_wrong(name):
- """Tell if the string would get a different meaning if written upside down"""
- chars = set(name)
- mistakable = set("69NZMWpbqd")
- rotatable = set("80oOxXIl").union(mistakable)
- return chars.issubset(rotatable) and not chars.isdisjoint(mistakable)
-
-
-def pairs(sequence):
- """Generate consecutive pairs throughout the given sequence; at last, it gives elements last, first."""
- i = iter(sequence)
- previous = first = next(i)
- for this in i:
- yield previous, this
- previous = this
- yield this, first
-
-
-def argmax_pair(array, key):
- """Find an (unordered) pair of indices that maximize the given function"""
- l = len(array)
- mi, mj, m = None, None, None
- for i in range(l):
- for j in range(i+1, l):
- k = key(array[i], array[j])
- if not m or k > m:
- mi, mj, m = i, j, k
- return mi, mj
-
-
-def fitting_matrix(v1, v2):
- """Get a matrix that rotates v1 to the same direction as v2"""
- return (1 / v1.length_squared) * M.Matrix((
- (v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y),
- (v1.x*v2.y - v1.y*v2.x, v1.x*v2.x + v1.y*v2.y)))
-
-
-def z_up_matrix(n):
- """Get a rotation matrix that aligns given vector upwards."""
- b = n.xy.length
- l = n.length
- if b > 0:
- return M.Matrix((
- (n.x*n.z/(b*l), n.y*n.z/(b*l), -b/l),
- (-n.y/b, n.x/b, 0),
- (0, 0, 0)
- ))
- else:
- # no need for rotation
- return M.Matrix((
- (1, 0, 0),
- (0, (-1 if n.z < 0 else 1), 0),
- (0, 0, 0)
- ))
-
-
-def create_blank_image(image_name, dimensions, alpha=1):
- """Create a new image and assign white color to all its pixels"""
- image_name = image_name[:64]
- width, height = int(dimensions.x), int(dimensions.y)
- image = bpy.data.images.new(image_name, width, height, alpha=True)
- if image.users > 0:
- raise UnfoldError("There is something wrong with the material of the model. "
- "Please report this on the BlenderArtists forum. Export failed.")
- image.pixels = [1, 1, 1, alpha] * (width * height)
- image.file_format = 'PNG'
- return image
-
-
-def bake(face_indices, uvmap, image):
- import bpy
- is_cycles = (bpy.context.scene.render.engine == 'CYCLES')
- if is_cycles:
- # please excuse the following mess. Cycles baking API does not seem to allow better.
- ob = bpy.context.active_object
- me = ob.data
- mat = bpy.data.materials.new("unfolder dummy")
- mat.use_nodes = True
- img = mat.node_tree.nodes.new('ShaderNodeTexImage')
- img.image = image
- mat.node_tree.nodes.active = img
- uv = mat.node_tree.nodes.new('ShaderNodeUVMap')
- uv.uv_map = uvmap.name
- mat.node_tree.links.new(uv.outputs['UV'], img.inputs['Vector'])
- uvmap.active = True
- recall_object_slots, recall_mesh_slots = [slot.material for slot in ob.material_slots], me.materials[:]
- for i, slot in enumerate(ob.material_slots):
- slot.material = me.materials[i] = mat
- me.materials.append(mat)
- loop = me.uv_layers[me.uv_layers.active_index].data
- face_indices = set(face_indices)
- ignored_uvs = [face.loop_start + i for face in me.polygons if face.index not in face_indices for i, v in enumerate(face.vertices)]
- for vid in ignored_uvs:
- loop[vid].uv[0] *= -1
- loop[vid].uv[1] *= -1
- bake_type = bpy.context.scene.cycles.bake_type
- sta = bpy.context.scene.render.bake.use_selected_to_active
- try:
- bpy.ops.object.bake(type=bake_type, margin=0, use_selected_to_active=sta, cage_extrusion=100, use_clear=False)
- except RuntimeError as e:
- raise UnfoldError(*e.args)
- finally:
- me.materials.pop()
- for slot, recall in zip(ob.material_slots, recall_object_slots):
- slot.material = recall
- for i, recall in enumerate(recall_mesh_slots):
- me.materials[i] = recall
- bpy.data.materials.remove(mat)
- for vid in ignored_uvs:
- loop[vid].uv[0] *= -1
- loop[vid].uv[1] *= -1
- else:
- texfaces = uvmap.data
- for fid in face_indices:
- texfaces[fid].image = image
- bpy.ops.object.bake_image()
- for fid in face_indices:
- texfaces[fid].image = None
-
-
-class UnfoldError(ValueError):
- pass
-
-
-class Unfolder:
- def __init__(self, ob):
- self.ob = ob
- self.mesh = Mesh(ob.data, ob.matrix_world)
- self.mesh.check_correct()
- self.tex = None
-
- def prepare(self, cage_size=None, create_uvmap=False, mark_seams=False, priority_effect=default_priority_effect, scale=1):
- """Create the islands of the net"""
- self.mesh.generate_cuts(cage_size / scale if cage_size else None, priority_effect)
- is_landscape = cage_size and cage_size.x > cage_size.y
- self.mesh.finalize_islands(is_landscape)
- self.mesh.enumerate_islands()
- if create_uvmap:
- self.tex = self.mesh.save_uv()
- if mark_seams:
- self.mesh.mark_cuts()
-
- def copy_island_names(self, island_list):
- """Copy island label and abbreviation from the best matching island in the list"""
- orig_islands = [{face.id for face in item.faces} for item in island_list]
- matching = list()
- for i, island in enumerate(self.mesh.islands):
- islfaces = {uvface.face.index for uvface in island.faces}
- matching.extend((len(islfaces.intersection(item)), i, j) for j, item in enumerate(orig_islands))
- matching.sort(reverse=True)
- available_new = [True for island in self.mesh.islands]
- available_orig = [True for item in island_list]
- for face_count, i, j in matching:
- if available_new[i] and available_orig[j]:
- available_new[i] = available_orig[j] = False
- self.mesh.islands[i].label = island_list[j].label
- self.mesh.islands[i].abbreviation = island_list[j].abbreviation
-
- def save(self, properties):
- """Export the document"""
- # Note about scale: input is direcly in blender length
- # Mesh.scale_islands multiplies everything by a user-defined ratio
- # exporters (SVG or PDF) multiply everything by 1000 (output in millimeters)
- Exporter = SVG if properties.file_format == 'SVG' else PDF
- filepath = properties.filepath
- extension = properties.file_format.lower()
- filepath = bpy.path.ensure_ext(filepath, "." + extension)
- # page size in meters
- page_size = M.Vector((properties.output_size_x, properties.output_size_y))
- # printable area size in meters
- printable_size = page_size - 2 * properties.output_margin * M.Vector((1, 1))
- unit_scale = bpy.context.scene.unit_settings.scale_length
- ppm = properties.output_dpi * 100 / 2.54 # pixels per meter
-
- # after this call, all dimensions wi
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list