Converting SVG to Three.js path - svg

Trying to use the sample SVG parsing code demonstrated at https://threejs.org/examples/#webgl_geometry_extrude_shapes2. It does not properly support the 'a' path command. I've made a few corrections found in https://gist.github.com/IkarosKappler/d3c39db08115085bcb18 and a few of my own referencing https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes, but still am coming up wrong.
Here's a sample with the original SVG shown.
https://codepen.io/matelich/pen/rKzXZV
Since stack wants code here, this is the code that incorrectly parses and interprets A and a paths:
// - elliptical arc
case "A":
case "a":
rx = eatNum();
ry = eatNum();
xar = eatNum() * DEGS_TO_RADS;
laf = eatNum(); //large arc flag
sf = eatNum(); //sweep flag
nx = eatNum();
ny = eatNum();
if (activeCmd == "a") {
// relative
nx += x;
ny += y;
}
if(rx != 0 && ry != 0) {
console.debug(
"Read arc params: rx=" + rx + ", ry=" + ry + ", xar=" + xar + ", laf=" + laf + ", sf=" + sf + ", nx=" + nx + ", ny=" + ny
);
//might need to bring this back if absellipse doesn't work
//if (rx !== ry)
// console.warn("Forcing elliptical arc to be a circular one :(", rx, ry);
// SVG implementation notes does all the math for us! woo!
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
// step1, using x1 as x1'
x1 = Math.cos(xar) * (x - nx) / 2 + Math.sin(xar) * (y - ny) / 2;
y1 = -Math.sin(xar) * (x - nx) / 2 + Math.cos(xar) * (y - ny) / 2;
// step 2, using x2 as cx'
console.debug( "TMP x1=" + x1 + ", y1=" + y1 + ", (rx*rx * y1*y1 + ry*ry * x1*x1)=" + (rx * rx * y1 * y1 + ry * ry * x1 * x1) + ", (rx*rx * ry*ry - rx*rx * y1*y1 - ry*ry * x1*x1)=" + (rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1));
var norm = Math.sqrt(
Math.abs(
(rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1) /
(rx * rx * y1 * y1 + ry * ry * x1 * x1)
)
);
if (laf === sf) norm = -norm;
x2 = norm * rx * y1 / ry;
y2 = norm * -ry * x1 / rx;
console.debug("TMP norm=" + norm + ", x2=" + x2 + ", y2=" + y2);
// step 3
cx = Math.cos(xar) * x2 - Math.sin(xar) * y2 + (x + nx) / 2;
cy = Math.sin(xar) * x2 + Math.cos(xar) * y2 + (y + ny) / 2;
console.debug("TMP cx=" + cx + ", cy=" + cy);
var u = new THREE.Vector2(1, 0),
v = new THREE.Vector2((x1 - x2) / rx, (y1 - y2) / ry);
var startAng = Math.acos(u.dot(v) / u.length() / v.length());
if (u.x * v.y - u.y * v.x < 0) startAng = -startAng;
// we can reuse 'v' from start angle as our 'u' for delta angle
u.x = (-x1 - x2) / rx;
u.y = (-y1 - y2) / ry;
var deltaAng = Math.acos(v.dot(u) / v.length() / u.length());
// This normalization ends up making our curves fail to triangulate...
if (u.x * v.y - u.y * v.x < 0) deltaAng = -deltaAng;
if (!sf && deltaAng > 0) deltaAng -= Math.PI * 2;
if (sf && deltaAng < 0) deltaAng += Math.PI * 2;
console.debug(
"Building arc from values: cx=" + cx + ", cy=" + cy + ", startAng=" + startAng + ", deltaAng=" + deltaAng + ", endAng=" + (startAng + deltaAng) + ", sweepFlag=" + sf );
// path.absarc(cx, cy, rx, startAng, startAng + deltaAng, sf);
path.absellipse(cx, cy, rx, ry, startAng, startAng + deltaAng, sf);
} else {
path.lineTo(nx, ny);
}
Or, perhaps its just my hack of ShapePath?
THREE.ShapePath.prototype.absarc = function( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
this.currentPath.absarc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise);
};
THREE.ShapePath.prototype.absellipse = function( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) {
this.currentPath.absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise );
};

You can still use SVGLoader to load the SVG and retrieve an array of ShapePath objects. You can then use ShapePath.toShapes and use these shapes for creating ExtrudeBufferGeometry's. It's actually the same workflow like in webgl_loader_svg.html, just with ExtrudeBufferGeometry

