To test the procedure more completely, I added contour lines for elevation 1000m.<div>Threshold distance was 100m instead of 25 in this test.<br><div>These contours have gaps between lines. 2 of them are included in the map frame, one is cut by the frame.</div>
<div>Img1 shows these new contours.</div><div><br></div><div>At the end of step 6, some linestrings are still in the seg table: contours entirely contained in the map frame.</div><div><br></div><div><div>• Recreate association table with remaining lines:</div>
<div><br></div><div><font face="'courier new', monospace">drop table tmp;</font></div><div><font face="'courier new', monospace">create table tmp as (</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">       </span>with closest as (</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>select s1.elev as elev, s1.gid, s1.path as path, s2.gid as closest,</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">               </span>s2.geom,</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>st_distance(st_collect(st_startpoint(s1.geom), st_endpoint(s1.geom)), st_collect(st_startpoint(s2.geom), st_endpoint(s2.geom))) as dist,</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>row_number() over (</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                       </span>partition by s1.gid </font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                        </span>order by s1.gid,</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                          </span>st_distance(st_collect(st_startpoint(s1.geom), st_endpoint(s1.geom)), st_collect(st_startpoint(s2.geom), st_endpoint(s2.geom)))) as r</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>from seg s1, seg s2</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">               </span>where s1.elev = s2.elev</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>and s1.gid <> s2.gid</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>) select distinct * from closest </font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>where r < 3 and dist < 100</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">  </span>order by elev, gid, r</font></div>
<div><font face="'courier new', monospace">);</font></div><div><br></div><div>• Then re-iterate to close remaining contours: brute force is used:</div><div>each remaining segment will be merged with its neighbors, leading to several duplicate lines:</div>
<div> as many duplicate as there are lines in a contour.</div><div>The final distinct clause will remove these duplicates.</div><div><br></div><div><font face="'courier new', monospace">drop table merged_contour2;</font></div>
<div><font face="'courier new', monospace">create table merged_contour2 as (</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>with recursive tab as (</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>select s.gid, s.elev, t.closest, array[s.gid, t.closest] as gids,</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">         </span>st_makeShortestLine(s.geom, t.geom) as geom, 1 as rank</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>from seg s, tmp t, frame f</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>where s.gid = t.gid</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>and s.elev = t.elev</font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">           </span>UNION ALL</font></div>
<div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">            </span>select tab.gid, tab.elev, tmp.closest, gids || tmp.closest,  </font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>st_makeShortestLine(tab.geom, tmp.geom) as geom, rank+1</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">           </span>from tmp, tab</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>where tmp.elev = tab.elev</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">         </span>and tmp.gid = tab.closest</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>and not (tmp.closest = any(gids)) </font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>) select distinct on (geom) geom, gid, elev, rank, gids from (</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>select distinct on (gid) gid, elev, rank, gids, st_forceClosed(geom) as geom </font></div><div><font face="'courier new', monospace">                from (</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                        </span>select * from tab </font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                        </span>order by gid, rank desc</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>) as foo</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">  </span>) as bar</font></div>
<div><font face="'courier new', monospace">);</font></div><div><br></div><div>• The final association will group all contours based on same elevation, from our working tables:</div><div>seg_closed, seg_border, merged_contour1 and merged_contour2:</div>
<div><br></div><div><font face="'courier new', monospace">drop table if exists all_contour;</font></div><div><font face="'courier new', monospace">create table all_contour as (</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>with all_c as (</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>select elev, geom from merged_contour1</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">            </span>UNION</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>select elev, geom from merged_contour2</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">            </span>UNION</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>SELECT elev, geom from seg_border</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">         </span>UNION</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">                </span>select elev, geom from seg_closed</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre"> </span>) select elev, st_union(geom) as geom</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>from all_c</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>group by elev</font></div>
<div><font face="'courier new', monospace">);</font></div></div></div><div><font face="'courier new', monospace"><br></font></div><div><font face="arial, helvetica, sans-serif">Img2 shows the final result.</font></div>
<div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">Nicolas</font></div>