"Almost-structured" 2d quadrilateral mesh in Gmsh - 2d

I'd like to generate a two-dimensional quadrilateral mesh using Gmsh. The mesh should be such that its cells are "as quadratic as possible" with a given edge length. That is, if the geometry is simple, I'd expect a perfectly structured grid, and if the geometry is more complex, I'd only expect local distortion.
Consider the following minimal example:
lc = 1;
Point(1) = {0, 0, 0, lc};
Point(2) = {10, 0, 0, lc} ;
Point(3) = {10, 4, 0, lc} ;
Point(4) = {0, 4, 0, lc} ;
Point(5) = {1, 1, 0, lc} ;
Point(6) = {3, 1, 0, lc} ;
Point(7) = {2, 2, 0, lc} ;
Line(1) = {1,2} ;
Line(2) = {3,2} ;
Line(3) = {3,4} ;
Line(4) = {4,1} ;
Line(5) = {5,6} ;
Line(6) = {6,7} ;
Line(7) = {7,5} ;
Line Loop(1) = {4,1,-2,3} ;
Line Loop(2) = {5,6,7} ;
Plane Surface(1) = {1,2} ;
The above yields a highly unstructured mesh, despite there being only a small hole in an otherwise simple and rectangular geometry:
What I'd have in mind is something like this (taken from Automesh2d's web site, a commercial mesh generator):
Can I get a similar "quasi-structured," two-dimensional quadrilateral mesh also using Gmsh (or for that matter, using any open source software)? I'd really appreciate any support.

This should be possible using Transfinite Lines. You define a Transfinite Line between certain points, in your case between the corner points of your large rectangle. While doing so, you can specify how many nodes should be included on this line. If you choose the same number of nodes on the opposing lines of the rectangle, you should be doing fine. Recombine the surface and you're done.
In this simple YouTube-Tutorial, you'll be guided through it step-by-step.
I have quickly tried a similar geometry to yours, this is what I get:
Mesh

Related

Threejs - How to offset all points on a 2d geometry by distance

Using Three.js, (although I believe this is more math related) I have a set of 2D points that can create a 2D geometry. such as square, rectangle, pentagon, or custom 2D shape. Based of the original 2D shape, I would like to create a method to offset the points inward or outward uniformly in such a way like the attached image.
I don't know if there is a simple way to offset/grow/shrink all the points (vector3) uniformly on the 2D shape inward or outward. And if so, it'll be cool if I can offset the points by X distance? Kinda of like saying offset the points on the 2D shape outward or inward by X distance.
And no, I'm not referring to scaling from a center point. While scaling may work for symmetrical shapes, it won't work when it comes to non-symmetrical shapes.
see image for example
Thanks in advance.
You can read that forum thread.
I've made some changes with ProfiledContourGeometry and got OffsetContour, so I leave it here, just in case, what if it helps :)
function OffsetContour(offset, contour) {
let result = [];
offset = new THREE.BufferAttribute(new Float32Array([offset, 0, 0]), 3);
console.log("offset", offset);
for (let i = 0; i < contour.length; i++) {
let v1 = new THREE.Vector2().subVectors(contour[i - 1 < 0 ? contour.length - 1 : i - 1], contour[i]);
let v2 = new THREE.Vector2().subVectors(contour[i + 1 == contour.length ? 0 : i + 1], contour[i]);
let angle = v2.angle() - v1.angle();
let halfAngle = angle * 0.5;
let hA = halfAngle;
let tA = v2.angle() + Math.PI * 0.5;
let shift = Math.tan(hA - Math.PI * 0.5);
let shiftMatrix = new THREE.Matrix4().set(
1, 0, 0, 0,
-shift, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let tempAngle = tA;
let rotationMatrix = new THREE.Matrix4().set(
Math.cos(tempAngle), -Math.sin(tempAngle), 0, 0,
Math.sin(tempAngle), Math.cos(tempAngle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let translationMatrix = new THREE.Matrix4().set(
1, 0, 0, contour[i].x,
0, 1, 0, contour[i].y,
0, 0, 1, 0,
0, 0, 0, 1,
);
let cloneOffset = offset.clone();
console.log("cloneOffset", cloneOffset);
shiftMatrix.applyToBufferAttribute(cloneOffset);
rotationMatrix.applyToBufferAttribute(cloneOffset);
translationMatrix.applyToBufferAttribute(cloneOffset);
result.push(new THREE.Vector2(cloneOffset.getX(0), cloneOffset.getY(0)));
}
return result;
}
Feel free to modify it :)
I have some doubts about solutions that do not include number of edges modification.
I faced the same issue in this project where I wanted to ensure a known distance between voronoi cells, and I quickly figured out that scale does not fulfill the use case. But one complication I faced was the disappearance of some edges that I had to handle in a while loop. It was so difficult to debug that I had to create a debug mode that helps see the points and lines, that I also left available. It's possible to activate this debug mode with a checkbox:
Note for the images, I have them as links not embedded as I'm still new contributor (might improve that later).
The edges that shall disappear are shown in red
retraction snapshot1
retraction with edges discard 1
retraction with edges discard 2
Here a link to the function in action, you might have to modify it to have another points format though :
https://github.com/WebSVG/voronoi/blob/8893768e3929ea713a47dba2c4d273b775e0bd82/src/voronoi_diag.js#L278
And here a link to the complete project integrating this function, it has link to a live demo too
https://github.com/WebSVG/voronoi

MPI Communication Pattern

I was wondering if there was a smart way to do this. Let's say I have three nodes, 0, 1, 2. And let's say each node has an array, a0, a1, a2. If the contents of each node is something like
a0 = {0, 1, 2, 1}
a1 = {1, 2, 2, 0}
a2 = {0, 0, 1, 2}
Is there a clever communication pattern so to move each number to it's corresponding node, i.e.
a0 = {0, 0, 0, 0}
a1 = {1, 1, 1, 1}
a2 = {2, 2, 2, 2}
The approach I have in mind, would involve sorting and temporary buffers, but I was wondering if there was a smarter way?
You can use MPI_Alltoallv for this in the following way:
Sort the local_data (a) by corresponding node of each element in increasing order.
Create a send_displacements array such that send_displacements[r] indicates the index of the first element in the local_data that refers to node r.
Create a send_counts array such that send_counts[r] equals the number of elements in local_data that correspond to node r. This can be computed send_counts[r] = send_displacements[r+1] - send_displacements[r] except for the last rank.
MPI_Alltoall(send_counts, 1, MPI_INT, recv_counts, 1, MPI_INT, comm)
Compute recv_displacements such that recv_displacements[r] = sum(recv_counts[r'] for all r' < r).
Prepare a recv_data with sum(recv_counts) elements.
MPI_Alltoallv(local_data, send_counts, send_displacements, MPI_INT, recv_data, recv_counts, recv_displacements, MPI_INT, comm)

How to cut mesh model matching robot template

Given a mesh model (e.g. a box) and a robot template containing volume, aspect ratio and linkage info of sub-parts (basically cuboids), we want to have a cutting algorithm to cut the mesh model into pieces that can match the robot template. We are using Maya for the modelling job.
For example, the mesh model is a 1X1X1 volume=1 box, the robot template has a 1:1:2 volume 0.5 head link with body, and a 1:1:2 volume 0.5 body link with head, then what we need is to cut the box into half.
The matching of volume, aspect ratio and linkage are not strict, reasonable errors can be accepted.
Is there any existing algorithms that can do the job or is there any related topics on this?
Also if you have any idea to solve this problem please enlighten me. Thanks!
EDIT
The problem is, given a mesh object, and a robot template, we need to transform it to the robot.
So now my idea is first cut the object into subparts which match the template, then transform the subparts into robot using Inverse Kinematic maybe.
Sample input and output:
I'd try to just cubes to the correct dimensions by setting the aspect ratio in the cube shape
import maya.cmds as cmds
def scaled_cube(volume, w, d, h):
scale_factor = pow( float(volume) / float(h* w * d), 1.0/3)
return cmds.polyCube(w = w * scale_factor, d = d * scale_factor, h = h * scale_factor)
Edit: After the above comments, this will cut out the portion of a mesh contained in a cuboid (defined here as a maya style bounding box (minx, miny, minz, maxx, maxy, maxz - the same thing you'd get from querying the maya bbox):
def cut_to_fit_bounds(mesh, bbox):
'''
splits an existing mesh
'''
cutmesh = cmds.duplicate(mesh)
minx, miny, minz, maxx, maxy, maxz = bbox
cmds.select(cutmesh)
cmds.polyCut(pc = (minx, 0, 0), ro = (0, 90,0), df =1, ch=0 )
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (maxx, 0, 0), ro = (0, -90,0), df = 1, ch=0)
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, 0, minz), ro = (0, 0,0), df =1, ch=0 )
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, 0, maxz), ro = (0, 180,0), df = 1, ch=0)
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, miny, 0), ro = (-90, 0,0), df =1,ch=0 )
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, maxy, 0), ro = (90, 0,0), df = 1, ch=0)
cmds.polyCloseBorder(ch=0)
cmds.select(cutmesh)
The previous routine could be used to create appropriately sized volumes - by placing them correctly and grabbing their bounding boxes with cmds.xform(q=True, bb=True) cut volumes could be made. After that you should have a cut up copy of the original, although I'd worry about normal artifacts, sliver polys and material issues which are common when using polyCut.

