You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					
					
						
							422 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
	
	
							422 lines
						
					
					
						
							18 KiB
						
					
					
				| library Vector
 | |
| 
 | |
| //*****************************************************************
 | |
| //*  VECTOR LIBRARY
 | |
| //*
 | |
| //*  written by: Anitarf
 | |
| //*
 | |
| //*  The library contains a struct named vector, which represents a
 | |
| //*  point in 3D space. As such, it has three real members, one for
 | |
| //*  each coordinate: x, y, z. It also has the following methods:
 | |
| //*
 | |
| //*        static method create takes real x, real y, real z returns vector
 | |
| //*  Creates a new vector with the given coordinates.
 | |
| //*
 | |
| //*        method getLength takes nothing returns real
 | |
| //*  Returns the length of the vector it is called on.
 | |
| //*
 | |
| //*        static method sum takes vector augend, vector addend returns vector
 | |
| //*  Returns the sum of two vectors as a new vector.
 | |
| //*
 | |
| //*        method add takes vector addend returns nothing
 | |
| //*  Similar to sum, except that it doesn't create a new vector for the result,
 | |
| //*  but changes the vector it is called on by adding the "added" to it.
 | |
| //*
 | |
| //*        static method difference takes vector minuend, vector subtrahend returns vector
 | |
| //*  Returns the difference between two vectors as a new vector.
 | |
| //*
 | |
| //*        method subtract takes vector subtrahend returns nothing
 | |
| //*  Similar to difference, except that it doesn't create a new vector for the result,
 | |
| //*  but changes the vector it is called on by subtracting the "subtrahend" from it.
 | |
| //*
 | |
| //*        method scale takes real factor returns nothing
 | |
| //*  Scales the vector it is called on by the given factor.
 | |
| //*
 | |
| //*        method setLength takes real length returns nothing
 | |
| //*  Sets the length of the vector it is called on to the given value, maintaining it's orientation.
 | |
| //*
 | |
| //*        static method dotProduct takes vector a, vector b returns real
 | |
| //*  Calculates the dot product (also called scalar product) of two vectors.
 | |
| //*
 | |
| //*        static method crossProduct takes vector a, vector b returns vector
 | |
| //*  Calculates the cross product (also called vector product) of two vectors
 | |
| //*  and returns it as a new vector.
 | |
| //*
 | |
| //*        static method tripleProductScalar takes vector a, vector b, vector c returns real
 | |
| //*  Calculates the triple scalar product of three vectors.
 | |
| //*
 | |
| //*        static method tripleProductVector takes vector a, vector b, vector c returns vector
 | |
| //*  Calculates the triple vector product of three vectors and returns it as a new vector.
 | |
| //*
 | |
| //*
 | |
| //*        static method projectionVector takes vector projected, vector direction returns vector
 | |
| //*  Calculates the projection of the vector "projected" onto the vector "direction"
 | |
| //*  and returns it as a new vector.
 | |
| //*  Returns null if the vector direction has a length of 0.
 | |
| //*
 | |
| //*        method projectVector takes vector direction returns nothing
 | |
| //*  Projects the vector it is called on onto the vector "direction".
 | |
| //*  Does nothing if the vector "direction" has a length of 0.
 | |
| //*
 | |
| //*        static method projectionPlane takes vector projected, vector normal returns vector
 | |
| //*  Calculates the projection of the vector projected onto a plane defined by
 | |
| //*  it's normal vector and returns it as a new vector.
 | |
| //*  Returns null if the vector "normal" has a length of 0.
 | |
| //*
 | |
| //*        method projectPlane takes vector normal returns nothing
 | |
| //*  Projects the vector it is called on onto a plane defined by it's normal vector.
 | |
| //*  Does nothing if the vector "normal" has a length of 0.
 | |
| //*
 | |
| //*        static method getAngle takes vector a, vector b returns real
 | |
| //*  Returns the angle between two vectors, in radians, returns a value between 0 and pi.
 | |
| //*  Returns 0.0 if any of the vectors are 0 units long.
 | |
| //*
 | |
| //*        method rotate takes vector axis, real angle returns nothing
 | |
| //*  Rotates the vector it is called on around the axis defined by the vector "axis"
 | |
| //*  by the given angle, which should be input in radians.
 | |
| //*  Does nothing if axis is 0 units long.
 | |
| //*
 | |
