#!BPY

"""
Name: 'Pipe Joints'
Blender: 248
Group: 'AddMesh'
"""
__author__ = ["Buerbaum Martin"]
__version__ = '0.4.2'
__url__ = ["http://wiki.blender.org/index.php/Extensions:Py/Scripts/Manual/Add/Pipe_Joint"]
__bpydoc__ = """

Usage:

Pipe Joints

This script lets the user create various types of pipe joints.

It was written for Blender 2.48, but should work a few revisions back.
v0.4.2 - Added pipe length to the GUI.
v0.4.1 - Removed the unfinished menu entries for now.
v0.4 - Tried to clean up the face creation in addWyeJoint
v0.3 - Code for wye (Y) shape (straight pipe with "branch" for now)
v0.2 - Restructured to allow different types of pipe (joints).
v0.1 - Initial revision.
"""

# --------------------------------------------------------------------------
# ***** 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, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

# Importing modules
import BPyAddMesh
import Blender
import math
from math import *

# --------------------------------------------------------------------------
"""
addElbow
	Create the vertices and polygons for a simple elbow pipe (bent pipe).
Parameters
	radius ... Radius of the pipe.
	div ... Number of vertices per circle/cross section.
	angle ... (in radiant) Bending angle. Measured from the center line of the starting pipe.
	startLength ... Length of start pipe (at its center)
	endLength ... Length of end (bent) pipe (at its center)
"""
def addElbow(radius, div, angle, startLength=1.0, endLength=1.0):
	verts = []
	faces = []

	# Create start circle
	for vertIdx in range(div):
		curVertAngle = vertIdx * (2.0 * pi / div)
		locX = sin(curVertAngle)
		locY = cos(curVertAngle)
		locZ = -startLength
		verts.append([locX * radius, locY * radius, locZ])

	# Create deformed joint circle
	baseJointLocZ = 0 # We have out middle point at the zero location - could change in other cases.
	for vertIdx in range(div):
		curVertAngle = vertIdx * (2.0 * pi / div)
		locX = sin(curVertAngle)
		locY = cos(curVertAngle)
		locZ = baseJointLocZ + locX * tan(angle / 2.0)
		verts.append([locX * radius, locY * radius, locZ])

	# Create end circle
	baseEndLocX = -endLength * sin(angle)
	baseEndLocZ = endLength * cos(angle)
	for vertIdx in range(div):
		curVertAngle = vertIdx * (2.0 * pi / div)
		# create circle
		locX = sin(curVertAngle) * radius
		locY = cos(curVertAngle) * radius
		locZ = 0.0

		# rotate circle
		locZ = locX * cos(pi/2.0 - angle)
		locX = locX * sin(pi/2.0 - angle)

		#add translated circle
		verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ])

	# Create faces
	vertIdxStart1 = div-1
	vertIdxStart2 = 0
	vertIdxJoint1 = vertIdxStart1 + div
	vertIdxJoint2 = vertIdxStart2 + div
	vertIdxEnd1 = vertIdxJoint1 + div
	vertIdxEnd2 = vertIdxJoint2 + div
	faces.append([vertIdxStart2, vertIdxStart1, vertIdxJoint1, vertIdxJoint2])
	faces.append([vertIdxJoint2, vertIdxJoint1, vertIdxEnd1, vertIdxEnd2])
	for vertIdx in range(div-1):
		vertIdxStart1 = vertIdx
		vertIdxStart2 = vertIdx + 1
		vertIdxJoint1 = vertIdxStart1 + div
		vertIdxJoint2 = vertIdxStart2 + div
		vertIdxEnd1 = vertIdxJoint1 + div
		vertIdxEnd2 = vertIdxJoint2 + div
		faces.append([vertIdxStart2, vertIdxStart1, vertIdxJoint1, vertIdxJoint2])
		faces.append([vertIdxJoint2, vertIdxJoint1, vertIdxEnd1, vertIdxEnd2])

	return verts, faces

