Mathematical library
In the CAD secondary development, the correct use of mathematics library is very important, we do not need a lot of mathematics, only need to ordinary four operations and call the api provided by mxcad.
We know through the Quick Start that if you open the drawing and want to perform various processing on the graph, you need a variety of calculations, mxcad provides some classes to participate in the calculation or represent some data structures.
Mathematical system of geometric graphic information
In cad, there are many different ways to describe the vertices, edges, lines, surfaces, bodies, and other kinds of information of a graph, and if we use different drawing systems, each drawing system may have a unique way or a specific API to solve a specific problem or class of problems
Because there are so many tools to choose from, it can be difficult to find the right one.
And if we only have the tools to solve specific problems, without a unified methodology, then we can't solve the root of the problem once and for all.
Therefore, in graphics, a simple mathematical system based on vector and matrix operations is established to describe the information of geometric graphics independent of each graphics system, and how to use this system to solve the problem of visual graphics presentation.
Coordinate system and coordinate mapping
First let's look at some of the coordinate systems that mxcad might use:
HTML uses the upper left corner of the window coordinate system as the origin of coordinates, x axis to the right, y axis down, coordinate values corresponding to pixel values, in CAD we are generally called screen coordinates.
webgl coordinate system, mxcad relies on mxdraw, mxdraw internal use a specific version of the modified three.js so, in general, we refer to the Three.js coordinate system
CAD coordinate system refers to the coordinate system of CAD drawings, and the coordinates of McGePoint3d in mxcad are the coordinates of CAD drawings
The method of mxcad coordinate system conversion is listed in mxdraw coordinate conversion We can directly use the API provided by mxdraw to convert mxcad related coordinates.
For example:
import { MxFun } from "mxdraw"
import { McGePoint3d } from "mxcad"
const pt = new McGePoint3d()
// CAD drawing coordinates to document coordinates
MxFun.cadCoord2Doc(pt.x, pt.y, pt.z)
Although these four coordinate systems are different in the origin position, axis direction, and coordinate range, they are all rectangular coordinate systems, so they all meet the characteristics of rectangular coordinate systems: no matter how the origin and axis direction change, with the same method to draw geometric figures, their shape and relative position are unchanged.
Vector McGeVector3d
Note
After the introduction of mxcad, three variables are automatically mounted globally, representing three.js If you find McGeVector3d, you can call the toVector3
method to get THREE.Vector3 uses the API provided by Three.js to perform vector operations To turn THREE.Vector3 into McGeVector3d, simply take THREE.Vector3 as an argument to the new McGeVector3d
So how do you represent a point and a line in a rectangular coordinate system?
The previous example contains three axes, x, y, and z, so they form a three-dimensional space of the plot, but usually we only need to consider x and y. Therefore, we can use two-dimensional vectors to represent points and line segments on this plane. A two-dimensional vector is just an array of two values, one for the x coordinate and one for the y coordinate.
Let's say we have a vector v in this rectangular plane coordinate system.
The vector v has two meanings: first, it can represent a point at (x, y) in this coordinate system; The second is a line segment that can be represented from the origin (0,0) to the coordinate (x,y)
The same two vectors can perform mathematical operations:
For example, I have two vectors, v1 and v2, and if I add them together, the result is the same as moving the end point of v1 (x1, y1) in the direction of v2 by a distance equal to the length of v2.
This gives us a new point on the plane (x1 + x2, y1 + y2), a new line segment [(0, 0), (x1 + x2, y1 + y2)], and a broken line: [(0, 0), (x1, y1), (x1 + x2, y1 + y2)].
Second, a vector contains length and direction information. Its length can be expressed as the square root of the sum of the squares of the vectors x and y
v.length = function(){return Math.hypot(this.x, this.y)};
Its direction can be expressed by its Angle to the X-axis, i.e. :
v.dir = function() { return Math.atan2(this.y, this.x);}
In the above code, Math.atan2 ranges from -π to π, with negative numbers below the X-axis and positive numbers above it
Finally, based on the definition of length and direction, we can also derive a set of relations:
v.x = v.length * Math.cos(v.dir);
v.y = v.length * Math.sin(v.dir);
This corollary implies an important fact: we can construct a drawing vector very simply. In other words, if we wanted to draw a line segment of length in some direction starting at the point (x0, y0), we would only need to construct one of the following vectors.
// dir is the direction of a vector (the Angle with the X-axis), and length is the length of the vector
function createV1(dir, length) {
return {
x: length * Math.cos(dir),
y: length * Math.sin(dir)
}
}
var v0 = { x: 0, y: 0 }
var v1 = createV1(Math.PI / 5, 30)
// And then we add the vector (x0, y0) to this vector v1, and we get the end of this line segment
The corresponding methods McGeVector3d.length
and McGeVector3d.angleTo1
are also provided in mxcad to find the vector length and direction Angle.
There is also McGeVector3d.add for adding two vectors. You can choose to use these apis that we provide to simplify the above calculation.
In three.js there is the vector 'THREE.Vector3' and the corresponding one exists in mxcad McGeVector3d said in 3 d space vector (vector)
In this class there are four axes kXAxis
, kYAxis
, kZAxis
, kNegateZAxis
, which are fixed vectors respectively.
THREE.Vector3
is completely equivalent to McGeVector3d
, except that it is McGeVector3d
that participates in the computation with other data in mxcad
The following is a brief description of some vector operations provided by mxcad:
import { McGeVector3d } from "mxcad"
const vet = new McGeVector3d(1, 0, 0)
// You get THREE.Vector3
const tVet = vet.toVector3()
const newVet = new McGeVector3d(tVet)
// Rotate
tVet.rotateBy(Math.PI. McGeVector3d.kXAxis)
// Take the inverse
vet.negate()
// Vertical 90 degrees
vet.perpVector()
// Calculate the Angle between two vectors
vet.angleTo1(newVet)
vet.angleTo1(newVet, McGeVector3d.kZAxis)
// Normalized
vet.normalize()
// Dot product
vet.dotProduct(newVet)
// Cross product
vet.crossProduct(newVet)
// Whether it is equal
vet.isEqualTo(newVet)
// The vector is multiplied by some value
vet.mult(10)
You can refer to the Math library demonstration effect click to get the vector length and Angle and get a line through a vector according to the direction and distance, to see if the corresponding method is used correctly.
The above code we use a lot of vector operations, maybe you do not understand what they represent, we roughly explain:
vector addition and subtraction
Their calculations are relatively easy to calculate:
// For example, vector v + vector v1:
(v.x + v1.x, v.y + v1.y)
// For example, vector v - vector v1:
(v.x - v1.x, v.y - v1.y)
So they add and subtract to get the vector. How do you understand that?
The result is that the starting point of the first vector points to the end point of the last vector vector a plus vector b, and after connecting a and b, the starting point of a points to the end point of b, that is, a + b.
Shift the two vectors to the common starting point O, from the end point of the subtraction vector B to the end point of the subtracted vector A for the subtraction result Move the starting point of vectors a and b to the common starting point O in the lower left corner, and the vector from point B to point A is A-B.
It may be more abstract to understand, below we view the math library demonstration effect click on the vector to see the specific effect and source code can be easier to understand.
Multiplication of vectors
There are two kinds of vector multiplication, one is the point product, the other is the cross product, and they have different geometric and physical meanings
If you don't quite understand it after reading it, you can click vector multiplication in the Math Library Demonstration Effect to see its practical application, reading the source code is easier to understand the concept.
Dot product
Suppose that we now have two n-dimensional vectors a and b, a = [a1, a2,...an], b = [b1, b2,...bn], and the dot product code of that vector is as follows:
a*b = a1*b1 + a2*b2 + ... + an*bn
In n-dimensional linear space, the geometric meaning of the dot product of vectors a and b is that a vector is multiplied by the projected component of b vector on a vector. Its physical meaning is equivalent to the work done by the a force acting on the object to produce the b shift. The dot product formula is shown in the figure below:
Of course, there are two special cases of dot multiplication:
If vectors a and b are parallel, the Angle between them is 0°, then a·b=|a|*|b| in JavaScript code is:
a.x * b.x + a.y * b.y === a.length * b.length;
If vectors a and b are perpendicular, then the Angle between them is 90°, then a·b=0 in JavaScript code is:
a.x * b.x + a.y * b.y === 0;
cross product
There are two differences between cross and dot products:
First, the result of the vector cross product operation is not a scalar, but a vector; Secondly, the cross product of two vectors is perpendicular to the coordinate plane formed by the two vectors
In two-dimensional space, for example, the cross product of vectors a and b is equivalent to the product of vector a (blue arrow segment) and the projection of vector b (red arrow segment) in the vertical direction As shown in the figure below, the geometric meaning of the cross product of two-dimensional vectors is the area of a parallelogram composed of vectors A and b
So how do you calculate the cross product mathematically? Suppose that we now have two three-dimensional vectors a(x1, y1, z1) and b(x2, y2, z2), then the cross product of a and b can be expressed as a determinant of the following figure:
Where i, j, and k are unit vectors of the x, y, and z axes, respectively. If we expand this determinant, we get the following formula:
a * b = [y1 * z2 - y2 * z1, - (x1 * z2 - x2 * z1), x1 * y2 - x2 * y1]
The physical meaning of the cross product in two dimensions is the moment of a and b (the moment you can think of as the tendency of an object to rotate around an axis under the action of a force).
3D Point McGePoint3d
This is the most commonly used class McGePoint3d that represents a point in 3D space.
By x
, y
, z
structure composed of three double precision values, of course, McGePoint3d is essentially a vector, above we said that the vector can also represent a point.
The distinction is made because it is meant to represent a point in a coordinate system, not a quantity,
If you want to change the position of this point, you need an affine transformation, which you can do by operating on the vector to get a new point position.
The following are some of the methods commonly used in this class, mainly by performing mathematical operations with vectors to get the position of new points.
import { McGePoint3d } from "mxcad"
const pt1 = new McGePoint3d(0, 0, 0)
// or
const pt2 new McGePoint3d({ x: 0, y: 0, z: 0})
// Provides some practical methods
// Determine whether two points are equal
pt1.isEqualTo(pt2)
// Calculate the distance between two points
pt1.distanceTo(pt2)
// Sets the vector of three.js to points
pt1.setFromVector3(new THREE.Vector3())
// Get the three.js vector corresponding to the point
pt1.toVector3()
// Subtract two points to get a new vector
const vet = pt1.sub(pt2)
// Add the new position of the vector
pt1.addvec(vet)
// Short for
pt1.av(vet)
// Subtract the new position of the vector
pt1.subvec(vet)
// Short for
pt1.sv(vet)
Affine transformation is simply "linear transformation + translation".
For example, setting the CSS transform property on an element applies an affine transform to the element.
The affine transformation of geometric figures has the following two properties:
- before the affine transformation is a straight line segment, after the affine transformation is still a straight line segment
- Apply the same affine transformation to the two straight line segments a and b, and the ratio of the length of the line segment before and after the transformation remains unchanged
Common forms of affine transformation include translation, rotation, scaling, and their combinations
The easiest thing to do is shift, in mxc In d, you can directly understand the McGePoint3d point by addvec method plus a vector McGeVector3d, which is the distance of the translation vector in the direction represented by the vector.
Matrix McGeMatrix3d
As we know how to translate a point, we can also rotate and scale a point by linear transformations.
So what is a linear transformation? We can also use vector operations to figure out how to rotate and scale.
Just rotation and scaling, which we chose to represent in matrix form, by multiplying matrices with vectors is called a linear transformation.
In addition to satisfying the two properties of affine transformations, linear transformations have two additional properties:
- the linear transformation does not change the origin of the coordinates (because if x0 and y0 are zero, then x and y must be zero);
- linear transformations can be superimposed, the superposition of multiple linear transformations is to multiply the matrix of the linear transformation in turn, and then multiply with the original vector.
Then according to the second property of linear transformations, we can summarize a general linear transformation formula, that is, a primitive vector P0 passes through M1, M2,... The linear transformation of degree Mn gives the final coordinate P
In mxcad the McGeMatrix3d class represents an affine transformation of a 3D space
In general, we need to combine translation, rotation, scaling, etc. to form a variety of complex radiological transformations are represented by linear transformations,
We just need to convert the original n-dimensional coordinates to n+ 1-dimensional coordinates. Such n+ 1-dimensional coordinates are called homogeneous coordinates, and the corresponding matrix is called homogeneous
Our McGeMatrix3d is also a homogeneous matrix, so we can make various linear transformations directly through McGeMatrix3d, and finally apply the affine transformation through the vector's transformBy
method.
The same matrix can also be applied to all geometric entities McDbEntity.transformBy in mxcad for affine transformations, because all geometric figures are based on points and lines.
We can think of a point or a line as a vector, and a radiative transformation of the entity is equivalent to a radiative transformation of all the points that make up the entity.
Matrix multiplication
Multiplication of matrices actually corresponds to the property that linear transformations can be superimposed,
We want to form a complex affine transformation by combining matrices one by one, that is, multiplying matrices one by one and the final matrix is the complex affine transformation formed by combining matrices
Where two matrices A and B are multiplied together, in the case of A, A can choose to multiply the matrix B left or right,
So if you multiply by left, that's B * A
and if you multiply by right, that's A * B
Here we can understand the difference between left and right multiplication by looking at the following figure:
Let's first assume matrix A:
设列向量:
用列向量去右乘矩阵A
It's equivalent to taking A linear combination of the column vectors in matrix A
Multiply A matrix A by a column vector
Equivalent to A left linear combination of the row vectors in matrix A
According to the above concept extended to the left and right multiplication of matrix multiplication, the idea is the same:
Set a matrix B:
Multiply matrix A by matrix B:
Therefore, every row of the new matrix obtained by multiplying matrix A by matrix B is A linear combination of the row vectors of matrix A, in the same way that every column of the new matrix obtained by multiplying matrix A by matrix B is a linear combination of the column vectors of matrix A
Here are some of the methods McGeMatrix3d offers:
import { McGeMatrix3d, McGePoint3d, McGeVector3d } from "mxcad"
// The identity matrix of multiplication
McGeMatrix3d.kIdentity
const m = new McGeMatrix3d()
const m1 = new McGeMatrix3d()
// Set to the identity matrix.
m.setToIdentity()
// Left multiply the specified matrix.
const m3 = m.preMultBy(m1)
// Right multiply the specified matrix.
m3.postMultBy(m1)
// Matrix is set to the product of two matrices.
new McGeMatrix3d().setToProduct(m1, m2)
// Inverse matrix.
m1.invert()
// Is it a singular matrix.
m1.isSingular()
// transpose
m1.transposeIt()
// Whether it is equal
m1.isEqualTo(m2)
// The determinant of the matrix.
m1.det()
// Sets the matrix to the specified coordinate system. The parameters are the origin and xyz axis
m1.setCoordSystem(new McGePoint3d(), new McGeVector3d(), new McGeVector3d(), new McGeVector3d())
// translation
m1.setToTranslation(new McGeVector3d(0, 1, 0))
// Rotation parameters: Angle, axis, center point of rotation
m1.setToRotation(Math.PI, McGeVector3d.kXAxis, new McGePoint3d())
// Scaling parameters: scaling factor, scaling center point
m1.setToScaling(0.5, new McGePoint3d())
// Set to mirror orientation matrix
m1.setMirror(new McGePoint3d(), new McGePoint3d())
// Get the scale factor
m1.scale()
// Gets the element value parameter row index and column index at the specified position in the matrix
m1.getData(0, 0)
How to use matrix in mxcad, you can see math library demonstration effect on the point rotation translation and scaling | entity affine transformation | view the specific effects and source code can be easier to understand and use.
MxCADResbuf
MxCADResbuf is a data structure used by resbuf
(i.e. "result buffer") to pass data in CAD secondary development.
It is generally used for object attribute query, definition and storage of custom objects, XDATA (extended data) processing, and editing of drawing entities.
For example, the filter object is represented in the MxCADSelectionSet selection set:
import { MxCADSelectionSet, MxCADResbuf } from "mxcad"
let ss = new MxCADSelectionSet();
let filter = new MxCADResbuf();
// Add the query character "0" here the second argument is data type 8 in CAD secondary development indicates that this is a null pointer (RTNUL) i.e. the resbuf structure does not contain any valid data and is usually used as a terminator at the end of a linked list
filter.AddString("0", 8);
// Select all entities on layer 0
ss.allSelect(filter);
ss.forEach((objId)=> console.log(objId))
calcBulge Calculates the convexity of the arc
MxCADUtility is an example provided by MxCADUtilityClass, which provides many practical ways.
MxCADUtility.calcBulge Calculates the convexity of the arc.
One of the parameters for adding points to a multi-segment entity is the convexity value, and mxcad provides the calcBulge method to calculate the convexity
Three parameters are required in order: the beginning point of the arc (starting point), the middle point of the arc, and the end point of the arc (endpoint).
import { MxCADUtility, McGePoint3d, McDbPolyline } from "mxcad"
// Starting point of the arc
const startPoint = new McGePoint3d(0, 0, 0);
// Midpoint of the arc
const midPoint = new McGePoint3d(0, 0, 0);
// End point of the arc
const endPoint = new McGePoint3d(0, 0, 0);
const bulge = MxCADUtility.calcBulge(startPoint, midPoint, endPoint).val
const pl = new McDbPolyline()
pl.addVertexAt(startPoint, bulge)
pl.addVertexAt(endPoint)
If you do not know any of the above three parameters, refer to the figure below to calculate the convexity yourself:
The convexity value is half the distance between the beginning point of the arc and the end point, minus the distance from the middle point of the line connecting the beginning point of the arc and the end point to the center of the arc
Mathematical library demonstration effect
The demo is based on vue3 and adopts tsx mode. Please refer to vue official website Tsx Description to write the code (expand the code to edit).