#!BPY

"""
Name: 'YAllViews r12'
Blender: 235
Group: 'Export'
Tooltip: 'Export front/side/top/user views to SVG file.'
"""
__bpydoc__ ="""\
                                                                 <br>
 Export front/side/top/user views to SVG file.                   <br>
                                                                 <br>
 (C) 2004 Yves Aubry (yves.aubry)(@)(netibu)(com)                <br>
 FOR TESTING ONLY, not for redistribution                        <br>
 Lastest version available for from:                             <br>
 http://www.netibu.com/blender.php                               <br>
                                                                 <br>
 USAGE:                                                          <br>
   -By Menu-                                                     <br>
     * Put this file in ~/.blender/scripts/                      <br>
     * Select one mesh, then choose "YqllViews" from the         <br>
        scripts menu.                                            <br>
   -By Running the script-                                       <br>
     * Load this file into blender's internal text editor        <br>
     * Select one mesh, then press Alt+P in the test editor      <br>
                                                                 <br>
 OPERATIONS:                                                     <br>
   On execution of the script, a file name is to be choosen      <br>
   After the script executes, the svg file is available          <br>
                                                                 <br>                                                                 <br>
 TO DO:                                                          <br>
  * choose the page format                                       <br>
  * add a grid                                                   <br>
  * export to postscript                                         <br>

-----------------------------------------------------------------
                                                                 
  Date:        Updates:                                          <br>
  23-Dec-2005  Initial Revision - working & ready to go          <br>
                                                                 
"""

__author__ = "Yves Aubry"
__version__ = "r1 23-Dec-05"
__email__ = ('Author EMail, yves.aubry:netibu*com')
__url__ = ('?','Script Web Page, http://www.netibu.com/blender.php')

import Blender
from Blender import Object
from Blender import Draw
from Blender import NMesh

SVGFile=0

# This function projects point I with mO then mV
#
# mO : object matrix
# mV : view matrix
# I  : point to project
#
# returns a 2x1 matrix
def Projection(mO,mV,Ix,Iy,Iz):
	Nx = mO[0][0] * Ix + mO[1][0] * Iy + mO[2][0] * Iz
	Ny = mO[0][1] * Ix + mO[1][1] * Iy + mO[2][1] * Iz
	Nz = mO[0][2] * Ix + mO[1][2] * Iy + mO[2][2] * Iz

	Mx = mV[0][0] * Nx + mV[1][0] * Ny + mV[2][0] * Nz
	My = mV[0][1] * Nx + mV[1][1] * Ny + mV[2][1] * Nz
	Mz = mV[0][2] * Nx + mV[1][2] * Ny + mV[2][2] * Nz

	return [Mx,-My]

# This function put the ObMesh object on the SVG page
#
# ViewMatrix    : from which direction the Mesh is viewed
# PagePosition  : position of the SVG object on the page
# Scale         : To be sure that the object is inside the page
#		0 : scale, 1 : translationX, 2 : translationY
# ObMesh        : the object itself
#
def UserView(ViewMatrix,PagePosition,Scale,ObMesh):
	global SVGFile,minX,maxX,minY,maxY
	# passage par tous les edges du mesh
	m = NMesh.GetRawFromObject(ObMesh.getName())

	for v in m.faces:
		for i in range(len(v)):
			xy1 = Projection(ObMesh.getMatrix(),ViewMatrix,v[i][0],v[i][1],v[i][2])
			xy2 = Projection(ObMesh.getMatrix(),ViewMatrix,v[(i+1)%len(v)][0],v[(i+1)%len(v)][1],v[(i+1)%len(v)][2])
			if (Scale == 0):
				if(xy1[0] < minX):
					minX = xy1[0]
				if(xy2[0] < minX):
					minX = xy2[0]
				if(xy1[0] > maxX):
					maxX = xy1[0]
				if(xy1[0] > maxX):
					maxX = xy2[0]

				if(xy1[1] < minY):
					minY = xy1[1]
				if(xy2[1] < minY):
					minY = xy2[1]
				if(xy1[1] > maxY):
					maxY = xy1[1]
				if(xy1[1] > maxY):
					maxY = xy2[1]
			else:
				# in both point are nearly at the same place, it makes silly things in inkscape (at least)
				# then the line is skipped
				if (abs(xy1[0]*Scale[0]+Scale[1]-xy2[0]*Scale[0]-Scale[1]) > 0.01 or abs(xy1[1]*Scale[0]+Scale[2]-xy2[1]*Scale[0]-Scale[2]) > 0.01):
					SVGFile.write(str('\t<line x1="%7.5f" y1="%7.5f" x2="%7.5f" y2="%7.5f" />\n' % (xy1[0]*Scale[0]+Scale[1],xy1[1]*Scale[0]+Scale[2],xy2[0]*Scale[0]+Scale[1],xy2[1]*Scale[0]+Scale[2])))

