[Small Feature] VTK IO support for Linear_cell_complex (#8998)

## Summary

This small feature adds the ability to read and write `.vtk` files
(legacy ASCII)
for 3D Linear_cell_complex (dimension 3, ambient dimension 3). 

It supports per-vertex and per-volume scalar fields and handles various
VTK cell types.

## Motivation

Enable import/export of mesh structures and scalar fields between CGAL
and VTK-based visualization tools
(ParaView, VisIt, etc.). Simplifies debugging and integration into
scientific pipelines.

## API Changes

- New functions in `Linear_cell_complex_vtk_io.h`:
  - `read_lcc_from_vtk()`
  - `write_lcc_to_vtk()`

Header-only implementation, no external dependency.

## Included

- Full implementation in `Linear_cell_complex_vtk_io.h` (merged `.impl`)
- Minimal example with `.3map` and `.vtk` files
- Unit test with scalar field preservation and structure comparison

## Maintainers

Feel free to suggest naming adjustments or style corrections. The
feature is scoped cleanly and does not affect other packages.


* Feature/Small Feature (if any):
[Read_write_vtk_for_LCC](https://cgalwiki.geometryfactory.com/CGAL/Members/wiki/Features/Small_Features/Read_write_vtk_for_LCC)
This commit is contained in:
Sebastien Loriot 2025-12-03 11:50:01 +01:00 committed by GitHub
commit be305f320f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 4819 additions and 159 deletions

View File

@ -1068,8 +1068,18 @@ If \link GenericMap::are_attributes_automatically_managed `are_attributes_automa
template <unsigned int i>
size_type remove_cell(Dart_descriptor d);
/*!
\ingroup PkgCombinatorialMapsRefIO
Writes `amap` in `os`, using our own internal file format in XML. Writes both the topology of the combinatorial map and its enabled attributes.
*/
friend std::ostream& operator<< (std::ostream& os, const GenericMap& amap);
/*!
\ingroup PkgCombinatorialMapsRefIO
Reads `amap` from `is`, using our own internal file format in XML. Reads both the topology of the combinatorial map and its enabled attributes which are present in `is`. Note that if `amap` is not empty before the reading, the new map is added in the previous one.
*/
friend std::ifstream& operator>> (std::ifstream& is, GenericMap& amap);
/// @}
}; /* end GenericMap */

View File

@ -6,6 +6,9 @@
/// \defgroup PkgCombinatorialMapsClasses Classes
/// \ingroup PkgCombinatorialMapsRef
/// \defgroup PkgCombinatorialMapsRefIO IO Functions for CMap
/// \ingroup PkgCombinatorialMapsRef
/*!
\addtogroup PkgCombinatorialMapsRef
\cgalPkgDescriptionBegin{Combinatorial Maps,PkgCombinatorialMaps}
@ -36,5 +39,9 @@
- `CGAL::Cell_attribute_with_id<CMap,Info_,Tag,OnMerge,OnSplit>`
- `CGAL::Generic_map_min_items`
\cgalCRPSubsection{IO Functions for CMap}
- \link PkgCombinatorialMapsRefIO `std::ostream& operator<< (std::ostream& os, const GenericMap& amap)` \endlink
- \link PkgCombinatorialMapsRefIO `std::ifstream& operator>> (std::ifstream& is, GenericMap& amap)` \endlink
*/

View File

@ -255,7 +255,7 @@ namespace CGAL {
}
}
// Create an mapping between darts of the two maps (originals->copies).
// Creates a mapping between darts of the two maps (originals->copies).
// (here we cannot use CGAL::Unique_hash_map because it does not provide
// iterators...
std::unordered_map<Dart_descriptor_2, Dart_descriptor> local_dartmap;
@ -585,7 +585,7 @@ namespace CGAL {
bool copy_perforated_darts=false,
size_type mark_perforated=INVALID_MARK)
{
// Create an mapping between darts of the two maps (originals->copies).
// Creates a mapping between darts of the two maps (originals->copies).
// (here we cannot use CGAL::Unique_hash_map because it does not provide
// iterators...
std::unordered_map
@ -661,7 +661,7 @@ namespace CGAL {
return is;
}
/** Create a new dart and add it to the map.
/** Creates a new dart and add it to the map.
* The marks of the darts are initialized with mmask_marks, i.e. the dart
* is unmarked for all the marks.
* @return a Dart_descriptor on the new dart.
@ -968,7 +968,7 @@ namespace CGAL {
size_type number_of_used_marks() const
{ return mnb_used_marks; }
/** Test if a given mark is reserved.
/** Tests if a given mark is reserved.
* @return true iff the mark is reserved (i.e. in used).
*/
bool is_reserved(size_type amark) const
@ -997,14 +997,14 @@ namespace CGAL {
return number_of_darts() - number_of_marked_darts(amark);
}
/** Test if all the darts are unmarked for a given mark.
/** Tests if all the darts are unmarked for a given mark.
* @param amark the mark index.
* @return true iff all the darts are unmarked for amark.
*/
bool is_whole_map_unmarked(size_type amark) const
{ return number_of_marked_darts(amark) == 0; }
/** Test if all the darts are marked for a given mark.
/** Tests if all the darts are marked for a given mark.
* @param amark the mark index.
* @return true iff all the darts are marked for amark.
*/
@ -1071,7 +1071,7 @@ namespace CGAL {
mmask_marks.flip(amark);
}
/** Test if a given dart is marked for a given mark.
/** Tests if a given dart is marked for a given mark.
* @param adart the dart to test.
* @param amark the given mark.
* @return true iff adart is marked for the mark amark.
@ -1239,7 +1239,7 @@ namespace CGAL {
std::size_t orient(size_type amark) const
{ negate_mark(amark); return number_of_darts(); }
/** Test if this map is without boundary for a given dimension.
/** Tests if this map is without boundary for a given dimension.
* @param i the dimension.
* @return true iff all the darts are not i-free.
* @pre 1<=i<=n
@ -1253,7 +1253,7 @@ namespace CGAL {
return true;
}
/** Test if this map is without boundary for all the dimensions.
/** Tests if this map is without boundary for all the dimensions.
* @return true iff all the darts are non free.
*/
bool is_without_boundary() const
@ -1334,7 +1334,7 @@ namespace CGAL {
return res;
}
/** Test if the map is valid.
/** Tests if the map is valid.
* @return true iff the map is valid.
*/
bool is_valid(bool show_errors=true) const
@ -1579,7 +1579,7 @@ namespace CGAL {
return os;
}
/// Create a new attribute.
/// Creates a new attribute.
/// @return a descriptor on the new attribute.
template<unsigned int i, typename ...Args>
typename Attribute_descriptor<i>::type create_attribute(const Args&... args)
@ -1988,7 +1988,7 @@ namespace CGAL {
else unlink_beta_for_involution(adart, i);
}
/** Test if it is possible to sew by betai the two given darts
/** Tests if it is possible to sew by betai the two given darts
* @param adart1 the first dart.
* @param adart2 the second dart.
* @return true iff \em adart1 can be i-sewn with \em adart2.
@ -3439,7 +3439,7 @@ namespace CGAL {
}
/** Test if the connected component of cmap containing dart dh1 is
/** Tests if the connected component of cmap containing dart dh1 is
* isomorphic to the connected component of map2 containing dart dh2,
* starting from dh1 and dh2.
* @param dh1 initial dart for this map
@ -3648,7 +3648,7 @@ namespace CGAL {
return match;
}
/** Test if this cmap is isomorphic to map2.
/** Tests if this cmap is isomorphic to map2.
* @pre cmap is connected.
* @param map2 the second combinatorial map
* @param testDartInfo Boolean to test the equality of dart info (true)
@ -3687,7 +3687,7 @@ namespace CGAL {
return false;
}
/** Test if the attributes of this map are automatically updated.
/** Tests if the attributes of this map are automatically updated.
* @return true iff the boolean automatic_attributes_management is set to true.
*/
bool are_attributes_automatically_managed() const
@ -3710,13 +3710,13 @@ namespace CGAL {
void set_automatic_attributes_management_without_correction(bool newval)
{ this->automatic_attributes_management = newval; }
/** Create a halfedge.
* @return a dart of the new halfedge.
/** Creates a halfedge.
* @return a dart of the new half-edge.
*/
Dart_descriptor make_half_edge()
{ return create_dart(); }
/** Create an edge.
/** Creates an edge.
* if closed==true, the edge has no 2-free dart.
* (note that for CMap there is no difference between true and false, but
* this is not the case for GMap)
@ -3730,7 +3730,7 @@ namespace CGAL {
return d1;
}
/** Create an edge given 2 Attribute_descriptor<0>.
/** Creates an edge given 2 Attribute_descriptor<0>.
* Note that this function can be used only if 0-attributes are non void
* @param h0 the first vertex descriptor.
* @param h1 the second vertex descriptor.
@ -3751,7 +3751,7 @@ namespace CGAL {
return d1;
}
/** Create a combinatorial polygon of length alg
/** Creates a combinatorial polygon of length alg
* (a cycle of alg darts beta1 links together).
* @return a new dart.
*/
@ -3772,7 +3772,7 @@ namespace CGAL {
return start;
}
/** Test if a face is a combinatorial polygon of length alg
/** Tests if a face is a combinatorial polygon of length alg
* (a cycle of alg darts beta1 links together).
* @param adart an initial dart
* @return true iff the face containing adart is a polygon of length alg.
@ -3794,7 +3794,7 @@ namespace CGAL {
return (nb==alg);
}
/** Create a triangle given 3 Attribute_descriptor<0>.
/** Creates a triangle given 3 Attribute_descriptor<0>.
* @param h0 the first descriptor.
* @param h1 the second descriptor.
* @param h2 the third descriptor.
@ -3814,7 +3814,7 @@ namespace CGAL {
return d1;
}
/** Create a quadrangle given 4 Vertex_attribute_descriptor.
/** Creates a quadrangle given 4 Vertex_attribute_descriptor.
* @param h0 the first vertex descriptor.
* @param h1 the second vertex descriptor.
* @param h2 the third vertex descriptor.
@ -3837,7 +3837,7 @@ namespace CGAL {
return d1;
}
/** Create a combinatorial tetrahedron from 4 triangles.
/** Creates a combinatorial tetrahedron from 4 triangles.
* @param d1 a dart onto a first triangle.
* @param d2 a dart onto a second triangle.
* @param d3 a dart onto a third triangle.
@ -3859,9 +3859,9 @@ namespace CGAL {
return d1;
}
/** Test if a volume is a combinatorial tetrahedron.
* @param adart an initial dart
* @return true iff the volume containing adart is a combinatorial tetrahedron.
/** Tests if a volume is a combinatorial tetrahedron.
* @param d1 an initial dart
* @return true iff the volume containing d1 is a combinatorial tetrahedron.
*/
bool is_volume_combinatorial_tetrahedron(Dart_const_descriptor d1) const
{
@ -3892,7 +3892,7 @@ namespace CGAL {
return true;
}
/** Create a new combinatorial tetrahedron.
/** Creates a new combinatorial tetrahedron.
* @return a new dart.
*/
Dart_descriptor make_combinatorial_tetrahedron()
@ -3905,7 +3905,7 @@ namespace CGAL {
return make_combinatorial_tetrahedron(d1, d2, d3, d4);
}
/** Create a combinatorial hexahedron from 6 quadrilaterals.
/** Creates a combinatorial hexahedron from 6 quadrilaterals.
* @param d1 a dart onto a first quadrilateral.
* @param d2 a dart onto a second quadrilateral.
* @param d3 a dart onto a third quadrilateral.
@ -3952,9 +3952,9 @@ namespace CGAL {
return d1;
}
/** Test if a volume is a combinatorial hexahedron.
* @param adart an initial dart
* @return true iff the volume containing adart is a combinatorial hexahedron.
/** Tests if a volume is a combinatorial hexahedron.
* @param d1 an initial dart
* @return true iff the volume containing d1 is a combinatorial hexahedron.
*/
bool is_volume_combinatorial_hexahedron(Dart_const_descriptor d1) const
{
@ -4004,7 +4004,7 @@ namespace CGAL {
return true;
}
/** Create a new combinatorial hexahedron.
/** Creates a new combinatorial hexahedron.
* @return a new dart.
*/
Dart_descriptor make_combinatorial_hexahedron()
@ -4019,7 +4019,362 @@ namespace CGAL {
return make_combinatorial_hexahedron(d1, d2, d3, d4, d5, d6);
}
/** Test if an i-cell can be removed.
/** Tests if a volume is a combinatorial prism.
* @param d1 an initial dart
* @return true iff the volume containing d1 is a combinatorial prism.
*/
bool is_volume_combinatorial_prism(Dart_const_descriptor d1) const
{
Dart_const_descriptor d2=beta(d1, 2);
Dart_const_descriptor d3=beta(d1, 1, 2);
Dart_const_descriptor d4=beta(d1, 0, 2);
Dart_const_descriptor d5=beta(d2, 1, 1, 2);
if ( d1==null_dart_descriptor || d2==null_dart_descriptor ||
d3==null_dart_descriptor || d4==null_dart_descriptor ||
d5==null_dart_descriptor ) { return false; }
if (!is_face_combinatorial_polygon(d1, 3) ||
!is_face_combinatorial_polygon(d2, 4) ||
!is_face_combinatorial_polygon(d3, 4) ||
!is_face_combinatorial_polygon(d4, 4) ||
!is_face_combinatorial_polygon(d5, 3)) { return false; }
// TODO do better with marks.
if (belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d1, d5) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d2, d5) ||
belong_to_same_cell<2,1>(d3, d4) ||
belong_to_same_cell<2,1>(d3, d5) ||
belong_to_same_cell<2,1>(d4, d5))
{ return false; }
if (beta(d2,0,2) !=beta(d3,1) ||
beta(d2,1,2) !=beta(d4,0) ||
beta(d3,0,2) !=beta(d4,1) ||
beta(d3,1,1,2)!=beta(d5,0) ||
beta(d4,1,1,2)!=beta(d5,1)) { return false; }
return true;
}
/** Creates a combinatorial prism from 2 triangles and 3 squares.
* @param d1 a dart onto a first triangle.
* @param d2 a dart onto a first square.
* @param d3 a dart onto a second square.
* @param d4 a dart onto a thirth square.
* @param d5 a dart onto a second triangle.
* @return a new dart.
*/
Dart_descriptor make_combinatorial_prism(Dart_descriptor d1,
Dart_descriptor d2,
Dart_descriptor d3,
Dart_descriptor d4,
Dart_descriptor d5)
{
// 2-link for first triangle
basic_link_beta_for_involution(d1, d2, 2);
basic_link_beta_for_involution(beta(d1, 1), d3, 2);
basic_link_beta_for_involution(beta(d1, 0), d4, 2);
// 2-link for quandrangles between them
basic_link_beta_for_involution(beta(d2, 0), beta(d3, 1), 2);
basic_link_beta_for_involution(beta(d2, 1), beta(d4, 0), 2);
basic_link_beta_for_involution(beta(d3, 0), beta(d4, 1), 2);
// 2-link for second triangle
basic_link_beta_for_involution(beta(d2, 1, 1), d5, 2);
basic_link_beta_for_involution(beta(d3, 1, 1), beta(d5, 0), 2);
basic_link_beta_for_involution(beta(d4, 1, 1), beta(d5, 1), 2);
return d1;
}
/** Creates a new combinatorial prism.
* @return a new dart.
*/
Dart_descriptor make_combinatorial_prism()
{
Dart_descriptor d1 = make_combinatorial_polygon(3);
Dart_descriptor d2 = make_combinatorial_polygon(4);
Dart_descriptor d3 = make_combinatorial_polygon(4);
Dart_descriptor d4 = make_combinatorial_polygon(4);
Dart_descriptor d5 = make_combinatorial_polygon(3);
return make_combinatorial_prism( d1, d2, d3, d4, d5);
}
/** Tests if a volume is a combinatorial pyramid.
* @param d1 an intial dart
* @return true iff the volume containing d1 is a combinatorial pyramid.
*/
bool is_volume_combinatorial_pyramid(Dart_const_descriptor d1) const
{
Dart_const_descriptor d2=beta(d1, 2);
Dart_const_descriptor d3=beta(d1, 0, 2);
Dart_const_descriptor d4=beta(d1, 1, 1, 2);
Dart_const_descriptor d5=beta(d1, 1, 2);
if (d1==null_dart_descriptor || d2==null_dart_descriptor ||
d3==null_dart_descriptor || d4==null_dart_descriptor ||
d5==null_dart_descriptor) { return false; }
if (!is_face_combinatorial_polygon(d1, 4) ||
!is_face_combinatorial_polygon(d2, 3) ||
!is_face_combinatorial_polygon(d3, 3) ||
!is_face_combinatorial_polygon(d4, 3) ||
!is_face_combinatorial_polygon(d5, 3)) { return false; }
// TODO do better with marks.
if (belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d1, d5) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d2, d5) ||
belong_to_same_cell<2,1>(d3, d4) ||
belong_to_same_cell<2,1>(d3, d5) ||
belong_to_same_cell<2,1>(d4, d5))
{ return false; }
if (beta(d2,1,2)!=beta(d3,0) ||
beta(d2,0,2)!=beta(d5,1) ||
beta(d5,0,2)!=beta(d4,1) ||
beta(d4,0,2)!=beta(d3,1)) { return false; }
return true;
}
/** Creates a combinatorial pyramid from 1 square and 4 triangles.
* @param d1 a dart onto the square.
* @param d2 a dart onto a first triangle.
* @param d3 a dart onto a second triangle.
* @param d4 a dart onto a thirth triangle.
* @param d5 a dart onto a fourth triangle.
* @return a new dart.
*/
Dart_descriptor make_combinatorial_pyramid(Dart_descriptor d1,
Dart_descriptor d2,
Dart_descriptor d3,
Dart_descriptor d4,
Dart_descriptor d5)
{
// 2-link for the square
basic_link_beta_for_involution(d1, d2, 2);
basic_link_beta_for_involution(beta(d1, 1), d5, 2);
basic_link_beta_for_involution(beta(d1, 1, 1), d4, 2);
basic_link_beta_for_involution(beta(d1, 0), d3, 2);
// 2-link for first triangle
basic_link_beta_for_involution(beta(d2, 1), beta(d3, 0), 2);
basic_link_beta_for_involution(beta(d2, 0), beta(d5, 1), 2);
// 2-link for triangles between them
basic_link_beta_for_involution(beta(d5, 0), beta(d4, 1), 2);
basic_link_beta_for_involution(beta(d4, 0), beta(d3, 1), 2);
return d1;
}
/** Creates a new combinatorial pyramid.
* @return a new dart.
*/
Dart_descriptor make_combinatorial_pyramid()
{
Dart_descriptor d1=make_combinatorial_polygon(4);
Dart_descriptor d2=make_combinatorial_polygon(3);
Dart_descriptor d3=make_combinatorial_polygon(3);
Dart_descriptor d4=make_combinatorial_polygon(3);
Dart_descriptor d5=make_combinatorial_polygon(3);
return make_combinatorial_pyramid(d1, d2, d3, d4, d5);
}
/** Tests if a volume is a combinatorial pentagonal prism.
* @param d1 an initial dart
* @return true iff the volume containing d1 is a combinatorial pentagonal prism.
*/
bool is_volume_combinatorial_pentagonal_prism(Dart_const_descriptor d1) const
{
Dart_const_descriptor d2=beta(d1, 2);
Dart_const_descriptor d3=beta(d1, 1, 2);
Dart_const_descriptor d4=beta(d1, 1, 1, 2);
Dart_const_descriptor d5=beta(d1, 0, 0, 2);
Dart_const_descriptor d6=beta(d1, 0, 2);
Dart_const_descriptor d7=beta(d2, 1, 1, 2);
if (d1==null_dart_descriptor || d2==null_dart_descriptor ||
d3==null_dart_descriptor || d4==null_dart_descriptor ||
d5==null_dart_descriptor || d6==null_dart_descriptor ||
d7==null_dart_descriptor)
{ return false; }
if (!is_face_combinatorial_polygon(d1, 5) ||
!is_face_combinatorial_polygon(d2, 4) ||
!is_face_combinatorial_polygon(d3, 4) ||
!is_face_combinatorial_polygon(d4, 4) ||
!is_face_combinatorial_polygon(d5, 4) ||
!is_face_combinatorial_polygon(d6, 4) ||
!is_face_combinatorial_polygon(d7, 5)) { return false; }
// TODO do better with marks.
if (belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d1, d5) ||
belong_to_same_cell<2,1>(d1, d6) ||
belong_to_same_cell<2,1>(d1, d7) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d2, d5) ||
belong_to_same_cell<2,1>(d2, d6) ||
belong_to_same_cell<2,1>(d2, d7) ||
belong_to_same_cell<2,1>(d3, d4) ||
belong_to_same_cell<2,1>(d3, d5) ||
belong_to_same_cell<2,1>(d3, d6) ||
belong_to_same_cell<2,1>(d3, d7) ||
belong_to_same_cell<2,1>(d4, d5) ||
belong_to_same_cell<2,1>(d4, d6) ||
belong_to_same_cell<2,1>(d4, d7) ||
belong_to_same_cell<2,1>(d5, d6) ||
belong_to_same_cell<2,1>(d5, d7) ||
belong_to_same_cell<2,1>(d6, d7))
{ return false; }
if (beta(d2,0,2) !=beta(d3,1) ||
beta(d3,0,2) !=beta(d4,1) ||
beta(d4,0,2) !=beta(d5,1) ||
beta(d5,0,2) !=beta(d6,1) ||
beta(d6,0,2) !=beta(d2,1) ||
beta(d3,1,1,2)!=beta(d7,0) ||
beta(d4,1,1,2)!=beta(d7,0,0) ||
beta(d5,1,1,2)!=beta(d7,1,1) ||
beta(d6,1,1,2)!=beta(d7,1)) { return false; }
return true;
}
/** Tests if a volume is a combinatorial hexagonal prism.
* @param d1 an initial dart
* @return true iff the volume containing d1 is a combinatorial hexagonal prism.
*/
bool is_volume_combinatorial_hexagonal_prism(Dart_const_descriptor d1) const
{
Dart_const_descriptor d2=beta(d1, 2);
Dart_const_descriptor d3=beta(d1, 1, 2);
Dart_const_descriptor d4=beta(d1, 1, 1, 2);
Dart_const_descriptor d5=beta(d1, 1, 1, 1, 2);
Dart_const_descriptor d6=beta(d1, 0, 0, 2);
Dart_const_descriptor d7=beta(d1, 0, 2);
Dart_const_descriptor d8=beta(d2, 1, 1, 2);
if (d1==null_dart_descriptor || d2==null_dart_descriptor ||
d3==null_dart_descriptor || d4==null_dart_descriptor ||
d5==null_dart_descriptor || d6==null_dart_descriptor ||
d7==null_dart_descriptor || d8==null_dart_descriptor)
{ return false; }
if (!is_face_combinatorial_polygon(d1, 6) ||
!is_face_combinatorial_polygon(d2, 4) ||
!is_face_combinatorial_polygon(d3, 4) ||
!is_face_combinatorial_polygon(d4, 4) ||
!is_face_combinatorial_polygon(d5, 4) ||
!is_face_combinatorial_polygon(d6, 4) ||
!is_face_combinatorial_polygon(d7, 4) ||
!is_face_combinatorial_polygon(d8, 6)) { return false; }
// TODO do better with marks.
if (belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d1, d5) ||
belong_to_same_cell<2,1>(d1, d6) ||
belong_to_same_cell<2,1>(d1, d7) ||
belong_to_same_cell<2,1>(d1, d8) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d2, d5) ||
belong_to_same_cell<2,1>(d2, d6) ||
belong_to_same_cell<2,1>(d2, d7) ||
belong_to_same_cell<2,1>(d2, d8) ||
belong_to_same_cell<2,1>(d3, d4) ||
belong_to_same_cell<2,1>(d3, d5) ||
belong_to_same_cell<2,1>(d3, d6) ||
belong_to_same_cell<2,1>(d3, d7) ||
belong_to_same_cell<2,1>(d3, d8) ||
belong_to_same_cell<2,1>(d4, d5) ||
belong_to_same_cell<2,1>(d4, d6) ||
belong_to_same_cell<2,1>(d4, d7) ||
belong_to_same_cell<2,1>(d4, d8) ||
belong_to_same_cell<2,1>(d5, d6) ||
belong_to_same_cell<2,1>(d5, d7) ||
belong_to_same_cell<2,1>(d5, d8) ||
belong_to_same_cell<2,1>(d6, d7) ||
belong_to_same_cell<2,1>(d6, d8) ||
belong_to_same_cell<2,1>(d7, d8))
{ return false; }
if (beta(d2,0,2) !=beta(d3,1) ||
beta(d3,0,2) !=beta(d4,1) ||
beta(d4,0,2) !=beta(d5,1) ||
beta(d5,0,2) !=beta(d6,1) ||
beta(d6,0,2) !=beta(d7,1) ||
beta(d7,0,2) !=beta(d2,1) ||
beta(d3,1,1,2)!=beta(d8,0) ||
beta(d4,1,1,2)!=beta(d8,0,0) ||
beta(d5,1,1,2)!=beta(d8,0,0,0) ||
beta(d6,1,1,2)!=beta(d8,1,1) ||
beta(d7,1,1,2)!=beta(d8,1)) { return false; }
return true;
}
/** Tests if a volume is a combinatorial tetrahedron10.
* @param d1 an initial dart
* @return true iff the volume containing d1 is a combinatorial tetrahedron10.
*/
bool is_volume_combinatorial_tetrahedron10(Dart_const_descriptor d1) const
{
Dart_const_descriptor d2=beta(d1, 2,0);
Dart_const_descriptor d3=beta(d2, 0,2);
Dart_const_descriptor d4=beta(d2, 1,1,1,2);
if(d1==null_dart_descriptor || d2==null_dart_descriptor ||
d3==null_dart_descriptor || d4==null_dart_descriptor)
{ return false; }
if(!is_face_combinatorial_polygon(d1, 6) ||
!is_face_combinatorial_polygon(d2, 6) ||
!is_face_combinatorial_polygon(d3, 6) ||
!is_face_combinatorial_polygon(d4, 6)) { return false; }
if(beta(d1, 1,2)!=beta(d1, 2,0) ||
beta(d2, 1,2)!=beta(d2, 2,0) ||
beta(d3, 1,2)!=beta(d3, 2,0) ||
beta(d4, 1,2)!=beta(d4, 2,0)) { return false; }
// TODO do better with marks (?).
if(belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d3, d4)) { return false; }
if(beta(d1,1,1,2)!=beta(d3,0) ||
beta(d1,0,2)!=beta(d4,1,1) ||
beta(d4,0,2)!=beta(d3,1,1)) { return false; }
return true;
}
/** Tests if an i-cell can be removed.
* An i-cell can be removed if i==dimension or i==dimension-1,
* or if there are at most two (i+1)-cell incident to it.
* @param adart a dart of the i-cell.
@ -4041,7 +4396,7 @@ namespace CGAL {
run(*this,adart,update_attributes);
}
/** Test if an i-cell can be contracted.
/** Tests if an i-cell can be contracted.
* An i-cell can be contracted if i==1
* or if there are at most two (i-1)-cell incident to it.
* @param adart a dart of the i-cell.
@ -4407,7 +4762,7 @@ namespace CGAL {
return this->template beta<0>(adart1);
}
/** Test if an edge can be inserted onto a 2-cell between two given darts.
/** Tests if an edge can be inserted onto a 2-cell between two given darts.
* @param adart1 a first dart.
* @param adart2 a second dart.
* @return true iff an edge can be inserted between adart1 and adart2.
@ -4443,7 +4798,7 @@ namespace CGAL {
return generic_insert_cell_1(adart1, adart2, false, update_attributes);
}
/** Test if an edge can be inserted between two different 2-cells
/** Tests if an edge can be inserted between two different 2-cells
* between two given darts.
* @param adart1 a first dart.
* @param adart2 a second dart.
@ -4627,7 +4982,7 @@ namespace CGAL {
return this->template beta<0>(adart1);
}
/** Test if a 2-cell can be inserted onto a given 3-cell along
/** Tests if a 2-cell can be inserted onto a given 3-cell along
* a path of edges.
* @param afirst iterator on the beginning of the path.
* @param alast iterator on the end of the path.

View File

@ -0,0 +1,208 @@
// Copyright (c) 2025 CNRS and LIRIS' Establishments (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
//
////////////////////////////////////////////////////////////////////////////////
#ifndef CMAP_ELEMENT_TOPO_H
#define CMAP_ELEMENT_TOPO_H
#include <string>
namespace CGAL {
namespace CMap {
namespace Element_topo {
enum cell_topo
{
SQUARE=0,
TRIANGLE=1,
HEXAHEDRON=2,
TETRAHEDRON=3,
PRISM=4,
PYRAMID=5,
GENERIC_2D=6,
GENERIC_3D=7,
EDGE=8,
TETRAHEDRON10=9,
PENTAGONAL_PRISM=10,
HEXAGONAL_PRISM=11,
NO_TYPE=-1
};
inline
std::string topo_name(cell_topo t)
{
switch(t)
{
case SQUARE: return "SQUARE";
case TRIANGLE: return "TRIANGLE";
case HEXAHEDRON: return "HEXAHEDRON";
case TETRAHEDRON: return "TETRAHEDRON";
case PRISM: return "PRISM";
case PYRAMID: return "PYRAMID";
case GENERIC_2D: return "GENERIC_2D";
case GENERIC_3D: return "GENERIC_3D";
case EDGE: return "EDGE";
case TETRAHEDRON10: return "TETRAHEDRON10";
case PENTAGONAL_PRISM: return "PENTAGONAL_PRISM";
case HEXAGONAL_PRISM: return "HEXAGONAL_PRISM";
case NO_TYPE: return "NO_TYPE";
}
return "UNKNOWN";
}
inline
cell_topo topo_from_name(const std::string& t)
{
if (t=="SQUARE") return SQUARE;
if (t=="TRIANGLE") return TRIANGLE;
if (t=="HEXAHEDRON") return HEXAHEDRON;
if (t=="TETRAHEDRON") return TETRAHEDRON;
if (t=="PRISM") return PRISM;
if (t=="PYRAMID") return PYRAMID;
if (t=="GENERIC_2D") return GENERIC_2D;
if (t=="GENERIC_3D") return GENERIC_3D;
if (t=="EDGE") return EDGE;
if (t=="TETRAHEDRON10") return TETRAHEDRON10;
if (t=="PENTAGONAL_PRISM") return PENTAGONAL_PRISM;
if (t=="HEXAGONAL_PRISM") return HEXAGONAL_PRISM;
if (t=="NO_TYPE") return NO_TYPE;
return NO_TYPE;
}
/**
* @brief To get the type of `dimD` cell of the `CMap` of `cmapdim` dimension.
*/
template<typename CMap, unsigned int dimcell,
unsigned int cmapdim=CMap::dimension>
struct Get_cell_topo
{
static cell_topo run(CMap&, typename CMap::Dart_descriptor dh,
typename CMap::Dart_descriptor& starting_dart)
{
starting_dart=dh;
return NO_TYPE;
}
};
/**
* @brief To get the type associated of an edge. For now only one type.
*/
template<typename CMap, unsigned int cmapdim>
struct Get_cell_topo<CMap, 1, cmapdim>
{
static cell_topo run(CMap&, typename CMap::Dart_descriptor it,
typename CMap::Dart_descriptor& starting_dart)
{
starting_dart=it;
return EDGE;
}
};
/**
* @brief To get the type of 2D cell of the CMap of cmapdim dimension.
*/
template<typename CMap, unsigned int cmapdim>
struct Get_cell_topo<CMap, 2, cmapdim>
{
static cell_topo run(CMap& cmap, typename CMap::Dart_descriptor it,
typename CMap::Dart_descriptor& starting_dart)
{
starting_dart=it;
if (cmap.is_face_combinatorial_polygon(it, 3))
{ return TRIANGLE; }
else if (cmap.is_face_combinatorial_polygon(it, 4))
{ return SQUARE; }
return GENERIC_2D;
}
};
/**
* @brief To get the type of 3D cell of the CMap of dimension 3.
*/
template<typename CMap>
struct Get_cell_topo<CMap, 3, 3>
{
static cell_topo run(CMap& cmap, typename CMap::Dart_descriptor it,
typename CMap::Dart_descriptor& starting_dart)
{
starting_dart=it;
if (cmap.is_volume_combinatorial_tetrahedron(it))
{ return TETRAHEDRON; }
else if (cmap.is_volume_combinatorial_hexahedron(it))
{ return HEXAHEDRON; }
else if(cmap.is_volume_combinatorial_tetrahedron10(it))
{ return TETRAHEDRON10; }
// For non symetric object, we need to test all darts
for (auto itv=cmap.template darts_of_cell<3>(it).begin(),
itvend=cmap.template darts_of_cell<3>(it).end(); itv!=itvend; ++itv)
{
starting_dart=itv;
if (cmap.is_volume_combinatorial_prism(itv))
{ return PRISM; }
else if (cmap.is_volume_combinatorial_pentagonal_prism(itv))
{ return PENTAGONAL_PRISM; }
else if (cmap.is_volume_combinatorial_pyramid(itv))
{ return PYRAMID; }
else if (cmap.is_volume_combinatorial_hexagonal_prism(itv))
{ return HEXAGONAL_PRISM; }
}
return GENERIC_3D;
}
};
template<unsigned int dimcell, typename CMap>
cell_topo get_cell_topo(CMap& cmap, typename CMap::Dart_descriptor it,
typename CMap::Dart_descriptor& starting_dart)
{ return Get_cell_topo<CMap, dimcell>::run(cmap, it, starting_dart); }
template<unsigned int dimcell, typename CMap>
cell_topo get_cell_topo(CMap& cmap, typename CMap::Dart_descriptor it)
{
typename CMap::Dart_descriptor dummy;
return get_cell_topo<dimcell, CMap>(cmap, it, dummy);
}
template<unsigned int dimcell, typename CMap>
cell_topo get_cell_topo(const CMap& cmap, typename CMap::Dart_const_descriptor it,
typename CMap::Dart_const_descriptor& starting_dart)
{
typename CMap::Dart_descriptor it2=const_cast<CMap&>(cmap).dart_descriptor
(cmap.darts().index(it));
typename CMap::Dart_descriptor sd2;
cell_topo res=Get_cell_topo<CMap, dimcell>::run(const_cast<CMap&>(cmap),
it2, sd2);
starting_dart=sd2;
return res;
}
template<unsigned int dimcell, typename CMap>
cell_topo get_cell_topo(const CMap& cmap, typename CMap::Dart_const_descriptor it)
{
typename CMap::Dart_descriptor it2=it;
return Get_cell_topo<CMap, dimcell>::run(const_cast<CMap&>(cmap), it2);
}
} } } // namespace CGAL::CMap::Element_topo
#endif // CMAP_ELEMENT_TOPO_H

View File

@ -0,0 +1,68 @@
namespace CGAL {
namespace IO {
/** \file VTK.h
* Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII
* format.
*
* Only supports:
* - `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>`
* - VTK legacy ASCII format (.vtk files)
* - Optional scalar fields for vertices and volumes
*
* Supported VTK cell types:
* - VTK_TETRA (10): Tetrahedron
* - VTK_VOXEL (11): Voxel (special hexahedron ordering)
* - VTK_HEXAHEDRON (12): Hexahedron
* - VTK_WEDGE (13): Prism/Wedge
* - VTK_PYRAMID (14): Pyramid
* - VTK_PENTAGONAL_PRISM (15): Pentagonal prism
* - VTK_HEXAGONAL_PRISM (16): Hexagonal prism
* - VTK_POLYHEDRON (42): Generic polyhedron
*/
/**
* \brief Reads a VTK legacy ASCII file and load it into a 3D
* linear cell complex.
* \ingroup PkgLinearCellComplexRefIOVTK
*
* \tparam LCC must be a `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>`
* \tparam VertexScalarType Type for vertex scalar data (default: float)
* \tparam VolumeScalarType Type for volume scalar data (default: float)
* \param filename Path to the VTK file
* \param alcc The linear cell complex to populate (will be cleared first)
* \param vertex_scalars Optional output vector to store per-vertex scalar values.
* If provided, will be resized to match number of vertices.
* \param volume_scalars Optional output vector to store per-volume scalar values.
* If provided, will be resized to match number of volumes.
* \return `true` if loading was successful, `false` otherwise
*/
template <typename LCC, typename VertexScalarType, typename VolumeScalarType>
bool read_VTK(const char* filename,
LCC& alcc,
std::vector<VertexScalarType>* vertex_scalars=nullptr,
std::vector<VolumeScalarType>* volume_scalars=nullptr);
/**
* \brief Writes a 3D Linear_cell_complex to a VTK legacy ASCII file.
* \ingroup PkgLinearCellComplexRefIOVTK
*
* \tparam LCC must be a `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>`
* \tparam VertexScalarType Type for vertex scalar data (default: float)
* \tparam VolumeScalarType Type for volume scalar data (default: float)
* \param filename Path to the output VTK file
* \param alcc The linear cell complex to export
* \param vertex_scalars Optional per-vertex scalar data. If provided, must have
* same size as number of vertex attributes in the LCC.
* \param volume_scalars Optional per-volume scalar data. If provided, must have
* same size as number of 3-cells in the LCC.
* \return `true` if writing was successful, `false` otherwise
*/
template <typename LCC, typename VertexScalarType, typename VolumeScalarType>
bool write_VTK(const char* filename,
const LCC& alcc,
const std::vector<VertexScalarType>* vertex_scalars=nullptr,
const std::vector<VolumeScalarType>* volume_scalars=nullptr);
} // namespace IO
} // namespace CGAL

View File

@ -289,6 +289,18 @@ The following example shows the use of \link GenericMap::insert_cell_1_between_t
Result of the run of the linear_cell_complex_3_insert program. A window shows the 3D cube where one face has a hole.
\cgalFigureEnd
\subsection Linear_cell_complexWriteVTK Writing a Linear Cell Complex to a VTK File
\anchor ssecLCCWriteVtK
This example loads a 3D linear cell complex from a `.3map` file (using the `operator>>`). It computes for each 3-cell (volume) the number of incident vertices (0-cells), stores these values in a `std::vector<std::size_t>`, and writes the result to a `.vtk` file using `CGAL::IO::write_VTK()`, with the computed values as scalars for each volume.
\cgalExample{Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp}
\cgalFigureBegin{fig_lcc_export_vtk,lcc-export-vtk.png}
Visualization of the VTK file generated by the `linear_cell_complex_3_vtk_io` program, using Paraview. Each volume is colored depending on its number of vertices.
\cgalFigureEnd
\section Linear_cell_complexDesign Design and Implementation History
This package was developed by Guillaume Damiand, with the help of Andreas Fabri, S&eacute;bastien Loriot and Laurent Rineau. Monique Teillaud and Bernd G&auml;rtner contributed to the manual.

View File

@ -23,6 +23,14 @@
/// \defgroup PkgDrawLinearCellComplex Draw a Linear Cell Complex
/// \ingroup PkgLinearCellComplexRef
/// \defgroup PkgLinearCellComplexRefIO IO Functions for LCC
/// \ingroup PkgLinearCellComplexRef
/*! High-level operations.
\cgalInclude{CGAL/Linear_cell_complex/IO/VTK.h}
*/
/// \defgroup PkgLinearCellComplexRefIOVTK VTK IO Functions for LCC
/// \ingroup PkgLinearCellComplexRefIO
/*!
\addtogroup PkgLinearCellComplexRef
@ -74,4 +82,10 @@
- \link PkgDrawLinearCellComplex CGAL::draw<LCC>() \endlink
- \link PkgDrawLinearCellComplex CGAL::add_in_graphics_scene<LCC, BufferType, DrawingFunctor>() \endlink
\cgalCRPSubsection{IO Functions for LCC}
- \link PkgCombinatorialMapsRefIO `std::ostream& operator<< (std::ostream& os, const GenericMap& amap)` \endlink
- \link PkgCombinatorialMapsRefIO `std::ifstream& operator>> (std::ifstream& is, GenericMap& amap)` \endlink
- \link PkgLinearCellComplexRefIOVTK `CGAL::IO::Read_VTK<LCC>()` \endlink
- \link PkgLinearCellComplexRefIOVTK `CGAL::IO::Write_VTK<LCC>()` \endlink
*/

View File

@ -6,4 +6,5 @@
\example Linear_cell_complex/linear_cell_complex_3_incremental_builder.cpp
\example Linear_cell_complex/draw_linear_cell_complex.cpp
\example Linear_cell_complex/linear_cell_complex_3_insert.cpp
\example Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -27,6 +27,7 @@ create_single_source_cgal_program("linear_cell_complex_4.cpp")
create_single_source_cgal_program("read_plane_graph_in_lcc_2.cpp")
create_single_source_cgal_program("voronoi_2.cpp")
create_single_source_cgal_program("voronoi_3.cpp")
create_single_source_cgal_program("linear_cell_complex_3_vtk_io.cpp")
create_single_source_cgal_program("draw_linear_cell_complex.cpp")
if(CGAL_Qt6_FOUND)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,34 @@
#include <CGAL/Linear_cell_complex_for_combinatorial_map.h>
#include <CGAL/Linear_cell_complex/IO/VTK.h>
#include <vector>
#include <cstdlib>
int main()
{
CGAL::Linear_cell_complex_for_combinatorial_map<3> lcc;
std::ifstream is("data/beam-with-mixed-cells.3map");
if(!is)
{
std::cout<<"Error opening data/beam-with-mixed-cells.3map."<<std::endl;
return EXIT_FAILURE;
}
is>>lcc;
// Compute per-volume vertex count
std::vector<std::size_t> volume_scalars;
for(auto it=lcc.template one_dart_per_cell<3>().begin(),
itend=lcc.template one_dart_per_cell<3>().end(); it!=itend; ++it)
{
std::size_t nbv=lcc.template one_dart_per_incident_cell<0,3>(it).size();
volume_scalars.push_back(nbv);
}
if(!CGAL::IO::write_VTK("beam-with-mixed-cells.vtk", lcc, nullptr,
&volume_scalars))
{
std::cout<<"Error for write_VTK."<<std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,719 @@
// Copyright (c) 2025 CNRS and LIRIS' Establishments (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
#ifndef CGAL_LCC_IO_VTK_H
#define CGAL_LCC_IO_VTK_H
#include <CGAL/Linear_cell_complex_incremental_builder_3.h>
#include <CGAL/assertions.h>
#include <CGAL/Element_topo.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <set>
namespace CGAL {
namespace IO {
/*
* Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII
* format.
*
* Only supports:
* - Linear_cell_complex_for_combinatorial_map<3,3>
* - VTK legacy ASCII format (.vtk files)
* - Optional scalar fields for vertices and volumes
*
* Supported VTK cell types:
* - VTK_TETRA (10): Tetrahedron
* - VTK_VOXEL (11): Voxel (special hexahedron ordering)
* - VTK_HEXAHEDRON (12): Hexahedron
* - VTK_WEDGE (13): Prism/Wedge
* - VTK_PYRAMID (14): Pyramid
* - VTK_PENTAGONAL_PRISM (15): Pentagonal prism
* - VTK_HEXAGONAL_PRISM (16): Hexagonal prism
* - VTK_POLYHEDRON (42): Generic polyhedron
*/
// ============================================================================
// Declarations
// ============================================================================
/*
* Read a VTK legacy ASCII file and load it into a 3D Linear_cell_complex.
*
* \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3>
* \tparam VertexScalarType Type for vertex scalar data (default: float)
* \tparam VolumeScalarType Type for volume scalar data (default: float)
* \param alcc The Linear_cell_complex to populate (will be cleared first)
* \param filename Path to the VTK file
* \param vertex_scalars Optional output vector to store per-vertex scalar values.
* If provided, will be resized to match number of vertices.
* \param volume_scalars Optional output vector to store per-volume scalar values.
* If provided, will be resized to match number of volumes.
* \return `true` if loading was successful, `false` otherwise
*/
template <typename LCC, typename VertexScalarType,
typename VolumeScalarType>
bool read_VTK(const char* filename,
LCC& alcc,
std::vector<VertexScalarType>* vertex_scalars,
std::vector<VolumeScalarType>* volume_scalars);
/*
* Write a 3D Linear_cell_complex to a VTK legacy ASCII file.
*
* \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3>
* \tparam VertexScalarType Type for vertex scalar data (default: float)
* \tparam VolumeScalarType Type for volume scalar data (default: float)
* \param alcc The Linear_cell_complex to export
* \param filename Path to the output VTK file
* \param vertex_scalars Optional per-vertex scalar data. If provided, must have
* same size as number of vertex attributes in the LCC.
* \param volume_scalars Optional per-volume scalar data. If provided, must have
* same size as number of 3-cells in the LCC.
* \return `true` if writing was successful, `false` otherwise
*/
template <typename LCC, typename VertexScalarType,
typename VolumeScalarType>
bool write_VTK(const char* filename,
const LCC& alcc,
const std::vector<VertexScalarType>* vertex_scalars,
const std::vector<VolumeScalarType>* volume_scalars);
// "Advanced" versions with functors
template <typename LCC, typename PointFunctor, typename CellFunctor>
bool write_VTK_with_fct(const char* filename, const LCC& alcc,
PointFunctor ptval, CellFunctor cellval);
// ============================================================================
// Implementation details
// ============================================================================
namespace internal
{
/////////////////////////////////////////////////////////////////////////////
// VTK type name mapping
// bit, unsigned_char, char, unsigned_short, short, unsigned_int, int,
// unsigned_long, long, float, double.
template<typename T>
struct gettype
{ static std::string name() { return "unknown"; }};
template<>
struct gettype<bool>
{ static std::string name() { return "bit"; }};
template<>
struct gettype<unsigned char>
{ static std::string name() { return "unsigned_char"; }};
template<>
struct gettype<char>
{ static std::string name() { return "char"; }};
template<>
struct gettype<unsigned short int>
{ static std::string name() { return "unsigned_short"; }};
template<>
struct gettype<short int>
{ static std::string name() { return "short"; }};
template<>
struct gettype<unsigned int>
{ static std::string name() { return "unsigned_int"; }};
template<>
struct gettype<int>
{ static std::string name() { return "int"; }};
template<>
struct gettype<unsigned long int>
{ static std::string name() { return "unsigned_long"; }};
template<>
struct gettype<long int>
{ static std::string name() { return "long"; }};
template<>
struct gettype<float>
{ static std::string name() { return "float"; }};
template<>
struct gettype<double>
{ static std::string name() { return "double"; }};
/////////////////////////////////////////////////////////////////////////////
// VTK cell type constants
enum VTK_Cell_Type
{
VTK_TETRA = 10,
VTK_VOXEL = 11,
VTK_HEXAHEDRON = 12,
VTK_WEDGE = 13, // Prism
VTK_PYRAMID = 14,
VTK_PENTAGONAL_PRISM = 15,
VTK_HEXAGONAL_PRISM = 16,
VTK_POLYHEDRON = 42 // Generic cell
};
/////////////////////////////////////////////////////////////////////////////
/// Write cell_data.
template<typename FCT>
struct Write_cell_data
{
/// nb is the number of cells,
/// fct is a function having 3 parameters: a lcc, a dart_descriptor,
/// an the index of the cell.
template<typename LCC>
static void run(std::ofstream& fo, LCC& lcc, std::size_t nb, FCT fct)
{
fo<<"CELL_DATA "<<nb<<std::endl;
fo<<"SCALARS cell_scalars "
<<gettype<decltype(fct(lcc, lcc.null_dart_descriptor, 0))>::name()
<<" 1"<<std::endl;
fo<<"LOOKUP_TABLE default"<<std::endl;
std::size_t i=0;
for(auto itvol=lcc.template one_dart_per_cell<3>().begin(),
itvolend=lcc.template one_dart_per_cell<3>().end();
itvol!=itvolend; ++itvol, ++i)
{ fo<<fct(lcc, itvol, i)<<std::endl; }
fo<<std::endl;
}
};
template<>
struct Write_cell_data<std::nullptr_t>
{
template<typename LCC>
static void run(std::ofstream&, LCC&, std::size_t, std::nullptr_t)
{}
};
/////////////////////////////////////////////////////////////////////////////
/// Write point_data.
template<typename FCT>
struct Write_point_data
{
/// nb is the number of cells,
/// fct is a function having 3 parameters: a lcc, a dart_descriptor,
/// an the index of the cell.
template<typename LCC>
static void run(std::ofstream& fo, LCC& lcc, std::size_t nb, FCT fct)
{
fo<<"POINT_DATA "<<nb<<std::endl;
fo<<"SCALARS point_scalars "
<<gettype<decltype(fct(lcc, lcc.null_dart_descriptor, 0))>::name()
<<" 1"<<std::endl;
fo<<"LOOKUP_TABLE default"<<std::endl;
std::size_t i=0;
for(auto itv=lcc.vertex_attributes().begin(),
itvend=lcc.vertex_attributes().end(); itv!=itvend; ++itv, ++i)
{ fo<<fct(lcc, lcc.template dart_of_attribute<0>(itv), i)<<std::endl; }
fo<<std::endl;
}
};
/////////////////////////////////////////////////////////////////////////////
template<>
struct Write_point_data<std::nullptr_t>
{
template<typename LCC>
static void run(std::ofstream&, LCC&, std::size_t, std::nullptr_t)
{}
};
/////////////////////////////////////////////////////////////////////////////
// Read data, stored values as T.
template<typename T>
bool read_data(std::istream& fi, std::string& line, std::vector<T>& data)
{
std::string txt, data_type;
std::size_t nb;
std::istringstream inputline(line);
inputline>>txt>>nb; // "CELL_DATA xxx"
fi>>txt>>txt; // "SCALARS cell_scalars "
fi>>data_type>>txt; // type for data
fi>>txt>>txt; // "LOOKUP_TABLE default"
if(!fi.good())
{ return false; }
data.clear();
data.reserve(nb);
for(std::size_t i=0; i<nb; ++i)
{
if(!(fi>>txt))
{ return false; }
std::stringstream ss{txt};
T t;
ss>>t;
data.push_back(t);
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
// Helper: detect VTK cell type from a 3-cell
template<typename LCC>
VTK_Cell_Type get_vtk_cell_type(const LCC& lcc,
typename LCC::Dart_const_descriptor itvol,
typename LCC::Dart_const_descriptor& sd)
{
using namespace CGAL::CMap::Element_topo;
cell_topo vol_type=get_cell_topo<3>(lcc, itvol, sd);
switch(vol_type)
{
case TETRAHEDRON: return VTK_TETRA;
case PYRAMID: return VTK_PYRAMID;
case PRISM: return VTK_WEDGE;
case HEXAHEDRON: return VTK_HEXAHEDRON;
// case PENTAGONAL_PRISM: return VTK_PENTAGONAL_PRISM;
// case HEXAGONAL_PRISM: return VTK_HEXAGONAL_PRISM;
// 24 QUADRATIC_TETRA
// 25 QUADRATIC_HEXAHEDRON
// 26 QUADRATIC_WEDGE
// 27 QUADRATIC_PYRAMID
default: break;
}
return VTK_POLYHEDRON;
}
/////////////////////////////////////////////////////////////////////////////
template <typename LCC, typename VertexScalarType=float,
typename CellScalarType=float>
bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc,
std::vector<VertexScalarType>* vertex_scalars=nullptr,
std::vector<CellScalarType>* cell_scalars=nullptr)
{
static_assert(LCC::dimension==3 && LCC::ambient_dimension==3,
"read_VTK() only supports 3D Linear_cell_complexes (3,3)");
using Point=typename LCC::Point;
using FT=typename LCC::FT;
Linear_cell_complex_incremental_builder_3<LCC> ib(alcc);
std::string line, tmp;
std::size_t npoints, ncells;
// Skip to POINTS section
while(std::getline(is, line) && line.find("POINTS")==std::string::npos)
{}
if(is.eof())
{
std::cerr<<"[ERROR] read_VTK: POINTS section not found"<<std::endl;
return false;
}
std::stringstream ss(line);
std::getline(ss, tmp, ' '); // skip "POINTS"
ss>>npoints;
// Read points
std::vector<typename LCC::Vertex_attribute_descriptor> points(npoints);
for(std::size_t i=0; i<npoints; ++i)
{
FT x, y, z;
if(!(is>>x>>y>>z))
{
std::cerr<<"[ERROR] read_VTK: failed to read point "<<i<<std::endl;
return false;
}
points[i]=ib.add_vertex(Point(x, y, z));
}
// Skip to CELLS section
while(std::getline(is, line) && line.find("CELLS")==std::string::npos)
{}
if(is.eof())
{
std::cerr<<"[ERROR] read_VTK: CELLS section not found"<<std::endl;
return false;
}
ss=std::stringstream(line);
std::getline(ss, tmp, ' '); // skip "CELLS"
ss>>ncells;
// Read connectivity
std::vector<std::vector<std::size_t>> faces(ncells);
std::size_t points_per_cell;
for(std::size_t i=0; i<ncells; ++i)
{
if(!(is>>points_per_cell))
{
std::cerr<<"[ERROR] read_VTK: failed to read cell "<<i<<std::endl;
return false;
}
faces[i].resize(points_per_cell);
for(std::size_t j=0; j<points_per_cell; ++j)
{
if(!(is>>faces[i][j]))
{
std::cerr<<"[ERROR] read_VTK: failed to read cell "<<i<<" vertex "<<j<< std::endl;
return false;
}
}
}
// Skip to CELL_TYPES section
while(std::getline(is, line) && line.find("CELL_TYPES")==std::string::npos)
{}
if(is.eof())
{
std::cerr<<"[ERROR] read_VTK: CELL_TYPES section not found"<<std::endl;
return false;
}
// Create cells based on types
std::size_t cell_type;
std::set<std::size_t> error_types;
for(std::size_t i = 0; i<ncells; ++i)
{
if(!(is>>cell_type))
{
std::cerr<<"[ERROR] read_VTK: failed to read cell type "<<i<< std::endl;
return false;
}
const auto& v=faces[i];
switch(cell_type)
{
case VTK_TETRA:
if(v.size()==4)
{ make_tetrahedron_with_builder(ib, v[0], v[1], v[2], v[3]); }
break;
case VTK_VOXEL:
if(v.size()==8)
{ make_hexahedron_with_builder(ib, v[0], v[1], v[3], v[2], v[4], v[5],
v[7], v[6]); }
break;
case VTK_HEXAHEDRON:
if(v.size()==8)
{ make_hexahedron_with_builder(ib, v[0], v[1], v[2], v[3], v[4], v[5],
v[6], v[7]); }
break;
case VTK_WEDGE: // PRISM
if(v.size()==6)
{ make_prism_with_builder(ib, v[0], v[1], v[2], v[3], v[4], v[5]); }
break;
case VTK_PYRAMID:
if(v.size()==5)
{ make_pyramid_with_builder(ib, v[0], v[1], v[2], v[3], v[4]); }
break;
case VTK_PENTAGONAL_PRISM:
if(v.size()==10)
{ make_pentagonal_prism_with_builder(ib, v[0], v[1], v[2], v[3], v[4],
v[5], v[6], v[7], v[8], v[9]); }
break;
case VTK_HEXAGONAL_PRISM:
if(v.size()==12)
{ make_hexagonal_prism_with_builder(ib, v[0], v[1], v[2], v[3], v[4],
v[5], v[6], v[7], v[8], v[9],
v[10], v[11]); }
break;
case VTK_POLYHEDRON: // GENERIC CELL
make_generic_cell_with_builder(ib, v);
break;
default:
if(error_types.count(cell_type)==0)
{
std::cerr<<"[ERROR] read_VTK: type "<<cell_type<<" unknown."<<std::endl;
error_types.insert(cell_type);
}
}
}
// Clean up unused vertex attributes
for(auto itv=alcc.vertex_attributes().begin();
itv!=alcc.vertex_attributes().end(); ++itv)
{
if(alcc.template dart_of_attribute<0>(itv)==alcc.null_descriptor)
{ alcc.erase_vertex_attribute(itv); }
}
if(vertex_scalars!=nullptr)
{ vertex_scalars->clear(); }
if(cell_scalars!=nullptr)
{ cell_scalars->clear(); }
while(std::getline(is, line))
{
// Read POINT_DATA scalars if present
if(vertex_scalars!=nullptr && line.find("POINT_DATA")!=std::string::npos)
{
if(!read_data(is, line, *vertex_scalars))
{
std::cerr<<"[ERROR] read_VTK: error when reading POINT_DATA."
<<std::endl;
}
}
// Read CELL_DATA scalars if present
else if(cell_scalars!=nullptr && line.find("CELL_DATA")!=std::string::npos)
{
if(!read_data(is, line, *cell_scalars))
{
std::cerr<<"[ERROR] read_VTK: error when reading CELL_DATA."
<<std::endl;
}
}
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
template<class LCC>
bool write_lcc_topo_to_vtk_ascii(std::ostream& os, const LCC& alcc,
std::size_t& nbpts, std::size_t& nbcells)
{
static_assert(LCC::dimension==3 && LCC::ambient_dimension==3,
"write_VTK() only supports 3D Linear_cell_complexes (3,3)");
// Write VTK header
os<<"# vtk DataFile Version 2.0\n";
os<<"CGAL Linear_cell_complex\n";
os<<"ASCII\n";
os<<"DATASET UNSTRUCTURED_GRID\n\n";
// Build vertex index map and write points
std::unordered_map<typename LCC::Vertex_attribute_const_descriptor, std::size_t>
index;
nbpts=0;
os<<"POINTS "<<alcc.vertex_attributes().size()<<" double"<<std::endl;
for(auto itv=alcc.vertex_attributes().begin(),
itvend=alcc.vertex_attributes().end(); itv!=itvend; ++itv)
{
os<<" "<<itv->point()<<std::endl;
index[itv]=nbpts++;
}
os<<std::endl;
// Count cells and build connectivity
nbcells=0;
std::size_t total_size=0;
std::ostringstream cell_stream, type_stream;
typename LCC::Dart_const_descriptor sd;
// Write cells section
for(typename LCC::template One_dart_per_cell_range<3>::const_iterator
itvol=alcc.template one_dart_per_cell<3>().begin(),
itvolend=alcc.template one_dart_per_cell<3>().end();
itvol!=itvolend; ++itvol)
{
++nbcells;
++total_size; // for the number of vertices
VTK_Cell_Type cell_type=get_vtk_cell_type(alcc, itvol, sd);
type_stream<<static_cast<int>(cell_type)<<std::endl;
if(cell_type==VTK_TETRA)
{
cell_stream<<" 4 "
<<index[alcc.vertex_attribute(sd)]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<1>(sd))]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<0>(sd))]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<2, 0>(sd))]<<std::endl;
total_size+=4;
}
else if(cell_type==VTK_PYRAMID)
{
cell_stream<<" 5 "
<<index[alcc.vertex_attribute(sd)]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<1>(sd))]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<1,1>(sd))]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<0>(sd))]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<2,0>(sd))]<<std::endl;
total_size+=5;
}
else if(cell_type==VTK_WEDGE)
{
cell_stream<<" 6 "
<<index[alcc.vertex_attribute(sd)]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<1>(sd))]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<0>(sd))]<<" ";
// Move to the up face
typename LCC::Dart_const_descriptor d2=alcc.template beta<2, 1, 1, 2>(sd);
cell_stream<<index[alcc.vertex_attribute(alcc.template beta<1>(d2))]<<" "
<<index[alcc.vertex_attribute(d2)]<<" "
<<index[alcc.vertex_attribute(alcc.template beta<0>(d2))]<<std::endl;
total_size+=6;
}
else if(cell_type==VTK_HEXAHEDRON)
{
cell_stream<<" 8 ";
for(unsigned int i=0; i<4; ++i)
{
cell_stream<<index[alcc.vertex_attribute(sd)]<<" ";
sd=alcc.template beta<1>(sd);
}
typename LCC::Dart_const_descriptor d2=alcc.template beta<2, 1, 1, 2, 1>(sd);
// Darts associated with particles 4, 5, 6, 7
for(unsigned int i = 0; i < 4; i++)
{
cell_stream<<index[alcc.vertex_attribute(d2)]<<" ";
d2 = alcc.template beta<0>(d2);
}
cell_stream<<std::endl;
total_size+=8;
}
// TODO: 15 PENTAGONAL_PRISM
// 16 HEXAGONAL_PRISM
// 24 QUADRATIC_TETRA
// 25 QUADRATIC_HEXAHEDRON
// 26 QUADRATIC_WEDGE
// 27 QUADRATIC_PYRAMID
else
{
// Generic polyhedron format write as face-vertex connectivity
std::vector<std::vector<std::size_t>> faces;
std::size_t cell_size=1; // Start with 1 for number of faces
++total_size; // for the same reason
for(auto itface=alcc.template one_dart_per_incident_cell<2, 3, 2>(itvol).begin(),
itfaceend=alcc.template one_dart_per_incident_cell<2, 3, 2>(itvol).end();
itface!=itfaceend; ++itface)
{
faces.push_back(std::vector<std::size_t>());
typename LCC::Dart_const_descriptor curdh=itface;
do
{
faces.back().push_back(index[alcc.vertex_attribute(curdh)]);
curdh=alcc.template beta<1>(curdh);
}
while(curdh!=itface);
cell_size+=faces.back().size()+1; // +1 for the number of vertices in the face
}
cell_stream<<cell_size<<" "<<faces.size();
for(const auto& face : faces)
{
cell_stream<<" "<<face.size();
for(auto v : face)
{ cell_stream<<" "<<v; }
total_size+=face.size()+1; // +1 for the number of vertices in the face
}
cell_stream<<std::endl;
}
}
os<<"CELLS "<<nbcells<<" "<<total_size<<std::endl;
os<<cell_stream.str()<<std::endl;
// Write cell types
os<<"CELL_TYPES "<<nbcells<<std::endl;
os<<type_stream.str()<<std::endl;
return true;
}
} // namespace internal
// ============================================================================
// Public interface implementation
// ============================================================================
////////////////////////////////////////////////////////////////////////////////////
template <typename LCC, typename VertexScalarType, typename VolumeScalarType>
bool read_VTK(const char* filename, LCC& alcc,
std::vector<VertexScalarType>* vertex_scalars,
std::vector<VolumeScalarType>* volume_scalars)
{
CGAL_assertion(filename!=nullptr);
std::ifstream file(filename);
if(!file.is_open())
{
std::cerr<<"[ERROR] read_VTK: cannot open file "<<filename<<std::endl;
return false;
}
return internal::read_lcc_from_vtk_ascii(file, alcc,
vertex_scalars, volume_scalars);
}
template <typename LCC>
bool read_VTK(const char* filename, LCC& alcc)
{ return read_VTK<LCC, float, float>(filename, alcc, nullptr, nullptr); }
template <typename LCC, typename VertexScalarType>
bool read_VTK(const char* filename, LCC& alcc,
std::vector<VertexScalarType>* vertex_scalars)
{ return read_VTK<LCC, VertexScalarType, float>
(filename, alcc, vertex_scalars, nullptr); }
template <typename LCC, typename VolumeScalarType>
bool read_VTK(const char* filename, LCC& alcc,
std::nullptr_t,
std::vector<VolumeScalarType>* volume_scalars)
{ return read_VTK<LCC, float, VolumeScalarType>
(filename, alcc, nullptr, volume_scalars); }
////////////////////////////////////////////////////////////////////////////////////
template <typename LCC, typename PointFunctor, typename CellFunctor>
inline bool write_VTK_with_fct(const char* filename, const LCC& alcc,
PointFunctor pointfct, CellFunctor cellfct)
{
CGAL_assertion(filename!=nullptr);
std::ofstream file(filename);
if(!file.good())
{
std::cerr<<"[ERROR] write_VTK: cannot open file "<<filename<<std::endl;
return false;
}
std::size_t nbpts=0, nbcells=0;
bool res=internal::write_lcc_topo_to_vtk_ascii(file, alcc, nbpts, nbcells);
if(res)
{
if(pointfct)
{ internal::Write_point_data<PointFunctor>::
run(file, alcc, nbpts, pointfct); }
if(cellfct)
{ internal::Write_cell_data<CellFunctor>::
run(file, alcc, nbcells, cellfct); }
}
file.close();
return true;
}
////////////////////////////////////////////////////////////////////////////////////
template <typename LCC, typename VertexScalarType, typename VolumeScalarType>
bool write_VTK(const char* filename, const LCC& alcc,
const std::vector<VertexScalarType>* vertex_scalars,
const std::vector<VolumeScalarType>* volume_scalars)
{
std::function<VertexScalarType(const LCC&,
typename LCC::Dart_const_descriptor,
std::size_t i)> vertexfct;
std::function<VolumeScalarType(const LCC&,
typename LCC::Dart_const_descriptor,
std::size_t i)> cellfct;
if(vertex_scalars!=nullptr)
{
vertexfct=[&vertex_scalars](const LCC&, typename LCC::Dart_const_descriptor,
std::size_t i) -> VertexScalarType
{ return (*vertex_scalars)[i]; };
}
if(volume_scalars!=nullptr)
{
cellfct=[&volume_scalars](const LCC&, typename LCC::Dart_const_descriptor,
std::size_t i) -> VolumeScalarType
{ return (*volume_scalars)[i]; };
}
return write_VTK_with_fct(filename, alcc, vertexfct, cellfct);
}
template <typename LCC>
bool write_VTK(const char* filename, const LCC& alcc)
{
return write_VTK<LCC, float, float>(filename, alcc, nullptr, nullptr);
}
template <typename LCC, typename VertexScalarType>
bool write_VTK(const char* filename, const LCC& alcc,
const std::vector<VertexScalarType>* vertex_scalars)
{
return write_VTK<LCC, VertexScalarType, float>(filename, alcc, vertex_scalars,
nullptr);
}
template <typename LCC, typename VolumeScalarType>
bool write_VTK(const char* filename, const LCC& alcc,
std::nullptr_t,
const std::vector<VolumeScalarType>* volume_scalars)
{
return write_VTK<LCC, float, VolumeScalarType>(filename, alcc, nullptr,
volume_scalars);
}
////////////////////////////////////////////////////////////////////////////////////
} // namespace IO
} // namespace CGAL
#endif // CGAL_LCC_IO_VTK_H

View File

@ -213,7 +213,7 @@ namespace CGAL {
return *this;
}
/** Create a vertex attribute.
/** Creates a vertex attribute.
* @return a handle on the new attribute.
*/
template<typename ...Args>
@ -221,7 +221,7 @@ namespace CGAL {
{ return Base::template create_attribute<0>(args...); }
/**
* Create a new dart associated with a handle through an attribute.
* Creates a new dart associated with a handle through an attribute.
* @param ahandle the point handle to associated with the dart.
* @return a Dart_descriptor on the new dart.
*/
@ -232,7 +232,7 @@ namespace CGAL {
return res;
}
/** Create a new dart associated with a point.
/** Creates a new dart associated with a point.
* @param apoint the point to associated with the dart.
* @return a Dart_descriptor on the new dart.
*/
@ -307,7 +307,7 @@ namespace CGAL {
return point_of_vertex_attribute(this->template attribute<0>(adart));
}
/** Test if the lcc is valid.
/** Tests if the lcc is valid.
* A Linear_cell_complex is valid if it is a valid Combinatorial_map with
* an attribute associated to each dart.
* @return true iff the map is valid.
@ -550,7 +550,7 @@ namespace CGAL {
return res;
}
/** Create a segment given 2 points.
/** Creates a segment given 2 points.
* @param p0 the first point.
* @param p1 the second point.
* if closed==true, the edge has no 2-free dart.
@ -564,7 +564,7 @@ namespace CGAL {
closed);
}
/** Create a triangle given 3 points.
/** Creates a triangle given 3 points.
* @param p0 the first point.
* @param p1 the second point.
* @param p2 the third point.
@ -579,7 +579,7 @@ namespace CGAL {
create_vertex_attribute(p2));
}
/** Create a quadrangle given 4 points.
/** Creates a quadrangle given 4 points.
* @param p0 the first point.
* @param p1 the second point.
* @param p2 the third point.
@ -598,7 +598,7 @@ namespace CGAL {
}
/** Create a tetrahedron given 4 Vertex_attribute_descriptor.
/** Creates a tetrahedron given 4 Vertex_attribute_descriptor.
* @param h0 the first vertex handle.
* @param h1 the second vertex handle.
* @param h2 the third vertex handle.
@ -619,7 +619,7 @@ namespace CGAL {
return this->make_combinatorial_tetrahedron(d1, d2, d3, d4);
}
/** Create a tetrahedron given 4 points.
/** Creates a tetrahedron given 4 points.
* @param p0 the first point.
* @param p1 the second point.
* @param p2 the third point.
@ -638,7 +638,7 @@ namespace CGAL {
create_vertex_attribute(p3));
}
/** Create an hexahedron given 8 Vertex_attribute_descriptor.
/** Creates an hexahedron given 8 Vertex_attribute_descriptor.
* (8 vertices, 12 edges and 6 facets)
* \verbatim
* 4----7
@ -660,13 +660,13 @@ namespace CGAL {
* h0,h5 and to the facet (h0,h5,h6,h1).
*/
Dart_descriptor make_hexahedron(Vertex_attribute_descriptor h0,
Vertex_attribute_descriptor h1,
Vertex_attribute_descriptor h2,
Vertex_attribute_descriptor h3,
Vertex_attribute_descriptor h4,
Vertex_attribute_descriptor h5,
Vertex_attribute_descriptor h6,
Vertex_attribute_descriptor h7)
Vertex_attribute_descriptor h1,
Vertex_attribute_descriptor h2,
Vertex_attribute_descriptor h3,
Vertex_attribute_descriptor h4,
Vertex_attribute_descriptor h5,
Vertex_attribute_descriptor h6,
Vertex_attribute_descriptor h7)
{
Dart_descriptor d1 = make_quadrangle(h0, h5, h6, h1);
Dart_descriptor d2 = make_quadrangle(h1, h6, h7, h2);
@ -678,7 +678,7 @@ namespace CGAL {
return this->make_combinatorial_hexahedron(d1, d2, d3, d4, d5, d6);
}
/** Create an hexahedron given 8 points.
/** Creates an hexahedron given 8 points.
* \verbatim
* 4----7
* /| /|
@ -717,6 +717,133 @@ namespace CGAL {
create_vertex_attribute(p7));
}
/** Creates a prism given 6 Vertex_attribute_descriptor.
* (6 vertices, 9 edges and 5 facets)
* \verbatim
* 3---4
* |\ /|
* 0-5-1
* \|/
* 2
* \endverbatim
* @param h0 the first vertex handle.
* @param h1 the second vertex handle.
* @param h2 the third vertex handle.
* @param h3 the fourth vertex handle.
* @param h4 the fifth vertex handle.
* @param h5 the sixth vertex handle.
* @return the dart of the new prism incident to h0 and to
* the facet (h0,h1,h2).
*/
Dart_descriptor make_prism(Vertex_attribute_descriptor h0,
Vertex_attribute_descriptor h1,
Vertex_attribute_descriptor h2,
Vertex_attribute_descriptor h3,
Vertex_attribute_descriptor h4,
Vertex_attribute_descriptor h5)
{
Dart_descriptor d1=make_triangle(h0, h1, h2);
Dart_descriptor d2=make_quadrangle(h1, h0, h3, h4);
Dart_descriptor d3=make_quadrangle(h2, h1, h4, h5);
Dart_descriptor d4=make_quadrangle(h0, h2, h5, h3);
Dart_descriptor d5=make_triangle(h4, h3, h5);
return make_combinatorial_prism(d1, d2, d3, d4, d5);
}
/** Creates a prism given 6 points.
* \verbatim
* 3---4
* |\ /|
* 0-5-1
* \|/
* 2
* \endverbatim
* @param p0 the first point.
* @param p1 the second point.
* @param p2 the third point.
* @param p3 the fourth point.
* @param p4 the fifth point.
* @param p5 the sixth point.
* @return the dart of the new prism incident to p0 and to
* the facet (p0,p1,p2).
*/
Dart_descriptor make_prism(const Point& p0,
const Point& p1,
const Point& p2,
const Point& p3,
const Point& p4,
const Point& p5)
{
return make_prism(create_vertex_attribute(p0),
create_vertex_attribute(p1),
create_vertex_attribute(p2),
create_vertex_attribute(p3),
create_vertex_attribute(p4),
create_vertex_attribute(p5));
}
/** Creates a pyramid given 5 Vertex_attribute_descriptor.
* (5 vertices, 8 edges and 5 facets)
* \verbatim
* 4
* /|\
* 0-|-1
* | | |
* 3---2
* \endverbatim
* @param h0 the first vertex handle.
* @param h1 the second vertex handle.
* @param h2 the third vertex handle.
* @param h3 the fourth vertex handle.
* @param h4 the fifth vertex handle.
* @return the dart of the new pyramid incident to h0 and to
* the facet (h0,h1,h2,h3).
*/
Dart_descriptor make_pyramid(Vertex_attribute_descriptor h0,
Vertex_attribute_descriptor h1,
Vertex_attribute_descriptor h2,
Vertex_attribute_descriptor h3,
Vertex_attribute_descriptor h4)
{
Dart_descriptor d1=make_quadrangle(h0, h1, h2, h3);
Dart_descriptor d2=make_triangle(h1, h0, h4);
Dart_descriptor d3=make_triangle(h0, h3, h4);
Dart_descriptor d4=make_triangle(h3, h2, h4);
Dart_descriptor d5=make_triangle(h2, h1, h4);
return make_combinatorial_pyramid(d1, d2, d3, d4, d5);
}
/** Creates a pyramid given 5 points.
* \verbatim
* 4
* /|\
* 0-|-1
* | | |
* 3---2
* \endverbatim
* @param p0 the first point.
* @param p1 the second point.
* @param p2 the third point.
* @param p3 the fourth point.
* @param p4 the fifth point.
* @return the dart of the new pyramid incident to p0 and to
* the facet (p0,p1,p2,p3).
*/
Dart_descriptor make_pyramid(const Point& p0,
const Point& p1,
const Point& p2,
const Point& p3,
const Point& p4)
{
return make_pyramid(create_vertex_attribute(p0),
create_vertex_attribute(p1),
create_vertex_attribute(p2),
create_vertex_attribute(p3),
create_vertex_attribute(p4));
}
/** Compute the barycenter of a given cell.
* @param adart a dart incident to the cell.
* @param adim the dimension of the cell.

View File

@ -261,7 +261,7 @@ public:
prev_dart =lcc.null_descriptor;
}
void add_vertex_to_facet(size_type i)
void add_vertex_to_facet(size_type i, std::vector<DH>* tabdarts = nullptr)
{
CGAL_assertion(i<vertex_map.size());
// std::cout<<i<<" "<<std::flush;
@ -289,6 +289,7 @@ public:
{ first_dart=cur_dart; min_vertex=max_vertex=i; min_dart=cur_dart; }
prev_dart=cur_dart;
if(tabdarts != nullptr) { tabdarts->push_back(cur_dart); }
}
// End of the facet. Return the first dart of this facet.
@ -325,11 +326,12 @@ public:
return first_dart;
}
DH add_facet(std::initializer_list<size_type> l)
DH add_facet(std::initializer_list<size_type> l, std::vector<DH>* tabdarts = nullptr)
{
if(tabdarts != nullptr) { tabdarts->reserve(tabdarts->size() + l.size()); }
begin_facet();
for (size_type i:l)
{ add_vertex_to_facet(i); }
{ add_vertex_to_facet(i, tabdarts); }
return end_facet();
}
@ -404,5 +406,197 @@ private:
} //namespace CGAL
///////////////////////////////////////////////////////////////////////////////
/* Create an hexahedron, given the indices of its vertices (in the following
* order), the vertex must already have been added in the incremental builder.
* 3
* /|\
* 0-|-2
* \|/
* 1
*/
template<typename IncrementalBuilder>
typename IncrementalBuilder::LCC::Dart_descriptor
make_tetrahedron_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::vector<typename IncrementalBuilder::LCC::Dart_descriptor>*
tabdarts=nullptr)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2}, tabdarts);
ib.add_facet({i1,i0,i3}, tabdarts);
ib.add_facet({i2,i1,i3}, tabdarts);
ib.add_facet({i0,i2,i3}, tabdarts);
return ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
/* 4
* /|\
* 0-|-3
* | | |
* 1---2
*/
template<typename IncrementalBuilder>
typename IncrementalBuilder::LCC::Dart_descriptor
make_pyramid_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4,
std::vector<typename IncrementalBuilder::LCC::Dart_descriptor>*
tabdarts=nullptr)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2,i3}, tabdarts);
ib.add_facet({i1,i0,i4}, tabdarts);
ib.add_facet({i2,i1,i4}, tabdarts);
ib.add_facet({i3,i2,i4}, tabdarts);
ib.add_facet({i0,i3,i4}, tabdarts);
return ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
/* 3
* /|\
* 4---5
* | | |
* | 0 |
* |/ \|
* 1---2
*/
template<typename IncrementalBuilder>
typename IncrementalBuilder::LCC::Dart_descriptor
make_prism_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4,
std::size_t i5,
std::vector<typename IncrementalBuilder::LCC::Dart_descriptor>*
tabdarts=nullptr)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2}, tabdarts);
ib.add_facet({i1,i0,i3,i4}, tabdarts);
ib.add_facet({i2,i1,i4,i5}, tabdarts);
ib.add_facet({i0,i2,i5,i3}, tabdarts);
ib.add_facet({i5,i4,i3}, tabdarts);
return ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
/* 7----6
* /| /|
* 4----5 |
* | 3--|-2
* |/ |/
* 0----1
*/
template<typename IncrementalBuilder>
typename IncrementalBuilder::LCC::Dart_descriptor
make_hexahedron_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4,
std::size_t i5,
std::size_t i6,
std::size_t i7,
std::vector<typename IncrementalBuilder::LCC::Dart_descriptor>*
tabdarts=nullptr)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2,i3}, tabdarts);
ib.add_facet({i1,i0,i4,i5}, tabdarts);
ib.add_facet({i2,i1,i5,i6}, tabdarts);
ib.add_facet({i3,i2,i6,i7}, tabdarts);
ib.add_facet({i0,i3,i7,i4}, tabdarts);
ib.add_facet({i7,i6,i5,i4}, tabdarts);
return ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
template<typename IncrementalBuilder>
typename IncrementalBuilder::LCC::Dart_descriptor
make_pentagonal_prism_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4,
std::size_t i5,
std::size_t i6,
std::size_t i7,
std::size_t i8,
std::size_t i9,
std::vector<typename IncrementalBuilder::LCC::Dart_descriptor>*
tabdarts=nullptr)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2,i3,i4}, tabdarts);
ib.add_facet({i1,i0,i5,i6}, tabdarts);
ib.add_facet({i2,i1,i6,i7}, tabdarts);
ib.add_facet({i3,i2,i7,i8}, tabdarts);
ib.add_facet({i4,i3,i8,i9}, tabdarts);
ib.add_facet({i0,i4,i9,i5}, tabdarts);
ib.add_facet({i9,i8,i7,i6,i5}, tabdarts);
return ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
template<typename IncrementalBuilder>
typename IncrementalBuilder::LCC::Dart_descriptor
make_hexagonal_prism_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4,
std::size_t i5,
std::size_t i6,
std::size_t i7,
std::size_t i8,
std::size_t i9,
std::size_t i10,
std::size_t i11,
std::vector<typename IncrementalBuilder::LCC::Dart_descriptor>*
tabdarts=nullptr)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2,i3,i4,i5}, tabdarts);
ib.add_facet({i1,i0,i6,i7}, tabdarts);
ib.add_facet({i2,i1,i7,i8}, tabdarts);
ib.add_facet({i3,i2,i8,i9}, tabdarts);
ib.add_facet({i4,i3,i9,i10}, tabdarts);
ib.add_facet({i5,i4,i10,i11}, tabdarts);
ib.add_facet({i0,i5,i11,i6}, tabdarts);
ib.add_facet({i11,i10,i9,i8,i7,i6}, tabdarts);
return ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
template<typename IncrementalBuilder>
typename IncrementalBuilder::LCC::Dart_descriptor
make_generic_cell_with_builder(IncrementalBuilder& ib,
const std::vector<std::size_t>& faces,
std::vector<typename IncrementalBuilder::LCC::Dart_descriptor>*
tabdarts=nullptr)
{
ib.begin_surface();
std::size_t i=1, end; // Start to 1 because faces[0] is the number of faces
for(; i<faces.size(); )
{
end=i+1+faces[i]; // faces[i] is the number of vertices of the face; +i is the index of the end
++i; // I prefer to increment i after its use!
ib.begin_facet();
for(; i<end; ++i)
{ ib.add_vertex_to_facet(faces[i], tabdarts); }
ib.end_facet();
}
return ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
#endif // CGAL_LINEAR_CELL_COMPLEX_INCREMENTAL_BUILDER_3_H //
// EOF //

View File

@ -15,6 +15,7 @@ create_single_source_cgal_program(Linear_cell_complex_3_test.cpp ${hfiles})
create_single_source_cgal_program(Linear_cell_complex_4_test.cpp ${hfiles})
create_single_source_cgal_program(Linear_cell_complex_copy_test.cpp ${hfiles})
create_single_source_cgal_program(LCC_3_incremental_builder_test.cpp ${hfiles})
create_single_source_cgal_program(Linear_cell_complex_vtk_io_test.cpp ${hfiles})
# Same targets, defining USE_COMPACT_CONTAINER_WITH_INDEX to test index version
add_executable(Linear_cell_complex_2_test_index Linear_cell_complex_2_test.cpp ${hfiles})

View File

@ -5,104 +5,6 @@
#include "Linear_cell_complex_3_test.h"
///////////////////////////////////////////////////////////////////////////////
/* 3
* /|\
* 0-|-2
* \|/
* 1
*/
template<typename IncrementalBuilder>
void make_tetrahedron_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2});
ib.add_facet({i1,i0,i3});
ib.add_facet({i2,i1,i3});
ib.add_facet({i0,i2,i3});
ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
/* 4
* /|\
* 0-|-3
* | | |
* 1---2
*/
template<typename IncrementalBuilder>
void make_pyramid_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2,i3});
ib.add_facet({i1,i0,i4});
ib.add_facet({i2,i1,i4});
ib.add_facet({i3,i2,i4});
ib.add_facet({i0,i3,i4});
ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
/* 3
* /|\
* 4---5
* | | |
* | 0 |
* |/ \|
* 1---2
*/
template<typename IncrementalBuilder>
void make_prism_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4,
std::size_t i5)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2});
ib.add_facet({i1,i0,i3,i4});
ib.add_facet({i2,i1,i4,i5});
ib.add_facet({i0,i2,i5,i3});
ib.add_facet({i5,i4,i3});
ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
/* 7----6
* /| /|
* 4----5 |
* | 3--|-2
* |/ |/
* 0----1
*/
template<typename IncrementalBuilder>
void make_hexahedron_with_builder(IncrementalBuilder& ib,
std::size_t i0,
std::size_t i1,
std::size_t i2,
std::size_t i3,
std::size_t i4,
std::size_t i5,
std::size_t i6,
std::size_t i7)
{
ib.begin_surface();
ib.add_facet({i0,i1,i2,i3});
ib.add_facet({i1,i0,i4,i5});
ib.add_facet({i2,i1,i5,i6});
ib.add_facet({i3,i2,i6,i7});
ib.add_facet({i0,i3,i7,i4});
ib.add_facet({i7,i6,i5,i4});
ib.end_surface();
}
///////////////////////////////////////////////////////////////////////////////
template<typename LCC>
bool test_ib(const char* filename)

View File

@ -0,0 +1,202 @@
#include <CGAL/Linear_cell_complex_for_combinatorial_map.h>
#include <CGAL/Linear_cell_complex/IO/VTK.h>
#include <cassert>
#include <vector>
#include <cstdlib>
typedef CGAL::Linear_cell_complex_for_combinatorial_map<3, 3> LCC;
bool test_file(const char* filename)
{
LCC lcc1, lcc2;
std::vector<float> vertex_scalars1, vertex_scalars2;
std::vector<std::size_t> volume_scalars1, volume_scalars2;
bool res=CGAL::IO::read_VTK(filename, lcc1);
if(!res)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK in test_file"<<std::endl;
return false;
}
std::size_t nb_vertices=lcc1.number_of_vertex_attributes();
vertex_scalars1.resize(nb_vertices);
for(std::size_t i=0;i<nb_vertices;++i)
{ vertex_scalars1[i]=static_cast<float>(i); }
std::size_t nb_volumes=0;
for(auto itvol=lcc1.one_dart_per_cell<3>().begin(),
itvolend=lcc1.one_dart_per_cell<3>().end(); itvol!=itvolend; ++itvol)
{ ++nb_volumes; }
volume_scalars1.reserve(nb_volumes);
for(auto itvol=lcc1.one_dart_per_cell<3>().begin(),
itvolend=lcc1.one_dart_per_cell<3>().end(); itvol!=itvolend; ++itvol)
{
std::size_t nbv=lcc1.template one_dart_per_incident_cell<0,3>(itvol).size();
volume_scalars1.push_back(nbv);
}
res=CGAL::IO::write_VTK("output.vtk", lcc1,
&vertex_scalars1, &volume_scalars1);
if(!res)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error write_VTK in test_file"<<std::endl;
return false;
}
res=CGAL::IO::read_VTK("output.vtk", lcc2,
&vertex_scalars2, &volume_scalars2);
if(!res)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 2 in test_file"<<std::endl;
return false;
}
if(!lcc1.is_isomorphic_to(lcc2, false, true, true))
{
std::cout<<"LCC1: ";
lcc1.display_characteristics(std::cout)<<std::endl;
std::cout<<"LCC2: ";
lcc2.display_characteristics(std::cout)<<std::endl;
std::cerr<<"[ERROR] LCC_vtk_io_test error lcc1 and lcc2 are not isomorphic in test_file"<<std::endl;
res=false;
}
if(vertex_scalars1!=vertex_scalars2)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error vertex_scalars1 and vertex_scalars2 are different in test_file"<<std::endl;
res=false;
}
if(volume_scalars1!=volume_scalars2)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error volume_scalars1 and volume_scalars2 are different in test_file"<<std::endl;
res=false;
}
return res;
}
bool test_different_scalars()
{
bool res=true;
LCC lcc;
std::vector<float> vertex_scalars;
std::vector<std::size_t> volume_scalars;
/// Read the last file generated by test_file("data/beam-with-mixed-cells.vtk")
/// i.e. beam-with-mixed-cells.vtk with point and cells scalars.
if(!CGAL::IO::read_VTK("output.vtk", lcc,
&vertex_scalars, &volume_scalars) ||
vertex_scalars.size()!=719 || volume_scalars.size()!=615)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK in test_different_scalars"<<std::endl;
return false;
}
/// Test write with and without scalars
if(!CGAL::IO::write_VTK("output_vol.vtk", lcc, nullptr, &volume_scalars))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error write_VTK 1 in test_different_scalars"<<std::endl;
return false;
}
if(!CGAL::IO::write_VTK("output_vertex.vtk", lcc, &vertex_scalars))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error write_VTK 2 in test_different_scalars"<<std::endl;
return false;
}
if(!CGAL::IO::write_VTK("output_none.vtk", lcc))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error write_VTK 3 in test_different_scalars"<<std::endl;
return false;
}
/// test read with only some scalars
if(!CGAL::IO::read_VTK("output.vtk", lcc, &vertex_scalars) ||
vertex_scalars.size()!=719)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 2 in test_different_scalars"<<std::endl;
return false;
}
if(!CGAL::IO::read_VTK("output.vtk", lcc,
nullptr, &volume_scalars) ||
volume_scalars.size()!=615)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 3 in test_different_scalars"<<std::endl;
return false;
}
if(!CGAL::IO::read_VTK("output.vtk", lcc))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 4 in test_different_scalars"<<std::endl;
return false;
}
/// test read all scalars when they are not in the file
if(!CGAL::IO::read_VTK("output_vertex.vtk", lcc, &vertex_scalars, &volume_scalars) ||
vertex_scalars.size()!=719 || volume_scalars.size()!=0)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 5 in test_different_scalars"<<std::endl;
return false;
}
if(!CGAL::IO::read_VTK("output_vol.vtk", lcc, &vertex_scalars, &volume_scalars) ||
vertex_scalars.size()!=0 || volume_scalars.size()!=615)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 6 in test_different_scalars"<<std::endl;
return false;
}
if(!CGAL::IO::read_VTK("output_none.vtk", lcc, &vertex_scalars, &volume_scalars) ||
vertex_scalars.size()!=0 || volume_scalars.size()!=0)
{
std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 7 in test_different_scalars"<<std::endl;
return false;
}
return res;
}
int main()
{
bool res=true;
if(!test_file("data/2tetra.vtk"))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error for file data/2tetra.vtk"<<std::endl;
res=false;
}
if(!test_file("data/2hexa.vtk"))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error for file data/2hexa.vtk"<<std::endl;
res=false;
}
if(!test_file("data/2prism.vtk"))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error for file data/2prism.vtk"<<std::endl;
res=false;
}
if(!test_file("data/2pyramid.vtk"))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error for file data/2pyramid.vtk"<<std::endl;
res=false;
}
if(!test_file("data/2generic_cell.vtk"))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error for file data/2generic_cell.vtk"<<std::endl;
res=false;
}
if(!test_file("data/beam-with-mixed-cells.vtk"))
{
std::cerr<<"[ERROR] LCC_vtk_io_test error for file data/beam-with-mixed-cells.vtk"<<std::endl;
res=false;
}
if(!test_different_scalars())
{ res=false; }
if(!res) { return EXIT_FAILURE; }
std::cout<<"[OK] all tests in Linear_cell_complex_vtk_io_test.cpp"<<std::endl;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,35 @@
# vtk DataFile Version 2.0
3D Mesh
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 21 double
0.797233 -3.0657 2.80231
1.04552 -2.81344 1.77789
-0.00261142 -2.87459 1.50879
-0.2509 -3.12685 2.53322
0.682428 -3.76202 2.31634
0.806573 -3.63589 1.80413
0.282506 -3.66646 1.66958
0.158362 -3.79259 2.1818
0.567624 -4.45834 1.83037
1.48429 0.147175 1.04918
-0.357656 0.0397078 0.576288
-0.146018 -1.80958 0.172206
1.69593 -1.70211 0.645098
-0.66619 -0.27376 1.84928
-0.974724 -0.587227 3.12228
-0.454552 -2.12305 1.4452
-0.763086 -2.43652 2.7182
1.38739 -2.01558 1.91809
1.07886 -2.32905 3.19109
1.17576 -0.166292 2.32218
0.867223 -0.47976 3.59517
CELLS 2 115
62 13 3 8 4 5 3 4 8 7 4 5 4 0 1 3 8 5 6 3 7 8 6 4 4 7 3 0 4 1 0 18 17 4 5 1 2 6 4 7 6 2 3 4 0 3 16 18 4 17 18 16 15 4 1 17 15 2 4 3 2 15 16
51 10 4 9 19 13 10 4 19 9 12 17 4 13 19 20 14 4 10 13 15 11 4 9 10 11 12 4 17 12 11 15 4 19 17 18 20 4 14 20 18 16 4 13 14 16 15 4 17 15 16 18
CELL_TYPES 2
42
42

View File

@ -0,0 +1,26 @@
# vtk DataFile Version 2.0
3D Mesh
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 12 double
-1 -1 -1
-1 1 -1
-1 -1 1
-1 1 1
1 -1 -1
1 1 -1
1 -1 1
1 1 1
3 -1 1
3 -1 -1
3 1 1
3 1 -1
CELLS 2 18
8 0 1 3 2 4 5 7 6
8 5 7 6 4 11 10 8 9
CELL_TYPES 2
12
12

View File

@ -0,0 +1,30 @@
# vtk DataFile Version 2.0
3D Mesh
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 14 double
-1.78261 2.8477 -1.15226
-1.6885 2.94623 2.26566
0.921521 1.54537 2.23417
1.01511 -1.41435 2.31691
-1.59491 -0.0134989 2.3484
0.920989 -1.51287 -1.10101
-1.68903 -0.112022 -1.06953
0.827405 1.44685 -1.18375
0.921521 1.54537 2.23417
1.01511 -1.41435 2.31691
-1.59491 -0.0134989 2.3484
0.920989 -1.51287 -1.10101
-1.68903 -0.112022 -1.06953
0.827405 1.44685 -1.18375
CELLS 3 21
6 6 0 7 4 1 2
6 2 4 3 7 6 5
6 9 8 10 11 13 12
CELL_TYPES 3
13
13
13

View File

@ -0,0 +1,21 @@
# vtk DataFile Version 2.0
3D Mesh
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 7 double
-0.149372 -0.608056 -1.19224
-2.05784 -0.0940108 -3.6419
-0.607052 -1.32749 -4.22213
0.70406 0.167065 -4.12109
-0.746726 1.40055 -3.54086
-2.13885 -2.38807 -3.52093
-1.35014 -2.31961 -1.69441
CELLS 2 12
5 2 1 4 3 0
5 2 0 6 5 1
CELL_TYPES 2
14
14

View File

@ -0,0 +1,33 @@
# vtk DataFile Version 2.0
CGAL Linear_cell_complex
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 5 double
-3.38189 0.624914 -0.442232
-3.04657 -1.38801 -0.227267
-1.24112 -0.450255 -0.494661
-1.42311 -1.94845 0.895599
-2.49044 0.337128 1.70461
CELLS 2 10
4 1 0 4 2
4 1 2 4 3
CELL_TYPES 2
10
10
POINT_DATA 5
SCALARS point_scalars float 1
LOOKUP_TABLE default
0
1
2
3
4
CELL_DATA 2
SCALARS cell_scalars unsigned_long 1
LOOKUP_TABLE default
4
4

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -22,6 +22,7 @@ each specific format.
- \ref IOStreamMedit
- \ref IOStreamTetgen
- \ref IOStreamWKT
- \ref IOStreamVTKLCC
\section IOStreamOFF Object File Format (OFF)
@ -504,6 +505,30 @@ The following \cgal data structures can be exported into the `.VTU` file format:
- `CGAL::Mesh_complex_3_in_triangulation_3`, using \link CGAL::IO::output_to_vtu() `CGAL::IO::output_to_vtu()` \endlink
- `CGAL::Constrained_Delaunay_triangulation_2`, using the function \link CGAL::IO::write_VTU `CGAL::IO::write_VTU()` \endlink
\section IOStreamVTKLCC VTK Legacy File Format for Linear Cell Complex
The VTK legacy format, using file extension `.vtk`, is an \ascii format used to store 3D volumetric meshes.
This specific implementation supports Linear Cell Complex structures with various 3D cell types including
tetrahedra, hexahedra, prisms, pyramids, and generic polyhedra. Optional scalar data can be associated
with both vertices and volumes.
<table class="iotable">
<tr>
<th colspan="4">VTK Legacy File Format for Linear Cell Complex</th>
</tr>
<tr>
<td rowspan="1" width="75">Input</td>
<td rowspan="1" width="175">3D Volumetric Mesh</td>
<td width="250">`CGAL::Linear_cell_complex_for_combinatorial_map<3,3>`</td>
<td width="550"> \link PkgLinearCellComplexRefIOVTK `CGAL::IO::read_VTK()` \endlink</td>
</tr>
<tr>
<td rowspan="1">Output</td>
<td rowspan="1">3D Volumetric Mesh</td>
<td>`CGAL::Linear_cell_complex_for_combinatorial_map<3,3>`</td>
<td> \link PkgLinearCellComplexRefIOVTK `CGAL::IO::Write_VTK<LCC>()` \endlink</td>
</tr>
</table>
\section IOStreamAvizo Avizo File Format

View File

@ -3,6 +3,7 @@ Arrangement_on_surface_2
BGL
Constrained_triangulation_3
Kernel_23
Linear_cell_complex
Manual
Mesh_2
Mesh_3