Related

How to calculate coordinates of 6 point of intersection between a circle and a equilateral triangle?

I know of an equilateral triangle the center (cx,cy) and the radius (r) of a blue circle which circumscribed it.
If I draw a green circle of any radius (radius), assuming the circle is large enough to have this intersection, can I get the coordinates of the 6 intersection points (P1, P2, P3...)?
I'm looking for P5JS/processing but any other clue can help me...
Thank you in advance
Distance from the center to top point is r.
Distance from the center to the lowest triangle side is r/2 (median intersection point is center, they are divided in 1:2 ratio).
Horizontal distance from cx to p4 (and p5) is (Pythagoras' theorem)
dx = sqrt(radius^2 - r^2/4)
So coordinates of p4 and p5 are (relative to center)
p4x = dx
p4y = r/2
p5x = -dx
p5y = r/2
Other points might be calculated using rotation by 120 degrees
p2x = p4x*(-1/2) - p4y*(sqrt(3)/2)
p2y = p4x*(sqrt(3)/2) + p4y*(-1/2)
and so on.
And finally add cx,cy to get absolute coordinates
If you want to test... ;-)
function setup() {
createCanvas(500, 500);
const cx = width / 2;
const cy = height / 2;
const r = 250; // taille du triangle
const radius = 180; // externe
noFill();
strokeWeight(3);
stroke(0, 0, 0);
drawTriangle(cx, cy, r);
strokeWeight(1);
stroke(0, 0, 255);
circle(cx, cy, r * 2);
strokeWeight(2);
stroke(8, 115, 0);
circle(cx, cy, radius * 2);
noStroke();
fill(215, 0, 0);
// dx = sqrt(Math.pow(r / 2, 2) - Math.pow(r / 2, 2 / 4));
dx = sqrt(radius * radius - (r * r) / 4);
p4x = dx;
p4y = r / 2;
circle(cx + p4x, cy + p4y, 20);
text("p4", cx + p4x, cy + p4y + 30);
p5x = -dx;
p5y = r / 2;
circle(cx + p5x, cy + p5y, 20);
text("p5", cx + p5x - 10, cy + p5y + 30);
p6x = p4x * (-1 / 2) - p4y * (sqrt(3) / 2);
p6y = p4x * (sqrt(3) / 2) + p4y * (-1 / 2);
circle(cx + p6x, cy + p6y, 20);
text("p6", cx + p6x - 30, cy + p6y);
p2x = p6x * (-1 / 2) - p6y * (sqrt(3) / 2);
p2y = p6x * (sqrt(3) / 2) + p6y * (-1 / 2);
circle(cx + p2x, cy + p2y, 20);
text("p2", cx + p2x + 10, cy + p2y - 10);
p1x = p5x * (-1 / 2) - p5y * (sqrt(3) / 2);
p1y = p5x * (sqrt(3) / 2) + p5y * (-1 / 2);
circle(cx + p1x, cy + p1y, 20);
text("p1", cx + p1x - 20, cy + p1y - 10);
p3x = p1x * (-1 / 2) - p1y * (sqrt(3) / 2);
p3y = p1x * (sqrt(3) / 2) + p1y * (-1 / 2);
circle(cx + p3x, cy + p3y, 20);
text("p3", cx + p3x + 20, cy + p3y - 10);
noFill();
stroke(0, 255, 255);
triangle(cx + p2x, cx + p2y, cx + p4x, cx + p4y, cx + p6x, cx + p6y);
stroke(255, 0, 255);
// prettier-ignore
triangle(
cx + p1x, cx + p1y,
cx + p3x, cx + p3y,
cx + p5x, cx + p5y,
)
}
function drawTriangle(cx, cy, radius) {
noFill();
trianglePoints = [];
for (var i = 0; i < 3; i++) {
var x = cx + radius * cos((i * TWO_PI) / 3.0 - HALF_PI);
var y = cy + radius * sin((i * TWO_PI) / 3.0 - HALF_PI);
trianglePoints[i] = {
x,
y,
};
}
triangle(
trianglePoints[0].x,
trianglePoints[0].y,
trianglePoints[1].x,
trianglePoints[1].y,
trianglePoints[2].x,
trianglePoints[2].y
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>

Find circle center by 3 points on perimeter - convert C# code into G-CODE

I am new to G-code -
Trying to convert the c# code to G-code syntax -
Finding the center of a circle by 3 points on the perimeter to find the center of a circle.
Trying to convert the c# code to G-code syntax -
Finding the center of a circle by 3 points on the perimeter to find the center of a circle.
using System;
using System.Globalization;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
double x1 = 2, y1 = 3;
double x2 = 2, y2 = 4;
double x3 = 5, y3 = -3;
findCircle(x1, y1, x2, y2, x3, y3);
Console.ReadKey();
}
static void findCircle(double x1, double y1,
double x2, double y2,
double x3, double y3)
{
NumberFormatInfo setPrecision = new NumberFormatInfo();
setPrecision.NumberDecimalDigits = 3; // 3 digits after the double point
double x12 = x1 - x2;
double x13 = x1 - x3;
double y12 = y1 - y2;
double y13 = y1 - y3;
double y31 = y3 - y1;
double y21 = y2 - y1;
double x31 = x3 - x1;
double x21 = x2 - x1;
double sx13 = (double)(Math.Pow(x1, 2) -
Math.Pow(x3, 2));
double sy13 = (double)(Math.Pow(y1, 2) -
Math.Pow(y3, 2));
double sx21 = (double)(Math.Pow(x2, 2) -
Math.Pow(x1, 2));
double sy21 = (double)(Math.Pow(y2, 2) -
Math.Pow(y1, 2));
double f = ((sx13) * (x12)
+ (sy13) * (x12)
+ (sx21) * (x13)
+ (sy21) * (x13))
/ (2 * ((y31) * (x12) - (y21) * (x13)));
double g = ((sx13) * (y12)
+ (sy13) * (y12)
+ (sx21) * (y13)
+ (sy21) * (y13))
/ (2 * ((x31) * (y12) - (x21) * (y13)));
double c = -(double)Math.Pow(x1, 2) - (double)Math.Pow(y1, 2) -
2 * g * x1 - 2 * f * y1;
double h = -g;
double k = -f;
double sqr_of_r = h * h + k * k - c;
// r is the radius
double r = Math.Round(Math.Sqrt(sqr_of_r), 5);
Console.WriteLine("Center of a circle: x = " + h.ToString("N", setPrecision) +
", y = " + k.ToString("N", setPrecision));
Console.WriteLine("Radius: " + r.ToString("N", setPrecision));
}
}
}

