09032006, 04:55 PM  #1 
Procrastination Incarnate
Development Director

Vector
Update: I have finished making a vJass version of this system. Vectors are implemented as a struct and all the operations that can be done with them have been greatly optimized. The vector methods should now be several times faster than the old functions. The post still contains the original nonvJass map if anyone needs it. Vector: 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 its 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 //* its 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 its 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 its 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 its 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.xsubtrahend.x set v.y = minuend.ysubtrahend.y set v.z = minuend.zsubtrahend.z return v endmethod method subtract takes vector subtrahend returns nothing set this.x=this.xsubtrahend.x set this.y=this.ysubtrahend.y set this.z=this.zsubtrahend.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("vector.setLength error: The length of the vector is 0.0!") 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*nc.x*m set v.y = b.y*nc.y*m set v.z = b.z*nc.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("vector.projectionVector error: The length of the direction vector is 0.0!") return 0 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("vector.projectVector error: The length of the direction vector is 0.0!") 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("vector.projectionPlane error: The length of the normal vector is 0.0!") return 0 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("vector.projectPlane error: The length of the normal vector is 0.0!") 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("vector.getAngle error: The length of at least one of the vectors is 0.0!") 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("vector.rotate error: The length of the axis vector is 0.0!") 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.xzx set xy = this.yzy set xz = this.zzz //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, xsampleRadius, y) set zx=GetLocationZ(vector.loc) call MoveLocation(vector.loc, x+sampleRadius, y) set zx=zxGetLocationZ(vector.loc) call MoveLocation(vector.loc, x, ysampleRadius) set zy=GetLocationZ(vector.loc) call MoveLocation(vector.loc, x, y+sampleRadius) set zy=zyGetLocationZ(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, xsampleRadius, y) set zx=GetLocationZ(vector.loc) call MoveLocation(vector.loc, x+sampleRadius, y) set zx=zxGetLocationZ(vector.loc) call MoveLocation(vector.loc, x, ysampleRadius) set zy=GetLocationZ(vector.loc) call MoveLocation(vector.loc, x, y+sampleRadius) set zy=zyGetLocationZ(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.xcylinderOrigin.x local real y = this.ycylinderOrigin.y local real z = this.zcylinderOrigin.z if x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z < 0.0 then //point below cylinder return false endif set x = xcylinderHeight.x set y = ycylinderHeight.y set z = zcylinderHeight.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("vector.isInCylinder error: The length of the cylinderHeight vector is 0.0!") 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.xconeOrigin.x local real y = this.yconeOrigin.y local real z = this.zconeOrigin.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("vector.isInCone error: The length of the coneHeight vector is 0.0!") 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.0l) then //point outside cone return false endif return true endmethod method isInSphere takes vector sphereOrigin, real sphereRadius returns boolean if sphereRadius*sphereRadius < ((this.xsphereOrigin.x)*(this.xsphereOrigin.x)+(this.ysphereOrigin.y)*(this.ysphereOrigin.y)+(this.zsphereOrigin.z)*(this.zsphereOrigin.z)) then return false endif return true endmethod endstruct endlibrary library VectorLib requires Vector // For backwards compatibility. endlibrary Last edited by Anitarf : 01232011 at 03:31 PM. 
Sponsored Links  Login to hide this ad! 

09032006, 07:39 PM  #2 
User
Join Date: Jan 2004
Posts: 388

Extremely useful. Thanks a lot for making this for everyone to use!
Just looked it over, and it even has TerrainNormal, that's smooth :) Had lot's of fun watching the bouncy ball forever and ever. Well, until it's always growing momentum med it bounce itself out of existance, dunno where it went. At one point it slid along the ground, painting it with 100+ bounce art effect. But in general, very smooth. Last edited by karukef : 09032006 at 07:59 PM. 
09032006, 09:11 PM  #3 
Moderator
Code Moderator
Join Date: Feb 2006
Posts: 1,405

