Brep.Repair makes valid brep invalid

I have the following brep and plugin command:

repair.3dm (80.3 KB)

using System;
using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input;
using Rhino.Input.Custom;

namespace LayupRH.Commands
{
	public class MyBrepRepair : Command
	{
		public MyBrepRepair()
		{
			Instance = this;
		}

		public static MyBrepRepair Instance { get; private set; }

		public override string EnglishName => "MyBrepRepair";

		protected override Result RunCommand(RhinoDoc doc, RunMode mode)
		{
			Brep brep;
			Guid brepGuid;

			using (GetObject go = new())
			{
				go.SetCommandPrompt("choose brep to repair");
				go.GeometryFilter = ObjectType.Brep;
				if (go.Get() == GetResult.Cancel)
				{
					return Result.Cancel;
				}
				brep = go.Object(0).Brep();
				brepGuid = go.Object(0).ObjectId;
			}

            if (!brep.IsValidTopology(out string log))
            {
                RhinoApp.WriteLine("invalid before repair: ");
                RhinoApp.WriteLine(log);
            }
            else
            {
                RhinoApp.WriteLine("valid before repair...");
            }

            brep.Repair(0.001);

            if (!brep.IsValidTopology(out log))
            {
                RhinoApp.WriteLine("invalid after repair: ");
                RhinoApp.WriteLine(log);
            }
            else
            {
                RhinoApp.WriteLine("valid after repair...");
            }
            RhinoDoc.ActiveDoc.Objects.Add(brep);

            return Result.Success;
		}
	}
}

When I run the command on the brep, the output is

choose brep to repair
valid before repair...
invalid after repair: 
brep.m_V[0] vertex or brep.m_E[1] edge is not valid.
	vertex.m_ei[0] = 1 but brep.m_E[1].m_vi[] = [2,1]. At least one edge m_vi[] value should be 0.
ON_Brep.m_V[0] is invalid.

I think it’d be safe to guess that this is not intended behavior. I am translating a foreign brep format and I’d like to call Brep.Repair on all translated breps. What should I do to account for this case?

The face with 2 surface singularities seems to be tripping up Brep.Repair, possibly one of its vertices and the vertex’s location from its relative singularity.

If you extract that face, untrim all edges, rejoin, Repair produces a valid Brep.

If you are OK with splitting the face with the 2 singularities into 2 faces with 1 singularity each, use BrepFaceList.SplitBipolarFaces method before Repair.

Thanks for investigating. As I said, I am translating from a foreign Brep format. If I want to call Brep.Repair on every shape, can you confirm that the functions BrepTrimList.MatchEnds, Brep.SetTolerancesBoxesAndFlags, and BrepFaceList.SplitBipolarFaces are enough to make Brep.Repair succeed at making a valid brep?

I have changed my code so that it simply doesn’t call Brep.Repair if the brep is already valid, so fixing the behavior of Brep.Repair is not critical to my code in its current state. I would still like to know the status of the bug report, though.

I can reproduce this and filed this here: RH-95842 Brep Repair: Makes a bad object for a developer to have a look at it.