Sure, there are lots of ways this could be done.
Before this NGon mesh stuff, VSPAERO would try to clean up tris into quads itself. It was generally pretty good about recovering simple quads split into two tris (though sometimes it would get confused and pair up regions in the 'wrong' way).
However, the simple case is not the tough part.
Here is a typical CompGeom intersection between a wing and a pod. Notice the ugly slivers near the intersection.
There are ways to try to clean this up, but it isn't trivial.
However, OpenVSP has an advantage. We created the tris from quads in the first place.
When I split the tris into quads, I give every try a number -- iQuad. It is simply an integer that counts which quad the triangle came from. There are other identifying numbers too -- such as tag, that identifies which surface and subsurface the tri came from.
When tris are intersected, intermediate nodes and edges are created. The intersected tris are then split into multiple smaller tris that obey the intersection edges. During this split, all the 'child' tris inherit their parent's identifying information.
Interior tris are identified and discarded -- leaving us with the mesh we get from CompGeom -- with ugly tris at the intersections.
Now, to convert this into an NGon mesh, I simply consider every edge in the mesh. If an edge is manifold (has two faces), and those faces have identical tag and iQuad, then I remove that edge -- merging those two faces. Tris become quads and quads become NGons.
This results in the NGon mesh like this:
The great thing about this is that it is essentially exact -- with no heuristics required. I simply have to track iQuad through the whole process and then manipulate the topology of the mesh to clean it up. There are no tolerances, to computations, no iteration, etc. It makes for a very fast conversion.
There are other more complex things going on during the NGon conversion -- but this is the core of the algorithm.
The only catch -- you must identify iQuad for every triangle before you perform the intersection etc.
If you want two neighboring tris to eventually get merged, they must have the same iQuad value from the start.
Rob