Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Philip Trettner
polymesh
Commits
1b68796e
Commit
1b68796e
authored
Jul 02, 2018
by
Philip Trettner
Browse files
rotate kinda works
parent
644f1cbc
Changes
6
Hide whitespace changes
Inline
Side-by-side
Readme.md
View file @
1b68796e
...
...
@@ -22,4 +22,6 @@ Best used with glm and glow.
*
opposite edges (from vertex)
*
cotangens weights etc.
*
smoothing
*
make handle.
<primitives>
() contain only valid ones and provide an all_
<primitives>
() version
\ No newline at end of file
*
make handle.
<primitives>
() contain only valid ones and provide an all_
<primitives>
() version
*
boundary iterators
*
_copy versions of topological operations that copy attributes
\ No newline at end of file
src/polymesh/Mesh.cc
View file @
1b68796e
...
...
@@ -189,6 +189,9 @@ void Mesh::assert_consistency() const
assert
(
h
.
vertex_from
().
outgoing_halfedges
().
contains
(
h
));
assert
(
h
.
edge
().
halfedgeA
()
==
h
||
h
.
edge
().
halfedgeB
()
==
h
);
assert
(
h
.
next
().
vertex_from
()
==
h
.
vertex_to
());
assert
(
h
.
prev
().
vertex_to
()
==
h
.
vertex_from
());
}
// check vertex consistencies
...
...
src/polymesh/Mesh.hh
View file @
1b68796e
...
...
@@ -140,6 +140,11 @@ private:
/// Does NOT invalidate iterators!
vertex_index
add_vertex
();
/// Allocates a new face
face_index
alloc_face
();
/// Allocates a new edge
edge_index
alloc_edge
();
/// Adds a face consisting of N vertices
/// The vertices must already be sorted in CCW order
/// (note: trying to add already existing halfedges triggers assertions)
...
...
@@ -155,6 +160,22 @@ private:
/// same as add_or_get_edge but returns the apattrriate half-edge
halfedge_index
add_or_get_halfedge
(
vertex_index
v_from
,
vertex_index
v_to
);
/// splits a face
vertex_index
face_split
(
face_index
f
);
/// splits an edge
vertex_index
edge_split
(
edge_index
f
);
/// splits a half-edge
vertex_index
halfedge_split
(
halfedge_index
f
);
/// rotates an edge to next
void
edge_rotate_next
(
edge_index
e
);
/// rotates an edge to prev
void
edge_rotate_prev
(
edge_index
e
);
/// rotates a half-edge to next
void
halfedge_rotate_next
(
halfedge_index
h
);
/// rotates a half-edge to prev
void
halfedge_rotate_prev
(
halfedge_index
h
);
/// removes a face (actually sets the removed status)
/// modifies all adjacent vertices so that they correctly report is_boundary true
void
remove_face
(
face_index
f_idx
);
...
...
src/polymesh/impl/impl_mesh.hh
View file @
1b68796e
...
...
@@ -17,6 +17,36 @@ inline vertex_index Mesh::add_vertex()
return
idx
;
}
inline
face_index
Mesh
::
alloc_face
()
{
auto
idx
=
face_index
((
int
)
mFaces
.
size
());
mFaces
.
push_back
(
face_info
());
// notify attributes
auto
fCnt
=
(
int
)
mFaces
.
size
();
for
(
auto
p
=
mFaceAttrs
;
p
;
p
=
p
->
mNextAttribute
)
p
->
resize
(
fCnt
,
false
);
return
idx
;
}
inline
edge_index
Mesh
::
alloc_edge
()
{
auto
idx
=
edge_index
((
int
)
mHalfedges
.
size
()
>>
1
);
mHalfedges
.
push_back
(
halfedge_info
());
mHalfedges
.
push_back
(
halfedge_info
());
// notify attributes
auto
hCnt
=
(
int
)
mHalfedges
.
size
();
auto
eCnt
=
(
int
)
mHalfedges
.
size
()
>>
1
;
for
(
auto
p
=
mEdgeAttrs
;
p
;
p
=
p
->
mNextAttribute
)
p
->
resize
(
eCnt
,
false
);
for
(
auto
p
=
mHalfedgeAttrs
;
p
;
p
=
p
->
mNextAttribute
)
p
->
resize
(
hCnt
,
false
);
return
idx
;
}
inline
face_index
Mesh
::
add_face
(
const
vertex_handle
*
v_handles
,
int
vcnt
)
{
mFaceInsertCache
.
resize
(
vcnt
);
...
...
@@ -500,6 +530,284 @@ inline halfedge_index Mesh::prev_valid_idx_from(halfedge_index idx) const
return
{};
// invalid
}
inline
vertex_index
Mesh
::
face_split
(
face_index
f
)
{
// TODO: can be made more performant
auto
h_begin
=
face
(
f
).
halfedge
;
// remove face
remove_face
(
f
);
// add vertex
vertex_index
vs
[
3
];
vs
[
0
]
=
add_vertex
();
// add triangles
auto
h
=
h_begin
;
do
{
vs
[
1
]
=
from_vertex_of
(
h
);
vs
[
2
]
=
to_vertex_of
(
h
);
add_face
(
vs
,
3
);
h
=
halfedge
(
h
).
next_halfedge
;
}
while
(
h
!=
h_begin
);
return
vs
[
0
];
}
inline
vertex_index
Mesh
::
edge_split
(
edge_index
f
)
{
// remove edge
// add vertex
// add two new edges
assert
(
0
&&
"not implemented"
);
return
{};
}
inline
vertex_index
Mesh
::
halfedge_split
(
halfedge_index
f
)
{
// add vertex
// add new half-edge
assert
(
0
&&
"not implemented"
);
return
{};
}
inline
void
Mesh
::
edge_rotate_next
(
edge_index
e
)
{
assert
(
!
handle_of
(
e
).
is_boundary
()
&&
"does not work on boundaries"
);
assert
(
handle_of
(
e
).
vertexA
().
adjacent_vertices
().
size
()
>
2
&&
"does not work on valence <= 2 vertices"
);
assert
(
handle_of
(
e
).
vertexB
().
adjacent_vertices
().
size
()
>
2
&&
"does not work on valence <= 2 vertices"
);
auto
h0
=
halfedge_of
(
e
,
0
);
auto
h1
=
halfedge_of
(
e
,
1
);
auto
&
h0_ref
=
halfedge
(
h0
);
auto
&
h1_ref
=
halfedge
(
h1
);
auto
h0_next
=
h0_ref
.
next_halfedge
;
auto
h0_prev
=
h0_ref
.
prev_halfedge
;
auto
h1_next
=
h1_ref
.
next_halfedge
;
auto
h1_prev
=
h1_ref
.
prev_halfedge
;
auto
&
h0_next_ref
=
halfedge
(
h0_next
);
auto
&
h0_prev_ref
=
halfedge
(
h0_prev
);
auto
&
h1_next_ref
=
halfedge
(
h1_next
);
auto
&
h1_prev_ref
=
halfedge
(
h1_prev
);
auto
h0_next_next
=
h0_next_ref
.
next_halfedge
;
auto
&
h0_next_next_ref
=
halfedge
(
h0_next_next
);
auto
h1_next_next
=
h1_next_ref
.
next_halfedge
;
auto
&
h1_next_next_ref
=
halfedge
(
h1_next_next
);
// fix vertices
auto
&
v0
=
vertex
(
h0_ref
.
to_vertex
);
if
(
v0
.
outgoing_halfedge
==
h1
)
v0
.
outgoing_halfedge
=
h0_next
;
auto
&
v1
=
vertex
(
h1_ref
.
to_vertex
);
if
(
v1
.
outgoing_halfedge
==
h0
)
v1
.
outgoing_halfedge
=
h1_next
;
// fix faces
face
(
h0_ref
.
face
).
halfedge
=
h0
;
face
(
h1_ref
.
face
).
halfedge
=
h1
;
// fix half-edges
h0_ref
.
to_vertex
=
h0_next_ref
.
to_vertex
;
h1_ref
.
to_vertex
=
h1_next_ref
.
to_vertex
;
h0_next_ref
.
face
=
h1_ref
.
face
;
h1_next_ref
.
face
=
h0_ref
.
face
;
// move to next
h1_prev_ref
.
next_halfedge
=
h0_next
;
h0_next_ref
.
prev_halfedge
=
h1_prev
;
h0_prev_ref
.
next_halfedge
=
h1_next
;
h1_next_ref
.
prev_halfedge
=
h0_prev
;
h0_next_ref
.
next_halfedge
=
h1
;
h1_ref
.
prev_halfedge
=
h0_next
;
h1_next_ref
.
next_halfedge
=
h0
;
h0_ref
.
prev_halfedge
=
h1_next
;
h0_ref
.
next_halfedge
=
h0_next_next
;
h0_next_next_ref
.
prev_halfedge
=
h0
;
h1_ref
.
next_halfedge
=
h1_next_next
;
h1_next_next_ref
.
prev_halfedge
=
h1
;
// fix boundary state
fix_boundary_state_of
(
h0_ref
.
face
);
fix_boundary_state_of
(
h1_ref
.
face
);
}
inline
void
Mesh
::
edge_rotate_prev
(
edge_index
e
)
{
assert
(
!
handle_of
(
e
).
is_boundary
()
&&
"does not work on boundaries"
);
assert
(
handle_of
(
e
).
vertexA
().
adjacent_vertices
().
size
()
>
2
&&
"does not work on valence <= 2 vertices"
);
assert
(
handle_of
(
e
).
vertexB
().
adjacent_vertices
().
size
()
>
2
&&
"does not work on valence <= 2 vertices"
);
auto
h0
=
halfedge_of
(
e
,
0
);
auto
h1
=
halfedge_of
(
e
,
1
);
auto
&
h0_ref
=
halfedge
(
h0
);
auto
&
h1_ref
=
halfedge
(
h1
);
auto
h0_next
=
h0_ref
.
next_halfedge
;
auto
h0_prev
=
h0_ref
.
prev_halfedge
;
auto
h1_next
=
h1_ref
.
next_halfedge
;
auto
h1_prev
=
h1_ref
.
prev_halfedge
;
auto
&
h0_next_ref
=
halfedge
(
h0_next
);
auto
&
h0_prev_ref
=
halfedge
(
h0_prev
);
auto
&
h1_next_ref
=
halfedge
(
h1_next
);
auto
&
h1_prev_ref
=
halfedge
(
h1_prev
);
auto
h0_prev_prev
=
h0_prev_ref
.
prev_halfedge
;
auto
&
h0_prev_prev_ref
=
halfedge
(
h0_prev_prev
);
auto
h1_prev_prev
=
h1_prev_ref
.
prev_halfedge
;
auto
&
h1_prev_prev_ref
=
halfedge
(
h1_prev_prev
);
// fix vertex
auto
&
v0
=
vertex
(
h0_ref
.
to_vertex
);
if
(
v0
.
outgoing_halfedge
==
h1
)
v0
.
outgoing_halfedge
=
h0_next
;
auto
&
v1
=
vertex
(
h1_ref
.
to_vertex
);
if
(
v1
.
outgoing_halfedge
==
h0
)
v1
.
outgoing_halfedge
=
h1_next
;
// fix faces
face
(
h0_ref
.
face
).
halfedge
=
h0
;
face
(
h1_ref
.
face
).
halfedge
=
h1
;
// fix half-edge
h1_ref
.
to_vertex
=
h0_prev_prev_ref
.
to_vertex
;
h0_ref
.
to_vertex
=
h1_prev_prev_ref
.
to_vertex
;
h0_prev_ref
.
face
=
h1_ref
.
face
;
h1_prev_ref
.
face
=
h0_ref
.
face
;
// move to next
h0_prev_ref
.
next_halfedge
=
h1_next
;
h1_next_ref
.
prev_halfedge
=
h0_prev
;
h1_prev_ref
.
next_halfedge
=
h0_next
;
h0_next_ref
.
prev_halfedge
=
h1_prev
;
h1_ref
.
next_halfedge
=
h0_prev
;
h0_prev_ref
.
prev_halfedge
=
h1
;
h0_ref
.
next_halfedge
=
h1_prev
;
h1_prev_ref
.
prev_halfedge
=
h0
;
h0_prev_prev_ref
.
next_halfedge
=
h0
;
h0_ref
.
prev_halfedge
=
h0_prev_prev
;
h1_prev_prev_ref
.
next_halfedge
=
h1
;
h1_ref
.
prev_halfedge
=
h1_prev_prev
;
// fix boundary state
fix_boundary_state_of
(
h0_ref
.
face
);
fix_boundary_state_of
(
h1_ref
.
face
);
}
inline
void
Mesh
::
halfedge_rotate_next
(
halfedge_index
h
)
{
assert
(
handle_of
(
h
).
next
().
next
().
next
()
!=
h
&&
"does not work for triangles"
);
assert
(
!
handle_of
(
h
).
edge
().
is_boundary
()
&&
"does not work on boundaries"
);
assert
(
handle_of
(
h
).
vertex_to
().
adjacent_vertices
().
size
()
>
2
&&
"does not work on valence <= 2 vertices"
);
auto
h0
=
h
;
auto
h1
=
opposite
(
h
);
auto
&
h0_ref
=
halfedge
(
h0
);
auto
&
h1_ref
=
halfedge
(
h1
);
auto
h0_next
=
h0_ref
.
next_halfedge
;
auto
h1_prev
=
h1_ref
.
prev_halfedge
;
auto
&
h0_next_ref
=
halfedge
(
h0_next
);
auto
&
h1_prev_ref
=
halfedge
(
h1_prev
);
auto
h0_next_next
=
h0_next_ref
.
next_halfedge
;
auto
&
h0_next_next_ref
=
halfedge
(
h0_next_next
);
// fix vertex
auto
&
v
=
vertex
(
h0_ref
.
to_vertex
);
if
(
v
.
outgoing_halfedge
==
h1
)
v
.
outgoing_halfedge
=
h0_next
;
// fix faces
face
(
h0_ref
.
face
).
halfedge
=
h0
;
face
(
h1_ref
.
face
).
halfedge
=
h1
;
// fix half-edges
h0_ref
.
to_vertex
=
h0_next_ref
.
to_vertex
;
h0_next_ref
.
face
=
h1_ref
.
face
;
// move to next
h1_prev_ref
.
next_halfedge
=
h0_next
;
h0_next_ref
.
prev_halfedge
=
h1_prev
;
h0_next_ref
.
next_halfedge
=
h1
;
h1_ref
.
prev_halfedge
=
h0_next
;
h0_ref
.
next_halfedge
=
h0_next_next
;
h0_next_next_ref
.
prev_halfedge
=
h0
;
// fix boundary state
fix_boundary_state_of
(
h0_ref
.
face
);
fix_boundary_state_of
(
h1_ref
.
face
);
}
inline
void
Mesh
::
halfedge_rotate_prev
(
halfedge_index
h
)
{
assert
(
handle_of
(
h
).
prev
().
prev
().
prev
()
!=
h
&&
"does not work for triangles"
);
assert
(
!
handle_of
(
h
).
edge
().
is_boundary
()
&&
"does not work on boundaries"
);
assert
(
handle_of
(
h
).
vertex_from
().
adjacent_vertices
().
size
()
>
2
&&
"does not work on valence <= 2 vertices"
);
auto
h0
=
h
;
auto
h1
=
opposite
(
h
);
auto
&
h0_ref
=
halfedge
(
h0
);
auto
&
h1_ref
=
halfedge
(
h1
);
auto
h0_prev
=
h0_ref
.
prev_halfedge
;
auto
h1_next
=
h1_ref
.
next_halfedge
;
auto
&
h0_prev_ref
=
halfedge
(
h0_prev
);
auto
&
h1_next_ref
=
halfedge
(
h1_next
);
auto
h0_prev_prev
=
h0_prev_ref
.
prev_halfedge
;
auto
&
h0_prev_prev_ref
=
halfedge
(
h0_prev_prev
);
// fix vertex
auto
&
v
=
vertex
(
h1_ref
.
to_vertex
);
if
(
v
.
outgoing_halfedge
==
h0
)
v
.
outgoing_halfedge
=
h1_next
;
// fix faces
face
(
h0_ref
.
face
).
halfedge
=
h0
;
face
(
h1_ref
.
face
).
halfedge
=
h1
;
// fix half-edge
h1_ref
.
to_vertex
=
h0_prev_prev_ref
.
to_vertex
;
h0_prev_ref
.
face
=
h1_ref
.
face
;
// move to next
h0_prev_ref
.
next_halfedge
=
h1_next
;
h1_next_ref
.
prev_halfedge
=
h0_prev
;
h1_ref
.
next_halfedge
=
h0_prev
;
h0_prev_ref
.
prev_halfedge
=
h1
;
h0_prev_prev_ref
.
next_halfedge
=
h0
;
h0_ref
.
prev_halfedge
=
h0_prev_prev
;
// fix boundary state
fix_boundary_state_of
(
h0_ref
.
face
);
fix_boundary_state_of
(
h1_ref
.
face
);
}
inline
void
Mesh
::
compactify
()
{
if
(
is_compact
())
...
...
src/polymesh/impl/impl_ranges.hh
View file @
1b68796e
...
...
@@ -245,6 +245,27 @@ auto smart_range<this_t, ElementT>::to_map(FuncT &&f) const -> std::map<ElementT
return
m
;
}
template
<
class
this_t
,
class
element_handle
>
int
primitive_ring
<
this_t
,
element_handle
>::
size
()
const
{
auto
cnt
=
0
;
for
(
auto
v
:
*
static_cast
<
this_t
const
*>
(
this
))
{
(
void
)
v
;
// unused
cnt
++
;
}
return
cnt
;
}
template
<
class
this_t
,
class
tag
>
bool
primitive_ring
<
this_t
,
tag
>::
contains
(
handle
v
)
const
{
for
(
auto
v2
:
*
static_cast
<
this_t
const
*>
(
this
))
if
(
v
==
v2
)
return
true
;
return
false
;
}
template
<
class
mesh_ptr
,
class
tag
,
class
iterator
>
int
smart_collection
<
mesh_ptr
,
tag
,
iterator
>::
size
()
const
{
...
...
@@ -272,7 +293,7 @@ typename primitive<tag>::template attribute<PropT> smart_collection<mesh_ptr, ta
template
<
class
mesh_ptr
,
class
tag
,
class
iterator
>
template
<
class
FuncT
,
class
PropT
>
typename
primitive
<
tag
>::
template
attribute
<
PropT
>
smart_collection
<
mesh_ptr
,
tag
,
iterator
>::
make_attribute
(
FuncT
&&
f
,
PropT
const
&
def_value
)
const
typename
primitive
<
tag
>::
template
attribute
<
PropT
>
smart_collection
<
mesh_ptr
,
tag
,
iterator
>::
make_attribute
(
FuncT
&&
f
,
PropT
const
&
def_value
)
const
{
auto
attr
=
make_attribute_default
<
PropT
>
(
def_value
);
for
(
auto
h
:
*
this
)
...
...
@@ -502,14 +523,68 @@ face_handle face_collection<iterator>::add(const halfedge_handle (&half_loop)[N]
}
template
<
class
iterator
>
edge_handle
edge_collection
<
iterator
>::
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
)
edge_handle
edge_collection
<
iterator
>::
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
{
return
this
->
mesh
->
handle_of
(
this
->
mesh
->
add_or_get_edge
(
v_from
.
idx
,
v_to
.
idx
));
}
template
<
class
iterator
>
halfedge_handle
halfedge_collection
<
iterator
>::
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
)
halfedge_handle
halfedge_collection
<
iterator
>::
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
{
return
this
->
mesh
->
handle_of
(
this
->
mesh
->
add_or_get_halfedge
(
v_from
.
idx
,
v_to
.
idx
));
}
template
<
class
iterator
>
edge_handle
edge_collection
<
iterator
>::
find
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
{
return
this
->
mesh
->
handle_of
(
this
->
mesh
->
edge_of
(
this
->
mesh
->
find_halfedge
(
v_from
.
idx
,
v_to
.
idx
)));
}
template
<
class
iterator
>
halfedge_handle
halfedge_collection
<
iterator
>::
find
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
{
return
this
->
mesh
->
handle_of
(
this
->
mesh
->
find_halfedge
(
v_from
.
idx
,
v_to
.
idx
));
}
template
<
class
iterator
>
vertex_handle
face_collection
<
iterator
>::
split
(
face_handle
f
)
const
{
return
this
->
mesh
->
handle_of
(
this
->
mesh
->
face_split
(
f
.
idx
));
}
template
<
class
iterator
>
vertex_handle
edge_collection
<
iterator
>::
split
(
edge_handle
e
)
const
{
return
this
->
mesh
->
handle_of
(
this
->
mesh
->
edge_split
(
e
.
idx
));
}
template
<
class
iterator
>
void
edge_collection
<
iterator
>::
rotate_next
(
edge_handle
e
)
const
{
this
->
mesh
->
edge_rotate_next
(
e
.
idx
);
}
template
<
class
iterator
>
void
edge_collection
<
iterator
>::
rotate_prev
(
edge_handle
e
)
const
{
this
->
mesh
->
edge_rotate_prev
(
e
.
idx
);
}
template
<
class
iterator
>
vertex_handle
halfedge_collection
<
iterator
>::
split
(
halfedge_handle
h
)
const
{
return
this
->
mesh
->
handle_of
(
this
->
mesh
->
halfedge_split
(
h
.
idx
));
}
template
<
class
iterator
>
void
halfedge_collection
<
iterator
>::
rotate_next
(
halfedge_handle
h
)
const
{
this
->
mesh
->
halfedge_rotate_next
(
h
.
idx
);
}
template
<
class
iterator
>
void
halfedge_collection
<
iterator
>::
rotate_prev
(
halfedge_handle
h
)
const
{
this
->
mesh
->
halfedge_rotate_prev
(
h
.
idx
);
}
}
src/polymesh/ranges.hh
View file @
1b68796e
...
...
@@ -99,7 +99,7 @@ struct smart_range
/// converts this range to a map containing {v, f(v)} entries
template
<
class
FuncT
>
auto
to_map
(
FuncT
&&
f
)
const
->
std
::
map
<
ElementT
,
tmp
::
decayed_result_type_of
<
FuncT
,
ElementT
>>
;
// TODO: (requires new ranges)
// - filter (or where?)
// - map
...
...
@@ -180,6 +180,11 @@ struct face_collection : smart_collection<Mesh*, face_tag, iterator>
face_handle
add
(
std
::
vector
<
halfedge_handle
>
const
&
half_loop
)
const
;
face_handle
add
(
halfedge_handle
const
*
half_loop
,
int
vcnt
)
const
;
/// Splits a face by inserting a vertex (which is returned) and creating triangles towards it
/// Preserves half-edge attributes
/// The face itself is deleted and multiple new ones are created
vertex_handle
split
(
face_handle
f
)
const
;
/// Removes a face (adjacent edges and vertices are NOT removed)
/// (marks it as removed, compactify mesh to actually remove it)
void
remove
(
face_handle
f
)
const
;
...
...
@@ -192,9 +197,25 @@ struct edge_collection : smart_collection<Mesh*, edge_tag, iterator>
{
/// Adds an edge between two existing, distinct vertices
/// if edge already exists, returns it
edge_handle
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
);
// TODO: find
edge_handle
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
;
/// Returns the edge handle between two vertices (invalid if not found)
/// O(valence) computation
edge_handle
find
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
;
/// Splits this edge in half by inserting a vertex (which is returned)
/// Preserves face attributes
/// The edge itself is deleted and two new ones are created
vertex_handle
split
(
edge_handle
e
)
const
;
/// Moves both half-edges vertices to their next half-edge vertex
/// Equivalent to an edge flip if both faces are triangular
/// Preserves all attributes
/// NOTE: does not work on boundaries!
/// TODO: image
void
rotate_next
(
edge_handle
e
)
const
;
/// Same as rotate_next but with the previous half-edge
void
rotate_prev
(
edge_handle
e
)
const
;
/// Removes an edge (and both adjacent faces, vertices are NOT removed)
/// (marks them as removed, compactify mesh to actually remove them)
...
...
@@ -209,9 +230,26 @@ struct halfedge_collection : smart_collection<Mesh*, halfedge_tag, iterator>
/// Adds an half-edge between two existing, distinct vertices
/// if half-edge already exists, returns it
/// (always adds opposite half-edge as well)
halfedge_handle
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
);
// TODO: find
halfedge_handle
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
;
/// Returns the half-edge handle between two vertices (invalid if not found)
/// O(valence) computation
halfedge_handle
find
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
;
/// Splits this half-edge in half by inserting a vertex (which is returned)
/// Preserves face attributes
/// Contraty to edges().split, the edge is preserved and a single new one is inserted AFTER h
/// (thus h->next() is the newly inserted edge and h->vertex_to() is the returned vertex)
vertex_handle
split
(
halfedge_handle
h
)
const
;
/// Moves the to-vertex of this half-edge to the same as the next half-edge
/// Preserves all attributes
/// NOTE: does not work on boundaries!
/// NOTE: does not work on triangles!
/// TODO: image
void
rotate_next
(
halfedge_handle
h
)
const
;
/// Same as rotate_next but with the previous half-edge
void
rotate_prev
(
halfedge_handle
h
)
const
;
/// Removes the edge and both half-edges belonging to it (and both adjacent faces, vertices are NOT removed)
/// (marks them as removed, compactify mesh to actually remove them)
...
...
@@ -382,28 +420,4 @@ struct vertex_face_ring : vertex_primitive_ring<face_tag, vertex_face_circulator
using
vertex_primitive_ring
<
face_tag
,
vertex_face_circulator
>::
vertex_primitive_ring
;
};
/// ======== IMPLEMENTATION ========
template
<
class
this_t
,
class
element_handle
>
int
primitive_ring
<
this_t
,
element_handle
>::
size
()
const
{
auto
cnt
=
0
;
for
(
auto
v
:
*
static_cast
<
this_t
const
*>
(
this
))
{
(
void
)
v
;
// unused
cnt
++
;
}
return
cnt
;
}
template
<
class
this_t
,
class
tag
>
bool
primitive_ring
<
this_t
,
tag
>::
contains
(
handle
v
)
const
{
for
(
auto
v2
:
*
static_cast
<
this_t
const
*>
(
this
))
if
(
v
==
v2
)
return
true
;
return
false
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment