Added merge option to shrinkwrap when using projection mode (bruteforce for now)
[blender.git] / release / scripts / CreatePlane.py
1 #!BPY
2
3 """
4 Name: 'Import Plane from Image'
5 Blender: 245
6 Group: 'Add'
7 Tooltip: 'Import a plane topology from a 2d Image'
8 """
9
10 __author__ = "AndrĂ© Pinto"
11 __url__ = ["www.blender.org"]
12 __version__ = "2008-06-06"
13
14 __bpydoc__ = """\
15 This script extracts a plane from an image.
16 """
17
18 # ***** BEGIN GPL LICENSE BLOCK *****
19 #
20 # This program is free software; you can redistribute it and/or
21 # modify it under the terms of the GNU General Public License
22 # as published by the Free Software Foundation; either version 2
23 # of the License, or (at your option) any later version.
24 #
25 # This program is distributed in the hope that it will be useful,
26 # but WITHOUT ANY WARRANTY; without even the implied warranty of
27 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 # GNU General Public License for more details.
29 #
30 # You should have received a copy of the GNU General Public License
31 # along with this program; if not, write to the Free Software Foundation,
32 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33 #
34 # The Original Code is Copyright (C) Blender Foundation.
35 # All rights reserved.
36 #
37 # The Original Code is: all of this file.
38 #
39 # Contributor(s): AndrĂ© Pinto
40 #
41 # ***** END GPL LICENSE BLOCK *****
42
43 import Blender, bpy
44
45 def matrix(dima, dimb):
46         return [[0 for b in range(dimb)] for a in range(dima)]
47
48 def dotProduct(a):
49         return reduce(lambda x, y: x + y*y, a) 
50
51 def manhattanDistance(a, b):
52         return reduce(lambda x, y: x + abs(y[0]-y[1]), zip(a, b), 0)
53
54 def xrange_tuple(low, upper):
55         for i in xrange( low[0], upper[0]):
56                 for j in xrange( low[1], upper[1]):
57                         yield (i,j)
58
59
60 # For now simply decompose in a triangle fan
61 def DecomposePolygon(poly):
62         for i in xrange(2, len(poly), 1):
63                 yield [ poly[0], poly[i-1], poly[i] ]
64
65 def Expand3dCoordsFrom2d(coords):
66         for c in coords:
67                 yield ( c[0] , c[1], 0 )
68
69
70 # For now return the full image
71 def ExtractSections(image):
72         x_samples = 250
73         y_samples = 250
74
75         mdim = max( image.size )
76         dx = float(image.size[0]) / x_samples
77         dy = float(image.size[1]) / y_samples
78
79         offset = [ -0.5*i for i in image.size]
80
81         def scale(a):
82                 return (a[0] + offset[0] , a[1] + offset[1])
83         
84         sx = 0
85 #(int) (float(image.size[0]) / (x_samples))
86         sy = 0
87 #(int) (float(image.size[1]) / (y_samples))
88
89         def get( center ):
90                 best = None
91                 for pos in xrange_tuple( (max(0, center[0]-sx),max(0, center[1]-sy)) , (min(image.size[0], center[0]+sx)+1, min(image.size[1], center[1]+sy)+1 )):
92                                 if dotProduct(image.getPixelHDR(pos[0],pos[1])) <= 1:
93                                         if best == None or manhattanDistance(center, pos) < manhattanDistance(center, best):
94                                                 best = pos
95                 return best
96
97
98         pos = matrix(x_samples, y_samples)
99         sdx = dx
100         sdy = dy
101         for a in xrange(x_samples):
102                 for b in xrange(y_samples):
103                         pos[a][b] = get(((int)(a*sdx),(int)(b*sdy)))
104
105         for a in xrange(x_samples-1):
106                 for b in xrange(y_samples-1):
107                         arround = [ (a,b) , (a+1,b), (a+1,b+1), (a,b+1) ]
108
109                         valid = [ pos[c[0]][c[1]] for c in arround if pos[c[0]][c[1]] != None]
110                         if len(valid) >= 3:
111                                 yield map( scale, valid )
112                                 
113
114 def ImportPlaneFromImage(image, mesh):
115
116         new_verts = []
117         new_faces = []
118
119         vert_dict = {}
120
121         def getVertex(vert):
122                 if vert not in vert_dict:
123                         new_verts.append( (vert[0], vert[1], 0) )
124                         vert_dict[ vert ] = len( new_verts )-1
125
126                 return vert_dict[ vert ]
127
128         for poly in ExtractSections(image):
129                 offset = len(new_verts)
130
131                 poly = map( getVertex, poly )
132                 if len(poly) == 4:
133                         new_faces.append( [poly[0], poly[1], poly[2],poly[3]] )
134                 if len(poly) == 3:
135                         new_faces.append( [ poly[0], poly[1], poly[2] ] )
136
137         # perform a single extend, extend is O( N )
138         mesh.verts.extend( new_verts )
139         mesh.faces.extend( new_faces )
140
141
142
143
144 def load_image(filename):
145         print "Loading ",filename
146         #for now create a new mesh
147         mesh = bpy.data.meshes.new('Plane')
148         Blender.Scene.GetCurrent().objects.new(mesh)
149
150         image = Blender.Image.Load(filename)
151         ImportPlaneFromImage(image, mesh)
152         Blender.Redraw()
153         
154
155 Blender.Window.FileSelector(load_image, "Load Image")
156 #use the current image on the image editor? or ask the user what image to load
157 #image = Blender.Image.GetCurrent()
158 #load_image("/home/darkaj/develop/blender/shrinkwrap/road.png")
159
160