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 |