Related
I have been scratching my head for days understanding how to fully describe a block to insert in DXF. For background I am interested in the rules and behaviour of how to do this, not simply trying to find an existing library.
I can create a block in dxf, lets say this is a simple cube. I can then in the Entities section insert this block.
To do this I enter the coordinates relative to the object coordinate system codes:(10, 20, 30), and the normal vector of the object codes:(210,220,230). There is also a value to rotate about the normal vector code: 50.
So there are two things to do:
Calculate the normal vector for my object
Calculate the object co-ordinates, given the world coordinates for the object.
To calculate the normal vector, I use quaternions to calculate the rotation applied to the world z-axis (0,0,1) if a yaw, pitch, or roll angle is applied (if not, I simply use the world z-axis). I can use the same quaternions to calculate the arbitrary x and y axis using the same rotation for each of the real world x and y axes.
For those looking for more info, this link has a very clear explanation of how to calculate them.
https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html
To help you, this calculator can help confirm if this has been implemented correctly or not by checking the results:
Rotation calculator
Then to calculate the object co-ordinates I simply cross multiply the world coordinate with each of the arbitrary axes/normal axes.
For most scenarios this appears to work. However I am left at a loss for additional rules and requirements which I cannot see documented anywhere:
If only a yaw angle is applied (rotation about z), then the normal is still (0,0,1). We need to apply a rotation about z in the scenario that pitch and roll are zero.
If I alter the pitch, the normal vector can change from a negative y-coordinate to a positive one. This change in slope appears to affect the direction the vector is headed and if positive, requires a rotation about the normal of 180 degrees to correct it.
For some unknown reason when I apply a roll angle, my object is rotated around the normal by 90 degrees, and I need to apply a correction here.
I am struggling to find any more clear direction on this online. Does anyone have any thorough explanations that describe the behaviour above, or any pointer material?
As suggested in another topic, a little matrix calculus can solve this issue.
Shortly, they are mainly two ways to describe the same Euler angles:
Tait-Bryan angles (yaw, pitch, roll) rotations about X, Y, Z axis;
Proper Euler angles (precession, nutation, intrisic rotation) rotations about Z, X, Z axis;
AutoCAD uses the second one to describe a bloc orientation. The combination of precession and nutation provides the OCS transformation matrix and the intrinsic rotation is the rotation value of the block.
A little F# example with 3x3 matrices to describe 3d rotations.
type vector = float list
module Vector =
// Computes the dot product of two vectors
let dotProduct (v1: vector) (v2: vector) = List.map2 (*) v1 v2 |> List.sum
type matrix(rows: vector list) =
// Gets the row vectors
member _.Rows = rows
// Transposes a matrix
member _.Transpose = List.transpose rows |> matrix
// Applies a matrix to a vector
static member (*)(m: matrix, v: vector) =
List.map (Vector.dotProduct v) m.Rows
// Multipies two matrices
static member (*)(m: matrix, q: matrix) =
let trp = q.Transpose
List.map (fun r -> trp * r) m.Rows |> matrix
// Describes a coordinate system data
type CoordinateSystem =
{ WcsToOcs: matrix
Normal: vector
Rotation: float }
// Matrix 3x3
module Matrix3x3 =
// Gets the identity matrix
let identity =
matrix [ [ 1.0; 0.0; 0.0 ]
[ 0.0; 1.0; 0.0 ]
[ 0.0; 0.0; 1.0 ] ]
// Gets the rotation matrix about X axis
let xRotation a =
matrix [ [ 1.0; 0.0; 0.0 ]
[ 0.0; cos a; -sin a ]
[ 0.0; sin a; cos a ] ]
// Gets the rotation matrix about Y axis
let yRotation a =
matrix [ [ cos a; 0.0; sin a ]
[ 0.0; 1.0; 0.0 ]
[ -sin a; 0.0; cos a ] ]
// Gets the rotation matrix about Z axis
let zRotation a =
matrix [ [ cos a; -sin a; 0.0 ]
[ sin a; cos a; 0.0 ]
[ 0.0; 0.0; 1.0 ] ]
// Creates the matrix according to Yaw, Pitch and Roll values
let createFromYawPitchRoll yaw pitch roll =
zRotation yaw * yRotation pitch * xRotation roll
// Gets the coordinate system data from a matrix 3x3
let getCoordinateSystem (mat: matrix) =
match mat.Rows with
| [ [ m00; m01; m02 ]; [ m10; m11; m12 ]; [ m20; m21; m22 ] ] ->
let nutation = acos m22
if abs nutation < 1e-8 then
{ WcsToOcs = identity
Normal = [ 0.0; 0.0; 1.0 ]
Rotation = atan2 m10 m11 }
else
let precession = atan2 m02 -m12
let spin = atan2 m20 m21
let xform =
(zRotation precession * xRotation nutation)
.Transpose
let normal = xform.Rows.Item 2
{ WcsToOcs = xform
Normal = normal
Rotation = spin }
| _ -> invalidArg "mat" "Invalid 3x3 matrix"
// Testing
module test =
let radians x = x * System.Math.PI / 180.0
// Input yaw, pitch, roll angles and WCS point
let yaw = radians 10.0
let pitch = radians 20.0
let roll = radians 30.0
let wcsPoint = [ 8.0; 5.0; 3.0 ]
// Computation of the coordinate system
let ocs =
Matrix3x3.createFromYawPitchRoll yaw pitch roll
|> Matrix3x3.getCoordinateSystem
let ocsPoint = ocs.WcsToOcs * wcsPoint
// Print results
printfn "Normal X (210): %f" (ocs.Normal.Item 0)
printfn "Normal Y (220): %f" (ocs.Normal.Item 1)
printfn "Normal Z (230): %f" (ocs.Normal.Item 2)
printfn "Rotation (50): %f" ocs.Rotation
printfn "OCS point X (10): %f" (ocsPoint.Item 0)
printfn "OCS point Y (20): %f" (ocsPoint.Item 1)
printfn "OCS point Z (30): %f" (ocsPoint.Item 2)
A C# implementation:
using static System.Math;
using static System.Console;
namespace CsharpMatrix3d
{
class Program
{
/// <summary>
/// Console testing
/// </summary>
static void Main()
{
double yaw = D2R(10.0);
double pitch = D2R(20.0);
double roll = D2R(30.0);
var wcsPoint = new Vector(8.0, 5.0, 3.0);
var ocs = ObjectCoordinateSystem.FromYawPitchRoll(yaw, pitch, roll);
var ocsPoint = ocs.WorldToPlane * wcsPoint;
WriteLine($"Normal X (210): {ocs.Normal.X}");
WriteLine($"Normal Y (220): {ocs.Normal.Y}");
WriteLine($"Normal Z (230): {ocs.Normal.Z}");
WriteLine($"Rotation (50): {ocs.Rotation}");
WriteLine($"OCS point X (10): {ocsPoint.X}");
WriteLine($"OCS point Y (20): {ocsPoint.Y}");
WriteLine($"OCS point Z (30): {ocsPoint.Z}");
}
static double D2R(double x) => x * PI / 180.0;
}
/// <summary>
/// Provides properties and method for an object coordinate system
/// </summary>
struct ObjectCoordinateSystem
{
public ObjectCoordinateSystem(Matrix3x3 m)
{
double nutation = Acos(m.Row2.Z);
if (Abs(nutation) < 1e-8)
{
Normal = new Vector(0.0, 0.0, 1.0);
Rotation = Atan2(m.Row1.X, m.Row1.Y);
WorldToPlane = Matrix3x3.Identity;
}
else
{
var precession = Atan2(m.Row0.Z, -m.Row1.Z);
WorldToPlane = (Matrix3x3.ZRotate(precession) * Matrix3x3.XRotate(nutation)).Transpose();
Normal = WorldToPlane.Row2;
Rotation = Atan2(m.Row2.X, m.Row2.Y);
}
}
public Vector Normal { get; }
public Matrix3x3 WorldToPlane { get; }
public double Rotation { get; }
public static ObjectCoordinateSystem FromYawPitchRoll(double yaw, double pitch, double roll) =>
new ObjectCoordinateSystem(
Matrix3x3.ZRotate(yaw) *
Matrix3x3.YRotate(pitch) *
Matrix3x3.XRotate(roll));
}
/// <summary>
/// Provides methods for vector calculus
/// </summary>
struct Vector
{
public Vector(double x, double y, double z)
{ X = x; Y = y; Z = z; }
public double X { get; }
public double Y { get; }
public double Z { get; }
public double DotProduct(Vector v) =>
X * v.X + Y * v.Y + Z * v.Z;
public static Vector operator *(Matrix3x3 m, Vector v) =>
new Vector(m.Row0.DotProduct(v), m.Row1.DotProduct(v), m.Row2.DotProduct(v));
}
/// <summary>
/// Provides methods for matrix calculus
/// </summary>
struct Matrix3x3
{
public Matrix3x3(Vector row0, Vector row1, Vector row2)
{ Row0 = row0; Row1 = row1; Row2 = row2; }
public Vector Row0 { get; }
public Vector Row1 { get; }
public Vector Row2 { get; }
public static Matrix3x3 Identity =>
new Matrix3x3(
new Vector(1.0, 0.0, 0.0),
new Vector(0.0, 1.0, 0.0),
new Vector(0.0, 0.0, 1.0));
public Matrix3x3 Transpose() =>
new Matrix3x3(
new Vector(Row0.X, Row1.X, Row2.X),
new Vector(Row0.Y, Row1.Y, Row2.Y),
new Vector(Row0.Z, Row1.Z, Row2.Z));
public static Matrix3x3 XRotate(double a) =>
new Matrix3x3(
new Vector(1.0, 0.0, 0.0),
new Vector(0.0, Cos(a), -Sin(a)),
new Vector(0.0, Sin(a), Cos(a)));
public static Matrix3x3 YRotate(double a) =>
new Matrix3x3(
new Vector(Cos(a), 0.0, Sin(a)),
new Vector(0.0, 1.0, 0.0),
new Vector(-Sin(a), 0.0, Cos(a)));
public static Matrix3x3 ZRotate(double a) =>
new Matrix3x3(
new Vector(Cos(a), -Sin(a), 0.0),
new Vector(Sin(a), Cos(a), 0.0),
new Vector(0.0, 0.0, 1.0));
public static Matrix3x3 operator *(Matrix3x3 a, Matrix3x3 b)
{
var trp = b.Transpose();
return new Matrix3x3(trp * a.Row0, trp * a.Row1, trp * a.Row2);
}
}
}
I know the following:
P (x,y coordinates).
A1 and A2 (angles in degrees)
R (radius of circle).
Now I need to calculate a center for the green circle, as to make it 'tangentize?' the two blue lines (it will later be minkowski'ed with other shapes to form a point of a rounded triangle).
Any help will be appreciated!
My code for the depicted example:
//KNOWNS
P=[-3.0,1.0,0.0];
A1=60; A2=-5;
R=5;
//UNKNOWN
SECRET_CALCULATION = [8.2,4.3,0];//???
//ILLUSTRATION
C0=[0,0,0,1]; C1=[0,1,1,0.3]; C2=[0,1,0,0.4]; C3=[1,0,0,0.4];//Colors
translate(P){
color(C1) rotate(A1) translate([0,-0.5,0]) square([250,1],0);
color(C1) rotate(A2) translate([0,-0.5,0]) square([250,1],0);
color(C2) translate(SECRET_CALCULATION) circle(R);
}
//EXPLANATIONS
color(C0) translate(P) {
translate(SECRET_CALCULATION){
translate([0,-0.2,0]) square([R,0.4],0);
translate([R+1,0,0]) rotate(-90) text(str("R:",R),halign="center",valign="top",0.75);
translate([0,0.2,0]) text("[x?,y?,0]",halign="center",valign="bottom",0.75);
}
rotate(((A1-A2)/2)-90) translate([0,-1,0]) text(str("P: ",P),halign="center",valign="top",0.75);
rotate(A1) text(str(" A1: ",A1,"°"),halign="left",valign="center",0.75);
rotate(A2) text(str(" A2: ",A2,"°"),halign="left",valign="center",0.75);
}
Center of circle lies at the bisector of rays A1 and A2. So we can find direction for this bisector as
B = (A1 + A2) / 2 = 27.5 here
(but don't forget about angle normalization - angle -5 might be represented as 355 and so on)
And angle between bisector and A1 or A2 is
D = (A1 - A2) / 2 = 32.5 here
We can see that points C(enter)-T(angentpoint)-P form right triangle with relation
L (P-C, DistAlongBisector) = R / Sin(D)
So we can find center coordinates as
C.X = P.X + Cos(B) * L
C.Y = P.Y + Sin(B) * L
Quick hand-check gives
L=5/Sin(32.5)=9.3
C.X = -3 + Cos(27.5)*9.3 = 5.24
C.Y = 1 + Sin(27.5)*9.3 = 5.3
when I use NuSMV tools to verify if my CTL is right, I encounter a problem that make me so confused.
My model is
and here's the NuSMV code:
MODULE main
VAR
state : {ROOT, A1, B1, C1, D1, F1, M1};
ASSIGN
init(state) := ROOT;
next(state) := case
state = ROOT : A1;
state = A1 : {B1, C1};
state = B1 : D1;
state = D1 : F1;
TRUE : state;
esac;
CTLSPEC
AG( state=A1 -> AX ( A [ state=B1 U ( state=D1 -> EX state=F1 ) ] ) );
CTLSPEC
AG( state=A1 -> AX ( A [ state=B1 U ( state=F1 -> EX state=C1 ) ] ) );
CTLSPEC
AG( state=A1 -> AX ( A [ state=M1 U ( state=F1 -> EX state=C1 ) ] ) );
My CTL formula is as follows:
"AG( A1 -> AX ( A [ B1 U ( D1 -> EX ( F1) ) ] ) )"
"AG( A1 -> AX ( A [ B1 U ( F1 -> EX ( C1) ) ] ) )"
"AG( A1 -> AX ( A [ M1 U ( F1 -> EX ( C1) ) ] ) )"
NuSMV verified the above three formulas all of which turns out to be true .
So my question is that why the formula 2 and formula 3 turn out to be true?
This question is old, but I think it's still worth an answer, as the issue might be misleading for other people.
M, s ⊨ A[ϕUψ] iff for all paths (s, s2,s3, s4, . ..) s.t. si Rt si+1 there is a state sj s.t. M, sj ⊨ ψ and M, si ⊨ ϕ for all i < j.
So, for the property to be verified, ϕ must be true up until when ψ fires.
Notice that if ψ fires immediately then the value of ϕ is not relevant.
It is easy to see that all three formulas are trivially verified because ψ is true in the first state of each path starting from B1 and C1.
This is the case because ψ is an implication which, in states B1 and C1, has a false premise.
Since we know that A [ ANYTHING U TRUE ] is verified for any state, we conclude that all three properties are satisfiable.
I am new to unity3d I want to make a path for animated object.
The path must be # elliptical circle # or # spring shape path #
I think there is a way to draw this path based on mathematics equation is it true?
or should I draw it using 3dmax.
Any help or related tutorial for this problem?
thanks
This is a helpful link for drawing a path w/ the mouse in game.
If you want to draw a spring programmatically you can use a Catmullrom or Bezier spline:
double bezier(double t, double p0,double p1,double p2,double p3){
double t2 = t*t;
double t3 = t2 * t;
return (0.16667 *( t3 * (-p0 + 3 * p1 + -3 * p2 + p3) + \
t2 * (3 * p0 + -6 * p1 + 3 * p2) + \
t * (-3*p0 + 3*p2) + \
1 * (p0 + 4*p1 + p2)));
}
double catmullrom(double t, double p0,double p1,double p2,double p3){
double t2 = t*t;
double t3 = t2 * t;
return (0.5 *( (2 * p1) + (-p0 + p2) * t +(2*p0 - 5*p1 + 4*p2 - p3) * t2 +(-p0 + 3*p1- 3*p2 + p3) * t3));
}
The inputs p0,p1,p2,p3 are the 4 control points for a particular segment. To see a spiral building example, the rest of this code can be found on my Github page. Look at BuildPath() in particular to see how to use those functions to build a continuous path. I dislike linking to external accounts but my usage example is a little too big for an SO answer.
If you want to draw an ellipse, the simplest way I can think is to solve the basic equation and build a ring of points:
List<Vector3> pts = new List<Vector3>();
for(float x=-2.0f; x<2.0f;x+=0.1){
y = sqrt( (1-x^2/a^2) * b^2 );//from eq. x^2/a^2 + y^2/b^2=1;
pts.Add(new Vector3(x,y,0));
}
That code assumes you have a horizontal major axis where 'a' is the radius of the horizontal major axis, 'b' is the radius of the vertical minor axis. Build the ellipse first along the X/Y axes and then apply whatever transform you wish to orient the ellipse.
Alternatively, and I don't have code for this, you can use the general parametric equations to generate a rotated ellipse already off origin.
Given the input:
double x1,y1,x2,y2;
How can I find the general form equation (double a,b,c where ax + by + c = 0) ?
Note: I want to be able to do this computationally. So the equivalent for slope-intercept form would be something like:
double dx, dy;
double m, b;
dx = x2 - x1;
dy = y2 - y1;
m = dy/dx;
b = y1;
Obviously, this is very simple, but I haven't been able to find the solution for the general equation form (which is more useful since it can do vertical lines). I already looked in my linear algebra book and two books on computational geometry (both too advanced to explain this).
If you start from the equation y-y1 = (y2-y1)/(x2-x1) * (x-x1) (which is the equation of the line defined by two points), through some manipulation you can get (y1-y2) * x + (x2-x1) * y + (x1-x2)*y1 + (y2-y1)*x1 = 0, and you can recognize that:
a = y1-y2,
b = x2-x1,
c = (x1-x2)*y1 + (y2-y1)*x1.
Get the tangent by subtracting the two points (x2-x1, y2-y1). Normalize it and rotate by 90 degrees to get the normal vector (a,b). Take the dot product with one of the points to get the constant, c.
If you start from the equation of defining line from 2 points
(x - x1)/(x2 - x1) = (y - y1)/(y2 - y1)
you can end up with the next equation
x(y2 - y1) - y(x2 - x1) - x1*y2 + y1*x2 = 0
so the coefficients will be:
a = y2 - y1
b = -(x2 - x1) = x1 - x2
c = y1*x2 - x1*y2
My implementation of the algorithm in C
inline v3 LineEquationFrom2Points(v2 P1, v2 P2) {
v3 Result;
Result.A = P2.y - P1.y;
Result.B = -(P2.x - P1.x);
Result.C = P1.y * P2.x - P1.x * P2.y;
return(Result);
}
Shortcut steps:
"Problem : (4,5) (3,-7)"
Solve:
m=-12/1 then
12x-y= 48
"NOTE:m is a slope"
COPY THE NUMERATOR, AFFIX "X"
Positive fraction Negative sign on between.
(tip: simmilar sign = add + copy the sign)
1.Change the second set into opposite signs,
2.ADD y1 to y2 (means add or subtract them depending of the sign),
3.ADD x1 to x2 (also means add or subtract them depending of the sign),
4.Then Multiply 12 and 1 to any of the problem set.
After that "BOOM" Tada!, you have your answer
#include <stdio.h>
main()
{
int a,b,c;
char x,y;
a=5;
b=10;
c=15;
x=2;
y=3;
printf("the equation of line is %dx+%dy=%d" ,a,b,c);
}