Skip to content
GitLab
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
693d0664
Commit
693d0664
authored
Aug 08, 2018
by
Philip Trettner
Browse files
added can_add_face interface, made obj more robust, fixed add_or_get_edge bug
parent
5bc97ea6
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/polymesh/formats/obj.cc
View file @
693d0664
...
...
@@ -134,6 +134,7 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
std
::
vector
<
face
>
poly
;
std
::
vector
<
halfedge_handle
>
poly_hs
;
std
::
vector
<
vertex_index
>
poly_vs
;
std
::
string
fs
;
std
::
string
line_s
;
...
...
@@ -205,6 +206,7 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
else
if
(
type
==
"f"
)
{
poly_hs
.
clear
();
poly_vs
.
clear
();
poly
.
clear
();
while
(
line
.
good
())
...
...
@@ -244,6 +246,7 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
f
.
vh
=
mesh
.
handle_of
(
vertex_index
(
f
.
v
-
1
));
poly
.
push_back
(
f
);
poly_vs
.
push_back
(
f
.
vh
);
}
if
(
poly
.
size
()
<
3
)
...
...
@@ -252,6 +255,12 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
continue
;
}
if
(
!
mesh
.
faces
().
can_add
(
poly_vs
))
{
n_error_faces
++
;
continue
;
}
poly_hs
.
resize
(
poly
.
size
());
for
(
auto
i
=
0u
;
i
<
poly
.
size
();
++
i
)
{
...
...
@@ -302,10 +311,16 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
std
::
cerr
<<
"Unable to parse line "
<<
line_nr
<<
": "
<<
line_s
<<
std
::
endl
;
}
}
if
(
n_error_faces
>
0
)
{
std
::
cerr
<<
"skipped "
<<
n_error_faces
<<
" face(s) because mesh would become non-manifold"
<<
std
::
endl
;
}
}
void
polymesh
::
read_obj
(
const
std
::
string
&
filename
,
Mesh
&
mesh
,
vertex_attribute
<
glm
::
vec3
>
&
position
)
bool
polymesh
::
read_obj
(
const
std
::
string
&
filename
,
Mesh
&
mesh
,
vertex_attribute
<
glm
::
vec3
>
&
position
)
{
obj_reader
reader
(
filename
,
mesh
);
position
=
reader
.
positions_vec3
();
return
reader
.
error_faces
()
==
0
;
}
src/polymesh/formats/obj.hh
View file @
693d0664
...
...
@@ -14,7 +14,7 @@ void write_obj(std::string const& filename,
vertex_attribute
<
glm
::
vec3
>
const
&
position
,
vertex_attribute
<
glm
::
vec2
>
const
*
tex_coord
=
nullptr
,
vertex_attribute
<
glm
::
vec3
>
const
*
normal
=
nullptr
);
void
read_obj
(
std
::
string
const
&
filename
,
Mesh
&
mesh
,
vertex_attribute
<
glm
::
vec3
>&
position
);
bool
read_obj
(
std
::
string
const
&
filename
,
Mesh
&
mesh
,
vertex_attribute
<
glm
::
vec3
>&
position
);
struct
obj_writer
{
...
...
@@ -56,11 +56,16 @@ public:
halfedge_attribute
<
glm
::
vec2
>
tex_coords_vec2
()
const
;
halfedge_attribute
<
glm
::
vec3
>
normals_vec3
()
const
;
/// Number of faces that could not be added
int
error_faces
()
const
{
return
n_error_faces
;
}
private:
void
parse
(
std
::
istream
&
in
,
Mesh
&
mesh
);
vertex_attribute
<
glm
::
vec4
>
positions
;
halfedge_attribute
<
glm
::
vec3
>
tex_coords
;
halfedge_attribute
<
glm
::
vec3
>
normals
;
int
n_error_faces
=
0
;
};
}
src/polymesh/impl/impl_low_level_api_base.hh
View file @
693d0664
...
...
@@ -41,54 +41,201 @@ tmp::ref_if_mut<halfedge_index, MeshT> low_level_api_base<MeshT>::outgoing_halfe
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_all_faces
()
const
{
return
m
.
size_all_faces
();
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_all_vertices
()
const
{
return
m
.
size_all_vertices
();
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_all_edges
()
const
{
return
m
.
size_all_edges
();
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_all_halfedges
()
const
{
return
m
.
size_all_halfedges
();
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_valid_faces
()
const
{
return
m
.
size_valid_faces
();
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_valid_vertices
()
const
{
return
m
.
size_valid_vertices
();
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_valid_edges
()
const
{
return
m
.
size_valid_edges
();
}
template
<
class
MeshT
>
template
<
class
MeshT
>
int
low_level_api_base
<
MeshT
>::
size_valid_halfedges
()
const
{
return
m
.
size_valid_halfedges
();
}
template
<
class
MeshT
>
bool
low_level_api_base
<
MeshT
>::
can_add_face
(
const
vertex_handle
*
v_handles
,
int
vcnt
)
const
{
if
(
vcnt
<
3
)
return
false
;
// too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for
(
auto
i
=
0
;
i
<
vcnt
;
++
i
)
{
if
(
!
is_boundary
(
v_handles
[
i
]))
return
false
;
// must be boundary
auto
v0
=
v_handles
[
i
];
auto
v1
=
v_handles
[(
i
+
1
)
%
vcnt
];
auto
v2
=
v_handles
[(
i
+
2
)
%
vcnt
];
auto
h0
=
find_halfedge
(
v0
,
v1
);
auto
h1
=
find_halfedge
(
v1
,
v2
);
if
(
h0
.
is_valid
()
&&
!
is_boundary
(
h0
))
return
false
;
// must be boundary
if
(
h0
.
is_invalid
())
continue
;
// will be added
if
(
h1
.
is_invalid
())
continue
;
// will be added
if
(
to_vertex_of
(
h0
)
!=
from_vertex_of
(
h1
))
return
false
;
// not a chain
if
(
next_halfedge_of
(
h0
)
==
h1
)
continue
;
// correctly wired
if
(
find_free_incident
(
opposite
(
h1
),
h0
).
is_invalid
())
return
false
;
// non-manifold
}
return
true
;
}
template
<
class
MeshT
>
bool
low_level_api_base
<
MeshT
>::
can_add_face
(
const
vertex_index
*
v_indices
,
int
vcnt
)
const
{
if
(
vcnt
<
3
)
return
false
;
// too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for
(
auto
i
=
0
;
i
<
vcnt
;
++
i
)
{
if
(
!
is_boundary
(
v_indices
[
i
]))
return
false
;
// must be boundary
auto
v0
=
v_indices
[
i
];
auto
v1
=
v_indices
[(
i
+
1
)
%
vcnt
];
auto
v2
=
v_indices
[(
i
+
2
)
%
vcnt
];
auto
h0
=
find_halfedge
(
v0
,
v1
);
auto
h1
=
find_halfedge
(
v1
,
v2
);
if
(
h0
.
is_valid
()
&&
!
is_boundary
(
h0
))
return
false
;
// must be boundary
if
(
h0
.
is_invalid
())
continue
;
// will be added
if
(
h1
.
is_invalid
())
continue
;
// will be added
if
(
to_vertex_of
(
h0
)
!=
from_vertex_of
(
h1
))
return
false
;
// not a chain
if
(
!
is_free
(
h0
))
return
false
;
// already contains a face
if
(
next_halfedge_of
(
h0
)
==
h1
)
continue
;
// correctly wired
if
(
find_free_incident
(
opposite
(
h1
),
h0
).
is_invalid
())
return
false
;
// non-manifold
}
return
true
;
}
template
<
class
MeshT
>
bool
low_level_api_base
<
MeshT
>::
can_add_face
(
const
halfedge_handle
*
half_loop
,
int
vcnt
)
const
{
if
(
vcnt
<
3
)
return
false
;
// too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for
(
auto
i
=
0
;
i
<
vcnt
;
++
i
)
{
auto
h0
=
half_loop
[
i
].
idx
;
auto
h1
=
half_loop
[(
i
+
1
)
%
vcnt
].
idx
;
if
(
to_vertex_of
(
h0
)
!=
from_vertex_of
(
h1
))
return
false
;
// not a chain
if
(
!
is_free
(
h0
))
return
false
;
// already contains a face
if
(
next_halfedge_of
(
h0
)
==
h1
)
continue
;
// correctly wired
if
(
find_free_incident
(
opposite
(
h1
),
h0
).
is_invalid
())
return
false
;
// non-manifold
}
return
true
;
}
template
<
class
MeshT
>
bool
low_level_api_base
<
MeshT
>::
can_add_face
(
const
halfedge_index
*
half_loop
,
int
vcnt
)
const
{
if
(
vcnt
<
3
)
return
false
;
// too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for
(
auto
i
=
0
;
i
<
vcnt
;
++
i
)
{
auto
h0
=
half_loop
[
i
];
auto
h1
=
half_loop
[(
i
+
1
)
%
vcnt
];
if
(
to_vertex_of
(
h0
)
!=
from_vertex_of
(
h1
))
return
false
;
// not a chain
if
(
!
is_free
(
h0
))
return
false
;
// already contains a face
if
(
next_halfedge_of
(
h0
)
==
h1
)
continue
;
// correctly wired
if
(
find_free_incident
(
opposite
(
h1
),
h0
).
is_invalid
())
return
false
;
// non-manifold
}
return
true
;
}
template
<
class
MeshT
>
halfedge_index
low_level_api_base
<
MeshT
>::
find_free_incident
(
halfedge_index
in_begin
,
halfedge_index
in_end
)
const
{
...
...
src/polymesh/impl/impl_low_level_api_mutable.hh
View file @
693d0664
...
...
@@ -104,8 +104,8 @@ inline edge_index low_level_api_mutable::add_or_get_edge(vertex_index v_from, ve
// setup data (self-connected edge)
to_vertex_of
(
h_from_to
)
=
v_to
;
to_vertex_of
(
h_to_from
)
=
v_from
;
ne
x
t_
halfedge_of
(
h_from_to
)
=
h_to_from
;
ne
x
t_
halfedge_of
(
h_to_from
)
=
h_from_to
;
con
ne
c
t_
prev_next
(
h_from_to
,
h_to_from
)
;
con
ne
c
t_
prev_next
(
h_to_from
,
h_from_to
)
;
// link from vertex
if
(
is_isolated
(
v_from
))
...
...
src/polymesh/impl/impl_ranges.hh
View file @
693d0664
...
...
@@ -660,24 +660,48 @@ face_handle face_collection<iterator>::add(const vertex_handle *v_handles, int v
return
this
->
mesh
->
handle_of
(
low_level_api
(
this
->
mesh
).
add_face
(
v_handles
,
vcnt
));
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
const
vertex_index
*
v_indices
,
int
vcnt
)
const
{
return
this
->
mesh
->
handle_of
(
low_level_api
(
this
->
mesh
).
add_face
(
v_indices
,
vcnt
));
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
const
halfedge_handle
*
half_loop
,
int
vcnt
)
const
{
return
this
->
mesh
->
handle_of
(
low_level_api
(
this
->
mesh
).
add_face
(
half_loop
,
vcnt
));
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
const
halfedge_index
*
half_loop
,
int
vcnt
)
const
{
return
this
->
mesh
->
handle_of
(
low_level_api
(
this
->
mesh
).
add_face
(
half_loop
,
vcnt
));
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
std
::
vector
<
vertex_handle
>
const
&
v_handles
)
const
{
return
add
(
v_handles
.
data
(),
v_handles
.
size
());
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
std
::
vector
<
vertex_index
>
const
&
v_indices
)
const
{
return
add
(
v_indices
.
data
(),
v_indices
.
size
());
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
std
::
vector
<
halfedge_handle
>
const
&
half_loop
)
const
{
return
add
(
half_loop
.
data
(),
(
int
)
half_loop
.
size
());
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
std
::
vector
<
halfedge_index
>
const
&
half_loop
)
const
{
return
add
(
half_loop
.
data
(),
(
int
)
half_loop
.
size
());
}
template
<
class
iterator
>
face_handle
face_collection
<
iterator
>::
add
(
vertex_handle
v0
,
vertex_handle
v1
,
vertex_handle
v2
)
const
{
...
...
@@ -735,6 +759,111 @@ face_handle face_collection<iterator>::add(const halfedge_handle (&half_loop)[N]
return
this
->
mesh
->
handle_of
(
low_level_api
(
this
->
mesh
).
add_face
(
hs
,
N
));
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
const
vertex_handle
*
v_handles
,
int
vcnt
)
const
{
return
low_level_api
(
this
->
mesh
).
can_add_face
(
v_handles
,
vcnt
);
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
const
vertex_index
*
v_indices
,
int
vcnt
)
const
{
return
low_level_api
(
this
->
mesh
).
can_add_face
(
v_indices
,
vcnt
);
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
const
halfedge_handle
*
half_loop
,
int
vcnt
)
const
{
return
low_level_api
(
this
->
mesh
).
can_add_face
(
half_loop
,
vcnt
);
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
const
halfedge_index
*
half_loop
,
int
vcnt
)
const
{
return
low_level_api
(
this
->
mesh
).
can_add_face
(
half_loop
,
vcnt
);
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
std
::
vector
<
vertex_handle
>
const
&
v_handles
)
const
{
return
can_add
(
v_handles
.
data
(),
v_handles
.
size
());
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
std
::
vector
<
vertex_index
>
const
&
v_indices
)
const
{
return
can_add
(
v_indices
.
data
(),
v_indices
.
size
());
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
std
::
vector
<
halfedge_handle
>
const
&
half_loop
)
const
{
return
can_add
(
half_loop
.
data
(),
(
int
)
half_loop
.
size
());
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
std
::
vector
<
halfedge_index
>
const
&
half_loop
)
const
{
return
can_add
(
half_loop
.
data
(),
(
int
)
half_loop
.
size
());
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
vertex_handle
v0
,
vertex_handle
v1
,
vertex_handle
v2
)
const
{
halfedge_index
hs
[
3
]
=
{
low_level_api
(
this
->
mesh
).
can_add_or_get_halfedge
(
v0
.
idx
,
v1
.
idx
),
//
low_level_api
(
this
->
mesh
).
can_add_or_get_halfedge
(
v1
.
idx
,
v2
.
idx
),
//
low_level_api
(
this
->
mesh
).
can_add_or_get_halfedge
(
v2
.
idx
,
v0
.
idx
),
//
};
return
low_level_api
(
this
->
mesh
).
can_add_face
(
hs
,
3
);
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
vertex_handle
v0
,
vertex_handle
v1
,
vertex_handle
v2
,
vertex_handle
v3
)
const
{
halfedge_index
hs
[
4
]
=
{
low_level_api
(
this
->
mesh
).
can_add_or_get_halfedge
(
v0
.
idx
,
v1
.
idx
),
//
low_level_api
(
this
->
mesh
).
can_add_or_get_halfedge
(
v1
.
idx
,
v2
.
idx
),
//
low_level_api
(
this
->
mesh
).
can_add_or_get_halfedge
(
v2
.
idx
,
v3
.
idx
),
//
low_level_api
(
this
->
mesh
).
can_add_or_get_halfedge
(
v3
.
idx
,
v0
.
idx
),
//
};
return
low_level_api
(
this
->
mesh
).
can_add_face
(
hs
,
4
);
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
halfedge_handle
h0
,
halfedge_handle
h1
,
halfedge_handle
h2
)
const
{
halfedge_index
hs
[
3
]
=
{
h0
.
idx
,
h1
.
idx
,
h2
.
idx
};
return
low_level_api
(
this
->
mesh
).
can_add_face
(
hs
,
3
);
}
template
<
class
iterator
>
bool
face_collection
<
iterator
>::
can_add
(
halfedge_handle
h0
,
halfedge_handle
h1
,
halfedge_handle
h2
,
halfedge_handle
h3
)
const
{
halfedge_index
hs
[
4
]
=
{
h0
.
idx
,
h1
.
idx
,
h2
.
idx
,
h3
.
idx
};
return
low_level_api
(
this
->
mesh
).
can_add_face
(
hs
,
4
);
}
template
<
class
iterator
>
template
<
size_t
N
>
bool
face_collection
<
iterator
>::
can_add
(
const
vertex_handle
(
&
v_handles
)[
N
])
const
{
halfedge_index
hs
[
N
];
for
(
auto
i
=
0
;
i
<
N
;
++
i
)
hs
[
i
]
=
low_level_api
(
this
->
mesh
).
find_halfedge
(
v_handles
[
i
].
idx
,
v_handles
[(
i
+
1
)
%
N
].
idx
);
return
low_level_api
(
this
->
mesh
).
can_add_face
(
hs
,
N
);
}
template
<
class
iterator
>
template
<
size_t
N
>
bool
face_collection
<
iterator
>::
can_add
(
const
halfedge_handle
(
&
half_loop
)[
N
])
const
{
halfedge_index
hs
[
N
];
for
(
auto
i
=
0
;
i
<
N
;
++
i
)
hs
[
i
]
=
half_loop
[
i
].
idx
;
return
low_level_api
(
this
->
mesh
).
can_add_face
(
hs
,
N
);
}
template
<
class
iterator
>
edge_handle
edge_collection
<
iterator
>::
add_or_get
(
vertex_handle
v_from
,
vertex_handle
v_to
)
const
{
...
...
src/polymesh/low_level_api.hh
View file @
693d0664
...
...
@@ -64,6 +64,14 @@ public:
face_index
prev_valid_idx_from
(
face_index
idx
)
const
;
halfedge_index
prev_valid_idx_from
(
halfedge_index
idx
)
const
;
// modification checks
public:
/// Returns true iff the face can be added
bool
can_add_face
(
vertex_handle
const
*
v_handles
,
int
vcnt
)
const
;
bool
can_add_face
(
vertex_index
const
*
v_indices
,
int
vcnt
)
const
;
bool
can_add_face
(
halfedge_handle
const
*
half_loop
,
int
vcnt
)
const
;
bool
can_add_face
(
halfedge_index
const
*
half_loop
,
int
vcnt
)
const
;
// topology helper
public:
/// Returns the opposite of a given valid half-edge
...
...
@@ -296,5 +304,4 @@ inline low_level_api_const low_level_api(Mesh const& m) { return {m}; }
inline
low_level_api_const
low_level_api
(
Mesh
const
*
m
)
{
return
{
*
m
};
}
inline
low_level_api_mutable
low_level_api
(
Mesh
&
m
)
{
return
{
m
};
}
inline
low_level_api_mutable
low_level_api
(
Mesh
*
m
)
{
return
{
*
m
};
}
}
src/polymesh/ranges.hh
View file @
693d0664
...
...
@@ -263,13 +263,35 @@ struct face_collection : smart_collection<Mesh*, face_tag, iterator>
face_handle
add
(
vertex_handle
v0
,
vertex_handle
v1
,
vertex_handle
v2
)
const
;
face_handle
add
(
vertex_handle
v0
,
vertex_handle
v1
,
vertex_handle
v2
,
vertex_handle
v3
)
const
;
face_handle
add
(
std
::
vector
<
vertex_handle
>
const
&
v_handles
)
const
;
face_handle
add
(
std
::
vector
<
vertex_index
>
const
&
v_indices
)
const
;
face_handle
add
(
vertex_handle
const
*
v_handles
,
int
vcnt
)
const
;
face_handle
add
(
vertex_index
const
*
v_indices
,
int
vcnt
)
const
;
template
<
size_t
N
>
face_handle
add
(
const
halfedge_handle
(
&
half_loop
)[
N
])
const
;
face_handle
add
(
halfedge_handle
h0
,
halfedge_handle
h1
,
halfedge_handle
h2
)
const
;
face_handle
add
(
halfedge_handle
h0
,
halfedge_handle
h1
,
halfedge_handle
h2
,
halfedge_handle
h3
)
const
;
face_handle
add
(
std
::
vector
<
halfedge_handle
>
const
&
half_loop
)
const
;
face_handle
add
(
std
::
vector
<
halfedge_index
>
const
&
half_loop
)
const
;
face_handle
add
(
halfedge_handle
const
*
half_loop
,
int
vcnt
)
const
;
face_handle
add
(
halfedge_index
const
*
half_loop
,
int
vcnt
)
const
;
/// Returns true if face can be added
template
<
size_t
N
>
bool
can_add
(
const
vertex_handle
(
&
v_handles
)[
N
])
const
;
bool
can_add
(
vertex_handle
v0
,
vertex_handle
v1
,
vertex_handle
v2
)
const
;
bool
can_add
(
vertex_handle
v0
,
vertex_handle
v1
,
vertex_handle
v2
,
vertex_handle
v3
)
const
;
bool
can_add
(
std
::
vector
<
vertex_handle
>
const
&
v_handles
)
const
;
bool
can_add
(
std
::
vector
<
vertex_index
>
const
&
v_indices
)
const
;
bool
can_add
(
vertex_handle
const
*
v_handles
,
int
vcnt
)
const
;
bool
can_add
(
vertex_index
const
*
v_indices
,
int
vcnt
)
const
;
template
<
size_t
N
>
bool
can_add
(
const
halfedge_handle
(
&
half_loop
)[
N
])
const
;
bool
can_add
(
halfedge_handle
h0
,
halfedge_handle
h1
,
halfedge_handle
h2
)
const
;
bool
can_add
(
halfedge_handle
h0
,
halfedge_handle
h1
,
halfedge_handle
h2
,
halfedge_handle
h3
)
const
;
bool
can_add
(
std
::
vector
<
halfedge_handle
>
const
&
half_loop
)
const
;
bool
can_add
(
std
::
vector
<
halfedge_index
>
const
&
half_loop
)
const
;
bool
can_add
(
halfedge_handle
const
*
half_loop
,
int
vcnt
)
const
;
bool
can_add
(
halfedge_index
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
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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