// simply_connected.cmd // Surface Evolver command to find seams for splitting a multiply-connected // surface into a simply connected surface. Meant for setting up Bonnet // rotations of triply-periodic minimal surfaces. define vertex attribute sc_vmark integer define edge attribute sc_emark integer define facet attribute sc_fmark integer define vertex attribute sc_vdistance integer define edge attribute sc_edistance integer define facet attribute sc_fdistance integer sc_startf := 0 sc_startv := 0 mark_distances := { local changes,current_distance,unmarked_edges,unmarked_vertices; // sanity checks if max(edge,valence) > 2 then { printf "mark_simply_connected error: there are edges with valence > 2.\n"; abort; }; set facet color white; set edge color black; // starting vertex if not valid_element(vertex[sc_startv]) then // find a starting facet foreach vertex vv do { sc_startv := vv.id; break; }; // initialize set vertex sc_vdistance -1; set edge sc_edistance -1; set facet sc_fdistance -1; foreach vertex[sc_startv].facet ff do { ff.sc_fdistance := 1; set ff.vertex sc_vdistance 1; set ff.edge sc_edistance 1; }; vertex[sc_startv].sc_vdistance := 0; current_distance := 1; // sweep with increasing distance, adding further facets that are // edge neighbors as long as Euler sum is ok. do { changes := 0; foreach edge ee where valence == 2 and ee.sc_edistance == current_distance and (ee.facet[1].sc_fdistance*ee.facet[2].sc_fdistance < 0) do { foreach ee.facet fff where fff.sc_fdistance == -1 do { // add facet fff.sc_fdistance := current_distance + 1; set fff.edges.sc_edistance current_distance + 1 where sc_edistance < 0; set fff.vertices.sc_vdistance current_distance + 1 where sc_vdistance < 0; changes += 1; fff.color := (current_distance imod 14) + 1; } }; current_distance += 1; printf "distance %d\n",current_distance; } while changes; } // old version calculates its own distances, but those can be messed // up by the simply-connected mechanism. mark_simply_connected_old := { local changes,current_distance,unmarked_edges,unmarked_vertices; // sanity checks if max(edge,valence) > 2 then { printf "mark_simply_connected error: there are edges with valence > 2.\n"; abort; }; set facet color white; set edge color black; // starting vertex if not valid_element(vertex[sc_startv]) then // find a starting facet foreach vertex vv do { sc_startv := vv.id; break; }; // initialize set vertex sc_vmark -1; set edge sc_emark -1; set facet sc_fmark -1; set facet sc_fdistance -1; foreach vertex[sc_startv].facet ff do { ff.sc_fdistance := 1; set ff.vertex sc_vmark 1; set ff.edge sc_emark 1; }; current_distance := 1; // sweep with increasing distance, adding further facets that are // edge neighbors as long as Euler sum is ok. do { changes := 0; foreach facet ff where sc_fdistance == current_distance do { foreach ff.edge ee where valence == 2 and (ee.facet[1].sc_fdistance*ee.facet[2].sc_fdistance < 0) do { foreach ee.facet fff where fff.sc_fdistance == -1 do { local unmarked_edges,unmarked_vertices; unmarked_edges := sum(fff.edge, sc_emark < 0); unmarked_vertices := sum(fff.vertex, sc_vmark < 0); if unmarked_vertices - unmarked_edges + 1 == 0 then { // add facet fff.sc_fdistance := current_distance + 1; set fff.edges.sc_emark current_distance + 1 where sc_emark < 0; set fff.vertices.sc_vmark current_distance + 1 where sc_vmark < 0; changes += 1; fff.color := (current_distance imod 14) + 1; } } } }; current_distance += 1; printf "distance %d\n",current_distance; } while changes; // distance numbers for the open band facets set facet sc_fmark (sc_fdistance > 0); do { changes := 0; foreach facet ff where sc_fmark == 0 do { local newdist; newdist := min(ff.edge ee where sc_emark > 0, sc_emark); if newdist > 0 and ((newdist < ff.sc_fdistance) or (ff.sc_fdistance < 0)) then { ff.sc_fdistance := newdist + 1; set ff.edge sc_emark newdist + 1; ff.color := (newdist imod 14) + 1; changes += 1; }; }; printf "changes %d\n",changes; } while changes; set edge ee color white where valence==2 and ee.facet[1].sc_fdistance == ee.facet[2].sc_fdistance and max(ee.facet, sc_fmark==0); set edge ee color green where valence==2 and abs(ee.facet[1].sc_fdistance-ee.facet[2].sc_fdistance)==2 and max(ee.facet, sc_fmark==0); } mark_simply_connected := { local max_dist; // assuming mark_distances has already been run. // sanity checks if max(edge,valence) > 2 then { printf "mark_simply_connected error: there are edges with valence > 2.\n"; abort; }; set facet color white; set edge color black; max_dist := max(facet,sc_fdistance); // starting vertex if not valid_element(vertex[sc_startv]) then // find a starting facet foreach vertex vv do { sc_startv := vv.id; break; }; // initialize set vertex sc_vmark -1; set edge sc_emark -1; set facet sc_fmark -1; foreach vertex[sc_startv].facet ff do { ff.sc_fmark := 1; set ff.vertex sc_vmark 1; set ff.edge sc_emark 1; ff.color := 2; }; // sweep with increasing distance, adding further facets that are // edge neighbors as long as Euler sum is ok. do { changes := 0; current_distance := 1; for ( current_distance := 1 ; current_distance <= max_dist ; current_distance += 1 ) { foreach edge ee where sc_emark > 0 and valence == 2 and sc_edistance == current_distance do // make it so only go UP in distance! { foreach ee.facet fff where fff.sc_fmark == -1 and fff.sc_fdistance > current_distance do { unmarked_edges := sum(fff.edge, sc_emark < 0); unmarked_vertices := sum(fff.vertex, sc_vmark < 0); if unmarked_vertices - unmarked_edges + 1 == 0 then { // add facet fff.sc_fmark := 1; set fff.edges.sc_emark 1; set fff.vertices.sc_vmark 1; changes += 1; fff.color := (current_distance imod 14) + 1; } } }; printf "distance %d\n",current_distance; } } while changes; set edge ee color white where valence==2 and ee.facet[1].sc_fdistance == ee.facet[2].sc_fdistance and max(ee.facet, sc_fmark==0); set edge ee color green where valence==2 and abs(ee.facet[1].sc_fdistance-ee.facet[2].sc_fdistance)==2 and max(ee.facet, sc_fmark==0); } // end simply_connected.cmd // Usage: mark_simply_connected