| //*
 | |
| //*        static method createTerrainPoint takes real x, real y returns vector
 | |
| //*  Creates a vector to the given terrain coordinate, taking it's z height into account.
 | |
| //*
 | |
| //*        method getTerrainPoint takes real x, real y returns nothing
 | |
| //*  Sets the vector it is called on to the given terrain coordinate, taking it's z height into account.
 | |
| //*
 | |
| //*        static method createTerrainNormal takes real x, real y, real sampleRadius returns vector
 | |
| //*  Creates the normal vector of the terrain at given coordinates. "sampleRadius" defines
 | |
| //*  how far apart the reference points will be, if they are further apart, the result will
 | |
| //*  be an impression of smoother terrain; normaly the value should be between 0 and 128.
 | |
| //*
 | |
| //*        method getTerrainNormal takes real x, real y, real sampleRadius returns nothing
 | |
| //*  Sets the vector it is called on to the normal of the terrain at given coordinates.
 | |
| //*
 | |
| //*
 | |
| //*        method isInCylinder takes vector cylinderOrigin, vector cylinderHeight, real cylinderRadius returns boolean
 | |
| //*  Determines if a point is within a given cylinder. The cylinder's origin vector points
 | |
| //*  to the center of one of the two paralel circular sides, and the height vector points
 | |
| //*  from the origin point to the center of the other of the two paralel circular sides.
 | |
| //*  Returns false if the point is not in the cylinder or if the vector cylinderHeight is 0 units long.
 | |
| //*
 | |
| //*        method isInCone takes vector coneOrigin, vector coneHeight, real coneRadius returns boolean
 | |
| //*  Determines if a point is within a given cone. The cone's origin vector points to the
 | |
| //*  center of the circular side, and the height vector points from the origin point to
 | |
| //*  the tip of the cone.
 | |
| //*  Returns false if the point is not in the cylinder or if the vector coneHeight is 0 units long.
 | |
| //*
 | |
| //*        method isInSphere takes vector sphereOrigin, real sphereRadius returns boolean
 | |
| //*  Determines if a point is within a give sphere. The sphere's origin vector points to the
 | |
| //*  center of the sphere.
 | |
| //*  Returns false if the point is not in the sphere.
 | |
| //*****************************************************************
 | |
| 
 | |
|     struct vector
 | |
|         real x
 | |
|         real y
 | |
|         real z
 | |
|         
 | |
|         static method create takes real x, real y, real z returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             set v.x=x
 | |
|             set v.y=y
 | |
|             set v.z=z
 | |
|             return v
 | |
|         endmethod
 | |
|         
 | |
|         method getLength takes nothing returns real
 | |
|           return SquareRoot(.x*.x + .y*.y + .z*.z)
 | |
|         endmethod
 | |
|         
 | |
|         static method sum takes vector augend, vector addend returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             set v.x = augend.x+addend.x
 | |
|             set v.y = augend.y+addend.y
 | |
|             set v.z = augend.z+addend.z
 | |
|             return v
 | |
|         endmethod
 | |
|         method add takes vector addend returns nothing
 | |
|             set this.x=this.x+addend.x
 | |
|             set this.y=this.y+addend.y
 | |
|             set this.z=this.z+addend.z
 | |
|         endmethod
 | |
|         
 | |
|         static method difference takes vector minuend, vector subtrahend returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             set v.x = minuend.x-subtrahend.x
 | |
|             set v.y = minuend.y-subtrahend.y
 | |
|             set v.z = minuend.z-subtrahend.z
 | |
|             return v
 | |
|         endmethod
 | |
|         method subtract takes vector subtrahend returns nothing
 | |
|             set this.x=this.x-subtrahend.x
 | |
|             set this.y=this.y-subtrahend.y
 | |
|             set this.z=this.z-subtrahend.z
 | |
|         endmethod
 | |
|         
 | |
|         method scale takes real factor returns nothing
 | |
|             set this.x=this.x*factor
 | |
|             set this.y=this.y*factor
 | |
|             set this.z=this.z*factor
 | |
|         endmethod
 | |
|         
 | |
|         method setLength takes real length returns nothing
 | |
|             local real l = SquareRoot(.x*.x + .y*.y + .z*.z)
 | |
|             if l == 0.0 then
 | |
|                 debug call BJDebugMsg("Attempted to set the length of a vector with no length!")
 | |