Mathematica: Filling under an infinite function

Mathematica: Filling an infinitely deep potential well
Comment: The proper page for Mathematica questions is this one
I would like to visualize a potential well for a particle in a box in Mathematica similar to the second picture from Wikipedia here.
I have defined my function piecewise
(*Length of the box*)
L = 4;
(*Infinitly deep potential well between 0 and L*)
V[x_] := Piecewise[{
{\[Infinity], x <= 0},
{0, 0 < x < L},
{\[Infinity], L <= x}}]
and would like to obtain a plot function which gives a filled area where the potential goes to infinity.
Unfortunately my tries end up in shaded areas between the "zero region" of the potential, while I would like to have the shading in the infinity region.
Table[Plot[V[x], {x, -5, 10},
Filling -> f], {f, {Top, Bottom, Axis, 0.3}}]
The problem is that Infinity is too much for plot. So let's just give it some other big number. But to prevent it from rescaling the y axis we need to be specific with the upper plot range
Block[{\[Infinity] = 1*^1},
Plot[V[x], {x, -5, 10}, Filling -> Bottom,
PlotRange -> {Automatic, 1}]
]
Alternatively you could plot V[x]/.\[Infinity]->1*^1 instead of Block but I like Block's way better
Just give it values instead of infinity:
(*Length of the box*)L = 4;
(*Infinitly deep potential well between 0 and L*)
V[x_] := Piecewise[{{1, x <= 0}, {0, 0 < x < L}, {1, L <= x}}]
Plot[V[x], {x, -5, 10}, Filling -> Bottom]
Another way using graphic primitives:
wellLeft = 0;
leftBorder = wellLeft - 1;
rightBorder = L + 1;
wellRight = L;
top = 5;
Graphics[{
Hue[0.67, 0.6, 0.6],
Opacity[0.2],
Rectangle[{leftBorder, 0}, {wellLeft, top}],
Rectangle[{wellRight, 0}, {rightBorder, top}]
}, Axes -> True]

Problem with Euler angles from YZX Rotation Matrix

