Steven, I'm a customer that had a similar issue. A good line cutting routine would be a nice addition to MapSuite. For your purposes of joining back together, your solution works great. But your solution will not work if you were to save the polygons to a shapefile, and then let the user try to join them later. You would have lost the original clipping buffer. But what bothers me more, is that the saved polygon is not truly the original polygon that was split (well, one part of the polygon that was split). It actually has a little missing area because of the width of your buffer... no matter how narrow. Your resultant layer now has little tiny gaps between the polygons. It's likely not an issue for your application.
For an academic discussion, I'll paste our solution. This was taken off of a post I found on Google about solving this problem with JTS. I converted it to use the free SQL Spatial Types library, but you could do the concept with NTS and MapSuite, I suspect. Like you, the idea is that you must buffer the cutting line to make a narrow polygon and subtract it from the original polygon. But, we immediately update the resultant multipolygon parts by comparing every vertex on the polygon part for being within tolerance of the original splitting line (tolerance being less than the buffer width). If so, snap that vertex back to the splitting line's closest vertex.
This ensures that both polygon parts are using exactly the same vertex (from the cutting line), and they will union back together in your current session, or two months later when the user changes their mind :)
/// <summary>
/// Cut a polygon into multiple parts with a cutting line. The internal tolerance values for this
/// routine are assuming a projected coordinate system with a linear unit in meters.
/// </summary>
/// <param name="ring">A polygon or multipolygon object that is to be split.</param>
/// <param name="line">A cutting line. This line must start outside of the ring,
/// and end outside of the ring, but there is no test in this function to ensure that.
/// The line can cross into and out of the ring any number of times.</param>
/// <returns>The source geometry decomposed into a list of all polygons that were not intersected
/// with the cutting line, and the parts of any polygon that lie on each side
/// of the cutting line when the polygon is intersected by the cutting line. Null
/// is returned if there is no intersection of the cutting line with the source geometry.
public static List<SqlGeometry> CutPolygonWithLine(SqlGeometry ring, SqlGeometry line)
{
// Clip the cutting line to the polygon boundary. If there is no intersection
// then just return.
SqlGeometry clippedLine = line.STIntersection(ring);
if (clippedLine.STIsEmpty())
return null;
// Create a polygon by buffering the cutting line by a token amount.
SqlGeometry bufferedLine = line.BufferWithTolerance(.01, .1, false);
// Split the polygon with the buffered line by subtracting the buffered line
// from the polygon. This ensures that the polygon gets turned into a multipolygon.
SqlGeometry parts = ring.STDifference(bufferedLine);
// Instantiate a collection of all of the parts of the multipolygon
List<SqlGeometry> sides = new List<SqlGeometry>();
// Iterate through the parts, and snap the vertices of each part that are close
// to the original cutting line back to the actual vertices on the cutting line.
// We are using the standard SqlGeometryBuilder construct to build a new geometry
// from an existing geometry, with an operation to be performed on each component
// of the original geometry during the build process. The operation we perform
// is snapping the point being copied to the nearest point on the origina line
// if it is within tolerance.
for (int idx = 1; idx <= parts.STNumGeometries(); idx++)
{
SqlGeometry part = parts.STGeometryN(idx);
// Instantiate the standard SqlGeometry builder
SqlGeometryBuilder builder = new SqlGeometryBuilder();
// Create a snapping object, to build into the provided builder object.
// This is the MapShots implementation of an object that the builder will call
// to evaluate every point being copied from the source geometry relative to the
// vertices of the clippedLine before copying the point to the new object.
GeometrySnapper snapper = new GeometrySnapper(builder, clippedLine);
// Execute the Populate method on the part, telling it to use our snapping object.
part.Populate(snapper);
// Add the newly constructed part to the list.
sides.Add(builder.ConstructedGeometry);
}
return sides;
}
}