Changing Monte Carlo calculation from VBA code to MATLAB

I am trying to convert this Clausing Factor Monte Carlo calculation code (written in Visual Basic):https://descanso.jpl.nasa.gov/SciTechBook/series1/Goebel_AppG_Clausing.pdf into MATLAB code.
When I try to run this code in Excel, it always returns a consistent value at the first time running. But when I implemented in MATLAB it returns the clausing factor randomly. Could you please help me with the MATLAB code so that it could do the same like in VBA.
The value I am talking about in the VBA code is Range("C11") = (rBottom ^ 2) * iescape / npart
Here are my MATLAB code solve for clausingFactor
thickScreen = 0.5;
thickAccel = 1;
rScreen = 0.8;
rAccel = 0.5;
gridSpace = 1;
npart = 313;
Pi = 3.14159265358979;
%assumes rTop = 1
rBottom = rScreen/rAccel;
lenBottom = (thickScreen + gridSpace)/rAccel;
lenTop = thickAccel / rAccel;
Length = lenTop + lenBottom;
iescape = 0;
maxcount = 0;
icount = 0;
nlost = 0;
vztot = 0;
vz0tot = 0;
for ipart = 1: npart
%launch form bottom
notgone = true;
r0 = rBottom * sqrt(rand());
z0 = 0;
costheta = sqrt(1 - rand());
if (costheta > 0.99999)
costheta = 0.99999;
end
Phi = 2 * Pi * rand();
sintheta = sqrt(1 - costheta);
vx = cos(Phi) * sintheta;
vy = sin(Phi) * sintheta;
vz = costheta;
rf = rBottom;
t = (vx * r0 + sqrt((vx^2 + vy^2) * rf^2 - (vy * r0)^2)) / (vx^2 + vy^2);
z = z0 + vz * t;
vz0tot = vz0tot + vz;
icount = 0;
while notgone
icount = icount +1;
if (z < lenBottom)
%hit wall of bottom cylinder and is re-emitted
r0 = rBottom;
z0 = z;
costheta = sqrt(1-rand());
if (costheta > 0.99999)
costheta = 0.99999;
end
Phi = 2 * Pi * rand();
sintheta = sqrt(1 - costheta^2);
vz = cos(Phi) * sintheta;
vy = sin(Phi) * sintheta;
vx = costheta;
rf = rBottom;
t = (vx * r0 + sqrt((vx^2 + vy^2) * rf^2 - (vy * r0)^2)) / (vx^2 + vy^2);
z = z0 + t * vz;
end %bottom cylinder re-emission
if ((z >= lenBottom) && (z0 < lenBottom))
%emitted below but going up
%find radius at lenBottom
t = (lenBottom - z0) / vz;
r = sqrt((r0 - vx * t)^2 + (vy * t)^2);
if (r <= 1)
%continuing upward
rf = 1;
t = (vx * r0 + sqrt((vx^2 + vy^2) * rf^2 - (vy * r0)^2)) / (vx^2 + vy^2);
z = z0 + vz*t;
else
% hit the upstram side of the accel grid and is
% re-emitted downward
r0 = r;
z0 = lenBottom;
costheta = sqrt(1 - rand());
if (costheta > 0.99999)
costheta = 0.99999;
end
Phi = 2 * Pi * rand();
sintheta = sqrt(1 - costheta^2);
vz = cos(Phi) * sintheta;
vy = sin(Phi) * sintheta;
vx = costheta;
rf = rBottom;
t = (vx * r0 + sqrt((vx^2 + vy^2) * rf^2 - (vy * r0)^2)) / (vx^2 + vy^2);
z = z0 + t * vz;
end
end %end upward
if ((z >= lenBottom) && (z<= Length))
%hit the upper cylinder wall and is re-emitted
r0 = 1;
z0 = z;
costheta = sqrt(1 - rand());
if (costheta > 0.99999)
costheta = 0.99999;
end
Phi = 2 * Pi * rand();
sintheta = sqrt(1 - costheta^2);
vz = cos(Phi) * sintheta;
vy = sin(Phi) * sintheta;
vx = costheta;
rf = 1;
t = (vx * r0 + sqrt((vx^2 + vy^2) * rf^2 - (vy * r0)^2)) / (vx^2 + vy^2);
z = z0 + t * vz;
if (z < lenBottom)
%find z when particle hits the bottom cylinder
rf = rBottom;
if ((vx^2 + vy^2) * rf^2 - (vy * r0)^2 < 0 )
t = (vx * r0) / (vx^2 + vy^2);
%if sqrt argument is less than 0 then set sqr term
%to 0 12 May 2004
else
t = (vx * r0 + sqrt((vx^2 + vy^2) * rf^2 - (vy * r0)^2)) / (vx^2 + vy^2);
end
z = z0 + vz * t;
end
end %end upper cylinder emission
if (z < 0)
notgone = false;
end
if (z > Length)
iescape = iescape + 1;
vztot = vztot + vz;
notgone = false;
end
if (icount > 1000)
notgone = false;
icount = 0;
nlost = nlost + 1;
end
end
if (maxcount < icount)
maxcount = icount;
end
end
clausingFactor = (rBottom^2) * iescape / npart;
vz0av = vz0tot / npart;
vzav = vztot / iescape;
DenCor = vz0av / vzav;
Thank you.