I've gotten stuck getting my euler angles out my rotation matrix.
My conventions are:
Left-handed (x right, z back, y up)
YZX
Left handed angle rotation
My rotation matrix is built up from Euler angles like (from my code):
var xRotationMatrix = $M([
[1, 0, 0, 0],
[0, cx, -sx, 0],
[0, sx, cx, 0],
[0, 0, 0, 1]
]);
var yRotationMatrix = $M([
[ cy, 0, sy, 0],
[ 0, 1, 0, 0],
[-sy, 0, cy, 0],
[ 0, 0, 0, 1]
]);
var zRotationMatrix = $M([
[cz, -sz, 0, 0],
[sz, cz, 0, 0],
[ 0, 0, 1, 0],
[ 0, 0, 0, 1]
]);
Which results in a final rotation matrix as:
R(YZX) = | cy.cz, -cy.sz.cx + sy.sx, cy.sz.sx + sy.cx, 0|
| sz, cz.cx, -cz.sx, 0|
|-sy.cz, sy.sz.cx + cy.sx, -sy.sz.sx + cy.cx, 0|
| 0, 0, 0, 1|
I'm calculating my euler angles back from this matrix using this code:
this.anglesFromMatrix = function(m) {
var y = 0, x = 0, z = 0;
if (m.e(2, 1) > 0.999) {
y = Math.atan2(m.e(1, 3), m.e(3, 3));
z = Math.PI / 2;
x = 0;
} else if (m.e(2, 1) < -0.999) {
y = Math.atan2(m.e(1, 3), m.e(3, 3));
z = -Math.PI / 2;
x = 0;
} else {
y = Math.atan2(-m.e(3, 1), -m.e(1, 1));
x = Math.atan2(-m.e(2, 3), m.e(2, 2));
z = Math.asin(m.e(2, 1));
}
return {theta: this.deg(x), phi: this.deg(y), psi: this.deg(z)};
};
I've done the maths backwards and forwards a few times, but I can't see what's wrong. Any help would hugely appreciated.
Your matrix and euler angles aren't consistent. It looks like you should be using
y = Math.atan2(-m.e(3, 1), m.e(1, 1));
instead of
y = Math.atan2(-m.e(3, 1), -m.e(1, 1));
for the general case (the else branch).
I said "looks like" because -- what language is this? I'm assuming you have the indexing correct for this language. Are you sure about atan2? There is no single convention for atan2. In some programming languages the sine term is the first argument, in others, the cosine term is the first argument.
The last and most important branch of the anglesFromMatrix function has a small sign error but otherwise works correctly. Use
y = Math.atan2(-m.e(3, 1), m.e(1, 1))
since only m.e(3, 1) of m.e(1, 1) = cy.cz and m.e(3, 1) = -sy.cz should be inverted. I haven't checked the other branches for errors.
Beware that since sz = m.e(2, 1) has two solutions, the angles (x, y, z) used to construct the matrix m might not be the same as the angles (rx, ry, rz) returned by anglesFromMatrix(m). Instead we can test that the matrix rm constructed from (rx, ry, rz) does indeed equal m.
I worked on this problem extensively to come up with the correct angles for a given matrix. The problem in the math comes from the inability to determine a precise value for the SIN since -SIN(x) = SIN(-x) and this will affect the other values of the matrix. The solution I came up with comes up with two equally valid solutions out of eight possible solutions. I used a standard Z . Y . X matrix form but it should be adaptable to any matrix. Start by findng the three angles from: X = atan(m32,m33): Y = -asin(m31) : Z = atan(m21,m11) : Then create angles X' = -sign(X)*PI+X : Y'= sign(Y)*PI-Y : Z = -sign(Z)*pi+Z . Using these angles create eight set of angle groups : XYZ : X'YZ : XYZ' : X'YZ' : X'Y'Z' : XY'Z' : X'Y'Z : XY'Z
Use these set to create the eight corresponding matrixes. Then do a sum of the difference between the unknown matrix and each matrix. This is a sum of each element of the unknown minus the same element of the test matrix. After doing this, two of the sums will be zero and those matrixes will represent the solution angles to the original matrix. This works for all possible angle combinations including 0's. As 0's are introduced, more of the eight test matrixes become valid. At 0,0,0 they all become idenity matrixes!
Hope this helps, it worked very well for my application.
Bruce
update
After finding problems with Y = -90 or 90 degrees in the solution above. I came up with this solution that seems to reproduce the matrix at all values!
X = if(or(m31=1,m31=-1),0,atan(m33+1e-24,m32))
Y = -asin(m31)
Z = if(or(m31=1,m31=-1),-atan2(m22,m12),atan2(m11+1e-24,m21))
I went the long way around to find this solution, but it wa very enlightening :o)
Hope this helps!
Bruce

Resources