Maths: Angle of line between points
#1

Hi. It's no secret I'm rubbish at maths, even though I got an A at school..

I'll try to explain this as clearly as possible. It's relatively complex maths, so please only try and help if you know what you're doing.

I'm trying to adjust an object's rotation to place it on a slope. In this instance, I'm trying to make it so when a spike strip is placed on a sloped surface (e.g. the hills in San Fierro) it adjusts its rotation to that of the hill.

I'm at a good starting point - I've got the Z height of each end of the spike strip relative to the ground using MapAndreas. I just need to work out the rotation to set on the object for it to line up with said points.

To illustrate my problem, I made a diagram:


Point A is the lowest point, and Point B is the highest point (z coordinate). These may be reversed. The red line is the spike strip. As you can see, it's at an angle of about 45 degrees to line up with the points. The question is, how do I get this angle from the Z value of point a and b? The rotation of the object that needs to be changed to match these coordinates is the X rotation. I need to do the same for the Y rotation, but I guess it would be easy to do after I can do the X? If not I'd need to know how to do that also.

I've been researching this for hours, and here are some of the results I've found:
http://stackoverflow.com/questions/7...orizontal-axis
http://math.stackexchange.com/questi...117-833-80-550
http://stackoverflow.com/questions/2...wo-points-java

I've tried intensely to get this to work, but it's not even close. I don't even know if you need to use atan2 or not.

If someone could help me out with this I'd appreciate it so much. Thank you in advance.

NOTES:
- The object's rotation is relative to itself, which makes it easier.
- The object can be placed in any rotation however, which may or may not affect this. I don't think so?
- Angles in GTA:SA are reversed (counter-clockwise). East is 270 when you'd expect it to be 90.

P.S. If you still don't understand what I'm trying to do, please let me know and I'll try and explain it differently.
Reply
#2

I used similar math here to set correct rotation for NPCs:
https://sampforum.blast.hk/showthread.php?tid=570188

You can try this:
Код:
static stock GetAimVector(Float:origin[3], Float:target[3], Float:out[3])
{
	new Float:diff[3];
	VectorDiff(origin, target, diff);
	GetUnitVector(diff, out);
}
In your case:
origin = point B
target = point A

then use this:
Код:
static stock GetRotFromAim(Float:vecAim[3], &Float:yaw, &Float:pitch, &Float:roll)
{
	yaw = atan2(vecAim[0], -vecAim[1]) + 180.0;
	pitch = -asin(vecAim[2]);
	roll = pitch * (-floatsin(yaw, degrees));
	pitch = pitch * floatcos(yaw, degrees);
}
In GTA yaw is the rotation around Z axis. Pitch and Roll should be X,Y or Y,X don't remember. So basically the aim vector tells your object where to "look". So your object should "look down" along the slope. Maybe this code needs some modification, but it works perfectly fine for PEDs. All the code I wrote is in RPG.inc
Reply
#3

MapAndreas can indeed calculate the RX/RY of a slope from there you would need to calculate the z-rotation with another function here is what I have for doing this. The other way to do this is with ColAndreas (Soon to be released) which is 100 percent accurate.

1.) Calculating the RX/RY slope.
pawn Код:
stock CalcSlopeAtPoint(Float:posx, Float:posy, &Float:RXAngle, &Float:RYAngle)
{
    new Float:North[3], Float:South[3], Float:East[3], Float:West[3], Float:opposite, Float:hypotenuse;

    // Set slope positions
    North[0] = posx;
    North[1] = posy + 1;

    South[0] = posx;
    South[1] = posy - 1;

    East[0] = posx + 1;
    East[1] = posy;

    West[0] = posx - 1;
    West[1] = posy;

    // Use map andreas to get Z Values
    MapAndreas_FindZ_For2DCoord(North[0], North[1], North[2]);
    MapAndreas_FindZ_For2DCoord(South[0], South[1], South[2]);
    MapAndreas_FindZ_For2DCoord(East[0], East[1], East[2]);
    MapAndreas_FindZ_For2DCoord(West[0], West[1], West[2]);

    // Calculate Slope angles
    // North South RX
    hypotenuse = getdist3d(North[0], North[1], North[2], South[0], South[1], South[2]);
    opposite = getdist3d(North[0], North[1], North[2], North[0], North[1], South[2]);

    RXAngle = asin(floatdiv(opposite, hypotenuse));
    if(South[2] > North[2]) RXAngle *= -1;

    // West East RY
    hypotenuse = getdist3d(West[0], West[1], West[2], East[0], East[1], East[2]);
    opposite = getdist3d(West[0], West[1], West[2], West[0], West[1], East[2]);

    RYAngle = asin(floatdiv(opposite, hypotenuse));
    if(East[2] > West[2]) RYAngle *= -1;
}
2.) Rotating an object Z rotation while maintaining RX/RY rotation relative to the slope.