Finally you submit this! The demonstration is beautiful. Approved.
__________________Constant accelerations produces parabolas. That very simple integration method will always increase or decrease energy since it can only exactly reproduce lines. If you flip the order of adding velocity/acceleration to position/velocity you'll see it decay instead of grow. Since the solution is exactly a parabola you can use an explicit formula. But if you want to be generic to non constant acceleration you can get the same exact integration of constant acceleration with a tiny bit more complexity: JASS: local integer k1v //unoptimized Runge Kutta 2 local integer k1x //Takes a trial half sized step local integer k2v //computes derivatives in middle of interval local integer k2x //uses those values to step from beginning to end set k1v = VectorAmplify(vectors[4],BouncyPeriod()*.5) set k1x = VectorAmplify(vectors[3],BouncyPeriod()*.5) set k2v = VectorAmplify(vectors[4],BouncyPeriod()) //recompute acceleration if it's time or position dependent set k2x = VectorSum(k1v,vectors[3]) call VectorScale(k2x,BouncyPeriod()) call VectorAdd(vectors[2],k2x) call VectorAdd(vectors[3],k2v) call VectorDestroy(k1v) call VectorDestroy(k1x) call VectorDestroy(k2v) call VectorDestroy(k2x) In general for spells the lack of conservation in the simple integrator is not a problem, but it will become one as you increase the time step. .01 is smaller than what is necessary for visually smooth. With this integrator you can safely increase to a less aggressive .03.05. 
09042006, 06:27 AM  #4  
Procrastination Incarnate
Development Director

Quote:
Quote:
Quote:
But in the end, it's up to the users to decide how to utilize these functions, for simple projectile parabola approximations or more detailed and complex physical models. 

09042006, 10:55 AM  #5 
BuranX

Anitarf  cool =) as for me your map (on the contest) was the best (after my XGMSoccer ;) ) real nice physic but have some problems with camera + how i remember you have a constant vector for "pushing" it was 0 degree... or not i don't remeber you must make it more terrain orintainted and not constant !
PS the only real sys what i respect... because of usage of GetLocationZ(). my TPC use it for Z correction. Anitarf  i all ready use it in my TPC =) for create more reallystic "bounces" but really the hole sys is to simple (i mean your example) but it's not areal problem + the performance is great ! PS the best system which i have ever seen ! (non my sys =) ) +10000 rep :D !!! Last edited by Toadcop : 09082006 at 03:17 PM. 
11112006, 03:57 PM  #6 
User

Anitarf, let me introduce Toadcop. He made a system, Toadcop's projectile creator. I don't feel like searching for it, I remember seeing a link at Infrane's PS. And his system allows to create dynamically moving projectiles with effects such as bounce, and other stuff...
I must admit that your sys is easier than TPC, I will not judge is it better, but it's easier. Toadcop, anytime you need help with english, drop me a PM. 
11112006, 07:20 PM  #7 
PhD
Cinematics Moderator

This system is not made for moving objects dynamically. This is for is using mathematical vectors, the demo map just has a moving ball to demonstrate the use.
__________________While this system is VERY usefull it is not a dynamically moving system on its own. My system uses these functions to calculate stuff. 
11212006, 11:48 AM  #8 
User

iNfraNe, I see, but I said it about geometrical base of these systems.
Last edited by ArchWorm : 11212006 at 11:50 AM. 
12202006, 04:04 AM  #9 
Banned
Join Date: Oct 2006
Posts: 858

ArchWorm look a poopie!
I noticed that by VECTOR he means SCALAR. A vector is a magnitude and direction combined, whilst a scalar is simply magnitude. For clarity, what he is doing is creating an x,y,Ø vector, and a 'z' scalar (for height). I will be releasing one of this humdingers not to compete with this one, but simply to polish up my math skills. GJ on this system I love the idea. Ø = Theta (angle) Edit: When going through it I was so confused how he incorporated height with vectors, but now I see they are just scalars. Edit: Oops sorry, I see the vectors now. This point has just been proven useless 'hoorah' Last edited by xombie : 12202006 at 08:16 AM. 
12202006, 09:46 AM  #10 
Moderator
Code Moderator
Join Date: Feb 2006
Posts: 1,405