# --------------------------------------------------------------------------
"""
addWyeJoint
	Create the vertices and polygons for a simple wye (Y) pipe joint.
	This one creates a straight pipe that has a "branch" on one side.

Parameters
	radius ... Radius of the pipe.
	div ... Number of vertices per circle/cross section.
	angle ... (in radiant) The angle of the branching pipe. Measured from the center line of the main pipe.
	startLength ... Length of starting pipe to branch point.
	branchLength ... Length of branching pipe.
	endLength ... Length of branch point to end of (main) pipe.
"""
# @todo We need to make sure that the number of vertices (div) is so that we can split the pipe exactly in 2.
def addWyeJoint(radius, div, angle, startLength=1.0, endLength=1.0, branchLength=1.0):
	verts = []
	faces = []

	# Create start circle (main pipe)
	for vertIdx in range(div):
		curVertAngle = vertIdx * (2.0 * pi / div)
		locX = sin(curVertAngle)
		locY = cos(curVertAngle)
		locZ = -startLength
		verts.append([locX * radius, locY * radius, locZ])

	offsetJoint = len(verts)
	# Create deformed joint circle
	baseJointLocZ = 0 # We have out middle point at the zero location - could change in other cases.
	for vertIdx in range(div):
		curVertAngle = vertIdx * (2.0 * pi / div)
		locX = sin(curVertAngle)
		locY = cos(curVertAngle)
		if (vertIdx < div / 2):
			# Straight side of main pipe.
			locZ = baseJointLocZ
		else:
			# Branching side
			locZ = baseJointLocZ + locX * tan(angle / 2.0)
		verts.append([locX * radius, locY * radius, locZ])

	offsetJoint2 = len(verts)
	# Create 2. deformed joint (half-)circle
	baseJointLocZ = 0 # We have out middle point at the zero location - could change in other cases.
	for vertIdx in range(div):
		if (vertIdx > div/2):
			curVertAngle = vertIdx * (2.0 * pi / div)
			locX = sin(curVertAngle)
			locY = -cos(curVertAngle)
			locZ = -(baseJointLocZ + locX * tan((pi - angle) / 2.0))
			verts.append([locX * radius, locY * radius, locZ])

	offsetBranch = len(verts)
	# Create end circle (branching pipe)
	baseEndLocX = -branchLength * sin(angle)
	baseEndLocZ = branchLength * cos(angle)
	for vertIdx in range(div):
		curVertAngle = vertIdx * (2.0 * pi / div)
		# create circle
		locX = sin(curVertAngle) * radius
		locY = cos(curVertAngle) * radius
		locZ = 0.0

		# rotate circle
		locZ = locX * cos(pi/2.0 - angle)
		locX = locX * sin(pi/2.0 - angle)

		#add translated circle
		verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ])

	offsetEnd = len(verts)
	# Create end circle (main pipe)
	for vertIdx in range(div):
		curVertAngle = vertIdx * (2.0 * pi / div)
		locX = sin(curVertAngle)
		locY = cos(curVertAngle)
		locZ = endLength
		verts.append([locX * radius, locY * radius, locZ])

	# Create faces
	# Start of main pipe towards the joint
	vertIdxStart1 = div-1
	vertIdxStart2 = 0
	vertIdxEnd1 = vertIdxStart1 + div
	vertIdxEnd2 = vertIdxStart2 + div
	faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
	for vertIdx in range(div-1):
		vertIdxStart1 = vertIdx
		vertIdxStart2 = (vertIdx + 1)
		vertIdxEnd1 = offsetJoint + vertIdx
		vertIdxEnd2 = offsetJoint + (vertIdx + 1)
		faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])

	# Joint towards the branch
	vertIdxStart1 = offsetJoint + div-1
	vertIdxStart2 = offsetJoint
	vertIdxEnd1 = offsetBranch + div-1
	vertIdxEnd2 = offsetBranch
	faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
	vertIdxStart1 = offsetJoint2 + div/2 - 2
	vertIdxStart2 = offsetJoint + div/2
	vertIdxEnd1 = offsetBranch + div/2 - 1
	vertIdxEnd2 = offsetBranch + div/2
	faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
	vertIdxStart1 = offsetJoint
	vertIdxStart2 = offsetJoint2
	vertIdxEnd1 = offsetBranch
	vertIdxEnd2 = offsetBranch + 1
	faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
	for vertIdx in range(div-1):
		if (vertIdx >= div/2):
			vertIdxStart1 = offsetJoint + vertIdx
			vertIdxStart2 = offsetJoint + (vertIdx + 1)
			vertIdxEnd1 = offsetBranch + vertIdx
			vertIdxEnd2 = offsetBranch + (vertIdx + 1)
			faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
		elif (vertIdx > 0) and vertIdx < (div/2 - 1):
			vertIdxStart1 = offsetJoint2 + vertIdx -1
			vertIdxStart2 = offsetJoint2 + vertIdx
			vertIdxEnd1 = offsetBranch + vertIdx
			vertIdxEnd2 = offsetBranch + (vertIdx + 1)
			faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])

	# Joint towards the end of the main pipe
	vertIdxStart1 = offsetJoint + div/2
	vertIdxStart2 = offsetJoint2 + div/2 - 2
	vertIdxEnd1 = offsetEnd + div/2
	vertIdxEnd2 = offsetEnd + div/2 + 1
	faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
	vertIdxStart1 = offsetJoint2
	vertIdxStart2 = offsetJoint
	vertIdxEnd1 = offsetEnd + div-1
	vertIdxEnd2 = offsetEnd
	faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
	for vertIdx in range(div-1):
		if (vertIdx >= div/2):
			# We skip the frist face.
			if (vertIdx > div/2):
				vertIdxStart1 = offsetJoint2 + (div - 1) - vertIdx
				vertIdxStart2 = offsetJoint2 + (div - 1) - (vertIdx + 1)
				vertIdxEnd1 = offsetEnd + vertIdx
				vertIdxEnd2 = offsetEnd + (vertIdx + 1)
				faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])
		else:
			# Straight part (main pipe)
			vertIdxStart1 = offsetJoint + vertIdx
			vertIdxStart2 = offsetJoint + (vertIdx + 1)
			vertIdxEnd1 = offsetEnd + vertIdx
			vertIdxEnd2 = offsetEnd + (vertIdx + 1)
			faces.append([vertIdxStart2, vertIdxStart1, vertIdxEnd1, vertIdxEnd2])

	return verts, faces