|                 return
 | |
|             endif
 | |
|             set l = length/l
 | |
|             set this.x = this.x*l
 | |
|             set this.y = this.y*l
 | |
|             set this.z = this.z*l
 | |
|         endmethod
 | |
|         
 | |
|         static method dotProduct takes vector a, vector b returns real
 | |
|             return (a.x*b.x+a.y*b.y+a.z*b.z)
 | |
|         endmethod
 | |
|         
 | |
|         static method crossProduct takes vector a, vector b returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             set v.x = a.y*b.z - a.z*b.y
 | |
|             set v.y = a.z*b.x - a.x*b.z
 | |
|             set v.z = a.x*b.y - a.y*b.x
 | |
|             return v
 | |
|         endmethod
 | |
| 
 | |
|         static method tripleProductScalar takes vector a, vector b, vector c returns real
 | |
|             return ((a.y*b.z - a.z*b.y)*c.x+(a.z*b.x - a.x*b.z)*c.y+(a.x*b.y - a.y*b.x)*c.z)
 | |
|         endmethod
 | |
| 
 | |
|         static method tripleProductVector takes vector a, vector b, vector c returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             local real n = a.x*c.x+a.y*c.y+a.z*c.z
 | |
|             local real m = a.x*b.x+a.y*b.y+a.z*b.z
 | |
|             set v.x = b.x*n-c.x*m
 | |
|             set v.y = b.y*n-c.y*m
 | |
|             set v.z = b.z*n-c.z*m
 | |
|             return v
 | |
|         endmethod
 | |
| 
 | |
| // ================================================================
 | |
| 
 | |
|         static method projectionVector takes vector projected, vector direction returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             local real l = direction.x*direction.x+direction.y*direction.y+direction.z*direction.z
 | |
|             if l == 0.0 then
 | |
|                 call v.destroy()
 | |
|                 debug call BJDebugMsg("Attempted to project onto a vector with no length!")
 | |
|                 return null
 | |
|             endif
 | |
|             set l = (projected.x*direction.x+projected.y*direction.y+projected.z*direction.z) / l
 | |
|             set v.x = direction.x*l
 | |
|             set v.y = direction.y*l
 | |
|             set v.z = direction.z*l
 | |
|             return v
 | |
|         endmethod
 | |
|         method projectVector takes vector direction returns nothing
 | |
|             local real l = direction.x*direction.x+direction.y*direction.y+direction.z*direction.z
 | |
|             if l == 0.0 then
 | |
|                 debug call BJDebugMsg("Attempted to project onto a vector with no length!")
 | |
|                 return
 | |
|             endif
 | |
|             set l = (this.x*direction.x+this.y*direction.y+this.z*direction.z) / l
 | |
|             set this.x = direction.x*l
 | |
|             set this.y = direction.y*l
 | |
|             set this.z = direction.z*l
 | |
|         endmethod
 | |
| 
 | |
|         static method projectionPlane takes vector projected, vector normal returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             local real l = normal.x*normal.x+normal.y*normal.y+normal.z*normal.z
 | |
|             if l == 0.0 then
 | |
|                 call v.destroy()
 | |
|                 debug call BJDebugMsg("Attempted to project onto an undefined plane!")
 | |
|                 return null
 | |
|             endif
 | |
|             set l = (projected.x*normal.x+projected.y*normal.y+projected.z*normal.z) / l
 | |
|             set v.x = projected.x - normal.x*l
 | |
|             set v.y = projected.y - normal.y*l
 | |
|             set v.z = projected.z - normal.z*l
 | |
|             return v
 | |
|         endmethod
 | |
|         method projectPlane takes vector normal returns nothing
 | |
|             local real l = normal.x*normal.x+normal.y*normal.y+normal.z*normal.z
 | |
|             if l == 0.0 then
 | |
|                 debug call BJDebugMsg("Attempted to project onto an undefined plane!")
 | |
|                 return
 | |
|             endif
 | |
|             set l = (this.x*normal.x+this.y*normal.y+this.z*normal.z) / l
 | |
|             set this.x = this.x - normal.x*l
 | |
|             set this.y = this.y - normal.y*l
 | |
|             set this.z = this.z - normal.z*l
 | |
|         endmethod
 | |
| 
 | |
|         static method getAngle takes vector a, vector b returns real
 | |
