I’ve come across an issue retrieving the infinite region on a non-manifold cube. The cube has internal planes dividing it into 4 internal regions as shown below (with a clipping plane). It also has some internal edges from earlier faces that have been moved/removed.
When I extract the infinite region I should just get a solid, manifold cube but instead get the geometry below. Note that the method to get the the brep representing the infinite region first calls the region.BoundaryBrep() method, which returns null, so I manually create a brep by extracting faces from the infinite region and merging them.
Here is the command that gets the infinite region, and I will also attach the cube model. If you can let me know why the infinite region is coming out as show that would be great. Thanks.
[CommandStyle(Style.ScriptRunner)]
public class InfiniteRegionTestCommand : Command
{
/// <summary>
/// Get the name of the command
/// </summary>
public override string EnglishName
{
get { return "TestGetInfiniteRegion"; }
}
/// <summary>
/// Logic to execute the command
/// </summary>
/// <param name="doc"></param>
/// <param name="mode"></param>
/// <returns></returns>
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
try
{
if (RhinoGet.GetOneObject("Select surface/polysurface to extract infinite region.", false,
ObjectType.Brep | ObjectType.Surface, out ObjRef objRef) == Result.Success)
{
Brep brep = null;
if (objRef.Geometry().HasBrepForm && (brep = Brep.TryConvertBrep(objRef.Geometry())) != null)
{
Brep boundaryBrep = null;
foreach (BrepRegion region in brep.GetRegions())
{
if (!region.IsFinite)
{
boundaryBrep = Utilities.GetBoundaryBrepFromRegion(region, doc.ModelAbsoluteTolerance);
break;
}
}
if (null != boundaryBrep && doc.Objects.AddBrep(boundaryBrep) != Guid.Empty) return Result.Success;
}
}
}
catch (Exception ex)
{
RhinoApp.WriteLine(string.Format("Failed command, {0}, because {1}", EnglishName, ex.Message));
}
return Result.Failure;
}
}
public static class Utilities
{
/// <summary>
/// Workaround method to retrieve the boundary brep for the region. Handles the situation where the Rhino
/// BoundaryBrep() method fails, which seems to happen on some occasions.
/// </summary>
/// <param name="rhinoRegion">The region to create a boundary brep from.</param>
/// <param name="tol">The absolute tolerance to use for the operation</param>
/// <param name="outwardNormals">True if the method should flip the normals if necessary to ensure the
/// normals are pointin outward. Optional argument that defaults to true.</param>
/// <returns>The boundary brep or null if no boundary brep could be created.</returns>
public static Brep GetBoundaryBrepFromRegion(BrepRegion rhinoRegion, double tol, bool outwardNormals = true)
{
if (null == rhinoRegion)
{
return null;
}
// Try to retrieve the boundary brep from the Rhino region. If that fails construct your own from the brep region faces
var boundaryBrep = rhinoRegion.BoundaryBrep();
if (null == boundaryBrep || !boundaryBrep.IsValid || !boundaryBrep.IsSolid || !boundaryBrep.IsManifold)
{
if (rhinoRegion.Brep.IsManifold && rhinoRegion.Brep.GetRegions().Length == 2)
{
boundaryBrep = rhinoRegion.Brep;
}
else
{
// Create a list of breps corresponding to the regions faces
List<Brep> faces = new List<Brep>();
foreach (var fs in rhinoRegion.GetFaceSides())
{
faces.Add(fs.Face.DuplicateFace(true));
}
// Merge the face breps first joining them and then merging if the join produced
// multiple breps such as might happen for a region with internal voids.
var boundaryBreps = Brep.JoinBreps(faces, tol);
if (boundaryBreps.Count() == 1)
{
boundaryBrep = boundaryBreps[0];
}
else if (boundaryBreps.Count() > 1)
{
boundaryBrep = Brep.MergeBreps(boundaryBreps, tol);
}
}
}
if (null != boundaryBrep && boundaryBrep.IsSolid)
{
if ((outwardNormals && boundaryBrep.SolidOrientation == BrepSolidOrientation.Inward) ||
(!outwardNormals && boundaryBrep.SolidOrientation == BrepSolidOrientation.Outward))
{
boundaryBrep.Flip(); // Flip the normals to get the desired normal direction
}
}
return boundaryBrep;
}
}