How to use this DXF Bulge Arc function getArcDataFromBulge()? - delphi

I have a problem to use this bulge arc (dxf parser) function in C++ getArcDataFromBulge().
https://github.com/Embroidermodder/Embroidermodder/blob/master/libembroidery/geom-arc.c
I have my drawArc() function which need 'start angle' and 'sweep angle' parameters from this getArcDataFromBulge() function.
My drawArc() function use OpenGL 2D coordinate system with right side zero angle position and when I get values from getArcDataFromBulge() and recalculate it (0+-, 180+-, 360+-) I have something like unexpected opposite angles as results. It looks like clockwise-counterclockwise problem, but I'm think is not, I'm not sure. Do you have some idea what is going on?
For example:
tempBulge.bulge := 0.70;
arcMidAngle := RadToDeg( atan2(tempBulge.arcMidY - tempBulge.arcCenterY,
tempBulge.arcCenterX - tempBulge.arcMidX) );
After calculaton: arcMidAngle = 179.999
When I add and subtract from this point half of arc chord angle, I get start and end angles of my arc: 90°, 270° but it's not the same arc when I open dxf with some CAD software, it is opposite than origin drawing.

If you have an arc from 0° to 90°, it could be a 1/4 circle or a 3/4 circle.
You need to parse the $ANGDIR and $ANGBASE variables from the HEADER section which tells you in which direction angles are defined ($ANGDIR) and where the 0° angle starts ($ANGBASE) within that specific DXF file:
Variable Group code Description
$ANGBASE 50 Angle 0 direction
$ANGDIR 70 1 = Clockwise angles, 0 = Counterclockwise
For DXF, if $ANGBASE = 0, then 0° is on the right of the center, alike Windows.
Furthermore, in DXF, the positive Y-axis is upwards, in contrast to many Windows API's where the positive Y-axis is downwards.

Related

Lua Ti-Nspire fillArc() not working as expected

I have this code:
platform.window:invalidate()
function on.paint(gc)
gc:setColorRGB(0,0,0)
for i=1,8,1 do
gc:fillArc(230,(i*30)-40,30,30,45,360-(i*60))
end
end
if you look at the first iteration, where i=1, the circle should be drawn from 45° - 300° counter-clockwise. This isn't what happens. The circle is drawn from what looks like 45° to 345°, which obviously is undesirable.
Some other odd occurrences happen when drawing other circles, which makes them seem flipped, or mirrored or something like that when drawn. This oddity can be replicated by inputting different values into the 2 last arguments of fillArc(). 90 and 270 draws from 90 to 360. 180 and 270 draws from 180 to 90. Why is this occurring?
https://imgur.com/a/Miww8
I don't have a device to test this on, but from what you are describing it looks like the "end angle" argument is taken to be relative to the "start angle", so 90 and 270 will be drawn from 90 to 90+270. This would not be my reading of the documentation -- "The arc is drawn beginning at startAngle degrees and ending at endAngle." -- but it can probably be interpreted either way.

Quaternions, rotate a model and align with a direction