|             local real l = SquareRoot(a.x*a.x + a.y*a.y + a.z*a.z)*SquareRoot(b.x*b.x + b.y*b.y + b.z*b.z)
 | |
|             if l == 0 then
 | |
|                 debug call BJDebugMsg("Attempted to get angle between vectors with no length!")
 | |
|                 return 0.0
 | |
|             endif
 | |
|             return Acos((a.x*b.x+a.y*b.y+a.z*b.z)/l) //angle is returned in radians
 | |
|         endmethod
 | |
|         
 | |
|         method rotate takes vector axis, real angle returns nothing //angle is taken in radians
 | |
|             local real xx
 | |
|             local real xy
 | |
|             local real xz
 | |
|             local real yx
 | |
|             local real yy
 | |
|             local real yz
 | |
|             local real zx
 | |
|             local real zy
 | |
|             local real zz
 | |
|             local real al = axis.x*axis.x+axis.y*axis.y+axis.z*axis.z //axis length^2
 | |
|             local real f
 | |
|             local real c = Cos(angle)
 | |
|             local real s = Sin(angle)
 | |
|             if al == 0.0 then
 | |
|                 debug call BJDebugMsg("Attempted to project onto a vector with no length!")
 | |
|                 return
 | |
|             endif
 | |
|             set f = (this.x*axis.x+this.y*axis.y+this.z*axis.z) / al
 | |
|             set zx = axis.x*f
 | |
|             set zy = axis.y*f
 | |
|             set zz = axis.z*f //axis component of rotated vector
 | |
|             set xx = this.x-zx
 | |
|             set xy = this.y-zy
 | |
|             set xz = this.z-zz //component of vector perpendicular to axis
 | |
|             set al = SquareRoot(al)
 | |
|             set yx = (axis.y*xz - axis.z*xy)/al
 | |
|             set yy = (axis.z*xx - axis.x*xz)/al //y same length as x by using cross product and dividing with axis length
 | |
|             set yz = (axis.x*xy - axis.y*xx)/al //x,y - coordinate system in which we rotate
 | |
|             set this.x=xx*c+yx*s+zx
 | |
|             set this.y=xy*c+yy*s+zy
 | |
|             set this.z=xz*c+yz*s+zz
 | |
|         endmethod
 | |
|         
 | |
| // ================================================================
 | |
| 
 | |
|         private static location loc = Location(0.0,0.0)
 | |
| 
 | |
|         static method createTerrainPoint takes real x, real y returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             call MoveLocation(vector.loc,x,y)
 | |
|             set v.x=x
 | |
|             set v.y=y
 | |
|             set v.z=GetLocationZ(loc)
 | |
|             return v
 | |
|         endmethod
 | |
|         method getTerrainPoint takes real x, real y returns nothing
 | |
|             call MoveLocation(vector.loc,x,y)
 | |
|             set this.x=x
 | |
|             set this.y=y
 | |
|             set this.z=GetLocationZ(loc)
 | |
|         endmethod
 | |
| 
 | |
|         static method createTerrainNormal takes real x, real y, real sampleRadius returns vector
 | |
|             local vector v = vector.allocate()
 | |
|             local real zx
 | |
|             local real zy
 | |
|             call MoveLocation(vector.loc, x-sampleRadius, y)
 | |
|             set zx=GetLocationZ(vector.loc)
 | |
|             call MoveLocation(vector.loc, x+sampleRadius, y)
 | |
|             set zx=zx-GetLocationZ(vector.loc)
 | |
|             call MoveLocation(vector.loc, x, y-sampleRadius)
 | |
|             set zy=GetLocationZ(vector.loc)
 | |
|             call MoveLocation(vector.loc, x, y+sampleRadius)
 | |
|             set zy=zy-GetLocationZ(vector.loc)
 | |
|             set sampleRadius=2*sampleRadius
 | |
|             set v.x = zx*sampleRadius
 | |
|             set v.y = zy*sampleRadius
 | |
|             set v.z = sampleRadius*sampleRadius
 | |
|             return v
 | |
|         endmethod
 | |
|         method getTerrainNormal takes real x, real y, real sampleRadius returns nothing
 | |
|             local real zx
 | |
|             local real zy
 | |
|             call MoveLocation(vector.loc, x-sampleRadius, y)
 | |
|             set zx=GetLocationZ(vector.loc)
 | |
