I am trying to programmatically (with pyqgis) clip contour lines that I've generated in QGIS, but make it so that the clipping mask forms the new edges of the contours, rather than leaving the contours open. The way I'm kind of thinking about this is that I want to "squeeze" down the contours to the extent of the clipping mask, at which point even numbers of overlapping lines on the edges will cancel each-other out and make open gaps (keeping things topologically sane).
The drawing below shows what I'm getting at. The left shows the contour lines for a single elevation that I'm clipping with a square bounding box. The middle shows the result of clipping. The right shows what I want to have as my result. The bottom shows the inverse of what I want to do.
I'm pretty sure I have a solid algorithm thought up to do this, but I want to see if there's a simple plugin or script that does this already so I don't have to sink a bunch of effort into implementing it. Working in QGIS 3.8.3 at the moment.
For those who are interested, here's my proposed algorithm. Please poke any holes you can. Where I say to connect two endpoints, assume there is a function that will figure out how to trace the edge of the bounding box rather than a straight connection (important for corners, for example). This relies on the contour lines not overlapping:
Generate contour lines.
Check orientation of all contour lines, and ensure all are oriented clockwise. (Is this already the case?) Flip any that aren't.
Clip contours using bounding mask.
Separate out the contour lines by elevation, and work on one elevation at a time.
Going clockwise, find all the endpoints on the edge of the clipping mask, and create an ordered list of the ID of the lines which those endpoints belong to: [1, 2, 3, 4, 4, 5, 6, 6, 5, 3, 2, 1]
Cycle that list to the first repeated ID (will have at least one): [4, 4, 5, 6, 6, 5, 3, 2, 1, 1, 2, 3]
Close those first two endpoints and check the orientation of the resulting polygon. If clockwise, continue. If counter-clockwise, you are about to create the bottom picture, so you need to revert that closure and cycle the list of IDs by 1.
Going through the ordered list of endpoints, connect each successive pair. If the endpoints have the same line ID, the contour is closed and you can continue. If the endpoints have different IDs, merge the second line onto the first and replace its IDs in the list with that of the first.
Do this for all contour elevations.