Suppose you have quaternion that describes the rotation of a 3D Model.
What I want to do is, given an Object (with rotationQuaternion, side vector...), I want to align it to a target point.
For a spaceship, I want the cockpit to point to a target.
Here is some code I have ... It's not doing what I want and I don't know why...
if (_target._ray.Position != _obj._ray.Position)
{
Vector3 vec = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);
float angle = (float)Math.Acos(Vector3.Dot(vec, _obj._ray.Direction));
Vector3 cross = Vector3.Cross(vec, _obj._ray.Direction);
if (cross == Vector3.Zero)
cross = _obj._side;
_obj._rotationQuaternion *= Quaternion.CreateFromAxisAngle(cross,angle);
}
// Updates direction, up, side vectors and model Matrix
_obj.UpdateMatrix();
after some time the rotationQuaternion is filled with almost Zero at X,Y,Z and W
Any help?
Thanks ;-)
This is a shortcut I've used to get the quaternion for lock-on-target rotation:
Matrix rot = Matrix.CreateLookAt(_arrow.Position, _cube.Position, Vector3.Down);
_arrow.Rotation = Quaternion.CreateFromRotationMatrix(rot);
For this example, I'm rendering an arrow and a cube, where the cube is moving around in a circle, and with the above code the arrow is always pointing at the cube. (Though I imagine there are some edge cases when cube is exactly above or below).
Once you get this quaternion (from spaceship to target), you can use Quaternion.Lerp() to interpolate between current ship rotation and the aligned one. This will give your rotation a smooth transition (not just snap to target).
Btw, might be that your rotation gets reduced to zero because you're using *= when assigning to it.
Your code's a bit funky.
if (_target._ray.Position != _obj._ray.Position)
{
This may or may not be correct. Clearly, you've overridden the equals comparator. The correct thing be be doing here would be to ensure that the dot-product between the two (unit-length) rays is close to 1. If the rays have the same origin, then presumably have equal 'positions' means they're the same.
Vector3 vec = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);
This seems particularly wrong. Unless the minus operator has been overridden in a strange way, subtracting this way doesn't make sense.
Here's pseudocode for what I recommend:
normalize3(targetRay);
normalize3(objectRay);
angleDif = acos(dotProduct(targetRay,objectRay));
if (angleDif!=0) {
orthoRay = crossProduct(objectRay,targetRay);
normalize3(orthoRay);
deltaQ = quaternionFromAxisAngle(orthoRay,angleDif);
rotationQuaternion = deltaQ*rotationQuaternion;
normalize4(rotationQuaternion);
}
Two things to note here:
Quaternions are not commutative. I've assumed that your quaternions are rotating column vectors; so I put deltaQ on the left. It's not clear what your *= operator is doing.
It's important to regularly normalize your quaternions after multiplication. Otherwise small errors accumulate and they drift away from unit length causing all manner of grief.
OMG! It worked!!!
Vector3 targetRay = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);
Vector3 objectRay = Vector3.Normalize(_obj._ray.Direction);
float angle = (float)Math.Acos(Vector3.Dot(targetRay, objectRay));
if (angle!=0)
{
Vector3 ortho = Vector3.Normalize(Vector3.Cross(objectRay, targetRay));
_obj._rotationQuaternion = Quaternion.CreateFromAxisAngle(ortho, angle) * _obj._rotationQuaternion;
_obj._rotationQuaternion.Normalize();
}
_obj.UpdateMatrix();
Thank you very much JCooper!!!
And niko I like the idea of Lerp ;-)

Corona SDK: How to make object move forward?

