For finite element purposes I need a frustum of a cone with a finite wall thickness, i.e. a tapered pipe.
To make a cone is easy
Needs["NDSolve`FEM`"]
c = BoundaryDiscretizeRegion[Cone[{{0, 0, 0}, {-1, 0, 0}}, 0.12]]
mesh = ToElementMesh[c]; mesh["Wireframe"]
So my idea was to use RegionDifference to make a frustum. Here is my module.
ClearAll[coneFrustum];
coneFrustum::usage =
"coneFrustum[{pt1, pt2, },r1 ,r2 ,height] generates a frustum of \
cone with axis going from pt1 to pt2 and with radii r1, r2";
coneFrustum[{{x1_, y1_, z1_}, {x2_, y2_, z2_}}, r1_, r2_, L_] :=
Module[{cL, vec},
cL = L r1/(r1 - r2);
vec = ({x2, y2, z2} - {x1, y1, z1})/
Norm[{x2, y2, z2} - {x1, y1, z1}];
RegionDifference[
BoundaryDiscretizeRegion[
Cone[{{x1, y1, z1}, cL vec}, r1]
],
BoundaryDiscretizeRegion[
Cone[{{x2, y2, z2}, (cL - L) vec}, r2]
]
]
]
This is what I get for a solid frustum
cf1 = coneFrustum[{{-0.1, 0, 0}, {-0.3, 0, 0}}, 0.12, 0.1, 0.2]
So I have my frustum but I have not managed to take away the part of the cone beyond the frustum. I have a hollow shell of the difference of the cones.
Is there a better way of doing this? I still have to go on to subtract a smaller inner frustum to make my hollow shape.
Edit
As kglr pointed out I made a simple error with my code. The tip has to have the same coordinates. Here is the corrected version.
ClearAll[coneFrustum];
coneFrustum::usage =
"coneFrustum[{pt1, pt2}, r1,r2, height] generates a frustum of cone \
with axis going from pt1 to pt2 and with radii r1, r2";
coneFrustum[{{x1_, y1_, z1_}, {x2_, y2_, z2_}}, r1_, r2_, L_] :=
Module[{cL, vec},
cL = L r1/(r1 - r2);
vec = ({x2, y2, z2} - {x1, y1, z1})/
Norm[{x2, y2, z2} - {x1, y1, z1}];
RegionDifference[
BoundaryDiscretizeRegion[
Cone[{{x1, y1, z1}, cL vec}, r1]
],
BoundaryDiscretizeRegion[
Cone[{{x2, y2, z2}, cL vec}, r2]
]
]
]
Now we make two frustums and subtract.
cf1 = coneFrustum[{{-0.1, 0, 0}, {-0.3, 0, 0}}, 0.12, 0.1, 0.2];
cf2 = coneFrustum[{{-0.1, 0, 0}, {-0.3, 0, 0}}, 0.1, 0.08, 0.2];
reg = RegionDifference[cf1, cf2]
And to get the mesh
mesh = ToElementMesh[reg]; mesh["Wireframe"]
The method from Henrik Schumacher below using ImplicitRegion
is also a good solution.
Are there any good reasons why one could be better than the other?