Snippet Vectors

Discussion in 'Systems and Snippets' started by krainert, Jul 17, 2011.

  1. Sgqvur

    Sgqvur FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi

    Ratings:
    +62 / 0 / -0
    Dirac:
    1. I think that has already been answered for you
    http://www.thehelper.net/forums/show...LocInclination

    1. The math seams different. There is no v.z = sampleRadius*sampleRadius in your thing.

    And you didn't address my other questions:
    "Is this the same thing as calculating a "surface normal"? Why isn't the resultant vector normalized?
     
  2. Bribe

    Bribe vJass errors are legion

    Ratings:
    +67 / 0 / -0
    A better question would have been why is he using a local location instead of a global, why it is a memory leak when used and why he doesn't even null the handle.

    Just use Anitarf's Vector or get him to add the features you want, or make an extension to his vector. Too many vector libraries and most of them are better left unused.
     
  3. krainert

    krainert Member

    Ratings:
    +10 / 0 / -0
    Ugh, sorry guy, I forgot to check back.

    People requested the addition of miscellaneous functionality found in Anitarf's Vector library, and I used his base implementation in my code. That was a while back, though, so I might have missed some leaks.

    This library seems fairly used (and hence reliable), but looking at Anitarf's code, its terrain normal function is borderline identical to mine. Hence, you might want to let him know if there is a leak in my implementation since it is then highly likely to be present in his as well.
    EDIT: Nope, Anitarf knew better ;)

    Anyway, I'll just have a look at the terrain normal algorithm and see if I can make some sense of it.
    What did you mean by nulling the handle, and which memory leak are you referring to, precisely?
    EDIT: Regarding the memory leak and the local/global location: I guess I found my answer here: http://www.thehelper.net/forums/showthread.php/167173-GetLocInclination?p=1371335#post1371335 (as referenced)
    Also, by the way, noticed any other flaws I should look at, Bribe?

    Thanks for the input.
     
  4. luorax

    luorax Invasion in Duskwood

    Ratings:
    +67 / 0 / -0
    JASS:
    static method createTerrainNormal takes real x, real y, real sampleRadius returns Vector3D
        local Vector3D v = Vector3D.allocate()
        local real zx
        local real zy
        local location loc = Location(0.0, 0.0)
        call MoveLocation(loc, x-sampleRadius, y)
        set zx = GetLocationZ(loc)
        call MoveLocation(loc, x+sampleRadius, y)
        set zx = zx-GetLocationZ(loc)
        call MoveLocation(loc, x, y-sampleRadius)
        set zy = GetLocationZ(loc)
        call MoveLocation(loc, x, y+sampleRadius)
        set zy = zy-GetLocationZ(loc)
        set sampleRadius = 2*sampleRadius
        set v.x = zx*sampleRadius
        set v.y = zy*sampleRadius
        set v.z = sampleRadius*sampleRadius
        return v
    endmethod


    This leaks, since location variables must be nulled and the location is actually never destroyed. Also:

    JASS:
    private static location loc=Location(0.,0.)
    static method createTerrainNormal takes real x, real y, real sampleRadius returns Vector3D
        local Vector3D v = Vector3D.allocate()
        local real zx
        local real zy
        call MoveLocation(thistype.loc,x-sampleRadius,y)
        set zx=GetLocationZ(thistype.loc)
        call MoveLocation(thistype.loc,x+sampleRadius,y)
        set zx=zx-GetLocationZ(thistype.loc)
        call MoveLocation(thistype.loc,x,y-sampleRadius)
        set zy=GetLocationZ(thistype.loc)
        call MoveLocation(thistype.loc,x,y+sampleRadius)
        set zy=zy-GetLocationZ(thistype.loc)
        set sampleRadius=2*sampleRadius
        set v.x=zx*sampleRadius
        set v.y=zy*sampleRadius
        set v.z=sampleRadius*sampleRadius
        return v
    endmethod
     
  5. krainert

    krainert Member

    Ratings:
    +10 / 0 / -0
    Aha, thanks.

    I'll just read up on JASS optimization (which I should've probably done in the first place) and optimize the library. Then I'll get back to you!
     
  6. krainert

    krainert Member

    Ratings:
    +10 / 0 / -0
    Right.

    Regarding terrain normal:
    This function returns an estimated normal vector to the terrain surface at point (x,y) where x and y are parameters of the function. Terrain height values are acquired at points (x-sampleRadius,y), (x+sampleRadius,y), (x,y-sampleRadius), and (x,y+sampleRadius), and the magnitude of the returned vector is 2*sampleRadius*sqrt(zx^2+zy^2) = 2*sampleRadius*sqrt((a-b)^2+(c-d)^2) where a, b, c, and d are the terrain height values at the four sample points, respectively and in the order mentioned. That is, zx=a-b and zy=c-d. To be exact, v=(2*sampleRadius*zx, 2*sampleRadius*zy, 4*sampleRadius^2) where v is the returned estimated normal vector.
    Correct?

    EDIT: Optimization question: Should I initialize and nullify my static location instance before and after every use, respectively, or leave it untouched? I suppose the different in performance in this case is negligible.

    EDIT 2: Regarding optimization: Well, fixing the location thing seems to be all the optimization it needed, amrite?
     
  7. luorax

    luorax Invasion in Duskwood

    Ratings:
    +67 / 0 / -0
    Just initialize it as I did in my example and leave it untouched.
     
  8. krainert

    krainert Member

    Ratings:
    +10 / 0 / -0
    Roger.

    Thank you all for putting up with my current display of amateurishness... I'll get back to you once I've run some tests.
     
  9. Trollvottel

    Trollvottel never aging title

    Ratings:
    +261 / 0 / -0
    Question:
    Am i missing something or is this:
    JASS:
      method angle takes Vector3D v returns real
            return Acos(dotProduct(v))
        endmethod


    wrong? normally cos(a) = dotproduct / product of lengths <=> a = Acos(dotproduct / product of lengths)

    so this would only work for vectors that have a length of 1, right?
     
  10. Sgqvur

    Sgqvur FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi

    Ratings:
    +62 / 0 / -0
    krainert:
    1. This function returns an estimated normal vector to the terrain surface at point (x,y) where x and y are parameters of the function. Terrain height values are acquired at points (x-sampleRadius,y), (x+sampleRadius,y), (x,y-sampleRadius), and (x,y+sampleRadius), and the magnitude of the returned vector is 2*sampleRadius*sqrt(zx^2+zy^2) = 2*sampleRadius*sqrt((a-b)^2+(c-d)^2) where a, b, c, and d are the terrain height values at the four sample points, respectively and in the order mentioned. That is, zx=a-b and zy=c-d. To be exact, v=(2*sampleRadius*zx, 2*sampleRadius*zy, 4*sampleRadius^2) where v is the returned estimated normal vector.

    1. Well tnx for translating the script in English but this tells nothing about the underling math that actually make it work.

    PS: Kudos to the dude that originally worked it out =).
     
  11. krainert

    krainert Member

    Ratings:
    +10 / 0 / -0
    I actually did most of a proof while trying to sort it out on a whiteboard... I'll upload a pic I took in a bit.

    EDIT:
    Wauw, it's even more unintelligible than I thought. Have a look, though:
    http://peecee.dk/uploads/102011/2011-10-26-20-31-25-710.jpg
     
  12. krainert

    krainert Member

    Ratings:
    +10 / 0 / -0
    Updated to 4.0.
     
  13. krainert

    krainert Member

    Ratings:
    +10 / 0 / -0
    Here's version 5.0:
    JASS:
    library Vectors
    
    //********************************************************************************************************************************
    //* Vectors
    //*  
    //*  ABOUT
    //*   Author:   krainert
    //*   Version:  5.0
    //*   
    //*  DESCRIPTION
    //*   This library provides two vector structs:
    //*   - Vector2D representing a two-dimensional vector
    //*   - Vector3D representing a three-dimensional vector
    //*   Note: All angles are in radians
    //*   
    //*  STRUCTS
    //*   ======== Vector2D ========
    //*    -- Description
    //*     Represents a two-dimensional vector
    //*    -- Methods
    //*     static Vector2D create(Vector2D v)                                      - returns a new vector as a clone of 'v'
    //*     static Vector2D createXY(real x, real y)                                - returns a new vector with x coordinate 'x' and y coordinate 'y'
    //*     static Vector2D createDM(real d, real m)                                - returns a new vector with direction 'd' and magnitude 'm'
    //*     static Vector2D createNull()                                            - returns a new vector with x and y coordinates 0
    //*     Vector2D clone()                                                        - returns a new vector as a clone of this vector
    //*     real     getX()                                                         - returns the x coordinate of this vector
    //*     real     getY()                                                         - returns the y coordinate of this vector
    //*     real     getDir()                                                       - returns the direction of this vector
    //*     real     getMag()                                                       - returns the magnitude of this vector
    //*     Vector2D setX(real x)                                                   - sets the x coordinate of this vector to 'x' and returns the result
    //*     Vector2D setY(real y)                                                   - sets the y coordinate of this vector to 'y' and returns the result
    //*     Vector2D setDir(real d)                                                 - sets the direction of this vector to 'd' and returns the result
    //*     Vector2D setMag(real m)                                                 - sets the magnitude of this vector to 'm' and returns the result
    //*     real     dotProduct(Vector2D v)                                         - returns the dot product of this vector and 'v'
    //*     real     angle(Vector2D v)                                              - returns the angle between this vector and 'v'
    //*     Vector2D unit()                                                         - sets the magnitude of this vector to 1 and returns the result
    //*     Vector2D flip()                                                         - sets the x coordinate of this vector to its previous y coordinate and the y coordinate of this vector to its previous x coordinate and returns the result
    //*     Vector2D invert()                                                       - sets the x coordinate of this vector to the inverse of its previous x coordinate and the y coordinate of this vector to the inverse of its previous y coordinate and returns the result
    //*     Vector2D scale(real s)                                                  - scales this vector by an amount equal to 's' and returns the result
    //*     Vector2D add(Vector2D v)                                                - adds 'v' to this vector and returns the vector
    //*     Vector2D sub(Vector2D v)                                                - subtracts 'v' from this vector and returns the result
    //*     Vector2D addXY(real x, real y)                                          - adds a vector with x coordinate 'x' and y coordinate 'y' to this vector and returns the result
    //*     Vector2D subXY(real x, real y)                                          - subtracts a vector with x coordinate 'x' and y coordinate 'y' from this vector and returns the result
    //*     Vector2D addDM(real d, real m)                                          - adds a vector with direction 'd' and magnitude 'm' to this vector and returns the result
    //*     Vector2D subDM(real d, real m)                                          - subtracts a vector with direction 'd' and magnitude 'm' from this vector and returns the result
    //*   ======== Vector3D ========
    //*    -- Description
    //*     Represents a three-dimensional vector
    //*    -- Methods
    //*     static Vector3D create(Vector3D v)                                      - returns a new vector as a clone of 'v'
    //*     static Vector3D createXYZ(real x, real y, real z)                       - returns a new vector with x coordinate 'x', y coordinate 'y', and z coordinate 'z'
    //*     static Vector3D createNull()                                            - returns a new vector with x, y, and z coordinates 0
    //*     static Vector3D createTerrainNormal(real x, real y, real sampleRadius)  - returns a new vector representing the normal of the terrain at the location with x coordinate 'x' and y coordinate 'y' with sample radius 'sampleRadius'
    //*     Vector3D clone()                                                        - returns a new vector as a clone of this vector
    //*     real     getX()                                                         - returns the x coordinate of this vector
    //*     real     getY()                                                         - returns the y coordinate of this vector
    //*     real     getZ()                                                         - returns the z coordinate of this vector
    //*     real     getMag()                                                       - returns the magnitude of this vector
    //*     Vector3D setX(real x)                                                   - sets the x coordinate of this vector to 'x' and returns the result
    //*     Vector3D setY(real y)                                                   - sets the y coordinate of this vector to 'y' and returns the result
    //*     Vector3D setZ(real z)                                                   - sets the z coordinate of this vector to 'z' and returns the result
    //*     Vector3D setMag(real m)                                                 - sets the magnitude of this vector to 'm' and returns the result
    //*     real     dotProduct(Vector3D v)                                         - returns the dot product of this vector and 'v'
    //*     real     tripleProductScalar(Vector3D v1, Vector3D v2)                  - returns the tripple scalar product of this vector, 'v1', and 'v2'
    //*     real     angle(Vector3D v)                                              - returns the angle between this vector and 'v'
    //*     Vector3D crossProduct(Vector3D v)                                       - sets this vector to the cross product of itself and 'v' and returns the result
    //*     Vector3D tripleProductVector(Vector3D v1, Vector3D v2)                  - sets this vector to the tripple scalar product of itself, 'v1', and 'v2' and returns the result
    //*     Vector3D projectionVector(Vector3D dir)                                 - sets this vector to the projection of itself onto the line through vector 'dir' and returns the result
    //*     Vector3D projectionPlane(Vector3D normal)                               - sets this vector to the projection of itself onto the plane with normal vector 'normal' and returns the result
    //*     Vector3D unit()                                                         - sets the magnitude of this vector to 1 and returns the result
    //*     Vector3D invert()                                                       - sets the x coordinate of this vector to the inverse of its previous x coordinate, the y coordinate of this vector to the inverse of its previous y coordinate, and the z coordinate of this vector to the inverse of its previous z coordinate and returns the result
    //*     Vector3D scale(real s)                                                  - scales this vector by an amount equal to 's' and returns the result
    //*     Vector3D rotate(Vector3D axis, real angle)                              - rotates this vector around the line through 'axis' by an amount equal to 'angle' and returns the result
    //*     Vector3D add(Vector3D v)                                                - adds 'v' to this vector and returns the result
    //*     Vector3D sub(Vector3D v)                                                - subtracts 'v' from this vector and returns the result
    //*     Vector3D addXYZ(real x, real y, real z)                                 - adds a vector with x coordinate 'x', y coordinate 'y', and z coordinate 'z' to this vector and returns the result
    //*     Vector3D subXYZ(real x, real y, real z)                                 - subtracts a vector with x coordinate 'x', y coordinate 'y', and z coordinate 'z' from this vector and returns the result
    //*     
    //*  CHANGELOG
    //*   1.0  2011-07-08  Original release
    //*   2.0  2011-07-13  vector redesigned and renamed to Vector2D
    //*                    Vector3D added
    //*   2.1  2011-07-17  modDir, modMag, and accumulative operations added to Vector2D
    //*   2.2  2011-08-04  setMag added to Vector3D
    //*                    crossProduct, tripleProductScalar, tripleProductVector, projectionVector, projectionPlane, rotate, mRotate, and static createTerrainNormal added to Vector3D
    //*                    Note: the implementations of the above methods were inspired by Anitarf's Vector library
    //*                    setMag optimized in Vector2D
    //*                    Operator < overloaded for Vector2D: returns true if the magnitude of this vector is lower than the magnitude of the other vector, false otherwise
    //*                    Operator < overloaded for Vector3D: returns true if the magnitude of this vector is lower than the magnitude of the other vector, false otherwise
    //*                    Operator == overloaded for Vector2D: returns true if the x and y coordinates of this vector are equal to the x and y coordinates of the other vector respectively, false otherwise
    //*                    Operator == overloaded for Vector3D: returns true if the x, y, and z coordinates of this vector are equal to the x, y, and z coordinates of the other vector respectively, false otherwise
    //*   2.3  2011-08-05  getMag, getDir, setMag, setDir, addXY, subXY, mAddXY, and mSubXY in Vector2D relocated to prevent trigger evaluation
    //*                    getMag, setMag, addXYZ, subXYZ, mAddXYZ, and mSubXYZ in Vector3D relocated to prevent trigger evaluation
    //*   3.0  2011-10-24  Extensive API modifications and reductions
    //*   4.0  2011-10-31  crossProduct, trippleProductVector, projectionVector, and projectionPlane in Vector3D changed into mutators
    //*                    Miscellaneous corrections
    //*   5.0  2012-01-16  Debug mode exclusive error messages added to Vector2D and Vector3D
    //*                    Empty onDestroy methods removed from Vector2D and Vector3D
    //*                    Documentation updated
    //*   
    //********************************************************************************************************************************
    
    globals
        private constant integer MAX_2D = 8191
        private constant integer MAX_3D = 8191
        debug private constant string ERR_NULL_VECT_DIR = "the direction of null vectors is undefined"
    endglobals
    
    struct Vector2D[MAX_2D]
        private real x
        private real y
        
        static if debug then
            static method err takes string message returns nothing
                call BJDebugMsg("[Vector2D] ERROR: " + message)
            endmethod
        endif
        
        static method create takes thistype v returns thistype
            local thistype r = .allocate()
            set r.x = v.x
            set r.y = v.y
            return r
        endmethod
        
        static method createXY takes real x, real y returns thistype
            local thistype r = .allocate()
            set r.x = x
            set r.y = y
            return r
        endmethod
        
        static method createDM takes real d, real m returns thistype
            local thistype r = .allocate()
            set r.x = Cos(d)*m
            set r.y = Sin(d)*m
            return r
        endmethod
        
        static method createNull takes nothing returns thistype
            local thistype r = .allocate()
            set r.x = 0
            set r.y = 0
            return r
        endmethod
        
        method clone takes nothing returns thistype
            local thistype r = .allocate()
            set r.x = .x
            set r.y = .y
            return r
        endmethod
        
        method getX takes nothing returns real
            return .x
        endmethod
        
        method getY takes nothing returns real
            return .y
        endmethod
        
        method getDir takes nothing returns real
            static if debug then
                if .x == 0 and .y == 0 then
                    call err("getDir(): " + )
                endif
            endif
            return Atan2(.y, .x)
        endmethod
        
        method getMag takes nothing returns real
            return SquareRoot(.x*.x+.y*.y)
        endmethod
        
        method setX takes real x returns thistype
            set .x = x
            return this
        endmethod
        
        method setY takes real y returns thistype
            set .y = y
            return this
        endmethod
        
        method setDir takes real d returns thistype
            local real m
            static if debug then
                if .x == 0 and .y == 0 then
                    call err("setDir(" + R2S(d) + "): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set m = .getMag()
            set .x = Cos(d)*m
            set .y = Sin(d)*m
            return this
        endmethod
        
        method setMag takes real m returns thistype
            local real f
            if m == 0 then
                set .x = 0
                set .y = 0
                return this
            endif
            static if debug then
                if .x == 0 and .y == 0 then
                    call err("setMag(" + R2S(m) + "): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set f = m/.getMag()
            set .x = f*.x
            set .y = f*.y
            return this
        endmethod
        
        method dotProduct takes thistype v returns real
            return .x*v.x+.y*v.y
        endmethod
        
        method angle takes thistype v returns real
            static if debug then
                if (.x == 0 and .y == 0) or (v.x == 0 and v.y == 0) then
                    call err("angle({Vector2D|x=" + v.x + ",y=" + v.y + "}): " + ERR_NULL_VECT_DIR)
                endif
            endif
            return Acos(.dotProduct(v)/(.getMag()*v.getMag()))
        endmethod
        
        method unit takes nothing returns thistype
            local real m
            static if debug then
                if .x == 0 and .y == 0 then
                    call err("unit(): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set m = .getMag()
            set .x = .x/m
            set .y = .y/m
            return this
        endmethod
        
        method flip takes nothing returns thistype
            local real x = .x
            set .x = .y
            set .y = x
            return this
        endmethod
        
        method invert takes nothing returns thistype
            set .x = -.x
            set .y = -.y
            return this
        endmethod
        
        method scale takes real s returns thistype
            set .x = s*.x
            set .y = s*.y
            return this
        endmethod
        
        method add takes thistype v returns thistype
            set .x = .x+v.x
            set .y = .y+v.y
            return this
        endmethod
        
        method sub takes thistype v returns thistype
            set .x = .x-v.x
            set .y = .y-v.y
            return this
        endmethod
        
        method addXY takes real x, real y returns thistype
            set .x = .x+x
            set .y = .y+y
            return this
        endmethod
        
        method subXY takes real x, real y returns thistype
            set .x = .x-x
            set .y = .y-y
            return this
        endmethod
        
        method addDM takes real d, real m returns thistype
            set .x = .x+Cos(d)*m
            set .y = .y+Sin(d)*m
            return this
        endmethod
        
        method subDM takes real d, real m returns thistype
            set .x = .x-Cos(d)*m
            set .y = .y-Sin(d)*m
            return this
        endmethod
    endstruct
    
    struct Vector3D[MAX_3D]
        private static location loc = Location(0., 0.)
        private real x
        private real y
        private real z
        
        static if debug then
            static method err takes string message returns nothing
                call BJDebugMsg("[Vector3D] ERROR: " + message)
            endmethod
        endif
        
        static method create takes thistype v returns thistype
            local thistype r = .allocate()
            set r.x = v.x
            set r.y = v.y
            set r.z = v.z
            return r
        endmethod
        
        static method createXYZ takes real x, real y, real z returns thistype
            local thistype r = .allocate()
            set r.x = x
            set r.y = y
            set r.z = z
            return r
        endmethod
        
        static method createNull takes nothing returns thistype
            local thistype r = .allocate()
            set r.x = 0
            set r.y = 0
            set r.z = 0
            return r
        endmethod
        
        static method createTerrainNormal takes real x, real y, real sampleRadius returns thistype
            local thistype v = .allocate()
            local real zx
            local real zy
            call MoveLocation(.loc, x-sampleRadius, y)
            set zx = GetLocationZ(.loc)
            call MoveLocation(.loc, x+sampleRadius, y)
            set zx = zx-GetLocationZ(.loc)
            call MoveLocation(.loc, x, y-sampleRadius)
            set zy = GetLocationZ(.loc)
            call MoveLocation(.loc, x, y+sampleRadius)
            set zy = zy-GetLocationZ(.loc)
            set sampleRadius = 2*sampleRadius
            set v.x = zx*sampleRadius
            set v.y = zy*sampleRadius
            set v.z = sampleRadius*sampleRadius
            return v
        endmethod
        
        method clone takes nothing returns thistype
            local thistype r = .allocate()
            set r.x = .x
            set r.y = .y
            set r.z = .z
            return r
        endmethod
        
        method getX takes nothing returns real
            return .x
        endmethod
        
        method getY takes nothing returns real
            return .y
        endmethod
        
        method getZ takes nothing returns real
            return .z
        endmethod
        
        method getMag takes nothing returns real
            return SquareRoot(.x*.x+.y*.y+.z*.z)
        endmethod
        
        method setX takes real x returns thistype
            set .x = x
            return this
        endmethod
        
        method setY takes real y returns thistype
            set .y = y
            return this
        endmethod
        
        method setZ takes real z returns thistype
            set .z = z
            return this
        endmethod
        
        method setMag takes real m returns thistype
            local real f
            if m == 0 then
                set .x = 0
                set .y = 0
                set .z = 0
                return this
            endif
            static if debug then
                if .x == 0 and .y == 0 and .z == 0 then
                    call err("setMag(" + R2S(m) + "): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set f = m/.getMag()
            set .x = f*.x
            set .y = f*.y
            set .z = f*.z
            return this
        endmethod
        
        method dotProduct takes thistype v returns real
            return .x*v.x+.y*v.y+.z*v.z
        endmethod
        
        method tripleProductScalar takes thistype v1, thistype v2 returns real
            return (.y*v1.z - .z*v1.y)*v2.x + (.z*v1.x - .x*v1.z)*v2.y + (.x*v1.y - .y*v1.x)*v2.z
        endmethod
        
        method angle takes thistype v returns real
            static if debug then
                if (.x == 0 and .y == 0 and .z == 0) or (v.x == 0 and v.y == 0 and v.z == 0) then
                    call err("angle({Vector3D|x=" + v.x + ",y=" + v.y + ",z=" + v.z + "}): " + ERR_NULL_VECT_DIR)
                endif
            endif
            return Acos(.dotProduct(v)/(.getMag()*v.getMag()))
        endmethod
        
        method crossProduct takes thistype v returns thistype
            local real x = .y*v.z - .z*v.y
            local real y = .z*v.x - .x*v.z
            set .z       = .x*v.y - .y*v.x
            set .x = x
            set .y = y
            return this
        endmethod
        
        method tripleProductVector takes thistype v1, thistype v2 returns thistype
            local real x = .y*v1.z - .z*v1.y
            local real y = .z*v1.x - .x*v1.z
            local real z = .x*v1.y - .y*v1.x
            set .x = y*v2.z - z*v2.y
            set .y = z*v2.x - x*v2.z
            set .z = x*v2.y - y*v2.x
            return this
        endmethod
        
        method projectionVector takes thistype dir returns thistype
            local real l
            static if debug then
                if .x == 0 and .y == 0 and .z == 0 then
                    call err("projectionVector({Vector3D|x=0,y=0,z=0}): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set l = (.x*dir.x + .y*dir.y + .z*dir.z) / (dir.x*dir.x + dir.y*dir.y + dir.z*dir.z)
            set .x = dir.x*l
            set .y = dir.y*l
            set .z = dir.z*l
            return this
        endmethod
        
        method projectionPlane takes thistype normal returns thistype
            local real l
            static if debug then
                if .x == 0 and .y == 0 and .z == 0 then
                    call err("projectionPlane({Vector3D|x=0,y=0,z=0}): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set l = (.x*normal.x + .y*normal.y + .z*normal.z) / (normal.x*normal.x + normal.y*normal.y + normal.z*normal.z)
            set .x = .x - normal.x*l
            set .y = .y - normal.y*l
            set .z = .z - normal.z*l
            return this
        endmethod
        
        method unit takes nothing returns thistype
            local real m
            static if debug then
                if .x == 0 and .y == 0 and .z == 0 then
                    call err("unit(): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set m = .getMag()
            set .x = .x/m
            set .y = .y/m
            set .z = .z/m
            return this
        endmethod
        
        method invert takes nothing returns thistype
            set .x = -.x
            set .y = -.y
            set .z = -.z
            return this
        endmethod
        
        method scale takes real s returns thistype
            set .x = s*.x
            set .y = s*.y
            set .z = s*.z
            return this
        endmethod
        
        method rotate takes thistype axis, real angle returns thistype
            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
            local real f
            local real c
            local real s
            static if debug then
                if .x == 0 and .y == 0 and .z == 0 then
                    call err("rotate({Vector3D|x=0,y=0,z=0}, " + R2S(angle) + "): " + ERR_NULL_VECT_DIR)
                endif
            endif
            set al = axis.x*axis.x + axis.y*axis.y + axis.z*axis.z
            set f  = (this.x*axis.x + this.y*axis.y + this.z*axis.z) / al
            set c  = Cos(angle)
            set s  = Sin(angle)
            set zx = axis.x*f
            set zy = axis.y*f
            set zz = axis.z*f
            set xx = this.x-zx
            set xy = this.y-zy
            set xz = this.z-zz
            set al = SquareRoot(al)
            set yx = (axis.y*xz - axis.z*xy) / al
            set yy = (axis.z*xx - axis.x*xz) / al
            set yz = (axis.x*xy - axis.y*xx) / al
            set .x = xx*c + yx*s + zx
            set .y = xy*c + yy*s + zy
            set .z = xz*c + yz*s + zz
            return this
        endmethod
        
        method add takes thistype v returns thistype
            set .x = .x+v.x
            set .y = .y+v.y
            set .z = .z+v.z
            return this
        endmethod
        
        method sub takes thistype v returns thistype
            set .x = .x-v.x
            set .y = .y-v.y
            set .z = .z-v.z
            return this
        endmethod
        
        method addXYZ takes real x, real y, real z returns thistype
            set .x = .x+x
            set .y = .y+y
            set .z = .z+z
            return this
        endmethod
        
        method subXYZ takes real x, real y, real z returns thistype
            set .x = .x-x
            set .y = .y-y
            set .z = .z-z
            return this
        endmethod
    endstruct
    
    endlibrary


    How does it look to you?
     

Share This Page