|
|
|
Trigonometry Class v0.6
Added on 12/3/2003
|
Trigonometry class collection, Fast precalculated tables. Good set of basic functions for use in gamephysics amongst others. openLingo material.
-- @Name trigmath
-- @Version 1.6
-- @Type Parent
-- @Author Christoffer Enedahl
-- @Home www.enedahl.com
-- @Home www.openlingo.org
-- @History Added v1.6 2003-10-27 GetFarAngle, InvCos, pAtan1
-- @History Added v1.5 2003-03-20 vectorToAngle(), vectorToDegree() Lazy use of atan
-- @History Added v1.4 2003-02-26 isPointInQuad()
-- @History Removed v1.4 2003-02-21 atan2, it turns out that this function is an undoc'd lingofunction. use: atan(y,x)
-- @History Added v1.3 2003-02-19 atan2
-- @History Optimize v1.2 2003-02-12 Using 3d functions for normalize2d and others
-- @History Added v1.2 2003-02-12 magnitude2d
-- @History Added v1.1 2003-01-16 vector functions
-- @History Created v1.0 2003-01-15
--
-- @Description Precalculate sin-, cos- and radtables for fast calculations
-- @Description Some angle operations on points.
--
-- @Dependencies olmath.ls sgn bitshiftleft bitshiftright
--
--Usage
-- p = trigmath.rotatePoint ( point(3,5), trigmath.angleToRad(-45) )
-- p = trigmath.rotatePointFast ( point(3,5), 315 )
--
-- @Todo Lots of trigonometry, feel free to contribute.
property pDegToRad
property pCosTable --index is degrees 1-360
property pSinTable --index is degrees 1-360
property pRadTable --index is degrees 1-360
property pAtan1 --Precalced Atan(1)
on new me
pDegToRad = pi / 180.0
pAtan1 = atan(1)
--Precalculate sin-, cos- and radtables for fast calculations
pCosTable = []
pSinTable = []
pRadTable = []
repeat with i = 1 to 360
pRadTable.append( me.degreeToRad(i) )
pCosTable.append( cos( pRadTable[i] ) )
pSinTable.append( sin( pRadTable[i] ) )
end repeat
return me
end
on degreeToRad(me, aDegree)
return aDegree * pDegToRad
end
on radToDegree (me, aRadian)
return aRadian / pDegToRad
end
on degreeToRadFast (me, aDegree)
-- aDegre must be an integer degree between 1 - 360
return pRadTable.getAt(aDegree)
end
on rotatePoint (me, aPoint, aTheta)
-- aTheta is a radian number.
p = point(.0,.0)
vCos = cos(aTheta)
vSin = sin(aTheta)
p[1] = vCos*aPoint[1] - vSin*aPoint[2]
p[2] = vSin*aPoint[1] + vCos*aPoint[2]
return p
end
--aTheta must be an integer degree between 1 - 360
on rotatePointFast (me, aPoint, aTheta)
p = point(0,0)
p[1] = pCosTable[aTheta]*aPoint[1] - pSinTable[aTheta]*aPoint[2]
p[2] = pSinTable[aTheta]*aPoint[1] + pCosTable[aTheta]*aPoint[2]
return p
end
on distance2d (me,aPoint1,aPoint2)
vVector = vector( aPoint1[1] - aPoint2[1], aPoint1[2] - aPoint2[2], 0)
return vVector.magnitude
end
on distance2dFast (me,aPoint1,aPoint2)
-- Remember the returned distance is squared the actual distance!
-- it about 5-10% faster than distance2d
d1 = aPoint1[1] - aPoint2[1]
d2 = aPoint1[2] - aPoint2[2]
return (d1*d1) + (d2*d2)
end
on approxDistance2d ( me, aPoint1, aPoint2)
dx = abs( aPoint2.loch - aPoint2.loch )
dy = abs( aPoint2.locv - aPoint2.locv )
if dx < dy then
vMin = dx
vMax = dy
else
vMin = dy
vMax = dx
end if
approx = ( vMax * 1007 ) + ( vMin * 441 )
if ( vMax < ( bitshiftleft(vMin,4) )) then approx = approx - ( vMax * 40 )
-- add 512 for proper rounding
return ( bitshiftright( approx + 512, 10 ) )
end
on vector2d (me,aPoint1,aPoint2)
return aPoint2 - aPoint1
end
on normalize2d (me,aPoint)
vVector = vector( the loch of aPoint, the locv of aPoint, 0)
vVector.normalize()
return point( vVector[1], vVector[2])
end
on magnitude2d me, aPoint
vVector = vector( aPoint[1], aPoint[2], 0)
return vVector.magnitude
end
on magnitude2dFast me, aPoint
-- Remember the returned distance is squared the actual distance!
-- it about 5-10% faster than magnitude2d
a = aPoint[1]
b = aPoint[2]
return (a*a) + (b*b)
end
on get2dNormal me, aVector
-- the resulting vector is the normal, but it is not normalized.
-- all that happens is a rotate by 90 degrees.
p = point(0,0)
p[1] = pCosTable[90]*aVector[1] - pSinTable[90]*aVector[2]
p[2] = pSinTable[90]*aVector[1] + pCosTable[90]*aVector[2]
return p
end
on vectorToDegree (me,aVector)
--Lazy use of atan
return me.radToDegree( atan(aVector.locv, aVector.loch) )
end
on vectorToAngle (me,aVector)
--Lazy use of atan
return atan(aVector.locv, aVector.loch)
end
on angleToVector (me, aTheta)
return point( cos(aTheta), sin(aTheta) )
end
on dotproduct2d (me, a ,b)
return dotproduct( vector( a[1],a[2],0), vector( b[1],b[2],0) )
end
on lineToQuad (me, aA, aB, aLineWidth, aEndLineWidth)
-- makes a quad, to use for example with copyPixels, then you can draw lines with the ability to blend it.
-- aEndLineWidth is optional
vQuad = [aA,aA,aB,aB]
vNormal = me.normalize2d( me.get2dNormal( me.vector2d(aA,aB) ) )
if voidP(aEndLineWidth) then
vNormal = vNormal * (aLineWidth/2.0)
vQuad[1] = vQuad[1] + vNormal
vQuad[2] = vQuad[2] - vNormal
vQuad[3] = vQuad[3] - vNormal
vQuad[4] = vQuad[4] + vNormal
else
vNormalEnd = vNormal * (aEndLineWidth/2.0)
vNormal = vNormal * (aLineWidth /2.0)
vQuad[1] = vQuad[1] + vNormal
vQuad[2] = vQuad[2] - vNormal
vQuad[3] = vQuad[3] - vNormalEnd
vQuad[4] = vQuad[4] + vNormalEnd
end if
return vQuad
end
on isPointInQuad(me, aQuad, aPoint)
--clockwize quad
vNextPoint = [2,3,4,1]
repeat with vVertexNum = 1 to 4
vArea = me.TriangleAreaFast(aPoint, aQuad[ vVertexNum ], aQuad[ vNextPoint[ vVertexNum ] ] )
if vArea < 0 then return 0
end repeat
return 1
end
on TriangleAreaFast(me, p, a, b )
--This function does not produce an accurate area of an triangle, but fast results determing order of points. used in isPointInQuad,
--if this result is negative: the points are counterclockwize, therefore the p lies outside of the line a-b
return (a.loch-p.loch) * (b.locv-p.locv) - (b.loch-p.loch)*(a.locv-p.locv)
end
on terminate me
end
on GetFarAngle (me,c,a,b)
--
-- |
-- |x
-- a | b
-- |___
-- c
--
-- return the radian angle of the far side of a triangle with known lengths
-- the corner of the far side of c
-- the triangle does not need to be a "right triangle"
-- CosineStatement: a2 = b2 + c2 - 2bc · cos vA
--
-- x = a*a + b*b - c*c
-- x = x / float(2*a*b)
-- x = me.InvCos(x)
--
-- return x
if a*b = 0 then return 0
return me.InvCos( (a*a + b*b - c*c) / float(2*a*b) )
end
on InvCos me, X
y = Sqrt(-X * X + 1)
if y = 0 then return 0 --y=NAN
return atan(-X / y) + 2 * pAtan1
end
--Other functions to be lingolized
--Secant Sec(X) = 1 / Cos(X)
--Cosecant Cosec(X) = 1 / Sin(X)
--Cotangent Cotan(X) = 1 / Tan(X)
--Inverse Sine Arcsin(X) = Atn(X / Sqr(-X * X + 1))
--Inverse Cosine Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
--Inverse Secant Arcsec(X) = Atn(X / Sqr(X * X – 1)) + Sgn((X) – 1) * (2 * Atn(1))
--Inverse Cosecant Arccosec(X) = Atn(X / Sqr(X * X - 1)) + (Sgn(X) – 1) * (2 * Atn(1))
--Inverse Cotangent Arccotan(X) = Atn(X) + 2 * Atn(1)
--Hyperbolic Sine HSin(X) = (Exp(X) – Exp(-X)) / 2
--Hyperbolic Cosine HCos(X) = (Exp(X) + Exp(-X)) / 2
--Hyperbolic Tangent HTan(X) = (Exp(X) – Exp(-X)) / (Exp(X) + Exp(-X))
--Hyperbolic Secant HSec(X) = 2 / (Exp(X) + Exp(-X))
--Hyperbolic Cosecant HCosec(X) = 2 / (Exp(X) – Exp(-X))
--Hyperbolic Cotangent HCotan(X) = (Exp(X) + Exp(-X)) / (Exp(X) – Exp(-X))
--Inverse Hyperbolic Sine HArcsin(X) = Log(X + Sqr(X * X + 1))
--Inverse Hyperbolic Cosine HArccos(X) = Log(X + Sqr(X * X – 1))
--Inverse Hyperbolic Tangent HArctan(X) = Log((1 + X) / (1 – X)) / 2
--Inverse Hyperbolic Secant HArcsec(X) = Log((Sqr(-X * X + 1) + 1) / X)
--Inverse Hyperbolic Cosecant HArccosec(X) = Log((Sgn(X) * Sqr(X * X + 1) + 1) / X)
--Inverse Hyperbolic Cotangent HArccotan(X) = Log((X + 1) / (X – 1)) / 2
--Logarithm to base N LogN(X) = Log(X) / Log(N)
|
|