# --------------------------------------------------------------------------
def main():
	pipeRadiusInput	= Blender.Draw.Create(1.0)
	pipeDivInput	= Blender.Draw.Create(32)
	pipeAngleInput	= Blender.Draw.Create(45.0)

	name = "Choose the type of pipe (joint)%t|Elbow%x1|Y (Wye) 1-sided%x2"
	#name = "Choose the type of pipe (joint)%t|Elbow%x1|Y (Wye) 1-sided%x2|Y (Wye) symetric TODO%x3|T (Tee) TODO%x4|+ (Cross) TODO%x5"
	result = Blender.Draw.PupMenu(name)

	if result <= 0:
		return

	if result==1:
		blockElbow = []
		pipeLengthMain	= Blender.Draw.Create(1.0)
		pipeLengthArm	= Blender.Draw.Create(1.0)
		blockElbow.append(("Radius:", pipeRadiusInput, 0.01, 100, "The radius of the pipe."))
		blockElbow.append(("Vertices:", pipeDivInput, 4, 100, "Number of vertices (divisions)."))
		blockElbow.append(("Angle:", pipeAngleInput, -179.9, 179.9, "The angle of the second arm of the pipe (from the main axis)."))
		blockElbow.append("Lengths")
		blockElbow.append(("Main pipe:", pipeLengthMain, 0.01, 100, "Length of the main pipe (the straight one)."))
		blockElbow.append(("Arm:", pipeLengthArm, 0.01, 100, "Length of the arm pipe (the bent one)."))

		if not Blender.Draw.PupBlock("Create Elbow Pipe", blockElbow):
			return

		# Create the mesh for this type
		verts, faces = addElbow(pipeRadiusInput.val, pipeDivInput.val, pipeAngleInput.val * pi / 180.0, pipeLengthMain.val, pipeLengthArm.val)

		# Add the generated mesh to the scene.
		BPyAddMesh.add_mesh_simple('Elbow Pipe', verts, [], faces)

	elif result==2:
		blockYPipe = []
		pipeLengthMainStart	= Blender.Draw.Create(1.0)
		pipeLengthMainEnd	= Blender.Draw.Create(3.0)
		pipeLengthArm		= Blender.Draw.Create(3.0)
		blockYPipe.append(("Radius:", pipeRadiusInput, 0.01, 100, "The radius of the pipe."))
		blockYPipe.append(("Vertices:", pipeDivInput, 4, 100, "Number of vertices (divisions)."))
		blockYPipe.append(("Angle:", pipeAngleInput, -179.9, 179.9, "The angle of the 2 arms branching of to each side (from the main axis)."))
		blockYPipe.append("Lengths")
		blockYPipe.append(("Main pipe start:", pipeLengthMainStart, 0.01, 100, "Length of the beginning of the main pipe (the straight one)."))
		blockYPipe.append(("Main pipe end:", pipeLengthMainEnd, 0.01, 100, "Length of the end of the main pipe (the straight one)."))
		blockYPipe.append(("Arm:", pipeLengthArm, 0.01, 100, "Length of the arm pipe (the bent one)."))

		if not Blender.Draw.PupBlock("Create Wye (Y) Joint Pipe", blockYPipe):
			return

		# Create the mesh for this type
		verts, faces = addWyeJoint(pipeRadiusInput.val, pipeDivInput.val, pipeAngleInput.val * pi / 180.0, pipeLengthMainStart.val, pipeLengthMainEnd.val, pipeLengthArm.val)

		# Add the generated mesh to the scene.
		BPyAddMesh.add_mesh_simple('Wye Joint', verts, [], faces)
		"""
	elif result==3:
		Blender.Draw.PupMenu("Not implemented yet.")
	elif result==4:
		Blender.Draw.PupMenu("Not implemented yet.")
	elif result==5:
		Blender.Draw.PupMenu("Not implemented yet.")
		"""
	else:
		msg = "No option '" + str(result) + "' available. Looks like a bug."
		Blender.Draw.PupMenu(msg)

# --------------------------------------------------------------------------
main()
