#!/usr/bin/env python2.2

from __future__ import division

import math
import random

class triple:
    def __init__(self, a, b, c ):
        self.data = [a, b, c]
        
    def __str__(self):
        return "%.02f %.02f %.02f" % (self.data[0], self.data[1], self.data[2])

    def __getitem__( self, i ):
        return self.data[i]

    def __setitem__( self, i, j ):
        self.data[i] = j

    def toGround( self ):
       return triple(  self.data[0],  self.data[1], 0 )
#        

class transformable:
  def angle_to_angle2PI( self, angle ):
    return 2 * math.pi * angle / 360

  def angle2PI_to_angle( self, angle2PI ):
    return 360 * (angle2PI / (2*math.pi))  
      
  def _rotate( self, coords, angle ):
    beta = self.angle_to_angle2PI( angle )
    x = coords[0]
    y = coords[1]
    z = coords[2]
    xx = x * math.cos( beta ) - y * math.sin( beta )
    yy = x * math.sin( beta ) + y * math.cos( beta )
    return triple(xx, yy, z)

  def _transformXY( self, coords, delta ):
    return triple( coords[0] + delta[0], coords[1] + delta[1], coords[2] ) # only change x and y

  def subVec( self, vec1, vec2 ):
      return triple( vec2[0] - vec1[0], vec2[1] - vec1[1], vec2[2] - vec1[2] )
#

class boxClass1( transformable ):
     def __init__( self ):
         self.coords   = triple( 0, 0, 0 )
         self.size     = triple( 0.5, 0.5, 1 )
         self.rotation = 0.00

     def render( self ):
         print """
         box
           position %s
           size %s
           rotation %.02f
         end
         """ % (self.coords, self.size, self.rotation)         
# boxClass1
         

class bridgeClass( transformable ):
     def __init__(self, coords1, coords2, width=10, num_stuetzen=-1 ):
         self.PE1   = coords1
         self.PE2   = coords2
         self.num_stuetzen = num_stuetzen
         self.elements = {}
         self.width     = width   # width of path
         self.thickness      = 0.2
	 self.blockthickness = 1.0
	 
	 self.abstand_stuetzen = 0

         dx = coords2[0] - coords1[0]
         dy = coords2[1] - coords1[1]
         length  = math.sqrt( (dx * dx) + (dy * dy) )  # length of bridge
         self.length = length # debug

	 if self.num_stuetzen > 0:
	   self.abstand_stuetzen = length / (self.num_stuetzen + 1)
	 if self.num_stuetzen == -1:
	   self.num_stuetzen = length // 20
	   self.abstand_stuetzen = length / (self.num_stuetzen + 1)
	   
         
	 self.angle2PI = math.acos( dx / length )
         self.angle    = self.angle2PI_to_angle( self.angle2PI )
 
                                   
         p1x = coords1[0] + (dx / 2)
         p1y = coords1[1] + (dy / 2)
         p1z = coords1[2]

         # P1 = center point of bridge:
	 self.P1 = triple( p1x, p1y, p1z )  # center point of bridge
         
         # the elements of the bridge:
	 self.elements["path"] = boxClass1()
         self.elements["path"].coords = triple( 0, 0, self.P1[2] - self.thickness )
         self.elements["path"].size = triple( length / 2, width / 2, self.thickness )
         
         #
         # .______________________.
         # |  [1]     [ ]    [ ]  |
         # |                      | path
         # |__[2]_____[_]____[_]__|
         #
         
         for num_stuetze in range( self.num_stuetzen ):
           name1 = "stuetze_%d_a" % (num_stuetze, )
           name2 = "stuetze_%d_b" % (num_stuetze, )
           posx  = (length / -2.0) + ((num_stuetze + 1) * self.abstand_stuetzen)
           bt2    = self.blockthickness / 2
           self.elements[ name1 ] = boxClass1()
           self.elements[ name1 ].coords = triple( posx, self.width / 4, 0 )
           self.elements[ name1 ].size = triple( bt2, bt2, self.P1[2] - self.thickness )
           self.elements[ name2 ] = boxClass1()
           self.elements[ name2 ].coords = triple( posx, self.width / -4, 0 )
           self.elements[ name2 ].size = triple( bt2, bt2, self.P1[2] - self.thickness )


	 # rotate and transform the elements:
         for name in self.elements.keys():
	   
	   # rotation setzen:
           self.elements[ name ].rotation = self.angle
       
           new_coords = self._rotate( self.elements[ name ].coords, self.angle )
	   self.elements[ name ].coords = new_coords
	
           # transformieren:
           new_coords = self._transformXY( self.elements[ name ].coords, self.P1 )
  	   # new_coords[2] = self.P1[2] - self.thickness  #... 
  	   self.elements[ name ].coords = new_coords


     def render( self ):
         print "# bridgeClass"
         print "# PE1 =", self.PE1
         print "# PE2 =", self.PE2
         print "# P1  =", self.P1

         keys = self.elements.keys()
         keys.sort()
         for name in keys:
	     print "#", name,":"
             self.elements[ name ].render()        
# bridgeClass
class treeClass:
  def __init__( self, x,y, height ):
    self.x = x
    self.y = y
    self.height = height
    self.rot = 360 * random.random()
    self.breite_unten   = 1 + 10 * random.random()
    self.anzahl_aeste   = random.randint(3, 10) # inclusive
    self.delta_asthoehe = (self.height - (self.height // 2)) / self.anzahl_aeste

  def getAstBreite( self, ast_nummer ):
    return (self.anzahl_aeste - ast_nummer ) * (self.breite_unten / self.anzahl_aeste)
  
  def render( self ):
    stamm_hoehe = 5 + (10 * random.random())
    if stamm_hoehe > self.height:
      stamm_hoehe = self.height // 2
    print """
    pyramid
      position %.02f %.02f 0
      size 1 1 %.02f
      rotation %.02f
    end""" % (self.x, self.y, self.height, self.rot)

    for i in range( self.anzahl_aeste ):
      ast_breite = self.getAstBreite( i )
      print """
      pyramid
        position %.02f %.02f %.02f
        size %.02f %.02f %.02f
        rotation %.02f
      end""" % (self.x, self.y, stamm_hoehe+(i*self.delta_asthoehe), ast_breite, ast_breite, self.delta_asthoehe,  360 * random.random() )

# ------------------------------------------



if __name__ == "__main__":

  # some trees:
  for i in range(130):
    x = 800 * random.random() - 400
    y = 800 * random.random() - 400
    height = 80 * random.random()
    tree = treeClass( x, y, height )
    tree.render()

  # some random bridges:
  for i in range(6):
    h = 5 + (10 * random.random())
    p1 = triple( random.randint(-150, 150), random.randint(-150, 150),  h )
    p2 = triple( random.randint(-350, 350), random.randint(-350, 350), h )
    bridge = bridgeClass( p1, p2 )
    bridge.render()

  # now I only need a women and a sun... :-)
   
