I'm trying to use gmsh 4.7.1 to create a mesh within a 3D volume, that is a sphere with a concentric spherical hole (in other words, I have a spherical shell). In order to do so, I wrote the following .geo file:
// Gmsh project created on Wed Feb 17 15:22:45 2021
SetFactory("OpenCASCADE");
//+
Sphere(1) = {0, 0, 0, 0.1, -Pi/2, Pi/2, 2*Pi};
//+
Sphere(2) = {0, 0, 0, 1, -Pi/2, Pi/2, 2*Pi};
//+
Surface Loop(3) = {2};
//+
Surface Loop(4) = {1};
//+
Volume(3) = {3, 4};
//+
Physical Surface(1) = {1};
//+
Physical Surface(2) = {2};
//+
Physical Volume(3) = {3};
But, as soon as I create a 3D mesh by using the 3D command in the gmsh gui, my inner hole gets meshed too, while I'd like to have no elements of the mesh within the hole.
What am I doing wrong? How can I obtain the desired result? Thank you.
There are several issues at play here:
Sphere command, already creates a volume, not surfaces as you expect.
due to the point above, the command Surface Loop(3) = {2}; is assumed to create a surface loop from a volume, which is 1) not a supported operation. 2) will try to use the surface with the tag 2. It is unclear, what it will do in reality (as a surface with the tag 2 probably still exists).
Thus, the Volume command gets some weird things as an input
and it is all connected with the fact that the characteristic length is not setup, thus the mesh density is quite arbitrary.
If you insist on using the OpenCASCADE kernel, you probably want to use boolean operations.
Here is the code I have with an arbitrarily chosen characteristic length of 0.05 for all the points defining the solid spherical shell:
SetFactory("OpenCASCADE");
Sphere(1) = {0, 0, 0, 0.1, -Pi/2, Pi/2, 2*Pi};
Sphere(2) = {0, 0, 0, 1, -Pi/2, Pi/2, 2*Pi};
BooleanDifference(3) = { Volume{2}; Delete; }{ Volume{1}; Delete; };
Characteristic Length{ PointsOf{ Volume{3}; } } = 0.05;
Visualization from Paraview of the produced mesh with clipping:
Related
I have detected blob keypoints in opencv c++. The centroid displays fine. How do I then draw a bounding box around the detected blob if I only have the blob center coordinates? I can't work backwards from center because of too many unknowns(or so I believe).
threshold(imageUndistorted, binary_image, 30, 255, THRESH_BINARY);
Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
// Detect blob
detector->detect(binary_image, binary_keypoints);
drawKeypoints(binary_image, binary_keypoints, bin_image_keypoints, Scalar(0, 0, 255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//draw BBox ?
What am I overlooking to draw the bounding box around the single blob?
I said:
I can't work backwards from center because of too many unknowns(or so I believe).
There is not limited information if blob size is used: keypoints.size which returns the diameter of the blob in question. Though there might be some inaccurate results with highly asymmetric or lopsided targets, this worked well for me b/c I used spheroid objects. Moments/ is probably the better approached for the asymmetrical targets.
keypoints.size should not be confused with keypoints.size(). The latter does a count in the vector of objects in my case the former is the diameter. Using both.
Using the diameter I can then calculate the rest with no problem:
float TLx = (ctr_x - r);
float TLy = (ctr_y - r);
float BRx = (ctr_x + r);
float Bry = (ctr_y + r);
Point TLp(TLx-10, TLy-10); //works fine without but more visible with enhancement
Point BRp(BRx+10, Bry+10); //same here
std::cout << "Top Left: " << TLp << std::endl << "Right Lower:" << BRp << std::endl;
cv::rectangle(bin_with_keypoints, TLp, BRp, cv::Scalar(0, 255, 0));
imshow("With Green Bounding Box:", bin_with_keypoints);
TLp = top left point with 10px adjustments to make box bigger.
BRp = bottom right point
TLx, TLy are calculated from blob center coordinates as well as BRps. If you are going to use multiple targets would suggest contours approach (with the moments). I have 1 - 2 blobs to keep track of which is a lot easier but keeps resource usage down.
Rectangle drawing function can also work with Rect (diameter = keypoint.size)
Rect r(TLp, BRp, center_x + diameter/2, center_y+diamter/2) // r(TLc, BRc, width, heigth)
cv::rectangle(bin_with_keypoints, rect, cv::Scalar(0, 255, 0));
I made a trinagle in Gmsh. The .geo file looks like this:
// Gmsh project created on Tue Jun 30 13:15:37 2020
SetFactory("OpenCASCADE");
//+
Point(1) = {0, 0, 0, 1.0};
//+
Point(2) = {1, 0, 0, 1.0};
//+
Point(3) = {0, 1, 0, 1.0};
//+
Line(1) = {1, 2};
//+
Line(2) = {2, 3};
//+
Line(3) = {3, 1};
//+
Curve Loop(1) = {1, 2, 3};
//+
Plane Surface(1) = {1};
Now I need a .msh V2 Ascii file. I export it (I tried checking the options "Save all elements" and "Save parametric coordinates" and I always get the following:
$MeshFormat
2.2 0 8
$EndMeshFormat
$Nodes
0
$EndNodes
$Elements
0
$EndElements
So it's basically empty and I just can't figure out whats wrong.
It is highly likely, that you have not generated the mesh yet. Thus, there are no elements to be exported.
Since you have a surface model, you are probably up for a 2-D mesh:
Mesh->2D
After that, you can proceed with exporting it in a .msh V2 format as you identified in your question.
The same can be achieved by pressing m->2 on the keyboard.
While this will work, the model you currently have is missing Physical Surfaces. And, potentially, Physical Lines if you are interested in 1-D meshes as well. By default, GMSH outputs all elements; however, very often one needs finer control over what mesh elements are exported and with which tags.
Your mesh is a 2D problem. You can generate the msh file in ascii v2 by exectuing in the terminal:
gmsh -2 <input_name>.geo -o <output_name>.msh -format msh2
The -2 indicates the dimension (for a 3D problem, it would be -3) and msh2 will save the file in ascii v2.
I am trying to import a 3D mesh produced with Gmsh in FiPy. A test with a 2D mesh worked fine. If the model then is extruded and imported with Gmsh3D I get an error message.
GmshException: Gmsh hasn't produced any cells! Check your Gmsh code.
I'm working on Win10 with Python 3.7.3, Fipy 3.1.3 and Gmsh 3.0.6 (as recommended).
The test2D.geo test file:
SetFactory("OpenCASCADE");
cl = 0.5;
bs = 2.;
Point(1) = {0, 0, 0, cl};
Point(2) = {0, bs, 0, cl};
Point(4) = { bs, 0, 0, cl};
Point(3) = {bs, bs, 0, cl};
Line(5) = {1, 2};
Line(6) = {2, 3};
Line(7) = {3, 4};
Line(8) = {4, 1};
Line Loop(10) = {6, 7, 8, 5};
Plane Surface(1) = {10};
Extrude {0, 0, 1} {
Surface{1};
}
and:
from fipy import *
mesh = Gmsh3D("test2D.msh")
The error message is:
GmshException: Gmsh hasn't produced any cells! Check your Gmsh code.
I don't see my mistake and hope someone can help me here.
Thanks in advance
Edited for the Gmsh output:
Gmsh output:
Info : Running 'gmsh C:\Users\Tinka\AppData\Local\Temp\tmpj4zr8g_c.geo -3 -nopopup -format msh -o C:\Users\Tinka\AppData\Local\Temp\tmpnz1bp4vu.msh' [Gmsh 3.0.6, 1 node, max. 1 thread]
Info : Started on Tue May 28 19:50:42 2019
Info : Reading 'C:\Users\Tinka\AppData\Local\Temp\tmpj4zr8g_c.geo'...
Info : Done reading 'C:\Users\Tinka\AppData\Local\Temp\tmpj4zr8g_c.geo'
Info : Finalized high order topology of periodic connections
Info : Meshing 1D...
Info : Done meshing 1D (0 s)
Info : Meshing 2D...
Info : Done meshing 2D (0 s)
Info : Meshing 3D...
Info : Done meshing 3D (0 s)
Info : 0 vertices 0 elements
Info : Writing 'C:\Users\Tinka\AppData\Local\Temp\tmpnz1bp4vu.msh'...
Info : Done writing 'C:\Users\Tinka\AppData\Local\Temp\tmpnz1bp4vu.msh'
Info : Stopped on Tue May 28 19:50:42 2019
This problem with gmsh and spyder has been fixed in FiPy 3.3, released earlier today; thank you for reporting it.
The other problem you reported in the chat is different. As documented for Gmsh2D, but not Gmsh3D:
... // attention: if you use any "Physical" labels, you *must* label
... // all elements that correspond to FiPy Cells (Physical Surface in 2D
... // and Physical Volume in 3D) or Gmsh will not include them and FiPy
... // will not be able to include them in the Mesh.
...
... // note: if you do not use any labels, all Cells will be included.
Adding Physical Volumes("cells") = {1}; to your .geo script will remedy that issue.
I changed the name of the argument in Gmsh3D to test2D.geo and removed the first line from the geo file and things seem to be working.
>>> from fipy import Gmsh3D
>>> mesh = Gmsh("test2D.geo")
>>> print(mesh.cellCenters)
[[1.34821429 1.24404762 1.34821429 ...
...
I'm not sure what the first line does, but I get Error : Gmsh requires OpenCASCADE to add vertex and no vertices or cells are generated if it's included, but it isn't necessary for generating the mesh.
I think that FiPy Gmsh classes take both geo and msh formatted files, but the file name does need to refer to the actually file on disk.
I'm using FiPy version, 3.2+2.gccec299e, and Gmsh version, 3.0.6.
I'm trying to make a mesh of a piece of beam with stirrup and bars, but I'm having some trouble with stirrup, it is inside the main domain, and I do not know how to solve it. I'm attaching the .geo file, hoping someone could help. Maybe there are other way to mesh it, I do not know.
SetFactory("OpenCASCADE");
// Input
Rectangle(1) = {0, 0, 0, 300, 300, 0};
Disk(2) = {50, 50, 0, 10, 10};
Disk(3) = {50,250,0,10,10};
Disk(4) = {250,250,0,10,10};
Disk(5) = {250,50,0,10,10};
Rectangle(6) = {30,30,146,240,240,10};
Rectangle(7) = {40,40,146,220,220,10};
// Start Operations
s() = BooleanFragments{ Surface{1}; Delete; }{ Surface{2,3,4,5}; Delete;};
ext() = Extrude{0,0,300} {Surface{s()}; Layers{10}; Recombine;};
st() = BooleanFragments{ Surface{6}; Delete;}{Surface{7}; Delete;};
Recursive Delete {Surface{7}; }
Extrude{0,0,10} {Surface{22}; Layers{10}; Recombine;}
BooleanFragments{ Volume{5}; Delete;}{Volume{6}; Delete;}
// Mesh Options all elements needs to be Hexa
Mesh.RecombineAll = 2;
Not a complete answer; however, I think I identified the problem that probably causes the major troubles:
The circular extrusions (cylinders) touch the stirrup exactly at the vertices, thus creating complications to OpenCASCADE-based BooleanFragments operation.
The following code:
SetFactory("OpenCASCADE");
// Input
Rectangle(1) = {0, 0, 0, 300, 300, 0};
Disk(2) = {52, 52, 0, 10, 10};
Disk(3) = {52,248,0,10,10};
Disk(4) = {248,248,0,10,10};
Disk(5) = {248,52,0,10,10};
Rectangle(6) = {30,30,146,240,240,10};
Rectangle(7) = {40,40,146,220,220,10};
// Start Operations
s() = BooleanFragments{ Surface{1}; Delete; }{ Surface{2,3,4,5}; Delete;};
ext() = Extrude{0,0,300} {Surface{s()}; Layers{10}; Recombine;};
st() = BooleanFragments{ Surface{6}; Delete;}{Surface{7}; Delete;};
Recursive Delete {Surface{7}; }
Extrude{0,0,10} {Surface{22}; Layers{10}; Recombine;}
BooleanFragments{ Volume{5}; Delete;}{Volume{6}; Delete;}
// Mesh Options all elements needs to be Hexa
Mesh.RecombineAll = 2;
where I slightly shifted the cylinders to the inside (50->52 and 250 -> 248) should not have the meshing problem.
However, this disconnects the cylinders from the loop and modifies the problem drastically. Here is a zoom on the problematic part in the original, unmodified setup.
So, what you required from the CAD tool, is to handle the merging of those two surfaces (the loop and the cylinder) automatically using BooleanFragments, which might be problematic, especially if one has to take floating-point arithmetic aspects into account.
I am looking for a solution to intersection point of a cube and a line. So i used
GLES20.glReadPixels(touchX, touchY, 1, 1, GLES20.GL_DEPTH_COMPONENT, GLES20.GL_FLOAT, zz);
and i showed the zz , but result was 0. so how could i get the depth buffer value of a Cube when i touched on the cube(actually on the 2d screen). I use GLES20 and Android API level15.And My code is below.
ByteBuffer PixelBuffer = ByteBuffer.allocateDirect(4);
ByteBuffer zBuffer = ByteBuffer.allocateDirect(4);
PixelBuffer.order(ByteOrder.nativeOrder());
PixelBuffer.position(0);
zBuffer.order(ByteOrder.nativeOrder());
zBuffer.position(0);
FloatBuffer zz;
zz = zBuffer.asFloatBuffer();
GLES20.glReadPixels(touchX, touchY, 1, 1, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, PixelBuffer);
GLES20.glReadPixels(touchX, touchY, 1, 1, GLES20.GL_DEPTH_COMPONENT, GLES20.GL_FLOAT, zz);
by the way picking color works fine.
Thanks!
You forget to prepare target framebuffer to read... Try like this:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, deviceWidth, deviceHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
Or just write simple shader and render your zbuffer data into your FBO, simething like
gl_FragColor = vec4(vec3(gl_FragCoord.z), 1.0);
and then read color information form this FBO...