# This function open the SVG file, call the UserView for each view
# the close the file
#
def GetFileName(filename):
	global SVGFile,minX,maxX,minY,maxY
	SVGFile = open(filename,'w')

	# Entete SVG
	SVGFile.write('<svg width="2970px" height="2100px">\n')

	objsel = Object.GetSelected()

	# retriving the bigest taille
	mult = 1e9
	
	# first step to get min and max of any view (scale will be from the bigest)
	for ob in objsel:
		maxX = -1e9
		minX = 1e9
		maxY = -1e9
		minY = 1e9
		UserView([[1,0,0],[0,0,-1],[0,1,0]],[-1,-1],0,ob) # front
		CenterXfront = (maxX+minX) / 2
		CenterYfront = (maxY+minY) / 2
		if (mult > 1050 / (maxY-minY)):
			mult = 1050 / (maxY-minY)
		if (mult > 1485 / (maxX-minX)):
			mult = 1485 / (maxX-minX)

		maxX = -1e9
		minX = 1e9
		maxY = -1e9
		minY = 1e9
		UserView([[0,0,1],[1,0,0],[0,1,0]],[1,1],0,ob) # side
		CenterXside = (maxX+minX) / 2
		CenterYside = (maxY+minY) / 2
		if (mult > 1050 / (maxY-minY)):
			mult = 1050 / (maxY-minY)
		if (mult > 1485 / (maxX-minX)):
			mult = 1485 / (maxX-minX)

		maxX = -1e9
		minX = 1e9
		maxY = -1e9
		minY = 1e9
		UserView([[1,0,0],[0,1,0],[0,0,1]],[-1,1],0,ob) # top
		CenterXtop = (maxX+minX) / 2
		CenterYtop = (maxY+minY) / 2
		if (mult > 1050 / (maxY-minY)):
			mult = 1050 / (maxY-minY)
		if (mult > 1485 / (maxX-minX)):
			mult = 1485 / (maxX-minX)

		maxX = -1e9
		minX = 1e9
		maxY = -1e9
		minY = 1e9
		UserView(Blender.Window.GetViewMatrix(),[1,-1],0,ob) # current view
		CenterXuser = (maxX+minX) / 2
		CenterYuser = (maxY+minY) / 2
		if (mult > 1050 / (maxY-minY)):
			mult = 1050 / (maxY-minY)
		if (mult > 1485 / (maxX-minX)):
			mult = 1485 / (maxX-minX)

	# not to touch the side of the boxes
	mult = mult*0.95
		
	# add a grid in gray
		# Front
	x = round(CenterXfront)
	while ((x-CenterXfront) * mult > -1485/2):
		x = x - 1
	x = x + 1
	while ((x-CenterXfront) * mult < 1485/2):
		SVGFile.write(str('<g fill="none" stroke="red" stroke-width="1"><line x1="%7.5f" y1="1100" x2="%7.5f" y2="2050" /></g>\n' % ((x-CenterXfront) * mult+742.5,(x-CenterXfront) * mult+742.5)))
		x = x + 1
	y = round(CenterYfront)
	while ((y-CenterYfront) * mult > -1050/2):
		y = y - 1
	y = y + 1
	while ((y-CenterYfront) * mult < 1050/2):
		SVGFile.write(str('<g fill="none" stroke="red"><line x1="50" y1="%7.5f" x2="1435" y2="%7.5f" /></g>\n' % ((y-CenterYfront) * mult+1575,(y-CenterYfront) * mult+1575)))
		y = y + 1
		
		# Top
	x = round(CenterXtop)
	while ((x-CenterXtop) * mult > -1485/2):
		x = x - 1
	x = x + 1
	while ((x-CenterXtop) * mult < 1485/2):
		SVGFile.write(str('<g fill="none" stroke="red"><line x1="%7.5f" y1="50" x2="%7.5f" y2="1000" /></g>\n' % ((x-CenterXtop) * mult+742.5,(x-CenterXtop) * mult+742.5)))
		x = x + 1
	y = round(CenterYtop)
	while ((y-CenterYtop) * mult > -1050/2):
		y = y - 1
	y = y + 1
	while ((y-CenterYtop) * mult < 1050/2):
		SVGFile.write(str('<g fill="none" stroke="red"><line x1="50" y1="%7.5f" x2="1435" y2="%7.5f" /></g>\n' % ((y-CenterYtop) * mult+525,(y-CenterYtop) * mult+525)))
		y = y + 1
		
		# Side
	x = round(CenterXside)
	while ((x-CenterXside) * mult > -1485/2):
		x = x - 1
	x = x + 1
	while ((x-CenterXside) * mult < 1485/2):
		SVGFile.write(str('<g fill="none" stroke="red"><line x1="%7.5f" y1="50" x2="%7.5f" y2="1000" /></g>\n' % ((x-CenterXside) * mult+2227.5,(x-CenterXside) * mult+2227.5)))
		x = x + 1
	y = round(CenterYside)
	while ((y-CenterYside) * mult > -1050/2):
		y = y - 1
	y = y + 1
	while ((y-CenterYside) * mult < 1050/2):
		SVGFile.write(str('<g fill="none" stroke="red"><line x1="1535" y1="%7.5f" x2="2920" y2="%7.5f" /></g>\n' % ((y-CenterYside) * mult+525,(y-CenterYside) * mult+525)))
		y = y + 1

	# second step is to put in SVG
	SVGFile.write(str('<g fill="none" stroke="black" stroke-width="2">\n'))
	for ob in objsel:
		UserView([[1,0,0],[0,0,-1],[0,1,0]],[-1,-1],[mult,-CenterXfront*mult+742.5,-CenterYfront*mult+1575],ob) # front
		UserView([[0,0,1],[1,0,0],[0,1,0]],[1,1],[mult,-CenterXside*mult+2227.5,-CenterYside*mult+525],ob) # side
		UserView([[1,0,0],[0,1,0],[0,0,1]],[-1,1],[mult,-CenterXtop*mult+742.5,-CenterYtop*mult+525],ob) # top
		UserView(Blender.Window.GetViewMatrix(),[1,-1],[mult,-CenterXuser*mult+2227.5,-CenterYuser*mult+1575],ob) # current view
	SVGFile.write(str('</g>\n'))

	# Fin SVG
	SVGFile.write('<g fill="none" stroke="black"><rect x="0" y="0" width="2970" height="2100" /></g>\n')
	SVGFile.write('<g fill="none" stroke="black"><line x1="0" y1="1050" x2="2970" y2="1050" /></g>\n')
	SVGFile.write('<g fill="none" stroke="black"><line x1="1485" y1="0" x2="1485" y2="2100" /></g>\n')
	SVGFile.write('<g><text x="0" y="30" font-size="30" font-family="times">TOP</text></g>\n')
	SVGFile.write('<g><text x="1485" y="30" font-size="30" font-family="times">SIDE</text></g>\n')
	SVGFile.write('<g><text x="0" y="1080" font-size="30" font-family="times">FRONT</text></g>\n')
	SVGFile.write('<g><text x="1485" y="1080" font-size="30" font-family="times">USER</text></g>\n')
	SVGFile.write("</svg>")
	SVGFile.close()

def DoSVG():
	objsel = Object.GetSelected()
	meshes = 0
	others = 0
	for ob in objsel :
		if ob.getType() == 'Mesh' :
			meshes += 1
		else:
			others += 1
	if others != 0 :
		Draw.PupMenu("ERROR : Only meshes should be selected")
		return
	if meshes != 1 :
		Draw.PupMenu("ERROR : only one mesh should be selected")
		return
	Blender.Window.FileSelector(GetFileName,"SVG filename")

DoSVG()
