Builds loops from a set of directed edges, turning left at each vertex
until a repeated edge is found (i.e., LoopType::CIRCUIT). The loops are
further grouped into connected components, where each component consists
of one or more loops connected by shared vertices.
This method is used to build polygon meshes from directed or undirected
input edges. To convert the output of this method into a mesh, the
client must determine how the loops in different components are related
to each other: for example, several loops from different components may
bound the same region on the sphere, in which case all of those loops are
combined into a single polygon. (See s2shapeutil::BuildPolygonBoundaries
and s2builderutil::LaxPolygonVectorLayer for details.)
Note that loops may include both edges of a sibling pair. When several
such edges are connected in a chain or a spanning tree, they form a
zero-area "filament". The entire loop may be a filament (i.e., a
degenerate loop with an empty interior), or the loop may have have
non-empty interior with several filaments that extend inside it, or the
loop may consist of several "holes" connected by filaments. These
filaments do not change the interior of any loop, so if you are only
interested in point containment then they can safely be removed by
setting the "degenerate_boundaries" parameter to DISCARD. (They can't be
removed by setting (options.sibling_pairs() == DISCARD) because the two
siblings might belong to different polygons of the mesh.) Note that you
can prevent multiple copies of sibling pairs by specifying
options.duplicate_edges() == MERGE.
Each loop is represented as a sequence of edges. The edge ordering and
loop ordering are automatically canonicalized in order to preserve the
input ordering as much as possible. Loops are non-crossing provided that
the graph contains no crossing edges. If some edges cannot be turned
into loops, returns false and sets "error" appropriately.
REQUIRES: options.degenerate_edges() == { DISCARD, DISCARD_EXCESS }
(but requires DISCARD if degenerate_boundaries == DISCARD)
REQUIRES: options.sibling_pairs() == { REQUIRE, CREATE }
[i.e., every edge must have a sibling edge]
Builds loops from a set of directed edges, turning left at each vertex until a repeated edge is found (i.e., LoopType::CIRCUIT). The loops are further grouped into connected components, where each component consists of one or more loops connected by shared vertices.
This method is used to build polygon meshes from directed or undirected input edges. To convert the output of this method into a mesh, the client must determine how the loops in different components are related to each other: for example, several loops from different components may bound the same region on the sphere, in which case all of those loops are combined into a single polygon. (See s2shapeutil::BuildPolygonBoundaries and s2builderutil::LaxPolygonVectorLayer for details.)
Note that loops may include both edges of a sibling pair. When several such edges are connected in a chain or a spanning tree, they form a zero-area "filament". The entire loop may be a filament (i.e., a degenerate loop with an empty interior), or the loop may have have non-empty interior with several filaments that extend inside it, or the loop may consist of several "holes" connected by filaments. These filaments do not change the interior of any loop, so if you are only interested in point containment then they can safely be removed by setting the "degenerate_boundaries" parameter to DISCARD. (They can't be removed by setting (options.sibling_pairs() == DISCARD) because the two siblings might belong to different polygons of the mesh.) Note that you can prevent multiple copies of sibling pairs by specifying options.duplicate_edges() == MERGE.
Each loop is represented as a sequence of edges. The edge ordering and loop ordering are automatically canonicalized in order to preserve the input ordering as much as possible. Loops are non-crossing provided that the graph contains no crossing edges. If some edges cannot be turned into loops, returns false and sets "error" appropriately.
REQUIRES: options.degenerate_edges() == { DISCARD, DISCARD_EXCESS } (but requires DISCARD if degenerate_boundaries == DISCARD) REQUIRES: options.sibling_pairs() == { REQUIRE, CREATE } [i.e., every edge must have a sibling edge]