In using 'intersection' to crop / clip a single 'braided' line using a rectangle (actually a grown version of that rectangle using 'buffer'), the internal portion of the line gets split on self-intersections. The result of the intersection operation is a MultiLineString.
I would like to avoid that, and just get one internal 'braided' line. Why does the intersection method do this? Is there a way to control it? Is there a quicker way to end up with one single line than joining the LineStrings end-to-end after the intersection operation?
The responses to Welding individual line segments into one LineString using Shapely seem to indicate that shapely.ops.linemerge should be the way to go - but it doesn't seem to do the trick, maybe there's something I'm misunderstanding:
from shapely.geometry import LineString,Polygon,MultiLineString,MultiPolygon,GeometryCollection
from shapely.ops import split,linemerge
...
result=targetGeom&boundaryGeom # could be MultiPolygon or MultiLinestring or GeometryCollection
logging.info('crop result:'+str(result))
result=linemerge(result)
logging.info('after linemerge:'+str(result))
Running the code on the above shapes:
INFO:root:crop: target=c1 boundary=c2
INFO:root:crop result:MULTILINESTRING ((-121.108305669868 39.29086839149927, -121.1084962057916 39.29034474676413, -121.1080157152655 39.29023810613076), (-121.1080157152655 39.29023810613076, -121.1070370840875 39.29002090757433, -121.1083674597589 39.28961403057203, -121.1080157152655 39.29023810613076), (-121.1080157152655 39.29023810613076, -121.1076812116669 39.29083159238037))
INFO:root:after linemerge:MULTILINESTRING ((-121.108305669868 39.29086839149927, -121.1084962057916 39.29034474676413, -121.1080157152655 39.29023810613076), (-121.1080157152655 39.29023810613076, -121.1076812116669 39.29083159238037), (-121.1080157152655 39.29023810613076, -121.1070370840875 39.29002090757433, -121.1083674597589 39.28961403057203, -121.1080157152655 39.29023810613076))
(shorthand translation - there is no rounding error, the endpoints are exact matches):
INFO:root:crop result:MULTILINESTRING ((A, B, C), (C, D, E, C), (C, F))
INFO:root:after linemerge:MULTILINESTRING ((A, B, C), (C, F), (C, D, E, C))
It looks like the last two segments of the multilinestring are swapped, but otherwise it's still the same three unmerged segments:
UPDATE: I guess this is really a question of how to preserve complex / non-simple lines (is_simple=False) during the geometry operations. Found the same question here from several years back, which had no great solution other than brute-force.