A vector is not a magnitude and direction, it's something you can add with other vectors and scale. E.g., the real number line is a vector space, but the vectors have only one component. The scalars are the things you scale the vectors with, they can be either real or complex numbers. This package implements a three dimensional real vector space. All three components are part of the vector, but "x","y" and "z" are scalars, as they prescribe how much unit vector to scale and add to the mix.
__________________The vectors this system implements can be represented as magnitude and direction. For these two concepts you need a little more structure than the addition/scaling a vector space gives you. Once you add a dot product that maps two vectors to a scalar you can measure lengths and angles and think about a magnitude/direction representation. In practice you don't use that for actual computations since it's a nightmarish mess. 
12202006, 10:21 AM  #11 
Banned
Join Date: Oct 2006
Posts: 858

I don't even know why I bothered doubting him lol, I should have automatically known he was right.
 I haven't gotten around to learning anything 3D in mathematics or physics (I'm in grade 12, and I take AP Calculus  basically means 1st year university calculus), my knowledge in the area of this is very scarce, and would appreciate learning. I've figured out a rough outline using a pen and paper on how this goes about working, but I would appreciate it if you or Anitarf could PM me a simple but thorough explanation of everything that is going on in this system. I could try to talk to Anitarf sometime on BNet but things like this intrigue me and I'd like to learn more. PS. Until then I'm going to be thoroughly looking through the map getting a better understanding of it  something I should be learning in school but hey! school sucks and doesn't teach you jack. Edit: Oh shit doublepost, I'll fix this. ______________________________________________________________________________________ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ JASS: function BouncyBallCreate takes nothing returns nothing local integer array vectors local timer t set udg_BouncyBall = CreateUnit(Player(0), 'ewsp', 0.0,0.0,0.0) // make it possible to change the unit's flyheight call UnitAddAbility(udg_BouncyBall, 'Amrf') call UnitRemoveAbility(udg_BouncyBall, 'Amrf') // create the unit's position vector set vectors[1]=VectorCreate(0.0,0.0,100.0) // create the unit's starting speed vector set vectors[2]=VectorCreate(GetRandomReal(100.0, 100.0)*BouncyPeriod(),GetRandomReal(100.0, 100.0)*BouncyPeriod(),500.0*BouncyPeriod()) // create the gravity acceleration vector set vectors[3]=VectorCreate(0.0, 0.0, 800.0*BouncyPeriod()*BouncyPeriod()) // to avoid having too many variables, we store these vectors into another vector set vectors[4]=VectorCreate(I2R(vectors[1]), I2R(vectors[2]), I2R(vectors[3])) call SetUnitUserData(udg_BouncyBall, vectors[4]) set t = CreateTimer() call TimerStart(t, BouncyPeriod(), true, function BouncyBallMove ) endfunction In your fourth vector creation, what do you convert the values to integers for? Also, more specifically than before: In your setting of vectors[1] you give the 'z' a value of 100.00. Later, in vectors[2], you create ANOTHER vector, equal to 5. Then, again, in vectors[3], you add an acceleration of gravity. I'm completely lost as to what you are doing here. Last edited by xombie : 12212006 at 06:40 AM. 
12212006, 03:32 PM  #12 
PhD
Cinematics Moderator

Actually, the 4th vector is being used as a storing method for the other 3. The beauty of this system is that it can link 3 reals to 1 integer. So what the 4th does is link the other 3 vectors to it, so they can be selected trough 1 integer. It actually, unlike the other 3, has nothing mathematical about it.
__________________on an offtopic note: your signature function would crash the WE since its lacking a return statement. Last edited by iNfraNe : 12212006 at 03:33 PM. 
12212006, 09:36 PM  #13 
Procrastination Incarnate
Development Director

What you were looking at is the initialization function. It just creates the three basic vectors that the bouncy ball needs: one to determine it's position, what's it's offset from the origin of the map; another to determine it's speed, how much does it move in one time unit; another to determine it's acceleration, how much does the speed change in one time unit. The fourth one has nothing to do with physics but is used as a data structure. Under it's "coordinates" it stores the IDs of the before mentioned 3 vectors.
__________________Then you have a periodic timer that calls the function that moves the ball every time unit. 
12252006, 07:53 AM  #14 
MaD Da ViNci
Respected User
Join Date: Apr 2003
Posts: 1,699

this system totally owns :D
__________________ 
12252006, 03:34 PM  #15 
User
Join Date: Sep 2006
Posts: 16

So I guess you need to know JASS to use it?
__________________ 
Thread Tools  Search this Thread 

