Is there an solid equivalent for the offset curve/washer tool that will slice out an annular cylinder around an existing hole?
I am meshing a part that has holes in surfaces with compound curvature, and I am trying to core out solids bounding the holes to create uniform boundary layers of elements around the holes. Currently, I am having to manually extrude cylindrical surfaces that are concentric with the hole cylinder and use these surfaces to slice the body. Unfortunately, I have many holes and this is very tedious. In many cases, the guide curves of the hole surface and extruded surfaces are clocked at different angles, causing problems for meshing.
How about using the Meshing Toolbox to put a washer surface around each hole quickly. Then use <Geometry><Solid><Embed Face...>? That will create the cylindrical solids you are looking for.
Unfortunately, that doesn't really work for me with the geometry I'm dealing with because the forward and rear surfaces are not parallel and are not perfectly perpendicular to the hole. Also, creating a washer doesn't work consistently because the edge of the hole is ovular rather than circular.
The method I've been using so far has been locating the working plane normal to the hole axis, drawing a circle, and extruding the circle as a surface to slice the body. This is just very tedious, and I can't always locate the central axis of the hole very well.
Have a look at Mark Sherman's post on offset curves. It should be able to do what you are looking for.
This is marginally closer, but still not quite what I'm looking for. I am looking for something that will not merely offset the curves but actually create a spliced solid that is offset from a hole. My ultimate aim here is to be able to create a uniform hex mesh boundary around a hole. The Offset Curve/Washer tool is really only useful for membrane-type meshing.
Once you have the offset curves you should be able to use the <Geometry><Solid><Embed Face...> command and that will give you the solids you are looking for. It might be helpful to perhaps post a picture or two of the geometry in question - or maybe a sample of the geometry if confidentiality allows...
Unfortunately, I do not believe I can share the geometry.
I do have another idea, but I could use some help, as I'm only an intermediate scripter. I have written a script to create lines through the axes of cylindrical surfaces. Ideally, I could expand the script to create a cylinder around these axes with a user specified radius/diameter. I have been looking through the Femap API documentation but there does not seem to be an object method or function that directly performs the same thing as <Geometry><Surface><Cylinder...>. Am I missing something?
Here is the script as is, for reference:
Sub Main Dim App As femap.model Set App = feFemap() Dim surf As femap.Surface Set surf = App.feSurface Dim surfSet As femap.Set Set surfSet = App.feSet Dim skippedSet As femap.Set Set skippedSet = App.feSet Dim rad As Double Dim aLength As Double Dim cBase As Variant Dim nBase(2) As Variant Dim aVect As Variant Dim cEnd(2) As Variant Dim pOffset As Double Dim tracker As femap.TrackData Set tracker = App.feTrackData Dim cTrack As femap.Set Set cTrack = App.feSet Dim checkTol As Double Dim rc As Long ' Begin tracking created curves tracker.Start(4) ' Select cylindrical surfaces rc = surfSet.Select(FT_SURFACE, True, "Select cylindrical surfaces to create Axes") If rc = FE_NOT_EXIST Then App.feAppMessage(FCM_ERROR, "One or more surfaces do not exist") Exit Sub ElseIf rc = FE_CANCEL Then Exit Sub End If ' Prompt user to select length of axis and where to center Begin Dialog UserDialog 270,105,"Axis Length" ' %GRID:10,7,1,1 text 30,14,100,21,"Axis length",.Text1 text 30,42,100,14,"Percent Offset",.Text2 TextBox 140,14,100,14,.axisLength TextBox 140,42,100,14,.offsetValue OKButton 20,70,100,28 CancelButton 140,70,100,28 End Dialog Dim dlg As UserDialog Dialog dlg ' Check axis length If IsNumeric(dlg.axisLength) Then aLength = CDbl(dlg.axisLength) Else App.feAppMessage(FCM_ERROR, "Axis length must be a numeric, non-zero value.") Exit Sub End If ' Check for baseOffset option and offsetValue If dlg.offsetValue = "" Then pOffset = 0.0 ElseIf IsNumeric(dlg.offsetValue) = False _ Or CDbl(dlg.offsetValue) > 1.0 _ Or CDbl(dlg.offsetValue) < 0.0 Then App.feAppMessage(FCM_ERROR, "Offset must be a value >=0 and <=1.") Exit Sub Else pOffset = CDbl(dlg.offsetValue) End If ' Create axis base point and vector Do While surf.NextInSet(surfSet.ID) If surf.Cylindrical(rad, cBase, aVect) = FE_FAIL Then skippedSet.Add(surfSet.CurrentID) Else ' Determine end points for axis For i = 0 To 2 nBase(i) = cBase(i) - aVect(i) * aLength * pOffset cEnd(i) = cBase(i) + aVect(i) * aLength * (1 - pOffset) Next i ' Create line App.feLinePoints(False, nBase, cEnd, False) End If Loop ' Set from created curves tracker.Stop(4) tracker.Created(4, cTrack.ID, False) ' Merge created coincident points and curves checkTol = 0.01 * aLength ' check tolerance as 1% of specified axis length App.feCheckCoincidentCurve(cTrack.ID, checkTol) App.feAppMessage(FCM_NORMAL, cTrack.Count() & " curve(s) created...") If skippedSet.Count() > 0 Then App.feAppMessage(FCM_ERROR, skippedSet.count() & " surfaces were non-cylindrical and skipped.") End If End Sub
Sub Main Dim App As femap.model Dim curveSet As femap.Set Dim surfacesOfCurve As femap.Set Dim firstSurfaces As femap.Set Dim secondSurfaces As femap.Set Dim surfacesNew As femap.Set Dim surfaces1 As femap.Surface Dim surfaces2 As femap.Surface Dim surfaceToCheck As femap.Surface Dim curve1 As femap.Curve Dim vBase As Variant, vNormal As Variant, vCenter As Variant Dim rc As Integer Dim curveID As Long, washerMode As Long, offsetModeFactor As Long Dim planarSurfaceOfCurve As Long, faceSurfaceID As Long Dim washerFactor As Double Dim autoSelect As Boolean, saveSplit As Boolean, extendCurvesToClosestEdge As Boolean Set App = feFemap() Set curveSet = App.feSet Set surfacesOfCurve = App.feSet Set firstSurfaces = App.feSet Set secondSurfaces = App.feSet Set surfacesNew = App.feSet Set surfaces1 = App.feSurface Set surfaceToCheck = App.feSurface Set curve1 = App.feCurve washerMode = 1 offsetModeFactor = 0 washerFactor = 1.0 autoSelect = False saveSplit = True extendCurvesToClosestEdge = True surfaces1.Reset While surfaces1.Next() rc = firstSurfaces.Add(surfaces1.ID) Wend rc = surfacesNew.Copy(firstSurfaces.ID) rc = curveSet.SelectID(FT_CURVE, "Select Curve for Washer", _ curveID) rc = curve1.Get(curveID) rc = curve1.Center(vCenter) rc = curveSet.Add(curveID) rc = surfacesOfCurve.AddRule(curveID, FGD_SURFACE_BYCURVE) surfacesOfCurve.Reset While surfacesOfCurve.Next() rc = surfaceToCheck.Get(surfacesOfCurve.CurrentID) rc = surfaceToCheck.Planar(vBase, vNormal) If rc = FE_OK Then faceSurfaceID =surfacesOfCurve.CurrentID End If Wend rc = App.feCurveOffsetCurveWasher2(curveSet.ID, _ faceSurfaceID, washerMode, _ autoSelect, saveSplit, extendCurvesToClosestEdge, _ washerFactor, offsetModeFactor) Set surfaces2 = App.feSurface surfaces2.Reset While surfaces2.Next() rc = secondSurfaces.Add(surfaces2.ID) Wend rc = surfacesNew.AddNewRemoveCommonSet(secondSurfaces.ID) surfacesNew.Reset rc = App.feSolidEmbedFace(faceSurfaceID, 0, 1, 0., 0., True) rc = App.feSolidEmbedFace(surfacesNew.First, 0, 1, 0., 0., True) End Sub
Create the circles (one per hole location), then project them onto the surfaces with the meshing toolbox/geometry editing/project curve. They won't be perfect circles anymore, but close enough. Then try using <Geometry><Solid><Embed Face...> as Chris suggested.
That's what I've been doing thus far. I'm just looking for something that would be more expedient than manually locating the work plane, drawing a circle, projecting it to a surface, and then embedding the face. It's fine for one to two holes, but gets cumbersome when you have many holes.