Draw all voxels that pass through a 3D line in 3D voxel space

I want to draw a 3D voxelized line, that is, to find all the voxels which a line passes. 3D bresenham always skips some voxels. As shown in the figure, the voxels generated by 3D bresenham cannot completely contain the line between the start voxel and target voxel.
The algorithm in this link: Algorithm for drawing a 4-connected line can solve my problem on a 2D plane, but I failed to improve it to 3D.
The method in Pierre Baret's link can solve my problem. When the line passes only the vertices of a certain voxel, whether to visit the current voxel is a very vague question, so I made a little changes to the method. When two or more values in tMaxX, tMaxY, and tMaxZ are equal, the voxels generated by the method in the paper are as shown in a. I made a little change to generate the result in b. A more normal condition is shown in c, which compares lines generated by 3D bresenham and this method respectively.
The code implemented by c++:
void line3D(int endX, int endY, int endZ, int startX, int startY, int startZ, void draw){
int x1 = endX, y1 = endY, z1 = endZ, x0 = startX, y0 = startY, z0 = startZ;
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int dz = abs(z1 - z0);
int stepX = x0 < x1 ? 1 : -1;
int stepY = y0 < y1 ? 1 : -1;
int stepZ = z0 < z1 ? 1 : -1;
double hypotenuse = sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2));
double tMaxX = hypotenuse*0.5 / dx;
double tMaxY = hypotenuse*0.5 / dy;
double tMaxZ = hypotenuse*0.5 / dz;
double tDeltaX = hypotenuse / dx;
double tDeltaY = hypotenuse / dy;
double tDeltaZ = hypotenuse / dz;
while (x0 != x1 || y0 != y1 || z0 != z1){
if (tMaxX < tMaxY) {
if (tMaxX < tMaxZ) {
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
}
else if (tMaxX > tMaxZ){
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
else{
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
}
else if (tMaxX > tMaxY){
if (tMaxY < tMaxZ) {
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
}
else if (tMaxY > tMaxZ){
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
else{
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
}
else{
if (tMaxY < tMaxZ) {
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
}
else if (tMaxY > tMaxZ){
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
else{
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
}
draw(x0, y0, z0);
}
}

Line Segment Circle Intersection

I am trying to determine the point at which a line segment intersect a circle. For example, given any point between P0 and P3 (And also assuming that you know the radius), what is the easiest method to determine P3?
Generally,
find the angle between P0 and P1
draw a line at that angle from P0 at a distance r, which will give you P3
In pseudocode,
theta = atan2(P1.y-P0.y, P1.x-P0.x)
P3.x = P0.x + r * cos(theta)
P3.y = P0.y + r * sin(theta)
From the center of the circle and the radius you can write the equation describing the circle.
From the two points P0 and P1 you can write the equation describing the line.
So you have 2 equations in 2 unknowns, which you can solved through substitution.
Let (x0,y0) = coordinates of the point P0
And (x1,y1) = coordinates of the point P1
And r = the radius of the circle.
The equation for the circle is:
(x-x0)^2 + (y-y0)^2 = r^2
The equation for the line is:
(y-y0) = M(x-x0) // where M = (y1-y0)/(x1-x0)
Plugging the 2nd equation into the first gives:
(x-x0)^2*(1 + M^2) = r^2
x - x0 = r/sqrt(1+M^2)
Similarly you can find that
y - y0 = r/sqrt(1+1/M^2)
The point (x,y) is the intersection point between the line and the circle, (x,y) is your answer.
P3 = (x0 + r/sqrt(1+M^2), y0 + r/sqrt(1+1/M^2))
Go for this code..its save the time
private boolean circleLineIntersect(float x1, float y1, float x2, float y2, float cx, float cy, float cr ) {
float dx = x2 - x1;
float dy = y2 - y1;
float a = dx * dx + dy * dy;
float b = 2 * (dx * (x1 - cx) + dy * (y1 - cy));
float c = cx * cx + cy * cy;
c += x1 * x1 + y1 * y1;
c -= 2 * (cx * x1 + cy * y1);
c -= cr * cr;
float bb4ac = b * b - 4 * a * c;
// return false No collision
// return true Collision
return bb4ac >= 0;
}
You have a system of equations. The circle is defined by: x^2 + y^2 = r^2. The line is defined by y = y0 + [(y1 - y0) / (x1 - x0)]·(x - x0). Substitute the second into the first, you get x^2 + (y0 + [(y1 - y0) / (x1 - x0)]·(x - x0))^2 = r^2. Solve this and you'll get 0-2 values for x. Plug them back into either equation to get your values for y.
MATLAB CODE
function [ flag] = circleLineSegmentIntersection2(Ax, Ay, Bx, By, Cx, Cy, R)
% A and B are two end points of a line segment and C is the center of
the circle, % R is the radius of the circle. THis function compute
the closest point fron C to the segment % If the distance to the
closest point > R return 0 else 1
Dx = Bx-Ax;
Dy = By-Ay;
LAB = (Dx^2 + Dy^2);
t = ((Cx - Ax) * Dx + (Cy - Ay) * Dy) / LAB;
if t > 1
t=1;
elseif t<0
t=0;
end;
nearestX = Ax + t * Dx;
nearestY = Ay + t * Dy;
dist = sqrt( (nearestX-Cx)^2 + (nearestY-Cy)^2 );
if (dist > R )
flag=0;
else
flag=1;
end
end

Resources