|             call MoveLocation(vector.loc, x+sampleRadius, y)
 | |
|             set zx=zx-GetLocationZ(vector.loc)
 | |
|             call MoveLocation(vector.loc, x, y-sampleRadius)
 | |
|             set zy=GetLocationZ(vector.loc)
 | |
|             call MoveLocation(vector.loc, x, y+sampleRadius)
 | |
|             set zy=zy-GetLocationZ(vector.loc)
 | |
|             set sampleRadius=2*sampleRadius
 | |
|             set this.x = zx*sampleRadius
 | |
|             set this.y = zy*sampleRadius
 | |
|             set this.z = sampleRadius*sampleRadius
 | |
|         endmethod
 | |
| 
 | |
| // ================================================================
 | |
| 
 | |
|         method isInCylinder takes vector cylinderOrigin, vector cylinderHeight, real cylinderRadius returns boolean
 | |
|             local real l
 | |
| 
 | |
|             local real x = this.x-cylinderOrigin.x
 | |
|             local real y = this.y-cylinderOrigin.y
 | |
|             local real z = this.z-cylinderOrigin.z
 | |
|             if x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z < 0.0 then //point below cylinder
 | |
|                 return false
 | |
|             endif
 | |
|             
 | |
|             set x = x-cylinderHeight.x
 | |
|             set y = y-cylinderHeight.y
 | |
|             set z = z-cylinderHeight.z
 | |
|             if x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z > 0.0 then //point above cylinder
 | |
|                 return false
 | |
|             endif
 | |
|             
 | |
|             set l = cylinderHeight.x*cylinderHeight.x+cylinderHeight.y*cylinderHeight.y+cylinderHeight.z*cylinderHeight.z
 | |
|             if l == 0.0 then
 | |
|                 debug call BJDebugMsg("Cylinder with no height!")
 | |
|                 return false
 | |
|             endif
 | |
|             set l = (x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z) / l
 | |
|             set x = x - cylinderHeight.x*l
 | |
|             set y = y - cylinderHeight.y*l
 | |
|             set z = z - cylinderHeight.z*l
 | |
|             if x*x+y*y+z*z > cylinderRadius*cylinderRadius then //point outside cylinder
 | |
|                 return false
 | |
|             endif
 | |
|             
 | |
|             return true
 | |
|         endmethod
 | |
| 
 | |
|         method isInCone takes vector coneOrigin, vector coneHeight, real coneRadius returns boolean
 | |
|             local real l
 | |
| 
 | |
|             local real x = this.x-coneOrigin.x
 | |
|             local real y = this.y-coneOrigin.y
 | |
|             local real z = this.z-coneOrigin.z
 | |
|             if x*coneHeight.x+y*coneHeight.y+z*coneHeight.z < 0.0 then //point below cone
 | |
|                 return false
 | |
|             endif
 | |
|             
 | |
|             set l = coneHeight.x*coneHeight.x+coneHeight.y*coneHeight.y+coneHeight.z*coneHeight.z
 | |
|             if l == 0.0 then
 | |
|                 debug call BJDebugMsg("cone with no height!")
 | |
|                 return false
 | |
|             endif
 | |
|             set l = (x*coneHeight.x+y*coneHeight.y+z*coneHeight.z) / l
 | |
|             set x = x - coneHeight.x*l
 | |
|             set y = y - coneHeight.y*l
 | |
|             set z = z - coneHeight.z*l
 | |
|             if SquareRoot(x*x+y*y+z*z) > coneRadius*(1.0-l) then //point outside cone
 | |
|                 return false
 | |
|             endif
 | |
|             
 | |
|             return true
 | |
|         endmethod
 | |
| 
 | |
|         method isInSphere takes vector sphereOrigin, real sphereRadius returns boolean
 | |
|             if sphereRadius*sphereRadius < ((this.x-sphereOrigin.x)*(this.x-sphereOrigin.x)+(this.y-sphereOrigin.y)*(this.y-sphereOrigin.y)+(this.z-sphereOrigin.z)*(this.z-sphereOrigin.z)) then
 | |
|                 return false
 | |
|             endif
 | |
|             return true
 | |
|         endmethod
 | |
|     endstruct
 | |
| 
 | |
| endlibrary
 | |
| library VectorLib requires Vector // For backwards compatibility.
 | |
| endlibrary |