Credits: Stylock for this function
pawn Код:
stock ObjectRotateZ(Float:RX, Float:RY, Float:RZ, Float:rot_z, &Float:NewRX, &Float:NewRY, &Float:NewRZ)
{
    new
        Float:sinx,
        Float:siny,
        Float:sinz,
        Float:cosx,
        Float:cosy,
        Float:cosz;

    FloatConvertValue(RX, RY, RZ, sinx, siny, sinz, cosx, cosy, cosz);
    // Convert from one euler angle sequence (ZXY) to another and add the rotation
    FloatConvertValue(asin(cosx * cosy), atan2(sinx, cosx * siny) + rot_z, atan2(cosy * cosz * sinx - siny * sinz, cosz * siny - cosy * sinx * -sinz),
        sinx, siny, sinz, cosx, cosy, cosz);

    // Convert back to the original euler angle sequence and apply the new rotation to the object
    NewRX = asin(cosx * siny),
    NewRY = atan2(cosx * cosy, sinx),
    NewRZ = atan2(cosz * sinx * siny - cosy * sinz, cosy * cosz + sinx * siny * sinz);
    return 1;
}

stock FloatConvertValue(Float:rot_x, Float:rot_y, Float:rot_z, &Float:sinx, &Float:siny, &Float:sinz, &Float:cosx, &Float:cosy, &Float:cosz)
{
    sinx = floatsin(rot_x, degrees);
    siny = floatsin(rot_y, degrees);
    sinz = floatsin(rot_z, degrees);
    cosx = floatcos(rot_x, degrees);
    cosy = floatcos(rot_y, degrees);
    cosz = floatcos(rot_z, degrees);
    return 1;
}
Reply
#4

Quote:
Originally Posted by ******
Посмотреть сообщение
I toyed with not posting this as I don't want to discourage you and I don't have a full answer for you, but equally I didn't want you to just end up being apparently ignored.

Unfortunately, since object rotations use Eular angles not quaternions, I suspect you will suffer from what is called gimble-lock when trying to do this, meaning that some angles (since you will need to rotate around all three axes) can't be done.



Adding in a second rotation makes it insanely hard, for what seems like it should be simple! Basically, the question is what is your angle relative to? If I rotate something 10° around the Z axis (easy), and then want to rotate it 10° around the Y axis, WHICH Y axis do I use - the original Y relative to the world, which the car used to be aligned along, or the new Y axis relative to the vehicle? Both methods have problems, in fact both methods very quickly break down. Three component angles are fine if you only want to change one, in that case everything is simple.
The rotation of an object is relative to itself. I've just done some testing with various angles (all 3) and gimbal-lock didn't occur even once. However, that being said, I have encountered gimbal-lock on objects in the past, but only when rotating by like 180 degrees to the point at which two axis align. The rotation should never go past about 45 degrees so I guess it's okay.

@Pottus & bartekdvd:
That's a lot to take in. I will do my best to try and work this out. Thanks for the help!

@Pottus: Could you explain the parameters of ObjectRotateZ please? (e.g. what is the different between RZ and rot_z?)
Reply
#5

You just put in all known values.

RX, RY from your slope calculation for RX, RY and 0.0 for RZ (Initial rotation) rot_z is the amount of Z rotation you want which is equal to the the facing angle of the player/vehicle.

I think bartek might be thinking of something else here that would seem to work for translating aiming vectors to rotation but he needs to sample the map it's self (collision) to do this.
Reply
#6

Working great Pottus, thank you! My only problem now is that the spike strips are placed under the road when the slope is extreme, depending on the angle. If I face north, it's 0.5 meters under the road, and if I face south it's 0.5 meters above. I assume this attributed to the low resolution of the data in Map Andreas (1x1 squares), so I tried MapAndreas_FindAverageZ but this made it worse..
Reply
#7

I found this and I think it may help...http://forum.sa-mp.com/archive/index.php/t-422306.html

Code:
pawn Код:
stock ObjectRotateZ(Float:RX, Float:RY, Float:RZ, Float:rot_z, &Float:NewRX, &Float:NewRY, &Float:NewRZ)
{
new
Float:sinx,
Float:siny,
Float:sinz,
Float:cosx,
Float:cosy,
Float:cosz;

FloatConvertValue(RX, RY, RZ, sinx, siny, sinz, cosx, cosy, cosz);
// Convert from one euler angle sequence (ZXY) to another and add the rotation
FloatConvertValue(asin(cosx * cosy), atan2(sinx, cosx * siny) + rot_z, atan2(cosy * cosz * sinx - siny * sinz, cosz * siny - cosy * sinx * -sinz),
sinx, siny, sinz, cosx, cosy, cosz);

// Convert back to the original euler angle sequence and apply the new rotation to the object
NewRX = asin(cosx * siny),
NewRY = atan2(cosx * cosy, sinx),
NewRZ = atan2(cosz * sinx * siny - cosy * sinz, cosy * cosz + sinx * siny * sinz);
return 1;
}

stock FloatConvertValue(Float:rot_x, Float:rot_y, Float:rot_z, &Float:sinx, &Float:siny, &Float:sinz, &Float:cosx, &Float:cosy, &Float:cosz)
{
sinx = floatsin(rot_x, degrees);
siny = floatsin(rot_y, degrees);
sinz = floatsin(rot_z, degrees);
cosx = floatcos(rot_x, degrees);
cosy = floatcos(rot_y, degrees);
cosz = floatcos(rot_z, degrees);
return 1;
}
Reply
#8

Yes it's the low resolution of MapAndreas just stick it out for now then you can exchange MapAndreas for ColAndreas down the road.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)