I have a physics body, and I want it to move forward in the direction that it is facing. I'm only thirteen which I hope explains why I'm so bad at trigonometry. Can anyone tell me how to do this in Corona?
I'm gonna assume you want to push your object with a force. Either way we'll need to get an x and y component of the direction your body is facing. Here's how to get the x and y from the rotation angle:
-- body is your physics body
local angle = math.rad(body.rotation) -- we need angle in radians
local xComp = math.cos(angle) -- the x component
local yComp = -math.sin(angle) -- the y component is negative because
-- "up" the screen is negative
(note: if this doesn't give the facing direction, you may need to add 90, 180, or 270 degrees to your angle, for example: math.rad(body.rotation+90) )
The above code will give you the x and y components of the unit vector in the direction of the rotation. You'll probably also need some multiplier to get the magnitude of force you want.
local forceMag = 0.5 -- change this value to apply more or less force
-- now apply the force
body:applyLinearImpulse(forceMag*xComp, forceMag*yComp, body.x, body.y)
Here's where I got the math: http://www.mathopenref.com/trigprobslantangle.html. Using a unit vector simplifies the math because the hypotenuse is always 1
How about making your own character moving towards an angle before using the confusing physics?
angle = math.rad(Insert the angle you want here)
character.x = character.x - math.sin(angle)
character.y = character.y + math.cos(angle)
Er. You don't need Trigonometry just to move the object.
Add
object:translate(distanceToMoveInXAxis,distanceToMoveInYAxis)
Or if you want to perform a transition,
transition.to(object,{x=object.x + distanceToMoveInXAxis,y=object.y + distanceToMoveInYAxis})

Problem rotating simple line image

It is stated, that to rotate a line by a certain angle, you multiply its end point coordinates by the matrix ({Cos(a), Sin(a)} {-Sin(a) Cos(a)}), where a is rotation angle. The resulting two numbers in matrix will be x and y coordinates of rotated line's end point. Rotation goes around line's start point.
Simplifying it, new coordinates will be {x*Cos(a) - y*Sin(a)} for x and {x*Sin(a) + y*Cos(a)} for y.
Task is to rotate a triangle, using this method. But the following code that uses this method, is giving out some crap instead of rotated image (twisted form of original triangle, rotated by "random" angle):
x0:=200;
y0:=200;
bx:=StrToInt(Edit1.Text);
by:=StrToInt(Edit2.Text);
cx:=StrToInt(Edit4.Text);
cy:=StrToInt(Edit5.Text);
a:=StrToInt(Edit3.Text);
//Original triangle
Form1.Canvas.Pen.Color:=clBlue;
Form1.Canvas.MoveTo(x0,y0);
Form1.Canvas.LineTo(bx,by);
Form1.Canvas.LineTo(cx,cy);
Form1.Canvas.LineTo(x0,y0);
//New triangle
Form1.Canvas.Pen.Color:=clGreen;
Form1.Canvas.MoveTo(x0,y0);
b1x:=Round(bx*cos(a*pi/180)-by*sin(a*pi/180));
b1y:=Round(bx*sin(a*pi/180)+by*cos(a*pi/180));
c1x:=Round(cx*cos(a*pi/180)-cy*sin(a*pi/180));
c1y:=Round(cx*sin(a*pi/180)+cy*cos(a*pi/180));
Form1.Canvas.LineTo(b1x,b1y);
Form1.Canvas.MoveTo(x0,y0);
Form1.Canvas.LineTo(c1x,c1y);
Form1.Canvas.LineTo(b1x,b1y);
end;
Well, I'm out of ideas. What am I doing wrong?
Thanks for your time.
The formula you are using rotates a point around (0, 0). To achieve the required result change your calculation to:
b1x:=x0 + Round((bx-x0)*cos(a*pi/180)-(by-y0)*sin(a*pi/180));
b1y:=y0 + Round((bx-x0)*sin(a*pi/180)+(by-y0)*cos(a*pi/180));
c1x:=x0 + Round((cx-x0)*cos(a*pi/180)-(cy-y0)*sin(a*pi/180));
c1y:=y0 + Round((cx-x0)*sin(a*pi/180)+(cy-y0)*cos(a*pi/180));
You appear to be rotating each individual line round its initial start point coordinates. So line 1 will get rotated about its start point (x0,y0); then line 2 will get rotated about bx,by; then line 3 will get rotated round cx. This will result in a twisted triangle. Instead you will need to rotate all three lines round the start point of the first line.

How do I CFrame parts?

I've heard that you can tilt a part by a precise amount using the .CFrame property. However, I'm unclear on how to use it. The following code does not work:
Workspace.Part.CFrame = CFrame.new(90,0,45)
It is not rotating the part by 90 degrees and 45 degrees. What am I doing wrong?
First, use the CFrame.fromEulerAnglesXYZ function to create a new CFrame pointing in the direction you wish. Then, use Vector3 math to move the CFrame into the desired position.
EG.
local cframe = CFrame.fromEulerAnglesXYZ(XRADIANS, YRADIANS, ZRADIANS)
cframe = (cframe - cframe.p) + Vector3.new(XPOS,YPOS,ZPOS)
The documentation states that a Coordinate Frame (CFrame) constructor that takes 3 parameters is defining a position offset. Therefore, your example code would move the part 90 along the x-axis and 45 along the z-axis. To perform a rotation as you attempted see the CFrame.fromEulerAnglesXYZ function.
The arguments taken specify position, not rotation
I had this trouble too when I was starting to CFrame. They are RADIANS, not DEGREES. I have written a quick CFraming guide on ROBLOX, here.
If you're struggling with radians, you should look at the ROBLOX wiki page on radians to gain a basic understanding: wiki.roblox.com/index.php/Radians
Thanks!
-pighead10
-- Rotates the part by 90 degrees. If you want to change the axis your
-- rotating it on Use a different placement such as CFrame.Angles(math.rad(90),0,0)
Workspace.Part.CFrame = Workspace.Part.CFrame * CFrame.Angles(0, math.rad(90), 0)

Resources