mirror of https://github.com/CGAL/cgal
Merge remote-tracking branch 'cgal/master' into PMP-decimation
This commit is contained in:
commit
cb672d4d90
|
|
@ -0,0 +1,30 @@
|
|||
table {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 24px;
|
||||
border-spacing: 0;
|
||||
border-bottom: 2px solid black;
|
||||
border-top: 2px solid black;
|
||||
}
|
||||
table th {
|
||||
padding: 3px 10px;
|
||||
background-color: white;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
table td {
|
||||
padding: 3px 10px;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
table tr.odd {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
table tr.even {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
name: List workflow last run
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 10 * * 1"
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
jobs:
|
||||
list_workflow:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
messages: ${{ steps.cat_output.outputs.message }}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: run script
|
||||
run: |
|
||||
chmod +x ./Scripts/developer_scripts/list_cgal_workflows_last_run.sh
|
||||
./Scripts/developer_scripts/list_cgal_workflows_last_run.sh > output.md
|
||||
- name: convert markdown to html
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y pandoc
|
||||
pandoc -f markdown -t html --self-contained --css=.github/workflows/list_workflow_last_run.css -o output.html output.md
|
||||
- name: set_output
|
||||
id: cat_output
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "message<<${delimiter}" >> "${GITHUB_OUTPUT}"
|
||||
echo "Subject:List workflow run \nContent-Type: text/html; charset=\"UTF-8\"\n" >> "${GITHUB_OUTPUT}"
|
||||
echo "<html><body>" >> "${GITHUB_OUTPUT}"
|
||||
cat output.html >> "${GITHUB_OUTPUT}"
|
||||
echo "</body></html>" >> "${GITHUB_OUTPUT}"
|
||||
echo "${delimiter}" >> "${GITHUB_OUTPUT}"
|
||||
call_send_email:
|
||||
needs: list_workflow
|
||||
uses: ./.github/workflows/send_email.yml
|
||||
with:
|
||||
message: ${{needs.list_workflow.outputs.messages}}
|
||||
secrets:
|
||||
email: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_TO }}
|
||||
private_key: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_SSH_PRIVATE_KEY }}
|
||||
user: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_SSH_USER }}
|
||||
host: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_SSH_HOST }}
|
||||
|
|
@ -28,4 +28,4 @@ jobs:
|
|||
ssh-keyscan -H ${{ secrets.host }} > ~/.ssh/known_hosts
|
||||
- name: send email via ssh
|
||||
run: |
|
||||
echo "${{ inputs.message }}" | ssh ${{ secrets.user }}@${{ secrets.host }} "/sbin/sendmail -t ${{ secrets.email }}"
|
||||
echo -e '${{ inputs.message }}' | ssh ${{ secrets.user }}@${{ secrets.host }} "/sbin/sendmail -t ${{ secrets.email }}"
|
||||
|
|
|
|||
|
|
@ -85,18 +85,17 @@ public:
|
|||
typedef Arr_counting_traits_2<Base> Self;
|
||||
|
||||
/*! Construct default */
|
||||
Arr_counting_traits_2() : Base()
|
||||
template<typename ... Args>
|
||||
Arr_counting_traits_2(Args ... args) :
|
||||
Base(args...)
|
||||
{
|
||||
clear_counters();
|
||||
increment();
|
||||
}
|
||||
|
||||
/*! Construct copy */
|
||||
Arr_counting_traits_2(const Arr_counting_traits_2& other) : Base(other)
|
||||
{
|
||||
clear_counters();
|
||||
increment();
|
||||
}
|
||||
/*! Disable copy constructor.
|
||||
*/
|
||||
Arr_counting_traits_2(const Arr_counting_traits_2&) = delete;
|
||||
|
||||
/*! Obtain the counter of the given operation */
|
||||
size_t count(Operation_id id) const
|
||||
|
|
|
|||
|
|
@ -272,6 +272,21 @@ before_handle_event(Event* event)
|
|||
if (m_prev_minus_inf_x_event != nullptr)
|
||||
m_prev_minus_inf_x_event->set_halfedge_handle(m_lh->next());
|
||||
m_prev_minus_inf_x_event = event;
|
||||
|
||||
// If the event lies also on the top boundary, associate all curve indices
|
||||
// of subcurves that "see" m_th from below with the top fictitious halfedge
|
||||
// (m_th->next()).
|
||||
if (ps_y == ARR_TOP_BOUNDARY) {
|
||||
if (m_he_ind_map_p != nullptr) {
|
||||
Indices_list& list_ref = (*m_he_ind_map_p)[m_th];
|
||||
list_ref.clear();
|
||||
list_ref.splice(list_ref.end(), m_subcurves_at_ubf);
|
||||
}
|
||||
else {
|
||||
m_subcurves_at_ubf.clear();
|
||||
}
|
||||
CGAL_assertion(m_subcurves_at_ubf.empty());
|
||||
}
|
||||
return;
|
||||
|
||||
case ARR_RIGHT_BOUNDARY:
|
||||
|
|
|
|||
|
|
@ -162,13 +162,18 @@ private:
|
|||
{ return m_flags & (0x1 << COMPARE_X_NEAR_BOUNDARY_OP); }
|
||||
|
||||
public:
|
||||
/*! Default constructor */
|
||||
Arr_tracing_traits_2() :
|
||||
Base()
|
||||
/*! Construct default */
|
||||
template<typename ... Args>
|
||||
Arr_tracing_traits_2(Args ... args) :
|
||||
Base(args...)
|
||||
{
|
||||
enable_all_traces();
|
||||
}
|
||||
|
||||
/*! Disable copy constructor.
|
||||
*/
|
||||
Arr_tracing_traits_2(const Arr_tracing_traits_2&) = delete;
|
||||
|
||||
/*! Enable the trace of a traits operation
|
||||
* \param id the operation identifier
|
||||
*/
|
||||
|
|
@ -650,13 +655,13 @@ public:
|
|||
/*! A functor that tests whether two x-monotone curves can be merged. */
|
||||
class Are_mergeable_2 {
|
||||
private:
|
||||
typename Base::Are_mergeable_2 m_object;
|
||||
const Base& m_base_traits;
|
||||
bool m_enabled;
|
||||
|
||||
public:
|
||||
/*! Construct */
|
||||
Are_mergeable_2(const Base* base, bool enabled = true) :
|
||||
m_object(base->are_mergeable_2_object()), m_enabled(enabled) {}
|
||||
Are_mergeable_2(const Base& base, bool enabled = true) :
|
||||
m_base_traits(base), m_enabled(enabled) {}
|
||||
|
||||
/*! Operate
|
||||
* \param xcv1 the first curve
|
||||
|
|
@ -667,14 +672,32 @@ public:
|
|||
*/
|
||||
bool operator()(const X_monotone_curve_2& xcv1,
|
||||
const X_monotone_curve_2& xcv2) const
|
||||
{
|
||||
if (!m_enabled) return m_object(xcv1, xcv2);
|
||||
{ return are_mergable_2_impl<Base>(xcv1, xcv2, 0); }
|
||||
|
||||
private:
|
||||
/*! The base does not have Are_mergable_2
|
||||
*/
|
||||
template <typename T>
|
||||
bool are_mergable_2_impl(const X_monotone_curve_2& /* xcv1 */,
|
||||
const X_monotone_curve_2& /* xcv2 */, long) const {
|
||||
CGAL_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! The base does have Are_mergable_2
|
||||
*/
|
||||
template <typename T>
|
||||
auto are_mergable_2_impl(const X_monotone_curve_2& xcv1,
|
||||
const X_monotone_curve_2& xcv2, int) const ->
|
||||
decltype(m_base_traits.are_mergeable_2_object().operator()(xcv1, xcv2)) {
|
||||
auto are_mergeable = m_base_traits.are_mergeable_2_object();
|
||||
if (! m_enabled) return are_mergeable(xcv1, xcv2);
|
||||
std::cout << "are_mergeable" << std::endl
|
||||
<< " xcv1: " << xcv1 << std::endl
|
||||
<< " xcv2: " << xcv2 << std::endl;
|
||||
bool are_mergeable = m_object(xcv1, xcv2);
|
||||
std::cout << " result: " << are_mergeable << std::endl;
|
||||
return are_mergeable;
|
||||
bool mergeable = are_mergeable(xcv1, xcv2);
|
||||
std::cout << " result: " << mergeable << std::endl;
|
||||
return mergeable;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3387,7 +3387,7 @@ public:
|
|||
*/
|
||||
Comparison_result operator()(const Point_2& p1, const Point_2& p2) const
|
||||
{
|
||||
Base base(m_self);
|
||||
const Base& base = m_self;
|
||||
return base.compare_xy_2_object()(p1, p2);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -549,56 +549,56 @@ public:
|
|||
typedef typename Base::Face_const_handle Face_const_handle;
|
||||
|
||||
/*! Default constructor.*/
|
||||
Arr_extended_dcel_text_formatter() :
|
||||
Base()
|
||||
{}
|
||||
Arr_extended_dcel_text_formatter() : Base() {}
|
||||
|
||||
/*! Construct an output formatter. */
|
||||
Arr_extended_dcel_text_formatter(std::ostream& os) :
|
||||
Base(os)
|
||||
{}
|
||||
Arr_extended_dcel_text_formatter(std::ostream& os) : Base(os) {}
|
||||
|
||||
/*! Construct an input formatter. */
|
||||
Arr_extended_dcel_text_formatter(std::istream& is) :
|
||||
Base(is)
|
||||
{}
|
||||
Arr_extended_dcel_text_formatter(std::istream& is) : Base(is) {}
|
||||
|
||||
/*! Write the auxiliary data associated with the given vertex. */
|
||||
virtual void write_vertex_data(Vertex_const_handle v)
|
||||
{
|
||||
this->out() << '\n' << v->data();
|
||||
}
|
||||
{ this->out() << '\n' << v->data(); }
|
||||
|
||||
/*! Read a vertex-data object and attach it to the given vertex. */
|
||||
virtual void read_vertex_data(Vertex_handle v)
|
||||
{
|
||||
this->in() >> v->data();
|
||||
virtual void read_vertex_data(Vertex_handle v) {
|
||||
using Vertex = typename Arrangement_2::Vertex;
|
||||
using Type = decltype(std::declval<Vertex>().data());
|
||||
using Data_type = typename std::remove_reference<Type>::type;
|
||||
Data_type data;
|
||||
this->in() >> data;
|
||||
v->set_data(data);
|
||||
this->_skip_until_EOL();
|
||||
}
|
||||
|
||||
/*! Write the auxiliary data associated with the given halfedge. */
|
||||
virtual void write_halfedge_data(Halfedge_const_handle he)
|
||||
{
|
||||
this->out() << '\n' << he->data();
|
||||
}
|
||||
{ this->out() << '\n' << he->data(); }
|
||||
|
||||
/*! Read a halfedge-data object and attach it to the given halfedge. */
|
||||
virtual void read_halfedge_data(Halfedge_handle he)
|
||||
{
|
||||
this->in() >> he->data();
|
||||
virtual void read_halfedge_data(Halfedge_handle he) {
|
||||
using Halfedge = typename Arrangement_2::Halfedge;
|
||||
using Type = decltype(std::declval<Halfedge>().data());
|
||||
using Data_type = typename std::remove_reference<Type>::type;
|
||||
Data_type data;
|
||||
this->in() >> data;
|
||||
he->set_data(data);
|
||||
this->_skip_until_EOL();
|
||||
}
|
||||
|
||||
/*! Write the auxiliary data associated with the given face. */
|
||||
virtual void write_face_data(Face_const_handle f)
|
||||
{
|
||||
this->out() << f->data() << '\n';
|
||||
}
|
||||
{ this->out() << f->data() << '\n'; }
|
||||
|
||||
/*! Read a face-data object and attach it to the given face. */
|
||||
virtual void read_face_data(Face_handle f)
|
||||
{
|
||||
this->in() >> f->data();
|
||||
virtual void read_face_data(Face_handle f) {
|
||||
using Face = typename Arrangement_2::Face;
|
||||
using Type = decltype(std::declval<Face>().data());
|
||||
using Data_type = typename std::remove_reference<Type>::type;
|
||||
Data_type data;
|
||||
this->in() >> data;
|
||||
f->set_data(data);
|
||||
this->_skip_until_EOL();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -706,6 +706,7 @@ user might encounter.
|
|||
- `CGAL::Halfedge_around_target_circulator`
|
||||
- `CGAL::Halfedge_around_face_circulator`
|
||||
- `CGAL::Vertex_around_target_circulator`
|
||||
- `CGAL::Vertex_around_face_circulator`
|
||||
- `CGAL::Face_around_target_circulator`
|
||||
- `CGAL::Face_around_face_circulator`
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,13 @@ bool read_polygon_mesh(const std::string& fname,
|
|||
* \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{use_binary_mode}
|
||||
* \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)}
|
||||
* \cgalParamType{Boolean}
|
||||
* \cgalParamDefault{`true`}
|
||||
* \cgalParamExtra{This parameter is only meaningful for formats that support binary encoding.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{verbose}
|
||||
* \cgalParamDescription{whether extra information is printed when an incident occurs during reading}
|
||||
* \cgalParamType{Boolean}
|
||||
|
|
|
|||
|
|
@ -980,6 +980,12 @@ faces_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, co
|
|||
return make_range(I(h,g), I(h,g,1));
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgBGLIterators
|
||||
* A bidirectional circulator with value type `boost::graph_traits<Graph>::%vertex_descriptor` over all vertices incident to the same face or border.
|
||||
* \tparam Graph must be a model of the concept `HalfedgeGraph`
|
||||
* \cgalModels `BidirectionalIterator`
|
||||
*/
|
||||
template <typename Graph>
|
||||
class Vertex_around_face_circulator
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
|
|
|
|||
|
|
@ -1,17 +1 @@
|
|||
ETH Zurich (Switzerland).
|
||||
Min_quadrilateral_2
|
||||
Min_sphere_of_spheres_d
|
||||
Matrix_search
|
||||
Approximate_min_ellipsoid_d
|
||||
Min_ellipse_2
|
||||
Min_circle_2
|
||||
Min_sphere_d
|
||||
Min_annulus_d
|
||||
Min_quadrilateral_2
|
||||
Min_sphere_of_spheres_d
|
||||
Matrix_search
|
||||
Approximate_min_ellipsoid_d
|
||||
Min_ellipse_2
|
||||
Min_circle_2
|
||||
Min_sphere_d
|
||||
Min_annulus_d
|
||||
ETH Zurich (Switzerland).
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <boost/cstdint.hpp> // for uint32_t, etc.
|
||||
#include <cstdint> // for uint32_t, etc.
|
||||
|
||||
#ifdef CGAL_USE_ZLIB
|
||||
#include <zlib.h>
|
||||
|
|
@ -562,38 +562,50 @@ struct Word_type_generator<WK_FLOAT, sign, 8>
|
|||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 1>
|
||||
{
|
||||
// typedef boost::int8_t type;
|
||||
// typedef std::int8_t type;
|
||||
typedef char type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 1>
|
||||
{
|
||||
typedef boost::uint8_t type;
|
||||
typedef std::uint8_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 2>
|
||||
{
|
||||
typedef boost::int16_t type;
|
||||
typedef std::int16_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 2>
|
||||
{
|
||||
typedef boost::uint16_t type;
|
||||
typedef std::uint16_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 4>
|
||||
{
|
||||
typedef boost::int32_t type;
|
||||
typedef std::int32_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 4>
|
||||
{
|
||||
typedef boost::uint32_t type;
|
||||
typedef std::uint32_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 8>
|
||||
{
|
||||
typedef std::int64_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 8>
|
||||
{
|
||||
typedef std::uint64_t type;
|
||||
};
|
||||
|
||||
template <WORD_KIND wordKind, SIGN sign, std::size_t wdim>
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
GeometryFactory (France)
|
||||
|
|
@ -566,6 +566,15 @@ void test_split_attribute_functor_one_dart
|
|||
Attribute_descriptor_i a1 = amap.template attribute<i>(adart);
|
||||
if ( found_attributes.is_defined(a1) )
|
||||
{ // Here the attribute was already present in the hash_map
|
||||
|
||||
// We need to call reserve for the cc with index case. Indeed, if the vector
|
||||
// is reallocated, the reference returned by get_attribute<i>(a1) will be
|
||||
// invalidated, and the copy will be wrong. Note that there is no overhead
|
||||
// since the creation of the attribute need one allocation.
|
||||
amap.template attributes<i>().reserve(amap.template attributes<i>().size()+1);
|
||||
|
||||
// Now we are sure that the creation of a new attribute will not imply
|
||||
// a realloc.
|
||||
Attribute_descriptor_i a2 = amap.template
|
||||
create_attribute<i>(amap.template get_attribute<i>(a1));
|
||||
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ namespace CGAL {
|
|||
{ return cit; }
|
||||
bool is_used(size_type i) const
|
||||
{ return mmap.mdarts.is_used(i); }
|
||||
bool owns(size_type i) const
|
||||
{ return mmap.mdarts.owns(i); }
|
||||
private:
|
||||
Self & mmap;
|
||||
};
|
||||
|
|
@ -286,6 +288,13 @@ namespace CGAL {
|
|||
{
|
||||
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
|
||||
"copy_attribute<i> called but i-attributes are disabled.");
|
||||
// We need to do a reserve before the emplace in order to avoid a bug of
|
||||
// invalid reference when the container is reallocated.
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).reserve
|
||||
(std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).size()+1);
|
||||
|
||||
typename Attribute_descriptor<i>::type res=
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).emplace(get_attribute<i>(ah));
|
||||
|
|
|
|||
|
|
@ -752,6 +752,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool owns(size_type i) const
|
||||
{ return i<capacity() && is_used(i); }
|
||||
|
||||
bool owns_dereferenceable(const_iterator cit) const
|
||||
{ return cit!=end() && owns(cit); }
|
||||
|
||||
|
|
@ -764,7 +767,6 @@ public:
|
|||
void reserve(size_type n)
|
||||
{
|
||||
if(capacity_>=n) return;
|
||||
capacity_=n;
|
||||
increase_size();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
CNRS and LIRIS' Establishments (France)
|
||||
|
|
@ -24,6 +24,8 @@ target_compile_definitions(Combinatorial_map_copy_test_index PUBLIC USE_COMPACT_
|
|||
target_link_libraries(Combinatorial_map_copy_test_index PUBLIC CGAL CGAL::Data)
|
||||
cgal_add_compilation_test(Combinatorial_map_copy_test_index)
|
||||
|
||||
create_single_source_cgal_program(cmap_test_split_attribute.cpp)
|
||||
|
||||
# Link with OpenMesh if possible
|
||||
find_package(OpenMesh QUIET)
|
||||
if(TARGET OpenMesh::OpenMesh)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
#include <CGAL/Combinatorial_map.h>
|
||||
#include <CGAL/Cell_attribute.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
struct MyInfo
|
||||
{
|
||||
MyInfo() :data(1)
|
||||
{}
|
||||
|
||||
MyInfo(int i) :data(i)
|
||||
{}
|
||||
|
||||
int data;
|
||||
};
|
||||
|
||||
struct Myitem1
|
||||
{
|
||||
using Use_index=CGAL::Tag_true; // use indices
|
||||
using Index_type=std::uint16_t; // 16 bits
|
||||
template<class CMap>
|
||||
struct Dart_wrapper
|
||||
{
|
||||
typedef CGAL::Cell_attribute<CMap, MyInfo> attrib;
|
||||
typedef std::tuple<void, void, attrib> Attributes;
|
||||
};
|
||||
};
|
||||
|
||||
struct Myitem2
|
||||
{
|
||||
template<class CMap>
|
||||
struct Dart_wrapper
|
||||
{
|
||||
typedef CGAL::Cell_attribute<CMap, MyInfo> attrib;
|
||||
typedef std::tuple<void, void, attrib> Attributes;
|
||||
};
|
||||
};
|
||||
|
||||
using CMap1=CGAL::Combinatorial_map<3,Myitem1>;
|
||||
using CMap2=CGAL::Combinatorial_map<3,Myitem2>;
|
||||
|
||||
#define NB 1000
|
||||
template<typename CMap>
|
||||
bool test(const std::string& s)
|
||||
{
|
||||
bool res=true;
|
||||
CMap m;
|
||||
// 1) create a face and one attribute.
|
||||
typename CMap::Dart_descriptor dd=m.make_combinatorial_polygon(4);
|
||||
m.template set_attribute<2>(dd, m.template create_attribute<2>(2));
|
||||
// 2) Split this face NB times => will create new 2-attributes for new faces
|
||||
for(std::size_t i=0; i<NB; ++i)
|
||||
{
|
||||
typename CMap::Dart_descriptor
|
||||
newd=m.insert_cell_1_in_cell_2(dd, m.next(m.next(dd)));
|
||||
if(m.template attribute<2>(newd)==CMap::null_descriptor)
|
||||
{
|
||||
std::cout<<"ERROR1: "<<s<<": "
|
||||
<<"attribute<2>(newd)==CMap::null_descriptor"<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
else if(m.template info<2>(newd).data!=2)
|
||||
{
|
||||
std::cout<<"ERROR2: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
|
||||
newd=m.template opposite<2>(newd);
|
||||
if(m.template attribute<2>(newd)==CMap::null_descriptor)
|
||||
{
|
||||
std::cout<<"ERROR3: "<<s<<": "
|
||||
<<"attribute<2>(newd)==CMap::null_descriptor"<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
else if(m.template info<2>(newd).data!=2)
|
||||
{
|
||||
std::cout<<"ERROR4: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if(!test<CMap1>("CMap1") || !test<CMap2>("CMap2"))
|
||||
{ return EXIT_FAILURE; }
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -3270,6 +3270,14 @@ pages = "207--221"
|
|||
year={1998}
|
||||
}
|
||||
|
||||
|
||||
@techreport{cgal:hssz-gmcabonbc-97,
|
||||
title={A generalized marching cubes algorithm based on non-binary classifications},
|
||||
author={H-C. Hege and M. Seebass and D. Stalling and M. Zöckler},
|
||||
number={SC 97-05},
|
||||
year={1997}
|
||||
}
|
||||
|
||||
% ----------------------------------------------------------------------------
|
||||
% END OF BIBFILE
|
||||
% ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -293,6 +293,13 @@ void GMap_test_split_attribute_functor_one_dart
|
|||
Attribute_descriptor_i a1 = amap.template attribute<i>(adart);
|
||||
if ( found_attributes.is_defined(a1) )
|
||||
{ // Here the attribute was already present in the hash_map
|
||||
|
||||
// We need to call reserve for the cc with index case. Indeed, if the vector
|
||||
// is reallocated, the reference returned by get_attribute<i>(a1) will be
|
||||
// invalidated, and the copy will be wrong. Note that there is no overhead
|
||||
// since the creation of the attribute need one allocation.
|
||||
amap.template attributes<i>().reserve(amap.template attributes<i>().size()+1);
|
||||
|
||||
Attribute_descriptor_i a2 = amap.template
|
||||
create_attribute<i>(amap.template get_attribute<i>(a1));
|
||||
|
||||
|
|
|
|||
|
|
@ -242,6 +242,13 @@ namespace CGAL {
|
|||
{
|
||||
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
|
||||
"copy_attribute<i> called but i-attributes are disabled.");
|
||||
// We need to do a reserve before the emplace in order to avoid a bug of
|
||||
// invalid reference when the container is reallocated.
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).reserve
|
||||
(std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).size()+1);
|
||||
|
||||
typename Attribute_descriptor<i>::type res=
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).emplace(get_attribute<i>(ah));
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
CNRS and LIRIS' Establishments (France)
|
||||
|
|
@ -18,3 +18,5 @@ add_executable(Generalized_map_test_index Generalized_map_test.cpp ${hfiles})
|
|||
target_compile_definitions(Generalized_map_test_index PUBLIC USE_COMPACT_CONTAINER_WITH_INDEX)
|
||||
target_link_libraries(Generalized_map_test_index PUBLIC CGAL CGAL::Data)
|
||||
cgal_add_compilation_test(Generalized_map_test_index)
|
||||
|
||||
create_single_source_cgal_program("gmap_test_split_attribute.cpp")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
#include <CGAL/Generalized_map.h>
|
||||
#include <CGAL/Cell_attribute.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
struct MyInfo
|
||||
{
|
||||
MyInfo() :data(1)
|
||||
{}
|
||||
|
||||
MyInfo(int i) :data(i)
|
||||
{}
|
||||
|
||||
int data;
|
||||
};
|
||||
|
||||
struct Myitem1
|
||||
{
|
||||
using Use_index=CGAL::Tag_true; // use indices
|
||||
using Index_type=std::uint16_t; // 16 bits
|
||||
template<class GMap>
|
||||
struct Dart_wrapper
|
||||
{
|
||||
typedef CGAL::Cell_attribute<GMap, MyInfo> attrib;
|
||||
typedef std::tuple<void, void, attrib> Attributes;
|
||||
};
|
||||
};
|
||||
|
||||
struct Myitem2
|
||||
{
|
||||
template<class GMap>
|
||||
struct Dart_wrapper
|
||||
{
|
||||
typedef CGAL::Cell_attribute<GMap, MyInfo> attrib;
|
||||
typedef std::tuple<void, void, attrib> Attributes;
|
||||
};
|
||||
};
|
||||
|
||||
using GMap1=CGAL::Generalized_map<3,Myitem1>;
|
||||
using GMap2=CGAL::Generalized_map<3,Myitem2>;
|
||||
|
||||
#define NB 1000
|
||||
template<typename GMap>
|
||||
bool test(const std::string& s)
|
||||
{
|
||||
bool res=true;
|
||||
GMap m;
|
||||
// 1) create a face and one attribute.
|
||||
typename GMap::Dart_descriptor dd=m.make_combinatorial_polygon(4);
|
||||
m.template set_attribute<2>(dd, m.template create_attribute<2>(2));
|
||||
// 2) Split this face NB times => will create new 2-attributes for new faces
|
||||
for(std::size_t i=0; i<NB; ++i)
|
||||
{
|
||||
typename GMap::Dart_descriptor
|
||||
newd=m.insert_cell_1_in_cell_2(dd, m.template alpha<0,1,0>(dd));
|
||||
if(m.template attribute<2>(newd)==GMap::null_descriptor)
|
||||
{
|
||||
std::cout<<"ERROR1: "<<s<<": "
|
||||
<<"attribute<2>(newd)==GMap::null_descriptor"<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
else if(m.template info<2>(newd).data!=2)
|
||||
{
|
||||
std::cout<<"ERROR2: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
|
||||
newd=m.template opposite<2>(newd);
|
||||
if(m.template attribute<2>(newd)==GMap::null_descriptor)
|
||||
{
|
||||
std::cout<<"ERROR3: "<<s<<": "
|
||||
<<"attribute<2>(newd)==GMap::null_descriptor"<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
else if(m.template info<2>(newd).data!=2)
|
||||
{
|
||||
std::cout<<"ERROR4: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
|
||||
res=false;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if(!test<GMap1>("GMap1") || !test<GMap2>("GMap2"))
|
||||
{ return EXIT_FAILURE; }
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -189,8 +189,12 @@ void test_point_generators_d()
|
|||
if (points[i][0] >0)
|
||||
g = g + (points[i] - o3);
|
||||
}
|
||||
assert( std::fabs( g[0]/nb_g - 3.0/16.0) < 0.01 );
|
||||
std::cout<<" center of mass 3/16~="<<g[0]/nb_g<<" checked"<<std::endl;
|
||||
if( std::fabs( g[0]/nb_g - 3.0/16.0) < 0.01 ){
|
||||
std::cout<<" center of mass 3/16~="<<g[0]/nb_g<<" checked"<<std::endl;
|
||||
}else{
|
||||
std::cout << "See Law of large numbers" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
// 100 random points in dim 26
|
||||
|
|
|
|||
|
|
@ -43,10 +43,19 @@ CGAL tetrahedral Delaunay refinement algorithm.
|
|||
- Added the functions `CGAL::Polygon_mesh_processing::remesh_planar_patches()` and
|
||||
`CGAL::Polygon_mesh_processing::remesh_almost_coplanar_patches()` to retriangulate patches of coplanar faces in a mesh.
|
||||
|
||||
- Added a named parameter to `CGAL::Polygon_mesh_processing::smooth_shape()` to disable scaling to compensate volume loss.
|
||||
|
||||
### [3D Simplicial Mesh Data Structure](https://doc.cgal.org/5.6/Manual/packages.html#PkgSMDS3) (new package)
|
||||
|
||||
- This new package wraps all the existing code that deals with a `MeshComplex_3InTriangulation_3` to describe 3D simplicial meshes, and makes the data structure independent from the tetrahedral mesh generation package.
|
||||
|
||||
### [Tetrahedral Mesh Generation](https://doc.cgal.org/5.6/Manual/packages.html#PkgMesh3)
|
||||
|
||||
- Added two new named parameters to the named constructor `CGAL::create_labeled_image_mesh_domain()`
|
||||
for automatic detection and protection
|
||||
of 1D-curves that lie at the intersection of three or more subdomains,
|
||||
extracted from labeled images.
|
||||
|
||||
### [Shape Detection](https://doc.cgal.org/5.6/Manual/packages.html#PkgShapeDetection) (breaking change, major changes)
|
||||
|
||||
- **Breaking change**: The region growing part of the package have been reworked to fix design issues introduced with the handling `FaceGraph` models.
|
||||
|
|
@ -68,6 +77,7 @@ CGAL tetrahedral Delaunay refinement algorithm.
|
|||
and cylinders in 3D.
|
||||
|
||||
### [2D Arrangements](https://doc.cgal.org/5.6/Manual/packages.html#PkgArrangementOnSurface2)
|
||||
|
||||
- Fixed some code that handles geodesic-curves on spheres that compare x- and y-coordinates on the boundary of the parameter space. It mainly effected the naive point-location.
|
||||
|
||||
### [2D Convex Hulls](https://doc.cgal.org/5.6/Manual/packages.html#PkgConvexHull2)
|
||||
|
|
|
|||
|
|
@ -22,4 +22,4 @@ else()
|
|||
${CMAKE_BINARY_DIR}/icons/Triangulation_2.qrc)
|
||||
endif()
|
||||
|
||||
qt5_wrap_ui(_CGAL_Qt5_UI_FILES ${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/resources/ImageInterface.ui)
|
||||
qt5_wrap_ui(_CGAL_Qt5_UI_FILES ${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/ImageInterface.ui)
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ namespace CGAL {
|
|||
{ return cit; }
|
||||
bool is_used(size_type i) const
|
||||
{ return mmap.mdarts.is_used(i); }
|
||||
bool owns(size_type i) const
|
||||
{ return mmap.mdarts.owns(i); }
|
||||
private:
|
||||
Self & mmap;
|
||||
};
|
||||
|
|
@ -307,6 +309,13 @@ namespace CGAL {
|
|||
{
|
||||
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
|
||||
"copy_attribute<i> called but i-attributes are disabled.");
|
||||
// We need to do a reserve before the emplace in order to avoid a bug of
|
||||
// invalid reference when the container is reallocated.
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).reserve
|
||||
(std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).size()+1);
|
||||
|
||||
typename Attribute_descriptor<i>::type res=
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).emplace(get_attribute<i>(ah));
|
||||
|
|
|
|||
|
|
@ -261,6 +261,13 @@ namespace CGAL {
|
|||
{
|
||||
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
|
||||
"copy_attribute<i> called but i-attributes are disabled.");
|
||||
// We need to do a reserve before the emplace in order to avoid a bug of
|
||||
// invalid reference when the container is reallocated.
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).reserve
|
||||
(std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).size()+1);
|
||||
|
||||
typename Attribute_descriptor<i>::type res=
|
||||
std::get<Helper::template Dimension_index<i>::value>
|
||||
(mattribute_containers).emplace(get_attribute<i>(ah));
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
CNRS and LIRIS' Establishments (France)
|
||||
|
|
@ -32,7 +32,7 @@ TD.error {background-color: rgb(100%,50%,50%)}
|
|||
TD.na {background-color: white;}
|
||||
TD.requirements { background-color: rgb(65%,65%,100%) }
|
||||
|
||||
TD.ok {background-color: rgb(44%,88%,44%)}
|
||||
TH.ok {background-color: rgb(44%,88%,44%)}
|
||||
TH.warning {background-color: rgb(100%,100%,50%)}
|
||||
TH.third_party_warning {background-color: rgb(75%,100%,50%)}
|
||||
TH.error {background-color: rgb(100%,50%,50%)}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ INPUT += \
|
|||
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_facet_topology.h \
|
||||
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_vertex_base_3.h \
|
||||
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_cell_base_3.h \
|
||||
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Compact_mesh_cell_base_3.h
|
||||
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Compact_mesh_cell_base_3.h \
|
||||
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_in_image.h \
|
||||
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_on_image_bbox.h
|
||||
|
||||
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Mesh Generation"
|
||||
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg \
|
||||
|
|
|
|||
|
|
@ -735,7 +735,6 @@ Surface of the output mesh generated with a very small `facet_distance`
|
|||
without the weights (left, 25563 vertices) and with the weights (right, 19936 vertices).
|
||||
\cgalFigureEnd
|
||||
|
||||
|
||||
\subsubsection Mesh_3DomainsFrom3DImagesWithCustomInitialization Domains From 3D Images, with a Custom Initialization
|
||||
|
||||
The example \ref Mesh_3/mesh_3D_image_with_custom_initialization.cpp is a modification
|
||||
|
|
@ -926,23 +925,27 @@ The first modification is the type of the mesh domain. Instead of being
|
|||
|
||||
\snippet Mesh_3/mesh_3D_image_with_features.cpp Domain definition
|
||||
|
||||
Then, in the function `%main()`, after the `%domain` object has been created,
|
||||
a dedicated function computes the 1D-features, and adds them to the domain.
|
||||
In the %main() function, the domain is created with an additional argument - a
|
||||
dedicated functor that computes the one-dimensional features, which are then
|
||||
added to the domain.
|
||||
|
||||
\snippet Mesh_3/mesh_3D_image_with_features.cpp Call add_1D_features
|
||||
\snippet Mesh_3/mesh_3D_image_with_detection_of_features.cpp Domain creation
|
||||
|
||||
The function template `%add_1D_features()` is defined in the example
|
||||
file. It uses non-documented code from \cgal, that should be copy-pasted in
|
||||
any user-code willing to use similar code. It uses the undocumented
|
||||
function template `%CGAL::polylines_to_protect` that computes the
|
||||
1D-features that correspond to the intersection of the bounding box of the
|
||||
image with the surfaces defined by the image. At the same time, a few other
|
||||
polylines are added as 1D-features, to protect 1D curves in the interior of
|
||||
the image. Then, the method
|
||||
`CGAL::Mesh_domain_with_polyline_features_3::add_features` is called twice
|
||||
to add the computed 1D-features to the mesh domain.
|
||||
The `CGAL::Mesh_3::Detect_features_in_image` functor is defined in its own
|
||||
header file. It computes the one-dimensional features that correspond to the
|
||||
intersections of the bounding box of the image with the surfaces defined by the
|
||||
image, as well as polylines that lie at the intersection of three or more
|
||||
subdomains (including the outside). It then constructs a graph of these polyline
|
||||
features. The named constructor adds this feature graph to the domain for later
|
||||
feature protection. The original feature detection algorithm was described in
|
||||
\cgalCite{cgal:hssz-gmcabonbc-97}, which provides a list of possible voxel
|
||||
configurations. The feature detection implemented in \cgal generalizes this
|
||||
description.
|
||||
|
||||
\snippet Mesh_3/mesh_3D_image_with_features.cpp Add 1D features
|
||||
The example \ref Mesh_3/mesh_3D_image_with_features.cpp shows how
|
||||
user-specified input polylines can further be added as 1D features to the mesh domain.
|
||||
|
||||
\snippet Mesh_3/mesh_3D_image_with_features.cpp Domain creation
|
||||
|
||||
In the meshing criteria, if 1D features are added to the domain, the user
|
||||
can define the parameter `edge_size` of the criteria class
|
||||
|
|
@ -970,7 +973,7 @@ protection of the 1D-features.
|
|||
Left: the mesh without any call to `%add_features()`.
|
||||
|
||||
Middle: the mesh with only the 1D-features computed by
|
||||
`%CGAL::polylines_to_protect()`.
|
||||
`CGAL::Mesh_3::Detect_features_on_image_bbox()`.
|
||||
|
||||
Right: the mesh with added 1D-features in the interior of the bounding box
|
||||
of the image.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
/// \ingroup PkgMesh3Ref
|
||||
/// The classes in this group are models of domain concepts and their associated classes.
|
||||
|
||||
/// \defgroup PkgMesh3FeatureDetection Feature Detection
|
||||
/// \ingroup PkgMesh3Ref
|
||||
/// The functors in this group perform polyline features detection in input domains.
|
||||
|
||||
/// \defgroup PkgMesh3Functions Mesh Generation Functions
|
||||
/// \ingroup PkgMesh3Ref
|
||||
/// The two main functions to generate a mesh are `make_mesh_3()` and `refine_mesh_3()`.
|
||||
|
|
@ -103,6 +107,11 @@ and their associated classes:
|
|||
- `CGAL::Labeled_image_mesh_domain_3<Image,BGT>` (deprecated)
|
||||
- `CGAL::Gray_image_mesh_domain_3<Image,BGT,Image_word_type>` (deprecated)
|
||||
|
||||
The following functors are available for feature detection:
|
||||
|
||||
- `CGAL::Mesh_3::Detect_features_in_image`
|
||||
- `CGAL::Mesh_3::Detect_features_on_image_bbox`
|
||||
|
||||
\cgalCRPSection{Function Templates}
|
||||
|
||||
- `CGAL::make_mesh_3()`
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
\example Mesh_3/mesh_3D_gray_image_with_custom_initialization.cpp
|
||||
\example Mesh_3/mesh_3D_image_with_features.cpp
|
||||
\example Mesh_3/mesh_3D_image_with_custom_initialization.cpp
|
||||
\example Mesh_3/mesh_3D_image_with_detection_of_features.cpp
|
||||
\example Mesh_3/mesh_3D_image_with_input_features.cpp
|
||||
\example Mesh_3/mesh_3D_weighted_image.cpp
|
||||
\example Mesh_3/random_labeled_image.h
|
||||
\example CGAL/Mesh_3/initialize_triangulation_from_gray_image.h
|
||||
|
|
|
|||
|
|
@ -133,6 +133,12 @@ if(TARGET CGAL::CGAL_ImageIO)
|
|||
create_single_source_cgal_program("mesh_3D_image_with_features.cpp")
|
||||
target_link_libraries(mesh_3D_image_with_features PUBLIC CGAL::Eigen3_support)
|
||||
|
||||
create_single_source_cgal_program("mesh_3D_image_with_input_features.cpp")
|
||||
target_link_libraries(mesh_3D_image_with_input_features PUBLIC CGAL::Eigen3_support)
|
||||
|
||||
create_single_source_cgal_program("mesh_3D_image_with_detection_of_features.cpp")
|
||||
target_link_libraries(mesh_3D_image_with_detection_of_features PUBLIC CGAL::Eigen3_support)
|
||||
|
||||
if(CGAL_ImageIO_USE_ZLIB)
|
||||
create_single_source_cgal_program("mesh_optimization_example.cpp")
|
||||
target_link_libraries(mesh_optimization_example PUBLIC CGAL::Eigen3_support)
|
||||
|
|
@ -185,6 +191,8 @@ if(CGAL_ACTIVATE_CONCURRENT_MESH_3 AND TARGET CGAL::TBB_support)
|
|||
mesh_3D_image_with_custom_initialization
|
||||
mesh_3D_gray_image_with_custom_initialization
|
||||
mesh_3D_image_with_features
|
||||
mesh_3D_image_with_detection_of_features
|
||||
mesh_3D_image_with_input_features
|
||||
mesh_implicit_domains
|
||||
mesh_implicit_sphere
|
||||
mesh_implicit_sphere_variable_size
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
#define CGAL_MESH_3_VERBOSE
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Mesh_triangulation_3.h>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <CGAL/Mesh_triangulation_3.h>
|
||||
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
|
||||
#include <CGAL/Mesh_criteria_3.h>
|
||||
|
||||
#include <CGAL/make_mesh_3.h>
|
||||
#include <CGAL/Image_3.h>
|
||||
|
||||
/// [Domain definition]
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
|
||||
#include <CGAL/Labeled_mesh_domain_3.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Labeled_mesh_domain_3<K> Image_domain;
|
||||
typedef CGAL::Mesh_domain_with_polyline_features_3<Image_domain> Mesh_domain;
|
||||
/// [Domain definition]
|
||||
|
||||
#include <CGAL/Mesh_3/Detect_features_in_image.h>
|
||||
|
||||
#ifdef CGAL_CONCURRENT_MESH_3
|
||||
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||
#else
|
||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||
#endif
|
||||
|
||||
// Triangulation
|
||||
typedef CGAL::Mesh_triangulation_3<Mesh_domain,CGAL::Default,Concurrency_tag>::type Tr;
|
||||
|
||||
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
|
||||
|
||||
// Criteria
|
||||
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
|
||||
|
||||
// To avoid verbose function and named parameters call
|
||||
namespace params = CGAL::parameters;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const std::string fname = (argc>1)?argv[1]:CGAL::data_file_path("images/420.inr");
|
||||
|
||||
/// [Loads image]
|
||||
CGAL::Image_3 image;
|
||||
if(!image.read(fname)){
|
||||
std::cerr << "Error: Cannot read file " << fname << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/// [Loads image]
|
||||
|
||||
/// [Domain creation]
|
||||
Mesh_domain domain
|
||||
= Mesh_domain::create_labeled_image_mesh_domain(image,
|
||||
params::features_detector = CGAL::Mesh_3::Detect_features_in_image());
|
||||
/// [Domain creation]
|
||||
|
||||
CGAL::Bbox_3 bbox = domain.bbox();
|
||||
double diag = CGAL::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) +
|
||||
CGAL::square(bbox.ymax() - bbox.ymin()) +
|
||||
CGAL::square(bbox.zmax() - bbox.zmin()));
|
||||
double sizing_default = diag * 0.05;
|
||||
|
||||
/// [Mesh criteria]
|
||||
/// Note that `edge_size` is needed with 1D-features
|
||||
Mesh_criteria criteria(params::edge_size = sizing_default,
|
||||
params::facet_angle = 30,
|
||||
params::facet_size = sizing_default,
|
||||
params::facet_distance = sizing_default / 10,
|
||||
params::facet_topology = CGAL::FACET_VERTICES_ON_SAME_SURFACE_PATCH,
|
||||
params::cell_radius_edge_ratio = 0,
|
||||
params::cell_size = 0
|
||||
);
|
||||
/// [Mesh criteria]
|
||||
|
||||
/// [Meshing]
|
||||
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria,
|
||||
params::no_exude(),
|
||||
params::no_perturb());
|
||||
/// [Meshing]
|
||||
|
||||
// Output
|
||||
CGAL::dump_c3t3(c3t3, "out");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ typedef CGAL::Labeled_mesh_domain_3<K> Image_domain;
|
|||
typedef CGAL::Mesh_domain_with_polyline_features_3<Image_domain> Mesh_domain;
|
||||
/// [Domain definition]
|
||||
|
||||
#include <CGAL/Mesh_3/Detect_features_on_image_bbox.h>
|
||||
|
||||
#ifdef CGAL_CONCURRENT_MESH_3
|
||||
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||
#else
|
||||
|
|
@ -34,40 +36,8 @@ typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
|
|||
|
||||
namespace params = CGAL::parameters;
|
||||
|
||||
/// [Add 1D features]
|
||||
// Read input features
|
||||
#include "read_polylines.h"
|
||||
#include <CGAL/Mesh_3/polylines_to_protect.h> // undocumented header
|
||||
|
||||
// Protect the intersection of the object with the box of the image,
|
||||
// by declaring 1D-features. Note that `CGAL::polylines_to_protect` is
|
||||
// not documented.
|
||||
bool add_1D_features(const CGAL::Image_3& image,
|
||||
Mesh_domain& domain,
|
||||
const std::string lines_fname)
|
||||
{
|
||||
typedef K::Point_3 Point_3;
|
||||
typedef unsigned char Word_type;
|
||||
|
||||
std::vector<std::vector<Point_3> > features_inside;
|
||||
if(!read_polylines(lines_fname, features_inside)) // see file "read_polylines.h"
|
||||
{
|
||||
std::cerr << "Error: Cannot read file " << lines_fname << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::vector<Point_3> > polylines_on_bbox;
|
||||
CGAL::polylines_to_protect<Point_3, Word_type>(image, polylines_on_bbox,
|
||||
features_inside.begin(),
|
||||
features_inside.end());
|
||||
|
||||
domain.add_features(polylines_on_bbox.begin(), polylines_on_bbox.end());
|
||||
|
||||
// It is very important that the polylines from the file `lines_fname`
|
||||
// contain only polylines in the inside of the box of the image.
|
||||
domain.add_features(features_inside.begin(), features_inside.end());
|
||||
return true;
|
||||
}
|
||||
/// [Add 1D features]
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
|
@ -79,21 +49,28 @@ int main(int argc, char* argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Domain
|
||||
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image);
|
||||
|
||||
/// Declare 1D-features, see above [Call add_1D_features]
|
||||
const std::string lines_fname = (argc>2)?argv[2]:CGAL::data_file_path("images/420.polylines.txt");
|
||||
|
||||
if(!add_1D_features(image, domain, lines_fname)) {
|
||||
/// Load 1D-features
|
||||
const std::string lines_fname = (argc > 2) ? argv[2] : CGAL::data_file_path("images/420.polylines.txt");
|
||||
std::vector<std::vector<K::Point_3> > features_inside;
|
||||
if (!read_polylines(lines_fname, features_inside)) // see file "read_polylines.h"
|
||||
{
|
||||
std::cerr << "Error: Cannot read file " << lines_fname << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/// [Call add_1D_features]
|
||||
|
||||
/// [Domain creation]
|
||||
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image,
|
||||
params::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox(),
|
||||
params::input_features = std::cref(features_inside));//use std::cref to avoid a copy
|
||||
/// [Domain creation]
|
||||
|
||||
/// Note that `edge_size` is needed with 1D-features [Mesh criteria]
|
||||
Mesh_criteria criteria(params::edge_size(6).
|
||||
facet_angle(30).facet_size(6).facet_distance(4).
|
||||
cell_radius_edge_ratio(3).cell_size(8));
|
||||
Mesh_criteria criteria(params::edge_size = 6.,
|
||||
params::facet_angle = 30,
|
||||
params::facet_size = 6,
|
||||
params::facet_distance = 4,
|
||||
params::cell_radius_edge_ratio = 3,
|
||||
params::cell_size = 8);
|
||||
/// [Mesh criteria]
|
||||
|
||||
// Meshing
|
||||
|
|
@ -104,5 +81,5 @@ int main(int argc, char* argv[])
|
|||
CGAL::IO::write_MEDIT(medit_file, c3t3);
|
||||
medit_file.close();
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <CGAL/Mesh_triangulation_3.h>
|
||||
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
|
||||
#include <CGAL/Mesh_criteria_3.h>
|
||||
|
||||
#include <CGAL/make_mesh_3.h>
|
||||
#include <CGAL/Image_3.h>
|
||||
|
||||
/// [Domain definition]
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
|
||||
#include <CGAL/Labeled_mesh_domain_3.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Labeled_mesh_domain_3<K> Image_domain;
|
||||
typedef CGAL::Mesh_domain_with_polyline_features_3<Image_domain> Mesh_domain;
|
||||
/// [Domain definition]
|
||||
|
||||
#ifdef CGAL_CONCURRENT_MESH_3
|
||||
using Concurrency_tag = CGAL::Parallel_tag;
|
||||
#else
|
||||
using Concurrency_tag = CGAL::Sequential_tag;
|
||||
#endif
|
||||
|
||||
// Triangulation
|
||||
typedef CGAL::Mesh_triangulation_3<Mesh_domain,CGAL::Default,Concurrency_tag>::type Tr;
|
||||
|
||||
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
|
||||
|
||||
// Criteria
|
||||
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
|
||||
|
||||
namespace params = CGAL::parameters;
|
||||
|
||||
#include "read_polylines.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const std::string fname = (argc>1)?argv[1]:CGAL::data_file_path("images/420.inr");
|
||||
// Loads image
|
||||
CGAL::Image_3 image;
|
||||
if(!image.read(fname)){
|
||||
std::cerr << "Error: Cannot read file " << fname << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/// Declare 1D-features
|
||||
const std::string lines_fname = (argc>2)?argv[2]:CGAL::data_file_path("images/420.polylines.txt");
|
||||
using Point_3 = K::Point_3;
|
||||
std::vector<std::vector<Point_3> > features_inside;
|
||||
if (!read_polylines(lines_fname, features_inside)) // see file "read_polylines.h"
|
||||
{
|
||||
std::cerr << "Error: Cannot read file " << lines_fname << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/// [Domain creation]
|
||||
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image,
|
||||
params::input_features = std::cref(features_inside));//use std::cref to avoid a copy
|
||||
/// [Domain creation]
|
||||
|
||||
/// Note that `edge_size` is needed with 1D-features [Mesh criteria]
|
||||
Mesh_criteria criteria(params::edge_size = 6,
|
||||
params::facet_angle = 30,
|
||||
params::facet_size = 6,
|
||||
params::facet_distance = 4,
|
||||
params::cell_radius_edge_ratio = 3,
|
||||
params::cell_size = 8);
|
||||
/// [Mesh criteria]
|
||||
|
||||
// Meshing
|
||||
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria);
|
||||
|
||||
// Output
|
||||
std::ofstream medit_file("out.mesh");
|
||||
CGAL::IO::write_MEDIT(medit_file, c3t3);
|
||||
medit_file.close();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <CGAL/Labeled_mesh_domain_3.h>
|
||||
#include <CGAL/Implicit_to_labeling_function_wrapper.h>
|
||||
#include <CGAL/Mesh_3/Null_subdomain_index.h>
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Labeled_mesh_domain_3.h>
|
||||
#include <CGAL/Mesh_3/Image_to_labeled_function_wrapper.h>
|
||||
#include <CGAL/Mesh_3/Null_subdomain_index.h>
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/Default.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <CGAL/Origin.h>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <CGAL/SMDS_3/internal/Handle_IO_for_pair_of_int.h>
|
||||
#include <CGAL/SMDS_3/internal/indices_management.h>
|
||||
|
|
@ -48,6 +49,11 @@
|
|||
#endif
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <CGAL/Mesh_3/Null_subdomain_index.h>
|
||||
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
|
||||
|
||||
#include <CGAL/Mesh_3/polylines_to_protect.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Mesh_3 {
|
||||
namespace internal {
|
||||
|
|
@ -117,15 +123,67 @@ namespace internal {
|
|||
}
|
||||
};
|
||||
|
||||
// Detect_features_in_domain
|
||||
template<typename Point, typename DetectFunctor>
|
||||
struct Detect_features_in_domain {
|
||||
std::vector<std::vector<Point>>
|
||||
operator()(const CGAL::Image_3& image, DetectFunctor functor) const {
|
||||
#if defined(BOOST_MSVC) && (BOOST_MSVC < 1910) //before msvc2017
|
||||
return functor.operator()<Point>(image);
|
||||
#else
|
||||
return functor.template operator()<Point>(image);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
// specialization for `Null_functor`: create the default functor
|
||||
template<typename Point>
|
||||
struct Detect_features_in_domain<Point, Null_functor> {
|
||||
std::vector<std::vector<Point>>
|
||||
operator()(const CGAL::Image_3&, Null_functor) const {
|
||||
return std::vector<std::vector<Point>>();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Point, typename DetectFunctor>
|
||||
std::vector<std::vector<Point>>
|
||||
detect_features(const CGAL::Image_3& image, DetectFunctor functor)
|
||||
{
|
||||
Detect_features_in_domain<Point, DetectFunctor> detector;
|
||||
return detector(image, functor);
|
||||
}
|
||||
|
||||
template<bool WithFeatures>
|
||||
struct Add_features_in_domain {
|
||||
template<typename MeshDomain, typename InputFeatureRange, typename DetectFunctor>
|
||||
void operator()(const CGAL::Image_3&, MeshDomain&, const InputFeatureRange&, DetectFunctor)
|
||||
{}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Add_features_in_domain<true>
|
||||
{
|
||||
template<typename MeshDomain, typename InputFeatureRange, typename DetectFunctor>
|
||||
void operator()(const CGAL::Image_3& image,
|
||||
MeshDomain& domain,
|
||||
const InputFeatureRange& input_features,
|
||||
DetectFunctor functor)
|
||||
{
|
||||
using P = typename MeshDomain::Point_3;
|
||||
auto detected_feature_range
|
||||
= CGAL::Mesh_3::internal::detect_features<P>(image, functor);
|
||||
|
||||
CGAL::merge_and_snap_polylines(image, detected_feature_range, input_features);
|
||||
|
||||
if (!input_features.empty())
|
||||
domain.add_features(input_features.begin(), input_features.end());
|
||||
domain.add_features(detected_feature_range.begin(), detected_feature_range.end());
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace CGAL::Mesh_3::internal
|
||||
} // end namespace CGAL::Mesh_3
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
struct Null_subdomain_index {
|
||||
template <typename T>
|
||||
bool operator()(const T& x) const { return 0 == x; }
|
||||
};
|
||||
|
||||
template <typename Subdomain_index>
|
||||
struct Construct_pair_from_subdomain_indices {
|
||||
typedef std::pair<Subdomain_index, Subdomain_index> result_type;
|
||||
|
|
@ -539,6 +597,11 @@ public:
|
|||
* domain to be discretized is the union of voxels that have non-zero
|
||||
* values.
|
||||
*
|
||||
* \returns either a `Labeled_mesh_domain_3`,
|
||||
* or a `Mesh_domain_with_polyline_features_3<Labeled_mesh_domain_3>`
|
||||
* depending on whether one or more of the named parameters
|
||||
* `features_detector` and `input_features` are provided.
|
||||
*
|
||||
* \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
|
||||
* \param image_ the input 3D image.
|
||||
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below:
|
||||
|
|
@ -565,6 +628,34 @@ public:
|
|||
* bound, relative to the diameter of the box of the image.}
|
||||
* \cgalParamDefault{FT(1e-3)}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{features_detector}
|
||||
* \cgalParamDescription{ a functor that implements
|
||||
* `std::vector<std::vector<Point>> operator()(const Image_3& img) const`,
|
||||
* where `%Point` matches the mesh domain point type.
|
||||
* It returns a range of detected polyline features, which are added
|
||||
* to the domain for feature protection.
|
||||
* See \ref PkgMesh3FeatureDetection for a list of available functors.}
|
||||
* \cgalParamDefault{CGAL::Null_functor()}
|
||||
* \cgalParamExtra{The return type of the function depends on whether this parameter
|
||||
or `input_features` are provided or not.}
|
||||
* \cgalParamExtra{If `weights` is provided, this parameter is ignored}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{input_features}
|
||||
* \cgalParamDescription{ a `Range` of polyline features, represented as `Range`s of `Point_3`.
|
||||
* Polyline features are added to the domain for further feature protection.
|
||||
* Input polyline features must be different from the detected features
|
||||
* and can intersect only at vertices, if they do. Otherwise,
|
||||
* the meshing process may not terminate.}
|
||||
* \cgalParamDefault{`std::vector<std::vector<Point_3>>()`}
|
||||
* \cgalParamExtra{The return type of the function depends on whether this parameter
|
||||
or `input_features` are provided or not.}
|
||||
* \cgalParamExtra{It is recommended to pass a const-reference for this parameter,
|
||||
* possibly using `std::cref(polylines_range)` to avoid useless copies.}
|
||||
* \cgalParamExtra{If `weights` is provided, this parameter is ignored}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* \cgalHeading{Example}
|
||||
|
|
@ -578,13 +669,24 @@ public:
|
|||
*
|
||||
* \snippet Mesh_3/mesh_3D_weighted_image.cpp Domain creation
|
||||
*
|
||||
* From the example (\ref Mesh_3/mesh_3D_image_with_detection_of_features.cpp)
|
||||
* where the features are detected in `image`:
|
||||
*
|
||||
* \snippet Mesh_3/mesh_3D_image_with_detection_of_features.cpp Domain creation
|
||||
*
|
||||
* From the example (\ref Mesh_3/mesh_3D_image_with_input_features.cpp)
|
||||
* where the features are provided by the user:
|
||||
*
|
||||
* \snippet Mesh_3/mesh_3D_image_with_input_features.cpp Domain creation
|
||||
*/
|
||||
template<typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL::Image_3& image_, const CGAL_NP_CLASS& np = parameters::default_values())
|
||||
static auto
|
||||
create_labeled_image_mesh_domain(const CGAL::Image_3& image_, const CGAL_NP_CLASS& np = parameters::default_values())
|
||||
{
|
||||
using parameters::get_parameter;
|
||||
using parameters::get_parameter_reference;
|
||||
using parameters::choose_parameter;
|
||||
|
||||
auto iso_value_ = choose_parameter(get_parameter(np, internal_np::iso_value_param), 0);
|
||||
auto value_outside_ = choose_parameter(get_parameter(np, internal_np::voxel_value), 0);
|
||||
FT relative_error_bound_ = choose_parameter(get_parameter(np, internal_np::error_bound), FT(1e-3));
|
||||
|
|
@ -592,41 +694,62 @@ public:
|
|||
CGAL::Random* p_rng_ = choose_parameter(get_parameter(np, internal_np::rng), nullptr);
|
||||
auto null_subdomain_index_ = choose_parameter(get_parameter(np, internal_np::null_subdomain_index_param), Null_functor());
|
||||
auto construct_surface_patch_index_ = choose_parameter(get_parameter(np, internal_np::surface_patch_index), Null_functor());
|
||||
const CGAL::Image_3& weights_ = choose_parameter(get_parameter_reference(np, internal_np::weights_param), CGAL::Image_3());
|
||||
|
||||
using Image_ref_type = typename internal_np::Lookup_named_param_def<internal_np::weights_param_t,
|
||||
CGAL_NP_CLASS,
|
||||
CGAL::Image_3>::reference;
|
||||
CGAL::Image_3 no_weights;
|
||||
const Image_ref_type weights_ = choose_parameter(get_parameter_reference(np, internal_np::weights_param), no_weights);
|
||||
auto features_detector_ = choose_parameter(get_parameter(np, internal_np::features_detector_param), Null_functor());
|
||||
|
||||
using Default_input_features = std::vector<std::vector<typename Labeled_mesh_domain_3::Point_3>>;
|
||||
using Input_features_ref_type = typename internal_np::Lookup_named_param_def<internal_np::input_features_param_t,
|
||||
CGAL_NP_CLASS,
|
||||
Default_input_features>::reference;
|
||||
Default_input_features empty_vec;
|
||||
Input_features_ref_type input_features_
|
||||
= choose_parameter(get_parameter_reference(np, internal_np::input_features_param), empty_vec);
|
||||
|
||||
CGAL_USE(iso_value_);
|
||||
namespace p = CGAL::parameters;
|
||||
|
||||
auto image_wrapper = weights_.is_valid()
|
||||
? create_weighted_labeled_image_wrapper(image_,
|
||||
weights_,
|
||||
image_values_to_subdomain_indices_,
|
||||
value_outside_)
|
||||
: create_labeled_image_wrapper(image_,
|
||||
image_values_to_subdomain_indices_,
|
||||
value_outside_);
|
||||
|
||||
// warning : keep Return_type consistent with actual return type
|
||||
const bool no_features
|
||||
= CGAL::parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::features_detector_param_t>::value
|
||||
&& CGAL::parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::input_features_param_t>::value;
|
||||
using Return_type = std::conditional_t <
|
||||
no_features,
|
||||
Labeled_mesh_domain_3,
|
||||
Mesh_domain_with_polyline_features_3<Labeled_mesh_domain_3>
|
||||
>;
|
||||
|
||||
Return_type domain
|
||||
(p::function = image_wrapper,
|
||||
p::bounding_object = Mesh_3::internal::compute_bounding_box(image_),
|
||||
p::relative_error_bound = relative_error_bound_,
|
||||
p::p_rng = p_rng_,
|
||||
p::null_subdomain_index =
|
||||
create_null_subdomain_index(null_subdomain_index_),
|
||||
p::construct_surface_patch_index =
|
||||
create_construct_surface_patch_index(construct_surface_patch_index_));
|
||||
|
||||
if (weights_.is_valid())
|
||||
{
|
||||
return Labeled_mesh_domain_3
|
||||
(p::function = create_weighted_labeled_image_wrapper
|
||||
(image_,
|
||||
weights_,
|
||||
image_values_to_subdomain_indices_,
|
||||
value_outside_),
|
||||
p::bounding_object = Mesh_3::internal::compute_bounding_box(image_),
|
||||
p::relative_error_bound = relative_error_bound_,
|
||||
p::p_rng = p_rng_,
|
||||
p::null_subdomain_index =
|
||||
create_null_subdomain_index(null_subdomain_index_),
|
||||
p::construct_surface_patch_index =
|
||||
create_construct_surface_patch_index(construct_surface_patch_index_));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Labeled_mesh_domain_3
|
||||
(p::function = create_labeled_image_wrapper
|
||||
(image_,
|
||||
image_values_to_subdomain_indices_,
|
||||
value_outside_),
|
||||
p::bounding_object = Mesh_3::internal::compute_bounding_box(image_),
|
||||
p::relative_error_bound = relative_error_bound_,
|
||||
p::p_rng = p_rng_,
|
||||
p::null_subdomain_index =
|
||||
create_null_subdomain_index(null_subdomain_index_),
|
||||
p::construct_surface_patch_index =
|
||||
create_construct_surface_patch_index(construct_surface_patch_index_));
|
||||
}
|
||||
return domain;
|
||||
|
||||
// features
|
||||
Mesh_3::internal::Add_features_in_domain<!no_features>()
|
||||
(image_, domain, input_features_, features_detector_);
|
||||
|
||||
return domain;
|
||||
}
|
||||
/// @}
|
||||
|
||||
|
|
@ -686,7 +809,7 @@ public:
|
|||
}
|
||||
|
||||
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT>
|
||||
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL_NP_CLASS& np)
|
||||
static auto create_labeled_image_mesh_domain(const CGAL_NP_CLASS& np)
|
||||
{
|
||||
static_assert(!parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::image_3_param_t>::value, "Value for required parameter not found");
|
||||
using parameters::get_parameter_reference;
|
||||
|
|
@ -698,10 +821,10 @@ public:
|
|||
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_1,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2,
|
||||
typename ... NP>
|
||||
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL::Image_3& image_,
|
||||
const CGAL_NP_CLASS_1& np1,
|
||||
const CGAL_NP_CLASS_2& np2,
|
||||
const NP& ... nps)
|
||||
static auto create_labeled_image_mesh_domain(const CGAL::Image_3& image_,
|
||||
const CGAL_NP_CLASS_1& np1,
|
||||
const CGAL_NP_CLASS_2& np2,
|
||||
const NP& ... nps)
|
||||
{
|
||||
return create_labeled_image_mesh_domain(image_, internal_np::combine_named_parameters(np1, np2, nps...));
|
||||
}
|
||||
|
|
@ -709,9 +832,9 @@ public:
|
|||
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_1,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2,
|
||||
typename ... NP>
|
||||
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL_NP_CLASS_1& np1,
|
||||
const CGAL_NP_CLASS_2& np2,
|
||||
const NP& ... nps)
|
||||
static auto create_labeled_image_mesh_domain(const CGAL_NP_CLASS_1& np1,
|
||||
const CGAL_NP_CLASS_2& np2,
|
||||
const NP& ... nps)
|
||||
{
|
||||
return create_labeled_image_mesh_domain(internal_np::combine_named_parameters(np1, np2, nps...));
|
||||
}
|
||||
|
|
@ -904,9 +1027,9 @@ public:
|
|||
// null(f(p)) means p is outside the domain
|
||||
Subdomain_index index = (r_domain_.function_)(p);
|
||||
if ( r_domain_.null(index) )
|
||||
return Subdomain();
|
||||
return Subdomain{};
|
||||
else
|
||||
return Subdomain(index);
|
||||
return Subdomain{ index };
|
||||
}
|
||||
private:
|
||||
const Labeled_mesh_domain_3& r_domain_;
|
||||
|
|
|
|||
|
|
@ -791,6 +791,7 @@ public:
|
|||
Moving_vertices_set& moving_vertices);
|
||||
|
||||
void update_restricted_facets();
|
||||
void update_restricted_cells();
|
||||
|
||||
#ifdef CGAL_INTRUSIVE_LIST
|
||||
template <typename OutdatedCells>
|
||||
|
|
@ -2924,6 +2925,18 @@ update_restricted_facets()
|
|||
updater(*fit);
|
||||
}
|
||||
|
||||
template <typename C3T3, typename MD>
|
||||
void
|
||||
C3T3_helpers<C3T3, MD>::
|
||||
update_restricted_cells()
|
||||
{
|
||||
Update_c3t3 updater(domain_, c3t3_);
|
||||
for (typename C3T3::Triangulation::Finite_cells_iterator
|
||||
cit = tr_.finite_cells_begin();
|
||||
cit != tr_.finite_cells_end(); ++cit)
|
||||
updater(cit);
|
||||
}
|
||||
|
||||
template <typename C3T3, typename MD>
|
||||
template <typename OutdatedCellsOutputIterator,
|
||||
typename DeletedCellsOutputIterator>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,290 @@
|
|||
// Copyright (c) 2022 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot, Jane Tournois
|
||||
//
|
||||
//******************************************************************************
|
||||
//
|
||||
//******************************************************************************
|
||||
|
||||
#ifndef CGAL_MESH_3_DETECT_FEATURES_IN_IMAGE_H
|
||||
#define CGAL_MESH_3_DETECT_FEATURES_IN_IMAGE_H
|
||||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
#include <CGAL/ImageIO.h>
|
||||
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Mesh_3/features_detection/features_detection.h>
|
||||
#include <CGAL/Mesh_3/features_detection/coordinates.h>
|
||||
#include <CGAL/Mesh_3/features_detection/combinations.h>
|
||||
#include <CGAL/Mesh_3/features_detection/cases_table.h>
|
||||
#include <CGAL/Mesh_3/features_detection/cube_isometries.h>
|
||||
#include <CGAL/Mesh_3/features_detection/features_detection_helpers.h>
|
||||
|
||||
#include <CGAL/Mesh_3/polylines_to_protect.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#ifdef CGAL_DEBUG_TRIPLE_LINES
|
||||
#include <boost/range/join.hpp>
|
||||
#endif
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
namespace Mesh_3
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
// Protect the intersection of the object with the box of the image,
|
||||
// by declaring 1D-features. Note that `CGAL::polylines_to_protect` is
|
||||
// not documented.
|
||||
template<typename Word_type, typename P>
|
||||
std::vector<std::vector<P>>
|
||||
detect_features_in_image_with_know_word_type(const CGAL::Image_3& image)
|
||||
{
|
||||
using Gt = typename CGAL::Kernel_traits<P>::Kernel;
|
||||
using Point_3 = P;
|
||||
using Vector_3 = typename Gt::Vector_3;
|
||||
using Polyline_type = std::vector<Point_3>;
|
||||
using Polylines = std::vector<Polyline_type>;
|
||||
|
||||
CGAL::Mesh_3::Triple_line_extractor<Point_3> lines;
|
||||
|
||||
Polylines features_inside;
|
||||
|
||||
const double vx = image.vx();
|
||||
const double vy = image.vy();
|
||||
const double vz = image.vz();
|
||||
const double dist_bound = (std::min)(vx, (std::min)(vy, vz)) / 256;
|
||||
const double sq_dist_bound = dist_bound * dist_bound;
|
||||
|
||||
const std::size_t xdim = image.xdim();
|
||||
const std::size_t ydim = image.ydim();
|
||||
const std::size_t zdim = image.zdim();
|
||||
|
||||
const float tx = image.tx();
|
||||
const float ty = image.ty();
|
||||
const float tz = image.tz();
|
||||
|
||||
using CGAL::IMAGEIO::static_evaluate;
|
||||
|
||||
using Del = CGAL::Delaunay_triangulation_3<Gt>;
|
||||
using Cell_handle = typename Del::Cell_handle;
|
||||
using Vertex_handle = typename Del::Vertex_handle;
|
||||
Del triangulation;
|
||||
Cell_handle start_cell;
|
||||
|
||||
using Word //use unsigned integral Word type to use it as an index
|
||||
= typename CGAL::IMAGEIO::Word_type_generator<WK_FIXED, SGN_UNSIGNED, sizeof(Word_type)>::type;
|
||||
|
||||
using Color_transform = internal::Color_transformation_helper<Word>;
|
||||
typename Color_transform::type color_transformation;
|
||||
std::array<Word, 8> inv_color_transformation;
|
||||
|
||||
using Permutation = internal::Permutation;
|
||||
using Coord = internal::Coordinates;
|
||||
|
||||
for (std::size_t k = 0, end_k = zdim - 1; k < end_k; ++k)
|
||||
for (std::size_t j = 0, end_j = ydim - 1; j < end_j; ++j)
|
||||
for (std::size_t i = 0, end_i = xdim - 1; i < end_i; ++i)
|
||||
{
|
||||
Vector_3 translation{ i * vx + tx,
|
||||
j * vy + ty,
|
||||
k * vz + tz };
|
||||
|
||||
const std::array<Word, 8> cube = {
|
||||
static_evaluate<Word>(image.image(), i , j , k),
|
||||
static_evaluate<Word>(image.image(), i + 1, j , k),
|
||||
static_evaluate<Word>(image.image(), i , j + 1, k),
|
||||
static_evaluate<Word>(image.image(), i + 1, j + 1, k),
|
||||
static_evaluate<Word>(image.image(), i , j , k + 1),
|
||||
static_evaluate<Word>(image.image(), i + 1, j , k + 1),
|
||||
static_evaluate<Word>(image.image(), i , j + 1, k + 1),
|
||||
static_evaluate<Word>(image.image(), i + 1, j + 1, k + 1),
|
||||
}; /// TODO: optimize the access to the image data
|
||||
bool monocolor = (cube[0] == cube[1]);
|
||||
for (int i = 2; i < 8; ++i) monocolor = monocolor && (cube[0] == cube[i]);
|
||||
if (monocolor) continue;
|
||||
|
||||
Color_transform::reset(color_transformation);
|
||||
|
||||
std::uint8_t nb_color = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (!Color_transform::is_valid(color_transformation, cube[i]))
|
||||
{
|
||||
color_transformation[cube[i]] = nb_color;
|
||||
inv_color_transformation[nb_color] = cube[i];
|
||||
++nb_color;
|
||||
}
|
||||
}
|
||||
std::array<std::uint8_t, 8> reference_cube = {
|
||||
color_transformation[cube[0]],
|
||||
color_transformation[cube[1]],
|
||||
color_transformation[cube[2]],
|
||||
color_transformation[cube[3]],
|
||||
color_transformation[cube[4]],
|
||||
color_transformation[cube[5]],
|
||||
color_transformation[cube[6]],
|
||||
color_transformation[cube[7]]
|
||||
};
|
||||
auto case_it = internal::find_case(internal::cases, reference_cube);
|
||||
const bool case_found = (case_it != std::end(internal::cases));
|
||||
if (case_found) reference_cube = internal::combinations[(*case_it)[8]];
|
||||
else {
|
||||
//std::cerr << "Warning: case not found: " << reference_cube << '\n';
|
||||
CGAL_error();
|
||||
};
|
||||
#ifdef CGAL_DEBUG_TRIPLE_LINES
|
||||
CGAL::Mesh_3::internal::debug_cerr("Cube", cube);
|
||||
CGAL::Mesh_3::internal::debug_cerr("reference cube", reference_cube);
|
||||
CGAL::Mesh_3::internal::debug_cerr("with transformation", internal::cube_isometries[(*case_it)[9]]);
|
||||
#endif // CGAL_DEBUG_TRIPLE_LINES
|
||||
|
||||
auto fct_it = lines.create_polylines_fcts.find(reference_cube);
|
||||
if (fct_it != lines.create_polylines_fcts.end())
|
||||
{
|
||||
#ifdef CGAL_DEBUG_TRIPLE_LINES
|
||||
CGAL::Mesh_3::internal::debug_cerr("Using the function of", Cube(fct_it->first));
|
||||
#endif // CGAL_DEBUG_TRIPLE_LINES
|
||||
|
||||
Polylines cube_features = (fct_it->second)(10);
|
||||
if (case_found)
|
||||
{
|
||||
const Permutation& transformation = internal::cube_isometries[(*case_it)[9]];
|
||||
|
||||
Coord a1 = internal::coordinates[transformation[0]];
|
||||
Coord u = internal::minus(internal::coordinates[transformation[1]], a1);
|
||||
Coord v = internal::minus(internal::coordinates[transformation[2]], a1);
|
||||
Coord w = internal::minus(internal::coordinates[transformation[4]], a1);
|
||||
|
||||
const Point_3 pa{ a1[0], a1[1], a1[2] };
|
||||
const Vector_3 vu{ u[0], u[1], u[2] };
|
||||
const Vector_3 vv{ v[0], v[1], v[2] };
|
||||
const Vector_3 vw{ w[0], w[1], w[2] };
|
||||
#ifdef CGAL_DEBUG_TRIPLE_LINES
|
||||
std::cerr << "pa: " << pa << "\n";
|
||||
std::cerr << "vu: " << vu << "\n";
|
||||
std::cerr << "vv: " << vv << "\n";
|
||||
std::cerr << "vw: " << vw << "\n";
|
||||
#endif // CGAL_DEBUG_TRIPLE_LINES
|
||||
for (auto& polyline : cube_features) {
|
||||
for (auto& point : polyline) {
|
||||
point = pa
|
||||
+ point.x() * vu
|
||||
+ point.y() * vv
|
||||
+ point.z() * vw;
|
||||
point = { vx * point.x(),
|
||||
vy * point.y(),
|
||||
vz * point.z(), };
|
||||
point = point + translation;
|
||||
}
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
Point_3& extremity = (i == 0) ? polyline.front() : polyline.back();
|
||||
Vertex_handle vh = triangulation.nearest_vertex(extremity, start_cell);
|
||||
if (Vertex_handle() != vh) {
|
||||
if (squared_distance(vh->point(), extremity) < sq_dist_bound) {
|
||||
extremity = vh->point();
|
||||
}
|
||||
}
|
||||
vh = triangulation.insert(extremity, start_cell);
|
||||
start_cell = vh->cell();
|
||||
}
|
||||
features_inside.push_back(std::move(polyline));
|
||||
} // end loop on polylines
|
||||
} // end case where the transformation is not the identity
|
||||
} // end if the reference_cube has polylines
|
||||
}
|
||||
|
||||
// call the split_graph_into_polylines, to create long polylines from the
|
||||
// short polylines that were generated per voxel.
|
||||
Polylines polylines_inside;
|
||||
CGAL::polylines_to_protect(polylines_inside,
|
||||
features_inside.begin(),
|
||||
features_inside.end());
|
||||
|
||||
Polylines polylines_on_bbox;
|
||||
CGAL::polylines_to_protect<Point_3, Word_type>(image, polylines_on_bbox,
|
||||
polylines_inside.begin(),
|
||||
polylines_inside.end());
|
||||
|
||||
polylines_inside.insert(polylines_inside.end(),
|
||||
polylines_on_bbox.begin(),
|
||||
polylines_on_bbox.end());
|
||||
|
||||
#ifdef CGAL_DEBUG_TRIPLE_LINES
|
||||
std::ofstream output_polylines("out-generated.polylines.txt");
|
||||
output_polylines.precision(17);
|
||||
for (auto poly : boost::range::join(polylines_on_bbox, polylines_inside)) {
|
||||
output_polylines << poly.size();
|
||||
for (auto p : poly) output_polylines << " " << p;
|
||||
output_polylines << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return polylines_inside;
|
||||
}
|
||||
|
||||
|
||||
}// namespace internal
|
||||
|
||||
/*!
|
||||
* \ingroup PkgMesh3FeatureDetection
|
||||
*
|
||||
* Functor for feature detection in labeled images.
|
||||
*/
|
||||
struct Detect_features_in_image
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* detects and constructs the polylines that lie at the
|
||||
* intersection of three or more subdomains.
|
||||
*
|
||||
* Each subdomain inside the bounding box
|
||||
* of the input labeled image is defined as the set of voxels
|
||||
* with the same value. The outside of the bounding box
|
||||
* of the image is considered as a subdomain with voxel value
|
||||
* `value_outside` (see \link CGAL::Labeled_mesh_domain_3::create_labeled_image_mesh_domain `create_labeled_image_mesh_domain()` \endlink
|
||||
* parameters description). Hence, this function also computes
|
||||
* intersections with the image bounding box.
|
||||
*
|
||||
* \tparam Point class model of `Kernel::Point_3`. It
|
||||
* must match the triangulation point type.
|
||||
*
|
||||
* \param image the input image
|
||||
*
|
||||
* \returns a `std::vector<std::vector<Point>>`
|
||||
* containing the constructed polylines for later feature protection.
|
||||
*/
|
||||
template<typename Point>
|
||||
std::vector<std::vector<Point>>
|
||||
operator()(const CGAL::Image_3& image) const
|
||||
{
|
||||
CGAL_IMAGE_IO_CASE(image.image(),
|
||||
return (internal::detect_features_in_image_with_know_word_type<Word, Point>(image));
|
||||
);
|
||||
CGAL_error_msg("This place should never be reached, because it would mean "
|
||||
"the image word type is a type that is not handled by "
|
||||
"CGAL_ImageIO.");
|
||||
|
||||
return std::vector<std::vector<Point>>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}//end namespace Mesh_3
|
||||
}//end namespace CGAL
|
||||
|
||||
|
||||
#endif //CGAL_MESH_3_DETECT_FEATURES_IN_IMAGE_H
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) 2022 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Laurent Rineau, Jane Tournois
|
||||
//
|
||||
//******************************************************************************
|
||||
//
|
||||
//******************************************************************************
|
||||
|
||||
#ifndef CGAL_MESH_3_DETECT_FEATURES_ON_IMAGE_BBOX_H
|
||||
#define CGAL_MESH_3_DETECT_FEATURES_ON_IMAGE_BBOX_H
|
||||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
#include <CGAL/Mesh_3/polylines_to_protect.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
namespace Mesh_3
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template<typename Point>
|
||||
std::vector<std::vector<Point>>
|
||||
detect_features_on_bbox(const CGAL::Image_3& image)
|
||||
{
|
||||
using Point_3 = Point;
|
||||
using Polyline_type = std::vector<Point_3>;
|
||||
using Polylines = std::vector<Polyline_type>;
|
||||
|
||||
Polylines polylines_on_bbox;
|
||||
|
||||
CGAL_IMAGE_IO_CASE(image.image(),
|
||||
{
|
||||
(CGAL::polylines_to_protect<Point_3, Word>(image, polylines_on_bbox));
|
||||
return polylines_on_bbox;
|
||||
}
|
||||
);
|
||||
CGAL_error_msg("This place should never be reached, because it would mean "
|
||||
"the image word type is a type that is not handled by "
|
||||
"CGAL_ImageIO.");
|
||||
return Polylines();
|
||||
}
|
||||
|
||||
}// namespace internal
|
||||
|
||||
/*!
|
||||
* \ingroup PkgMesh3FeatureDetection
|
||||
*
|
||||
* Functor for feature detection in labeled images.
|
||||
*/
|
||||
struct Detect_features_on_image_bbox
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* detects and constructs the polylines that lie at the
|
||||
* intersection of two or more subdomains and the bounding box
|
||||
* of the input labeled image.
|
||||
*
|
||||
* Each subdomain inside the bounding box
|
||||
* of the input labeled image is defined as the set of voxels
|
||||
* with the same value. The outside of the bounding box
|
||||
* of the image is considered as a subdomain with voxel value
|
||||
* `value_outside` (see \link CGAL::Labeled_mesh_domain_3::create_labeled_image_mesh_domain `create_labeled_image_mesh_domain()` \endlink
|
||||
* parameters description). Hence, this function computes
|
||||
* intersections of "internal" subdomains with the image bounding box.
|
||||
*
|
||||
* \tparam Point class model of `Kernel::Point_3`. The point type
|
||||
* must match the triangulation point type.
|
||||
*
|
||||
* \param image the input image
|
||||
*
|
||||
* \returns a `std::vector<std::vector<Point>>`
|
||||
* containing the constructed polylines for later feature protection.
|
||||
*/
|
||||
template<typename Point>
|
||||
std::vector<std::vector<Point>>
|
||||
operator()(const CGAL::Image_3& image) const
|
||||
{
|
||||
return internal::detect_features_on_bbox<Point>(image);
|
||||
}
|
||||
};
|
||||
|
||||
}//end namespace Mesh_3
|
||||
}//end namespace CGAL
|
||||
|
||||
|
||||
#endif //CGAL_MESH_3_DETECT_FEATURES_ON_IMAGE_BBOX_H
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2015 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_MESH_3_NULL_SUBDOMAIN_INDEX
|
||||
#define CGAL_MESH_3_NULL_SUBDOMAIN_INDEX
|
||||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
|
||||
namespace CGAL {
|
||||
struct Null_subdomain_index {
|
||||
template <typename T>
|
||||
bool operator()(const T& x) const { return 0 == x; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif //CGAL_MESH_3_NULL_SUBDOMAIN_INDEX
|
||||
|
|
@ -57,25 +57,40 @@ public:
|
|||
IndexToIgnoreIterator end,
|
||||
const AABBTraits& aabb_traits,
|
||||
IndexPropertyMap index_map = IndexPropertyMap())
|
||||
: m_closest_point(hint),
|
||||
m_closest_point_initialized(true),
|
||||
set_of_indices(begin, end),
|
||||
aabb_traits(aabb_traits),
|
||||
index_map(index_map)
|
||||
: Filtered_projection_traits(begin, end, aabb_traits, index_map)
|
||||
{
|
||||
m_closest_point = hint;
|
||||
m_closest_point_initialized = true;
|
||||
}
|
||||
|
||||
Filtered_projection_traits(const Point_3& hint,
|
||||
Index_type index,
|
||||
const AABBTraits& aabb_traits,
|
||||
IndexPropertyMap index_map = IndexPropertyMap())
|
||||
: m_closest_point(hint),
|
||||
m_closest_point_initialized(true),
|
||||
set_of_indices(),
|
||||
aabb_traits(aabb_traits),
|
||||
index_map(index_map)
|
||||
: Filtered_projection_traits(index, aabb_traits, index_map)
|
||||
{
|
||||
set_of_indices.insert(index);
|
||||
m_closest_point = hint;
|
||||
m_closest_point_initialized = true;
|
||||
}
|
||||
|
||||
template <typename IndexToIgnoreIterator>
|
||||
Filtered_projection_traits(const Point_and_primitive_id& hint,
|
||||
IndexToIgnoreIterator begin,
|
||||
IndexToIgnoreIterator end,
|
||||
const AABBTraits& aabb_traits,
|
||||
IndexPropertyMap index_map = IndexPropertyMap())
|
||||
: Filtered_projection_traits(hint.first, begin, end, aabb_traits, index_map)
|
||||
{
|
||||
m_closest_primitive = hint.second;
|
||||
}
|
||||
|
||||
Filtered_projection_traits(const Point_and_primitive_id& hint,
|
||||
Index_type index,
|
||||
const AABBTraits& aabb_traits,
|
||||
IndexPropertyMap index_map = IndexPropertyMap())
|
||||
: Filtered_projection_traits(hint.first, index, aabb_traits, index_map)
|
||||
{
|
||||
m_closest_primitive = hint.second;
|
||||
}
|
||||
|
||||
template <typename IndexToIgnoreIterator>
|
||||
|
|
@ -83,8 +98,7 @@ public:
|
|||
IndexToIgnoreIterator end,
|
||||
const AABBTraits& aabb_traits,
|
||||
IndexPropertyMap index_map = IndexPropertyMap())
|
||||
: m_closest_point_initialized(false),
|
||||
set_of_indices(begin, end),
|
||||
: set_of_indices(begin, end),
|
||||
aabb_traits(aabb_traits),
|
||||
index_map(index_map)
|
||||
{
|
||||
|
|
@ -93,12 +107,10 @@ public:
|
|||
Filtered_projection_traits(Index_type index,
|
||||
const AABBTraits& aabb_traits,
|
||||
IndexPropertyMap index_map = IndexPropertyMap())
|
||||
: m_closest_point_initialized(false),
|
||||
set_of_indices(),
|
||||
: set_of_indices({index}),
|
||||
aabb_traits(aabb_traits),
|
||||
index_map(index_map)
|
||||
{
|
||||
set_of_indices.insert(index);
|
||||
}
|
||||
|
||||
bool go_further() const { return true; }
|
||||
|
|
@ -151,7 +163,7 @@ public:
|
|||
private:
|
||||
Point_3 m_closest_point;
|
||||
typename Primitive::Id m_closest_primitive;
|
||||
bool m_closest_point_initialized;
|
||||
bool m_closest_point_initialized = false;
|
||||
Set_of_indices set_of_indices;
|
||||
const AABBTraits& aabb_traits;
|
||||
IndexPropertyMap index_map;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
#include "Get_curve_index.h"
|
||||
#include <CGAL/Mesh_3/Protect_edges_sizing_field.h> // for weight_modifier
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#if defined(CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY) || defined(CGAL_NO_ASSERTIONS) == 0
|
||||
# include <sstream>
|
||||
|
|
@ -57,6 +61,8 @@ struct Sizing_field_with_aabb_tree
|
|||
typedef CGAL::Delaunay_triangulation_3<Kernel_> Dt;
|
||||
|
||||
typedef Input_facets_AABB_tree Input_facets_AABB_tree_;
|
||||
typedef typename Input_facets_AABB_tree_::AABB_traits AABB_traits;
|
||||
using Point_and_primitive_id = typename AABB_traits::Point_and_primitive_id;
|
||||
typedef typename Input_facets_AABB_tree_::Primitive Input_facets_AABB_tree_primitive_;
|
||||
typedef typename MeshDomain::Curves_AABB_tree Input_curves_AABB_tree_;
|
||||
typedef typename Input_curves_AABB_tree_::Primitive Input_curves_AABB_tree_primitive_;
|
||||
|
|
@ -71,6 +77,22 @@ struct Sizing_field_with_aabb_tree
|
|||
typename Input_facets_AABB_tree::Primitive>
|
||||
>::type Facet_patch_id_map;
|
||||
|
||||
struct Face_ids_traversal_traits {
|
||||
using Limits = std::numeric_limits<Patch_index>;
|
||||
Patch_index min{Limits::max()};
|
||||
Patch_index max{Limits::lowest()};
|
||||
Facet_patch_id_map index_map{};
|
||||
|
||||
bool go_further() const { return true; }
|
||||
template <typename T> bool do_intersect(std::nullptr_t, const T&) { return true; }
|
||||
|
||||
template <typename P> void intersection(std::nullptr_t, const P& primitive) {
|
||||
const Patch_index id = get(index_map, primitive.id());
|
||||
if (id < min) min = id;
|
||||
if (id > max) max = id;
|
||||
}
|
||||
};
|
||||
|
||||
Sizing_field_with_aabb_tree
|
||||
(typename Kernel_::FT d,
|
||||
const Input_facets_AABB_tree_& aabb_tree,
|
||||
|
|
@ -78,87 +100,127 @@ struct Sizing_field_with_aabb_tree
|
|||
Get_curve_index get_curve_index = Get_curve_index(),
|
||||
Facet_patch_id_map facet_patch_id_map = Facet_patch_id_map()
|
||||
)
|
||||
: d_(d), aabb_tree(aabb_tree),
|
||||
domain(domain),
|
||||
dt(),
|
||||
get_curve_index(get_curve_index),
|
||||
facet_patch_id_map(facet_patch_id_map)
|
||||
: d_ptr{std::make_shared<Private_data>(d,
|
||||
aabb_tree,
|
||||
domain,
|
||||
get_curve_index,
|
||||
facet_patch_id_map)}
|
||||
{
|
||||
if(!d_ptr->aabb_tree.empty()) {
|
||||
// Initialize the per-patch kd-trees
|
||||
// - First compute the number of patches and min/max patch ids
|
||||
Face_ids_traversal_traits traversal_traits;
|
||||
d_ptr->aabb_tree.traversal(nullptr, traversal_traits);
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
std::cerr << "min: " << traversal_traits.min << ", max: " << traversal_traits.max << '\n';
|
||||
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
d_ptr->min_patch_id = traversal_traits.min;
|
||||
d_ptr->kd_trees_ptrs.resize(traversal_traits.max - d_ptr->min_patch_id + 1);
|
||||
|
||||
using Node = CGAL::AABB_node<AABB_traits>;
|
||||
using Primitive = typename AABB_traits::Primitive;
|
||||
using Point_and_primitive_id = typename AABB_traits::Point_and_primitive_id;
|
||||
|
||||
std::vector<std::set<Point_and_primitive_id>> vertices_per_patch;
|
||||
vertices_per_patch.resize(d_ptr->kd_trees_ptrs.size());
|
||||
|
||||
// - then fill sets of vertices per patch
|
||||
auto push_vertex = [&](const auto& primitive) {
|
||||
const Patch_index id = get(d_ptr->facet_patch_id_map, primitive.id());
|
||||
const Point_3& p = primitive.reference_point();
|
||||
vertices_per_patch[id - d_ptr->min_patch_id].emplace(p, primitive.id());
|
||||
};
|
||||
|
||||
struct Visit_all_primitives {
|
||||
decltype(push_vertex) register_vertex;
|
||||
bool go_further() const { return true; }
|
||||
bool do_intersect(std::nullptr_t, const Node&) { return true; }
|
||||
void intersection(std::nullptr_t, const Primitive& primitive)
|
||||
{
|
||||
register_vertex(primitive);
|
||||
}
|
||||
} visit_all_primitives{push_vertex};
|
||||
d_ptr->aabb_tree.traversal(nullptr, visit_all_primitives);
|
||||
|
||||
// - then create the kd-trees
|
||||
for(std::size_t i = 0; i < vertices_per_patch.size(); ++i) {
|
||||
if(!vertices_per_patch[i].empty()) {
|
||||
d_ptr->kd_trees_ptrs[i] = std::make_unique<Kd_tree>(vertices_per_patch[i].begin(),
|
||||
vertices_per_patch[i].end());
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
Corner_index maximal_corner_index = 0;
|
||||
typedef std::pair<Corner_index, Point_3> Corner_index_and_point;
|
||||
std::vector<Corner_index_and_point > corners_tmp;
|
||||
domain.get_corners(std::back_inserter(corners_tmp));
|
||||
d_ptr->domain.get_corners(std::back_inserter(corners_tmp));
|
||||
for(const Corner_index_and_point& pair : corners_tmp)
|
||||
{
|
||||
// Fill `corners_indices`
|
||||
if(pair.first > maximal_corner_index) maximal_corner_index = pair.first;
|
||||
corners_indices.
|
||||
d_ptr->corners_indices.
|
||||
insert(typename Corners_indices::value_type(pair.second, pair.first));
|
||||
}
|
||||
corners.resize(maximal_corner_index+1);
|
||||
d_ptr->corners.resize(maximal_corner_index+1);
|
||||
for(const Corner_index_and_point& pair : corners_tmp)
|
||||
{
|
||||
// Fill `corners`
|
||||
corners[pair.first] = pair.second;
|
||||
d_ptr->corners[pair.first] = pair.second;
|
||||
}
|
||||
}
|
||||
|
||||
//fill incidences of corners with curves
|
||||
corners_incident_curves.resize(corners.size());
|
||||
for(const typename Corners_indices::value_type& pair :
|
||||
corners_indices)
|
||||
{
|
||||
dt.insert(pair.first);
|
||||
d_ptr->corners_incident_curves.resize(d_ptr->corners.size());
|
||||
for(const typename Corners_indices::value_type& pair : d_ptr->corners_indices) {
|
||||
d_ptr->dt.insert(pair.first);
|
||||
|
||||
// Fill `corners_incident_curves[corner_id]`
|
||||
Curves_ids& incident_curves = corners_incident_curves[pair.second];
|
||||
domain.get_corner_incident_curves(pair.second,
|
||||
Curves_ids& incident_curves = d_ptr->corners_incident_curves[pair.second];
|
||||
d_ptr->domain.get_corner_incident_curves(pair.second,
|
||||
std::inserter(incident_curves,
|
||||
incident_curves.end()));
|
||||
// For each incident loops, insert a point on the loop, as far as
|
||||
// possible.
|
||||
for(Curve_index curve_index : incident_curves) {
|
||||
if(domain.is_loop(curve_index)) {
|
||||
FT curve_lenght = domain.curve_length(curve_index);
|
||||
FT curve_length = d_ptr->domain.curve_length(curve_index);
|
||||
Point_3 other_point =
|
||||
domain.construct_point_on_curve(pair.first,
|
||||
curve_index,
|
||||
curve_lenght / 2);
|
||||
dt.insert(other_point);
|
||||
d_ptr->domain.construct_point_on_curve(pair.first,
|
||||
curve_index,
|
||||
curve_length / 2);
|
||||
d_ptr->dt.insert(other_point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aabb_tree.empty())
|
||||
if (d_ptr->aabb_tree.empty())
|
||||
return;//there is no surface --> no surface patches
|
||||
|
||||
//fill incidences with patches
|
||||
curves_incident_patches.resize(domain.maximal_curve_index()+1);
|
||||
corners_incident_patches.resize(corners.size());
|
||||
d_ptr->curves_incident_patches.resize(domain.maximal_curve_index()+1);
|
||||
d_ptr->corners_incident_patches.resize(d_ptr->corners.size());
|
||||
for (Curve_index curve_id = 1;
|
||||
std::size_t(curve_id) < curves_incident_patches.size();
|
||||
std::size_t(curve_id) < d_ptr->curves_incident_patches.size();
|
||||
++curve_id)
|
||||
{
|
||||
const typename MeshDomain::Surface_patch_index_set& incident_patches =
|
||||
domain.get_incidences(curve_id);
|
||||
d_ptr->domain.get_incidences(curve_id);
|
||||
|
||||
// Fill `curves_incident_patches[curve_id]`
|
||||
curves_incident_patches[curve_id].
|
||||
d_ptr->curves_incident_patches[curve_id].
|
||||
insert(boost::container::ordered_unique_range,
|
||||
incident_patches.begin(), incident_patches.end());
|
||||
}
|
||||
for(const typename Corners_indices::value_type& pair :
|
||||
corners_indices)
|
||||
{
|
||||
for(const typename Corners_indices::value_type& pair : d_ptr->corners_indices) {
|
||||
// Get `corners_incident_curves[corner_id]`
|
||||
Curves_ids& incident_curves = corners_incident_curves[pair.second];
|
||||
Curves_ids& incident_curves = d_ptr->corners_incident_curves[pair.second];
|
||||
|
||||
// Fill `corners_incident_patches[corner_id]`
|
||||
Patches_ids& incident_patches = corners_incident_patches[pair.second];
|
||||
Patches_ids& incident_patches = d_ptr->corners_incident_patches[pair.second];
|
||||
for(Curve_index curve_index : incident_curves) {
|
||||
const Patches_ids& curve_incident_patches =
|
||||
curves_incident_patches[curve_index];
|
||||
d_ptr->curves_incident_patches[curve_index];
|
||||
incident_patches.insert(boost::container::ordered_unique_range,
|
||||
curve_incident_patches.begin(),
|
||||
curve_incident_patches.end());
|
||||
|
|
@ -166,6 +228,37 @@ struct Sizing_field_with_aabb_tree
|
|||
}
|
||||
}
|
||||
|
||||
boost::optional<Point_and_primitive_id>
|
||||
closest_point_on_surfaces(const Point_3& p,
|
||||
const Patches_ids& patch_ids_to_ignore) const
|
||||
{
|
||||
boost::optional<Point_and_primitive_id> result{};
|
||||
if(d_ptr->aabb_tree.empty()) return result;
|
||||
for(std::size_t i = 0; i < d_ptr->kd_trees_ptrs.size(); ++i) {
|
||||
const auto patch_id = static_cast<Patch_index>(i + d_ptr->min_patch_id);
|
||||
if(patch_ids_to_ignore.find(patch_id) != patch_ids_to_ignore.end()) continue;
|
||||
if(d_ptr->kd_trees_ptrs[i]) {
|
||||
const Kd_tree& kd_tree = *d_ptr->kd_trees_ptrs[i];
|
||||
const Point_and_primitive_id closest_point = kd_tree.closest_point(p);
|
||||
if(!result || CGAL::compare_distance(p, closest_point.first, result->first) == CGAL::SMALLER)
|
||||
{
|
||||
result = closest_point;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!result) return result;
|
||||
CGAL::Mesh_3::Filtered_projection_traits<
|
||||
AABB_traits,
|
||||
Facet_patch_id_map
|
||||
> projection_traits(*result,
|
||||
patch_ids_to_ignore.begin(), patch_ids_to_ignore.end(),
|
||||
d_ptr->aabb_tree.traits(),
|
||||
d_ptr->facet_patch_id_map);
|
||||
d_ptr->aabb_tree.traversal(p, projection_traits);
|
||||
result = projection_traits.closest_point_and_primitive();
|
||||
return result;
|
||||
}
|
||||
|
||||
double operator()(const Point_3& p,
|
||||
const int dim,
|
||||
const Index& id) const
|
||||
|
|
@ -177,9 +270,9 @@ struct Sizing_field_with_aabb_tree
|
|||
<< ", index=#" << CGAL::IO::oformat(id) << "): ";
|
||||
}
|
||||
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
double result = d_;
|
||||
double result = d_ptr->d_;
|
||||
if(dim == 0) {
|
||||
if(dt.dimension() < 1) {
|
||||
if(d_ptr->dt.dimension() < 1) {
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
std::cerr << result << "(dt.dimension() < 1)\n";
|
||||
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
|
|
@ -189,15 +282,15 @@ struct Sizing_field_with_aabb_tree
|
|||
|
||||
typename Dt::Locate_type lt;
|
||||
int li, lj;
|
||||
const typename Dt::Cell_handle ch = dt.locate(p, lt, li, lj);
|
||||
const typename Dt::Cell_handle ch = d_ptr->dt.locate(p, lt, li, lj);
|
||||
if(lt == Dt::VERTEX) {
|
||||
// std::cerr << "lt == Dt::VERTEX\n";
|
||||
const typename Dt::Vertex_handle vh = ch->vertex(li);
|
||||
std::vector<typename Dt::Vertex_handle> vs;
|
||||
vs.reserve(32);
|
||||
dt.finite_adjacent_vertices(vh, std::back_inserter(vs));
|
||||
d_ptr->dt.finite_adjacent_vertices(vh, std::back_inserter(vs));
|
||||
CGAL_assertion(!vs.empty());
|
||||
nearest = dt.point(vs[0]);
|
||||
nearest = d_ptr->dt.point(vs[0]);
|
||||
// std::cerr << "sq_dist = " << CGAL::squared_distance(p, nearest)
|
||||
// << std::endl;
|
||||
typename Kernel_::Compare_distance_3 compare_dist;
|
||||
|
|
@ -206,44 +299,38 @@ struct Sizing_field_with_aabb_tree
|
|||
{
|
||||
// std::cerr << "sq_dist = " << CGAL::squared_distance(p, dt.point(*it))
|
||||
// << std::endl;
|
||||
if(compare_dist(p, dt.point(*it), nearest) == CGAL::SMALLER) {
|
||||
if(compare_dist(p, d_ptr->dt.point(*it), nearest) == CGAL::SMALLER) {
|
||||
// std::cerr << " nearest!\n";
|
||||
nearest = dt.point(*it);
|
||||
nearest = d_ptr->dt.point(*it);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// std::cerr << "lt=" << lt << std::endl;
|
||||
const typename Dt::Vertex_handle vh = dt.nearest_vertex(p, ch);
|
||||
nearest = dt.point(vh);
|
||||
const typename Dt::Vertex_handle vh = d_ptr->dt.nearest_vertex(p, ch);
|
||||
nearest = d_ptr->dt.point(vh);
|
||||
}
|
||||
const FT dist = CGAL_NTS sqrt(CGAL::squared_distance( nearest, p));
|
||||
// std::cerr << (std::min)(dist / FT(1.5), d_) << "\n";
|
||||
result = (std::min)(dist / FT(2), result);
|
||||
|
||||
// now search in the AABB tree
|
||||
typename Corners_indices::const_iterator ids_it = corners_indices.find(p);
|
||||
if(ids_it == corners_indices.end()) {
|
||||
typename Corners_indices::const_iterator ids_it =
|
||||
d_ptr->corners_indices.find(p);
|
||||
if(ids_it == d_ptr->corners_indices.end()) {
|
||||
std::cerr << "ERROR at " << __FILE__ << " line " << __LINE__ << "\n";
|
||||
}
|
||||
else if(!aabb_tree.empty()) {
|
||||
const Patches_ids& ids = corners_incident_patches[ids_it->second];
|
||||
else if(!d_ptr->aabb_tree.empty()) {
|
||||
const Patches_ids& ids = d_ptr->corners_incident_patches[ids_it->second];
|
||||
CGAL_assertion(! ids.empty());
|
||||
|
||||
CGAL::Mesh_3::Filtered_projection_traits<
|
||||
typename Input_facets_AABB_tree_::AABB_traits,
|
||||
Facet_patch_id_map
|
||||
> projection_traits(ids.begin(), ids.end(),
|
||||
aabb_tree.traits(),
|
||||
facet_patch_id_map);
|
||||
const auto closest_point_and_primitive = closest_point_on_surfaces(p, ids);
|
||||
|
||||
aabb_tree.traversal(p, projection_traits);
|
||||
|
||||
if(projection_traits.found()) {
|
||||
if(closest_point_and_primitive != boost::none) {
|
||||
result =
|
||||
(std::min)(0.9 / CGAL::sqrt(CGAL::Mesh_3::internal::weight_modifier) *
|
||||
CGAL_NTS
|
||||
sqrt(CGAL::squared_distance(p,
|
||||
projection_traits.closest_point())),
|
||||
closest_point_and_primitive->first)),
|
||||
result);
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
{
|
||||
|
|
@ -258,10 +345,10 @@ struct Sizing_field_with_aabb_tree
|
|||
"Ids are { ")
|
||||
% group(setprecision(17),result)
|
||||
% group(setprecision(17),p)
|
||||
% CGAL::IO::oformat(get(facet_patch_id_map,
|
||||
projection_traits.closest_point_and_primitive().second))
|
||||
% CGAL::IO::oformat(get(d_ptr->facet_patch_id_map,
|
||||
closest_point_and_primitive->second))
|
||||
% group(setprecision(17),
|
||||
projection_traits.closest_point_and_primitive().first);
|
||||
closest_point_and_primitive->first);
|
||||
for(Patch_index i : ids) {
|
||||
s << CGAL::IO::oformat(i) << " ";
|
||||
}
|
||||
|
|
@ -285,37 +372,33 @@ struct Sizing_field_with_aabb_tree
|
|||
}
|
||||
else { // dim == 1
|
||||
const typename MeshDomain::Curve_index& curve_id =
|
||||
domain.curve_index(id);
|
||||
if(!aabb_tree.empty()) {
|
||||
const Patches_ids& ids = curves_incident_patches[curve_id];
|
||||
CGAL_assertion(! ids.empty());
|
||||
d_ptr->domain.curve_index(id);
|
||||
const Patches_ids& ids = d_ptr->curves_incident_patches[curve_id];
|
||||
CGAL_assertion(! ids.empty());
|
||||
|
||||
if(!d_ptr->aabb_tree.empty()) {
|
||||
//Compute distance to surface patches
|
||||
CGAL::Mesh_3::Filtered_projection_traits
|
||||
<
|
||||
typename Input_facets_AABB_tree_::AABB_traits
|
||||
, Facet_patch_id_map
|
||||
> projection_traits(ids.begin(), ids.end(),
|
||||
aabb_tree.traits(),
|
||||
facet_patch_id_map);
|
||||
|
||||
aabb_tree.traversal(p, projection_traits);
|
||||
|
||||
if(!projection_traits.found()) {
|
||||
const auto closest_point_and_primitive = closest_point_on_surfaces(p, ids);
|
||||
if(closest_point_and_primitive == boost::none) {
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
std::cerr << result << " (projection not found)\n";
|
||||
std::cerr << result << " (projection not found) ids:";
|
||||
for(Patch_index i : ids) {
|
||||
std::cerr << " " << CGAL::IO::oformat(i);
|
||||
}
|
||||
std::cerr << "\n";
|
||||
|
||||
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
return result;
|
||||
}
|
||||
|
||||
CGAL_assertion(ids.count(get(facet_patch_id_map,
|
||||
projection_traits.closest_point_and_primitive().second)) == 0);
|
||||
CGAL_assertion(ids.count(get(d_ptr->facet_patch_id_map,
|
||||
closest_point_and_primitive->second)) == 0);
|
||||
|
||||
result =
|
||||
(std::min)(0.9 / CGAL::sqrt(CGAL::Mesh_3::internal::weight_modifier) *
|
||||
CGAL_NTS
|
||||
sqrt(CGAL::squared_distance(p,
|
||||
projection_traits.closest_point())),
|
||||
closest_point_and_primitive->first)),
|
||||
result);
|
||||
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
|
|
@ -327,8 +410,8 @@ struct Sizing_field_with_aabb_tree
|
|||
"Closest face id: %4%\n"
|
||||
"Ids are { ")
|
||||
% result % p % curve_id
|
||||
% CGAL::IO::oformat(get(facet_patch_id_map,
|
||||
projection_traits.closest_point_and_primitive().second));
|
||||
% CGAL::IO::oformat(get(d_ptr->facet_patch_id_map,
|
||||
closest_point_and_primitive->second));
|
||||
for(Patch_index i : ids) {
|
||||
s << CGAL::IO::oformat(i) << " ";
|
||||
}
|
||||
|
|
@ -346,8 +429,8 @@ struct Sizing_field_with_aabb_tree
|
|||
"Closest face id: %4%\n"
|
||||
"Ids are { ")
|
||||
% result % p % curve_id
|
||||
% CGAL::IO::oformat(get(facet_patch_id_map,
|
||||
projection_traits.closest_point_and_primitive().second));
|
||||
% CGAL::IO::oformat(get(d_ptr->facet_patch_id_map,
|
||||
closest_point_and_primitive->second));
|
||||
for(Patch_index i : ids) {
|
||||
s << CGAL::IO::oformat(i) << " ";
|
||||
}
|
||||
|
|
@ -362,7 +445,7 @@ struct Sizing_field_with_aabb_tree
|
|||
"Closest face id: %4%\n"
|
||||
"Ids are { ")
|
||||
% result % p % curve_id
|
||||
% projection_traits.closest_point_and_primitive().second->patch_id();
|
||||
% closest_point_and_primitive->second->patch_id();
|
||||
for(Patch_index i : ids) {
|
||||
s << CGAL::IO::oformat(i) << " ";
|
||||
}
|
||||
|
|
@ -377,25 +460,25 @@ struct Sizing_field_with_aabb_tree
|
|||
CGAL::Mesh_3::Filtered_projection_traits<typename Input_curves_AABB_tree_::AABB_traits,
|
||||
Get_curve_index >
|
||||
curves_projection_traits(curve_id,
|
||||
domain.curves_aabb_tree().traits(),
|
||||
get_curve_index);
|
||||
d_ptr->domain.curves_aabb_tree().traits(),
|
||||
d_ptr->get_curve_index);
|
||||
|
||||
domain.curves_aabb_tree().traversal(p, curves_projection_traits);
|
||||
d_ptr->domain.curves_aabb_tree().traversal(p, curves_projection_traits);
|
||||
|
||||
//Compute distance to the curve on which p lies
|
||||
typedef typename GeomTraits::Segment_3 Segment_3;
|
||||
typedef typename GeomTraits::Plane_3 Plane_3;
|
||||
|
||||
const typename Input_curves_AABB_tree_::Point_and_primitive_id& ppid
|
||||
= domain.curves_aabb_tree().closest_point_and_primitive(p);
|
||||
= d_ptr->domain.curves_aabb_tree().closest_point_and_primitive(p);
|
||||
|
||||
Segment_3 curr_segment(*ppid.second.second, *(ppid.second.second + 1));
|
||||
Plane_3 curr_ortho_plane(p, curr_segment.to_vector()/*normal*/);
|
||||
Input_curves_AABB_tree_primitive_ curr_prim(ppid.second);
|
||||
|
||||
std::vector<Input_curves_AABB_tree_primitive_> prims;
|
||||
domain.curves_aabb_tree().all_intersected_primitives(curr_ortho_plane,
|
||||
std::back_inserter(prims));
|
||||
d_ptr->domain.curves_aabb_tree().
|
||||
all_intersected_primitives(curr_ortho_plane, std::back_inserter(prims));
|
||||
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
std::cerr << std::endl;
|
||||
|
|
@ -421,12 +504,12 @@ struct Sizing_field_with_aabb_tree
|
|||
if (const Point_3* pp = boost::get<Point_3>(&*int_res))
|
||||
{
|
||||
FT new_sqd = CGAL::squared_distance(p, *pp);
|
||||
FT gdist = CGAL::abs(domain.signed_geodesic_distance(p, *pp, curve_id));
|
||||
FT dist = CGAL::abs(d_ptr->domain.signed_geodesic_distance(p, *pp, curve_id));
|
||||
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
std::cerr << "Intersection point : Point_3(" << *pp << ") ";
|
||||
std::cerr << "\n new_sqd = " << new_sqd ;
|
||||
std::cerr << "\n gdist = " << gdist << "\n";
|
||||
std::cerr << "\n dist = " << dist << "\n";
|
||||
#endif
|
||||
if (new_sqd * 1e10 < CGAL::squared_distance(curr_segment.source(),
|
||||
curr_segment.target()))
|
||||
|
|
@ -437,7 +520,7 @@ struct Sizing_field_with_aabb_tree
|
|||
#endif
|
||||
continue;
|
||||
}
|
||||
if (CGAL_NTS sqrt(new_sqd) > 0.9 * gdist)
|
||||
if (CGAL_NTS sqrt(new_sqd) > 0.9 * dist)
|
||||
continue;
|
||||
if (sqd_intersection == -1 || new_sqd < sqd_intersection)
|
||||
{
|
||||
|
|
@ -468,7 +551,7 @@ struct Sizing_field_with_aabb_tree
|
|||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
std::cout << " curve_id = " << curve_id
|
||||
<< " proj_cid = " << closest_primitive.id().first->first
|
||||
<< " (" << get(get_curve_index, closest_primitive.id()) << ")"
|
||||
<< " (" << get(d_ptr->get_curve_index, closest_primitive.id()) << ")"
|
||||
<< std::endl;
|
||||
std::cerr << " --- domain.curves_aabb_tree().traversal \n";
|
||||
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
|
|
@ -482,7 +565,7 @@ struct Sizing_field_with_aabb_tree
|
|||
double new_result =
|
||||
(std::min)(0.45 / CGAL::sqrt(CGAL::Mesh_3::internal::weight_modifier) *
|
||||
CGAL_NTS sqrt(sqd_intersection),
|
||||
d_);
|
||||
d_ptr->d_);
|
||||
|
||||
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
|
||||
std::cerr << "result = " << result << "\n";
|
||||
|
|
@ -515,17 +598,34 @@ struct Sizing_field_with_aabb_tree
|
|||
return result;
|
||||
}
|
||||
private:
|
||||
typename Kernel_::FT d_;
|
||||
const Input_facets_AABB_tree_& aabb_tree;
|
||||
const MeshDomain& domain;
|
||||
Dt dt;
|
||||
Corners corners;
|
||||
Corners_indices corners_indices;
|
||||
Curves_incident_patches curves_incident_patches;
|
||||
Corners_incident_patches corners_incident_patches;
|
||||
Corners_incident_curves corners_incident_curves;
|
||||
Get_curve_index get_curve_index;
|
||||
Facet_patch_id_map facet_patch_id_map;
|
||||
using Kd_tree = CGAL::AABB_search_tree<AABB_traits>;
|
||||
struct Private_data {
|
||||
using FT = typename Kernel_::FT;
|
||||
Private_data(FT d, const Input_facets_AABB_tree_& aabb_tree,
|
||||
const MeshDomain& domain,
|
||||
Get_curve_index get_curve_index,
|
||||
Facet_patch_id_map facet_patch_id_map)
|
||||
: d_(d)
|
||||
, aabb_tree(aabb_tree)
|
||||
, domain(domain)
|
||||
, get_curve_index(get_curve_index)
|
||||
, facet_patch_id_map(facet_patch_id_map)
|
||||
{}
|
||||
FT d_;
|
||||
const Input_facets_AABB_tree_& aabb_tree;
|
||||
const MeshDomain& domain;
|
||||
Get_curve_index get_curve_index;
|
||||
Facet_patch_id_map facet_patch_id_map;
|
||||
Dt dt{};
|
||||
Corners corners{};
|
||||
Corners_indices corners_indices{};
|
||||
Curves_incident_patches curves_incident_patches{};
|
||||
Corners_incident_patches corners_incident_patches{};
|
||||
Corners_incident_curves corners_incident_curves{};
|
||||
std::vector<std::unique_ptr<Kd_tree>> kd_trees_ptrs{};
|
||||
Patch_index min_patch_id{};
|
||||
};
|
||||
std::shared_ptr<Private_data> d_ptr;
|
||||
};
|
||||
|
||||
#endif // CGAL_MESH_3_SIZING_FIELD_WITH_AABB_TREE_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,235 @@
|
|||
// Copyright (c) 2022 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
//
|
||||
//******************************************************************************
|
||||
//
|
||||
//******************************************************************************
|
||||
|
||||
|
||||
#ifndef CGAL_MESH_3_FEATURES_DETECTION_COMBINATIONS_H
|
||||
#define CGAL_MESH_3_FEATURES_DETECTION_COMBINATIONS_H
|
||||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
namespace Mesh_3
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
const std::array<std::uint8_t, 8> combinations[]
|
||||
= {
|
||||
// 1 color
|
||||
{0,0,0,0,0,0,0,0}, //0
|
||||
// 2 colors
|
||||
{0,0,0,0,0,0,0,1}, //1
|
||||
{0,0,0,0,0,0,1,1}, //2
|
||||
// 3 colors
|
||||
{0,0,0,0,0,0,1,2}, //3
|
||||
{0,0,0,0,0,1,1,0},
|
||||
{0,0,0,0,0,1,1,1},
|
||||
{0,0,0,0,0,1,1,2},
|
||||
{0,0,0,0,0,1,2,0},
|
||||
{0,0,0,0,0,1,2,1},
|
||||
{0,0,0,0,1,1,1,1},
|
||||
{0,0,0,0,1,1,1,2},
|
||||
{0,0,0,0,1,1,2,2},
|
||||
{0,0,0,0,1,2,2,1},
|
||||
{0,0,0,1,0,1,1,0},
|
||||
{0,0,0,1,0,1,1,1},
|
||||
{0,0,0,1,0,1,1,2},
|
||||
{0,0,0,1,0,1,2,0},
|
||||
{0,0,0,1,0,1,2,1},
|
||||
{0,0,0,1,0,1,2,2},
|
||||
{0,0,0,1,1,0,0,0},
|
||||
{0,0,0,1,1,0,0,1},
|
||||
{0,0,0,1,1,0,0,2},
|
||||
{0,0,0,1,1,0,1,1},
|
||||
{0,0,0,1,1,0,1,2},
|
||||
{0,0,0,1,1,0,2,2},
|
||||
{0,0,0,1,1,1,1,0},
|
||||
{0,0,0,1,1,1,1,2},
|
||||
{0,0,0,1,1,1,2,0},
|
||||
{0,0,0,1,1,1,2,1},
|
||||
{0,0,0,1,1,1,2,2},
|
||||
{0,0,0,1,1,2,2,0},
|
||||
{0,0,0,1,1,2,2,1},
|
||||
{0,0,0,1,1,2,2,2},
|
||||
{0,0,0,1,2,0,0,0},
|
||||
{0,0,0,1,2,0,0,1},
|
||||
{0,0,0,1,2,0,0,2},
|
||||
{0,0,0,1,2,0,1,2},
|
||||
{0,0,0,1,2,0,2,1},
|
||||
{0,0,0,1,2,1,1,0},
|
||||
{0,0,0,1,2,1,1,2},
|
||||
{0,0,0,1,2,1,2,0},
|
||||
{0,0,0,1,2,1,2,1},
|
||||
{0,0,0,1,2,1,2,2},
|
||||
{0,0,0,1,2,2,2,1},
|
||||
{0,0,1,1,1,1,0,0},
|
||||
{0,0,1,1,1,1,0,2},
|
||||
{0,0,1,1,1,1,2,2},
|
||||
{0,0,1,1,1,2,0,2},
|
||||
{0,0,1,1,1,2,2,0},
|
||||
{0,0,1,2,1,2,0,0},
|
||||
{0,0,1,2,1,2,0,1},
|
||||
{0,0,1,2,1,2,2,1},
|
||||
{0,0,1,2,2,1,0,0},
|
||||
{0,0,1,2,2,1,0,1},
|
||||
{0,1,1,0,1,0,0,1},
|
||||
{0,1,1,0,1,0,0,2},
|
||||
{0,1,1,0,1,2,2,1},
|
||||
{0,1,1,2,1,2,2,0}, //57
|
||||
// 4 colors
|
||||
{0,0,0,0,0,1,2,3}, //58
|
||||
{0,0,0,0,1,1,2,3},
|
||||
{0,0,0,0,1,2,2,3},
|
||||
{0,0,0,1,0,1,2,3},
|
||||
{0,0,0,1,0,2,3,0},
|
||||
{0,0,0,1,0,2,3,1},
|
||||
{0,0,0,1,1,0,2,3},
|
||||
{0,0,0,1,1,1,2,3},
|
||||
{0,0,0,1,1,2,2,3},
|
||||
{0,0,0,1,1,2,3,0},
|
||||
{0,0,0,1,1,2,3,1},
|
||||
{0,0,0,1,1,2,3,2},
|
||||
{0,0,0,1,2,0,0,3},
|
||||
{0,0,0,1,2,0,1,3},
|
||||
{0,0,0,1,2,0,2,3},
|
||||
{0,0,0,1,2,0,3,3},
|
||||
{0,0,0,1,2,1,1,3},
|
||||
{0,0,0,1,2,1,2,3},
|
||||
{0,0,0,1,2,1,3,0},
|
||||
{0,0,0,1,2,1,3,1},
|
||||
{0,0,0,1,2,1,3,2},
|
||||
{0,0,0,1,2,1,3,3},
|
||||
{0,0,0,1,2,2,2,3},
|
||||
{0,0,0,1,2,2,3,0},
|
||||
{0,0,0,1,2,2,3,1},
|
||||
{0,0,0,1,2,2,3,2},
|
||||
{0,0,0,1,2,2,3,3},
|
||||
{0,0,0,1,2,3,3,0},
|
||||
{0,0,0,1,2,3,3,1},
|
||||
{0,0,0,1,2,3,3,2},
|
||||
{0,0,0,1,2,3,3,3},
|
||||
{0,0,1,1,1,1,2,3},
|
||||
{0,0,1,1,1,2,0,3},
|
||||
{0,0,1,1,1,2,2,3},
|
||||
{0,0,1,1,1,2,3,0},
|
||||
{0,0,1,1,1,2,3,2},
|
||||
{0,0,1,1,1,2,3,3},
|
||||
{0,0,1,1,2,2,3,3},
|
||||
{0,0,1,1,2,3,2,3},
|
||||
{0,0,1,1,2,3,3,2},
|
||||
{0,0,1,2,1,2,0,3},
|
||||
{0,0,1,2,1,2,2,3},
|
||||
{0,0,1,2,1,2,3,3},
|
||||
{0,0,1,2,1,3,0,0},
|
||||
{0,0,1,2,1,3,0,1},
|
||||
{0,0,1,2,1,3,0,2},
|
||||
{0,0,1,2,1,3,2,0},
|
||||
{0,0,1,2,1,3,2,1},
|
||||
{0,0,1,2,1,3,2,3},
|
||||
{0,0,1,2,2,1,0,3},
|
||||
{0,0,1,2,2,1,1,3},
|
||||
{0,0,1,2,2,1,3,3},
|
||||
{0,0,1,2,2,3,0,0},
|
||||
{0,0,1,2,2,3,0,1},
|
||||
{0,0,1,2,2,3,0,2},
|
||||
{0,0,1,2,2,3,1,3},
|
||||
{0,0,1,2,2,3,3,1},
|
||||
{0,1,1,0,1,0,2,3},
|
||||
{0,1,1,0,1,2,2,3},
|
||||
{0,1,1,0,1,2,3,1},
|
||||
{0,1,1,0,2,3,3,2},
|
||||
{0,1,1,2,1,2,2,3},
|
||||
{0,1,1,2,1,2,3,0},
|
||||
{0,1,1,2,2,3,3,0},
|
||||
{0,1,1,2,3,0,2,3},
|
||||
{0,1,2,3,3,2,1,0}, //123
|
||||
// 5 colors
|
||||
{0,0,0,0,1,2,3,4}, //124
|
||||
{0,0,0,1,0,2,3,4},
|
||||
{0,0,0,1,1,2,3,4},
|
||||
{0,0,0,1,2,0,3,4},
|
||||
{0,0,0,1,2,1,3,4},
|
||||
{0,0,0,1,2,2,3,4},
|
||||
{0,0,0,1,2,3,3,4},
|
||||
{0,0,0,1,2,3,4,0},
|
||||
{0,0,0,1,2,3,4,1},
|
||||
{0,0,0,1,2,3,4,2},
|
||||
{0,0,0,1,2,3,4,3},
|
||||
{0,0,1,1,1,2,3,4},
|
||||
{0,0,1,1,2,2,3,4},
|
||||
{0,0,1,1,2,3,2,4},
|
||||
{0,0,1,1,2,3,3,4},
|
||||
{0,0,1,2,1,2,3,4},
|
||||
{0,0,1,2,1,3,0,4},
|
||||
{0,0,1,2,1,3,2,4},
|
||||
{0,0,1,2,1,3,4,0},
|
||||
{0,0,1,2,1,3,4,1},
|
||||
{0,0,1,2,1,3,4,2},
|
||||
{0,0,1,2,1,3,4,4},
|
||||
{0,0,1,2,2,1,3,4},
|
||||
{0,0,1,2,2,3,0,4},
|
||||
{0,0,1,2,2,3,1,4},
|
||||
{0,0,1,2,2,3,2,4},
|
||||
{0,0,1,2,2,3,3,4},
|
||||
{0,0,1,2,2,3,4,4},
|
||||
{0,0,1,2,3,4,0,0},
|
||||
{0,0,1,2,3,4,0,1},
|
||||
{0,0,1,2,3,4,1,4},
|
||||
{0,0,1,2,3,4,2,1},
|
||||
{0,0,1,2,3,4,2,3},
|
||||
{0,1,1,0,1,2,3,4},
|
||||
{0,1,1,0,2,3,3,4},
|
||||
{0,1,1,2,1,2,3,4},
|
||||
{0,1,1,2,1,3,4,0},
|
||||
{0,1,1,2,1,3,4,1},
|
||||
{0,1,1,2,2,0,3,4},
|
||||
{0,1,1,2,2,3,3,4},
|
||||
{0,1,1,2,2,3,4,0},
|
||||
{0,1,1,2,3,0,2,4},
|
||||
{0,1,2,3,3,2,1,4}, //166
|
||||
// 6 colors
|
||||
{0,0,0,1,2,3,4,5}, //167
|
||||
{0,0,1,1,2,3,4,5},
|
||||
{0,0,1,2,1,3,4,5},
|
||||
{0,0,1,2,2,3,4,5},
|
||||
{0,0,1,2,3,4,0,5},
|
||||
{0,0,1,2,3,4,1,5},
|
||||
{0,0,1,2,3,4,2,5},
|
||||
{0,0,1,2,3,4,5,5},
|
||||
{0,1,1,0,2,3,4,5},
|
||||
{0,1,1,2,1,3,4,5},
|
||||
{0,1,1,2,2,3,4,5},
|
||||
{0,1,1,2,3,0,4,5},
|
||||
{0,1,1,2,3,4,4,5},
|
||||
{0,1,1,2,3,4,5,3},
|
||||
{0,1,2,3,3,2,4,5}, //181
|
||||
// 7 colors
|
||||
{0,0,1,2,3,4,5,6}, //182
|
||||
{0,1,1,2,3,4,5,6},
|
||||
{0,1,2,3,3,4,5,6}, //184
|
||||
// 8 colors
|
||||
{0,1,2,3,4,5,6,7} //185
|
||||
|
||||
};
|
||||
|
||||
}//end namespace internal
|
||||
}//end namespace Mesh_3
|
||||
}//end namespace CGAL
|
||||
|
||||
|
||||
#endif // CGAL_MESH_3_FEATURES_DETECTION_COMBINATIONS_H
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2022 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
//
|
||||
//******************************************************************************
|
||||
//
|
||||
//******************************************************************************
|
||||
|
||||
|
||||
#ifndef CGAL_MESH_3_FEATURES_DETECTION_COORDINATES_H
|
||||
#define CGAL_MESH_3_FEATURES_DETECTION_COORDINATES_H
|
||||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
namespace Mesh_3
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
using Coordinates = std::array<int, 3>;
|
||||
constexpr Coordinates coordinates[8] = { {0, 0, 0},
|
||||
{1, 0, 0},
|
||||
{0, 1, 0},
|
||||
{1, 1, 0},
|
||||
{0, 0, 1},
|
||||
{1, 0, 1},
|
||||
{0, 1, 1},
|
||||
{1, 1, 1} };
|
||||
|
||||
inline Coordinates minus(const Coordinates& b, const Coordinates& a) {
|
||||
return { b[0] - a[0], b[1] - a[1], b[2] - a[2] };
|
||||
}
|
||||
|
||||
inline Coordinates cross(Coordinates a, Coordinates b) {
|
||||
return { a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] };
|
||||
}
|
||||
|
||||
inline Coordinates square(Coordinates c) {
|
||||
return { c[0] * c[0], c[1] * c[1], c[2] * c[2] };
|
||||
}
|
||||
|
||||
inline int dist(Coordinates a, Coordinates b) {
|
||||
auto s = square(minus(b, a));
|
||||
return s[0] + s[1] + s[2];
|
||||
}
|
||||
|
||||
}//end namespace internal
|
||||
}//end namespace Mesh_3
|
||||
}//end namespace CGAL
|
||||
|
||||
#endif // CGAL_MESH_3_FEATURES_DETECTION_COORDINATES_H
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2022 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
//
|
||||
//******************************************************************************
|
||||
//
|
||||
//******************************************************************************
|
||||
|
||||
#ifndef CGAL_MESH_3_FEATURES_DETECTION_CUBE_ISOMETRIES_H
|
||||
#define CGAL_MESH_3_FEATURES_DETECTION_CUBE_ISOMETRIES_H
|
||||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
namespace Mesh_3
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
using Permutation = std::array<std::uint8_t, 8>;
|
||||
|
||||
constexpr Permutation cube_isometries[] = {
|
||||
{0,1,2,3,4,5,6,7},
|
||||
{1,0,3,2,5,4,7,6},
|
||||
{4,5,0,1,6,7,2,3},
|
||||
{5,4,1,0,7,6,3,2},
|
||||
{6,7,4,5,2,3,0,1},
|
||||
{7,6,5,4,3,2,1,0},
|
||||
{2,3,6,7,0,1,4,5},
|
||||
{3,2,7,6,1,0,5,4},
|
||||
{1,5,3,7,0,4,2,6},
|
||||
{5,1,7,3,4,0,6,2},
|
||||
{5,4,7,6,1,0,3,2},
|
||||
{4,5,6,7,0,1,2,3},
|
||||
{4,0,6,2,5,1,7,3},
|
||||
{0,4,2,6,1,5,3,7},
|
||||
{1,3,0,2,5,7,4,6},
|
||||
{3,1,2,0,7,5,6,4},
|
||||
{3,2,1,0,7,6,5,4},
|
||||
{2,3,0,1,6,7,4,5},
|
||||
{2,0,3,1,6,4,7,5},
|
||||
{0,2,1,3,4,6,5,7},
|
||||
{1,0,5,4,3,2,7,6},
|
||||
{0,1,4,5,2,3,6,7},
|
||||
{7,3,5,1,6,2,4,0},
|
||||
{3,7,1,5,2,6,0,4},
|
||||
{7,6,3,2,5,4,1,0},
|
||||
{6,7,2,3,4,5,0,1},
|
||||
{2,6,0,4,3,7,1,5},
|
||||
{6,2,4,0,7,3,5,1},
|
||||
{4,6,5,7,0,2,1,3},
|
||||
{6,4,7,5,2,0,3,1},
|
||||
{7,5,6,4,3,1,2,0},
|
||||
{5,7,4,6,1,3,0,2},
|
||||
{0,4,1,5,2,6,3,7},
|
||||
{4,0,5,1,6,2,7,3},
|
||||
{3,1,7,5,2,0,6,4},
|
||||
{1,3,5,7,0,2,4,6},
|
||||
{5,7,1,3,4,6,0,2},
|
||||
{7,5,3,1,6,4,2,0},
|
||||
{3,7,2,6,1,5,0,4},
|
||||
{7,3,6,2,5,1,4,0},
|
||||
{0,2,4,6,1,3,5,7},
|
||||
{2,0,6,4,3,1,7,5},
|
||||
{5,1,4,0,7,3,6,2},
|
||||
{1,5,0,4,3,7,2,6},
|
||||
{6,2,7,3,4,0,5,1},
|
||||
{2,6,3,7,0,4,1,5},
|
||||
{6,4,2,0,7,5,3,1},
|
||||
{4,6,0,2,5,7,1,3}
|
||||
};
|
||||
|
||||
constexpr int num_isometries = 48;
|
||||
|
||||
}//end namespace internal
|
||||
}//end namespace Mesh_3
|
||||
}//end namespace CGAL
|
||||
|
||||
#endif // CGAL_MESH_3_FEATURES_DETECTION_CUBE_ISOMETRIES_H
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2022 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot, Jane Tournois
|
||||
//
|
||||
//******************************************************************************
|
||||
//
|
||||
//******************************************************************************
|
||||
|
||||
|
||||
#ifndef CGAL_MESH_3_FEATURES_DETECTION_HELPERS_H
|
||||
#define CGAL_MESH_3_FEATURES_DETECTION_HELPERS_H
|
||||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
namespace Mesh_3
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template<typename Word_type, bool b = (sizeof(Word_type) > 1)>
|
||||
struct Color_transformation_helper
|
||||
{
|
||||
using type = std::unordered_map<Word_type, std::uint8_t>;
|
||||
static void reset(type& t)
|
||||
{
|
||||
t.clear();
|
||||
}
|
||||
static bool is_valid(const type& t, const Word_type& w)
|
||||
{
|
||||
return t.find(w) != t.end();
|
||||
}
|
||||
};
|
||||
template<typename Word_type>
|
||||
struct Color_transformation_helper<Word_type, false>
|
||||
{
|
||||
using type = std::array<std::uint8_t, (1 << (sizeof(Word_type) * 8))>;
|
||||
static void reset(type& t)
|
||||
{
|
||||
std::fill(t.begin(), t.end(), 8/*invalid_word*/);
|
||||
}
|
||||
static bool is_valid(const type& t, const Word_type& w)
|
||||
{
|
||||
return t[w] != 8;/*invalid_word*/
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Array>
|
||||
void debug_cerr(const char* title, const Array& tab)
|
||||
{
|
||||
std::cerr << title << " [";
|
||||
for (const auto t : tab)
|
||||
std::cout << std::to_string(t) << " ";
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
||||
}//end namespace internal
|
||||
}//end namespace Mesh_3
|
||||
}//end namespace CGAL
|
||||
|
||||
#endif // CGAL_MESH_3_FEATURES_DETECTION_HELPERS_H
|
||||
|
|
@ -309,9 +309,9 @@ CGAL::Image_3 generate_label_weights_with_known_word_type(const CGAL::Image_3& i
|
|||
* @returns a `CGAL::Image_3` of weights used to build a quality `Labeled_mesh_domain_3`,
|
||||
* with the same dimensions as `image`
|
||||
*/
|
||||
|
||||
inline
|
||||
CGAL::Image_3 generate_label_weights(const CGAL::Image_3& image,
|
||||
const float& sigma)
|
||||
const float& sigma)
|
||||
{
|
||||
CGAL_IMAGE_IO_CASE(image.image(),
|
||||
return generate_label_weights_with_known_word_type<Word>(image, sigma);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include <CGAL/license/Mesh_3.h>
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <utility> // std::swap
|
||||
|
|
@ -23,17 +22,23 @@
|
|||
|
||||
#include <CGAL/tuple.h>
|
||||
#include <CGAL/Image_3.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
#include <CGAL/squared_distance_3.h>
|
||||
|
||||
#include <CGAL/boost/graph/split_graph_into_polylines.h>
|
||||
#include <CGAL/Mesh_3/internal/Graph_manipulations.h>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <CGAL/Labeled_mesh_domain_3.h> // for CGAL::Null_subdomain_index
|
||||
#include <CGAL/number_utils.h>
|
||||
|
||||
#include <boost/utility.hpp> // for boost::prior
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <CGAL/Search_traits_3.h>
|
||||
#include <CGAL/Orthogonal_incremental_neighbor_search.h>
|
||||
|
||||
#include <CGAL/Mesh_3/Null_subdomain_index.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Mesh_3 {
|
||||
namespace internal {
|
||||
|
|
@ -1128,6 +1133,63 @@ polylines_to_protect(const CGAL::Image_3& cgal_image,
|
|||
existing_polylines_end);
|
||||
}
|
||||
|
||||
|
||||
template <typename PolylineRange1, typename PolylineRange2>
|
||||
void
|
||||
merge_and_snap_polylines(const CGAL::Image_3& image,
|
||||
PolylineRange1& polylines_to_snap,
|
||||
const PolylineRange2& existing_polylines)
|
||||
{
|
||||
static_assert(std::is_same<typename PolylineRange1::value_type::value_type,
|
||||
typename PolylineRange2::value_type::value_type>::value,
|
||||
"Polyline ranges should have same point type");
|
||||
using P = typename PolylineRange1::value_type::value_type;
|
||||
using K = typename Kernel_traits<P>::Kernel;
|
||||
|
||||
using CGAL::internal::polylines_to_protect_namespace::Vertex_info;
|
||||
using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,
|
||||
Vertex_info<P> >;
|
||||
using vertex_descriptor = typename boost::graph_traits<Graph>::vertex_descriptor;
|
||||
|
||||
// build graph of polylines_to_snap
|
||||
Graph graph;
|
||||
typedef Mesh_3::internal::Returns_midpoint<K, int> Midpoint_fct;
|
||||
Mesh_3::internal::Graph_manipulations<Graph,
|
||||
P,
|
||||
int,
|
||||
Midpoint_fct> g_manip(graph);
|
||||
|
||||
for (const auto& polyline : polylines_to_snap)
|
||||
{
|
||||
if (polyline.size() < 2)
|
||||
continue;
|
||||
|
||||
auto pit = polyline.begin();
|
||||
while (boost::next(pit) != polyline.end())
|
||||
{
|
||||
vertex_descriptor v = g_manip.get_vertex(*pit, false);
|
||||
vertex_descriptor w = g_manip.get_vertex(*boost::next(pit), false);
|
||||
g_manip.try_add_edge(v, w);
|
||||
++pit;
|
||||
}
|
||||
}
|
||||
|
||||
// snap graph to existing_polylines
|
||||
snap_graph_vertices(graph,
|
||||
image.vx(), image.vy(), image.vz(),
|
||||
boost::begin(existing_polylines), boost::end(existing_polylines),
|
||||
K());
|
||||
|
||||
// rebuild polylines_to_snap
|
||||
polylines_to_snap.clear();
|
||||
Mesh_3::Polyline_visitor<P, Graph> visitor(polylines_to_snap, graph);
|
||||
Less_for_Graph_vertex_descriptors<Graph> less(graph);
|
||||
const Graph& const_graph = graph;
|
||||
Mesh_3::Angle_tester<K> angle_tester(90.);
|
||||
split_graph_into_polylines(const_graph, visitor, angle_tester, less);
|
||||
}
|
||||
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_MESH_3_POLYLINES_TO_PROTECT_H
|
||||
|
|
|
|||
|
|
@ -232,6 +232,13 @@ struct C3t3_initializer < C3T3, MD, MC, true, CGAL::Tag_true >
|
|||
if (c3t3.number_of_facets() == 0) {
|
||||
need_more_init = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
helper.update_restricted_cells();
|
||||
if(c3t3.number_of_cells() == 0) {
|
||||
need_more_init = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(need_more_init) {
|
||||
init_c3t3(c3t3, domain, criteria,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ create_single_source_cgal_program( "test_without_detect_features.cpp" )
|
|||
if(CGAL_ImageIO_USE_ZLIB)
|
||||
create_single_source_cgal_program( "test_meshing_3D_image.cpp" )
|
||||
create_single_source_cgal_program( "test_meshing_3D_image_deprecated.cpp" )
|
||||
create_single_source_cgal_program( "test_meshing_3D_image_with_features.cpp" )
|
||||
create_single_source_cgal_program( "test_meshing_3D_gray_image.cpp" )
|
||||
create_single_source_cgal_program( "test_meshing_3D_gray_image_deprecated.cpp" )
|
||||
else()
|
||||
|
|
@ -64,6 +65,7 @@ foreach(target
|
|||
test_without_detect_features
|
||||
test_meshing_3D_image
|
||||
test_meshing_3D_image_deprecated
|
||||
test_meshing_3D_image_with_features
|
||||
test_meshing_3D_gray_image
|
||||
test_meshing_3D_gray_image_deprecated
|
||||
test_meshing_implicit_function
|
||||
|
|
|
|||
|
|
@ -0,0 +1,199 @@
|
|||
// Copyright (c) 2009 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Stephane Tayeb, Jane Tournois
|
||||
//
|
||||
//******************************************************************************
|
||||
// File Description :
|
||||
//******************************************************************************
|
||||
|
||||
#include "test_meshing_utilities.h"
|
||||
#include <CGAL/Image_3.h>
|
||||
#include <CGAL/Labeled_mesh_domain_3.h>
|
||||
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
|
||||
#include <CGAL/Mesh_3/Detect_features_in_image.h>
|
||||
#include <CGAL/Mesh_3/Detect_features_on_image_bbox.h>
|
||||
#include <CGAL/use.h>
|
||||
#include <vector>
|
||||
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
|
||||
template <typename Point_3>
|
||||
bool read_polylines(const std::string fname,
|
||||
std::vector<std::vector<Point_3> >& polylines)
|
||||
{
|
||||
std::ifstream ifs(fname);
|
||||
if(ifs.bad()) return false;
|
||||
std::size_t n;
|
||||
while(ifs >> n) {
|
||||
polylines.resize(polylines.size()+1);
|
||||
std::vector<Point_3>& polyline = polylines.back();
|
||||
while(n-- != 0) {
|
||||
Point_3 p;
|
||||
ifs >> p;
|
||||
if(ifs.fail()) return false;
|
||||
polyline.push_back(p);
|
||||
}
|
||||
}
|
||||
if(ifs.bad()) return false;
|
||||
else return ifs.eof();
|
||||
}
|
||||
|
||||
template <typename Concurrency_tag = CGAL::Sequential_tag>
|
||||
struct Image_tester : public Tester<K_e_i>
|
||||
{
|
||||
typedef CGAL::Image_3 Image;
|
||||
typedef CGAL::Labeled_mesh_domain_3<K_e_i> Domain;
|
||||
typedef CGAL::Mesh_domain_with_polyline_features_3<Domain> Mesh_domain;
|
||||
|
||||
typedef typename CGAL::Mesh_triangulation_3<
|
||||
Mesh_domain,
|
||||
CGAL::Kernel_traits<Mesh_domain>::Kernel,
|
||||
Concurrency_tag>::type Tr;
|
||||
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
|
||||
|
||||
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
|
||||
|
||||
void mesh_and_verify(Mesh_domain& domain, const Image& image, const double volume) const
|
||||
{
|
||||
namespace p = CGAL::parameters;
|
||||
// Set mesh criteria
|
||||
Mesh_criteria criteria(p::edge_size = 2 * image.vx(),
|
||||
p::facet_angle = 30,
|
||||
p::facet_size = 20 * image.vx(),
|
||||
p::facet_distance = 5 * image.vx(),
|
||||
p::cell_radius_edge_ratio = 3.,
|
||||
p::cell_size = 25 * image.vx());
|
||||
|
||||
// Mesh generation
|
||||
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria,
|
||||
CGAL::parameters::no_exude(),
|
||||
CGAL::parameters::no_perturb());
|
||||
|
||||
c3t3.remove_isolated_vertices();
|
||||
|
||||
// Verify
|
||||
this->verify_c3t3_volume(c3t3, volume * 0.95, volume * 1.05);
|
||||
this->verify(c3t3, domain, criteria, Bissection_tag());
|
||||
|
||||
typedef typename Mesh_domain::Surface_patch_index Patch_id;
|
||||
CGAL_static_assertion(CGAL::Output_rep<Patch_id>::is_specialized);
|
||||
CGAL_USE_TYPE(Patch_id);
|
||||
}
|
||||
|
||||
public:
|
||||
void image() const
|
||||
{
|
||||
namespace p = CGAL::parameters;
|
||||
std::cout << "\tSeed is\t"
|
||||
<< CGAL::get_default_random().get_seed() << std::endl;
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Data generation
|
||||
//-------------------------------------------------------
|
||||
Image image;
|
||||
image.read(CGAL::data_file_path("images/liver.inr.gz"));
|
||||
|
||||
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = image,
|
||||
p::relative_error_bound = 1e-9,
|
||||
CGAL::parameters::p_rng = &CGAL::get_default_random(),
|
||||
CGAL::parameters::features_detector = CGAL::Mesh_3::Detect_features_in_image());
|
||||
|
||||
mesh_and_verify(domain, image, 1772330.);
|
||||
}
|
||||
|
||||
void image_in_bbox() const
|
||||
{
|
||||
namespace p = CGAL::parameters;
|
||||
std::cout << "\tSeed is\t"
|
||||
<< CGAL::get_default_random().get_seed() << std::endl;
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Data generation
|
||||
//-------------------------------------------------------
|
||||
Image image;
|
||||
image.read(CGAL::data_file_path("images/40420.inr"));
|
||||
|
||||
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = image,
|
||||
p::relative_error_bound = 1e-9,
|
||||
CGAL::parameters::p_rng = &CGAL::get_default_random(),
|
||||
CGAL::parameters::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox());
|
||||
|
||||
mesh_and_verify(domain, image, 625044.);
|
||||
}
|
||||
|
||||
void image_with_input_features() const
|
||||
{
|
||||
namespace p = CGAL::parameters;
|
||||
std::cout << "\tSeed is\t"
|
||||
<< CGAL::get_default_random().get_seed() << std::endl;
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Data generation
|
||||
//-------------------------------------------------------
|
||||
Image image;
|
||||
image.read(CGAL::data_file_path("images/40420.inr"));
|
||||
|
||||
const std::string lines_fname = CGAL::data_file_path("images/420.polylines.txt");
|
||||
using Point_3 = Domain::Point_3;
|
||||
std::vector<std::vector<Point_3> > features_input;
|
||||
if (!read_polylines(lines_fname, features_input)) // see file "read_polylines.h"
|
||||
assert(false);
|
||||
|
||||
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = image,
|
||||
p::relative_error_bound = 1e-9,
|
||||
CGAL::parameters::p_rng = &CGAL::get_default_random(),
|
||||
CGAL::parameters::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox(),
|
||||
CGAL::parameters::input_features = std::cref(features_input));
|
||||
|
||||
mesh_and_verify(domain, image, 632091.);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
Image_tester<> test_epic;
|
||||
std::cerr << "Mesh generation from a 3D image"
|
||||
<< " with detection of triple lines:\n";
|
||||
test_epic.image();
|
||||
|
||||
std::cerr << "Mesh generation from a 3D image"
|
||||
<< " with detection of triple lines on bbox only:\n";
|
||||
test_epic.image_in_bbox();
|
||||
|
||||
std::cerr << "Mesh generation from a 3D image"
|
||||
<< " with detection of triple lines on bbox"
|
||||
<< " and input feature polylines:\n";
|
||||
test_epic.image_with_input_features();
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
Image_tester<CGAL::Parallel_tag> test_epic_p;
|
||||
std::cerr << "Parallel mesh generation from a 3D image"
|
||||
<< " with detection of triple lines:\n";
|
||||
test_epic_p.image();
|
||||
|
||||
std::cerr << "Parallel mesh generation from a 3D image"
|
||||
<< " with detection of triple lines on bbox only:\n";
|
||||
test_epic_p.image_in_bbox();
|
||||
|
||||
std::cerr << "Parallel mesh generation from a 3D image"
|
||||
<< " with detection of triple lines on bbox"
|
||||
<< " and input feature polylines:\n";
|
||||
test_epic_p.image_with_input_features();
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
INRIA (France)
|
||||
|
|
@ -662,10 +662,6 @@ CGAL::Comparison_result
|
|||
// NT
|
||||
friend bool operator == (const Sqrt_extension& p, const NT& num)
|
||||
{ return (p-num).is_zero();}
|
||||
friend bool operator < (const Sqrt_extension& p, const NT& num)
|
||||
{ return ( p.compare(num) == CGAL::SMALLER ); }
|
||||
friend bool operator > (const Sqrt_extension& p, const NT& num)
|
||||
{ return ( p.compare(num) == CGAL::LARGER ); }
|
||||
|
||||
//CGAL_int(NT)
|
||||
friend bool operator == (const Sqrt_extension& p, CGAL_int(NT) num)
|
||||
|
|
@ -676,6 +672,19 @@ CGAL::Comparison_result
|
|||
{ return ( p.compare(num) == CGAL::LARGER ); }
|
||||
};
|
||||
|
||||
// The two operators are moved out of the class scope (where they were friends)
|
||||
// in order to work around a VC2017 compilation problem
|
||||
template <class NT, class ROOT_, class ACDE_TAG_, class FP_TAG >
|
||||
bool operator < (const Sqrt_extension<NT, ROOT_, ACDE_TAG_, FP_TAG>& p, const NT& num)
|
||||
{
|
||||
return (p.compare(num) == CGAL::SMALLER);
|
||||
}
|
||||
|
||||
template <class NT, class ROOT_, class ACDE_TAG_, class FP_TAG >
|
||||
bool operator > (const Sqrt_extension<NT, ROOT_, ACDE_TAG_, FP_TAG>& p, const NT& num)
|
||||
{
|
||||
return (p.compare(num) == CGAL::LARGER);
|
||||
}
|
||||
/*!
|
||||
* Compute the square of a one-root number.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ Both \ascii and binary formats are supported, and the format is automatically de
|
|||
The format consists of the number of points of the outer boundary followed
|
||||
by the points themselves in counterclockwise order, followed by the number of holes,
|
||||
and for each hole, the number of points of the outer boundary is followed
|
||||
by the points themselves in clockwise order.
|
||||
by the points themselves, in clockwise order.
|
||||
|
||||
\relates Polygon_with_holes_2
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -70,13 +70,14 @@ public:
|
|||
Shape_smoother(TriangleMesh& mesh,
|
||||
VertexPointMap& vpmap,
|
||||
VertexConstraintMap& vcmap,
|
||||
const GeomTraits& traits)
|
||||
const bool scale_volume_after_smoothing = true,
|
||||
const GeomTraits& traits = GeomTraits())
|
||||
:
|
||||
mesh_(mesh),
|
||||
vpmap_(vpmap),
|
||||
vcmap_(vcmap),
|
||||
vimap_(get(Vertex_local_index(), mesh_)),
|
||||
scale_volume_after_smoothing(true),
|
||||
scale_volume_after_smoothing_(scale_volume_after_smoothing),
|
||||
traits_(traits),
|
||||
weight_calculator_(mesh_, vpmap_, traits_, false /*no clamping*/, false /*no bounding from below*/)
|
||||
{ }
|
||||
|
|
@ -104,12 +105,12 @@ public:
|
|||
if(anchor_point == boost::none)
|
||||
anchor_point = get(vpmap_, v);
|
||||
else
|
||||
scale_volume_after_smoothing = false;
|
||||
scale_volume_after_smoothing_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!CGAL::is_closed(mesh_))
|
||||
scale_volume_after_smoothing = false;
|
||||
scale_volume_after_smoothing_ = false;
|
||||
}
|
||||
|
||||
void setup_system(Eigen_matrix& A,
|
||||
|
|
@ -222,12 +223,12 @@ public:
|
|||
{
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
if(!scale_volume_after_smoothing)
|
||||
if(!scale_volume_after_smoothing_)
|
||||
return update_mesh_no_scaling(Xx, Xy, Xz);
|
||||
|
||||
const FT old_vol = volume(mesh_, parameters::vertex_point_map(vpmap_).geom_traits(traits_));
|
||||
|
||||
// If no vertex is constrained, then the smoothed mesh will simply share the same centroid as the input mesh
|
||||
// If no vertex is constrained, then the smoothed mesh will share the same centroid as the input mesh
|
||||
Point pre_smooth_anchor_point;
|
||||
if(anchor_point != boost::none)
|
||||
pre_smooth_anchor_point = *anchor_point;
|
||||
|
|
@ -362,7 +363,7 @@ private:
|
|||
// of volume. We need an anchor point to scale up, either a constrained point or the centroid
|
||||
// of the initial mesh if no vertex is constrained. If there is more than a constrained vertex,
|
||||
// then no scaling can be done without violating the constraint.
|
||||
bool scale_volume_after_smoothing;
|
||||
bool scale_volume_after_smoothing_;
|
||||
boost::optional<Point> anchor_point;
|
||||
|
||||
// linear system data
|
||||
|
|
|
|||
|
|
@ -61,6 +61,25 @@ namespace Polygon_mesh_processing {
|
|||
* \cgalParamDefault{`1`}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{vertex_is_constrained_map}
|
||||
* \cgalParamDescription{a property map containing the constrained-or-not status of each vertex of `tmesh`.}
|
||||
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
|
||||
* as key type and `bool` as value type. It must be default constructible.}
|
||||
* \cgalParamDefault{a default property map where no vertex is constrained}
|
||||
* \cgalParamExtra{A constrained vertex cannot be modified at all during smoothing.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{do_scale}
|
||||
* \cgalParamDescription{Whether to apply rescaling after smoothing. This is useful because
|
||||
* the mean curvature flow tends to shrink the surface.}
|
||||
* \cgalParamType{Boolean}
|
||||
* \cgalParamDefault{`true`}
|
||||
* \cgalParamExtra{Scaling can only be applied if the mesh is closed and if there is no more than
|
||||
* a single constrained vertex.}
|
||||
* \cgalParamExtra{If a vertex is constrained, it is the fixed point of the scaling, otherwise
|
||||
* the centroid is used.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{vertex_point_map}
|
||||
* \cgalParamDescription{a property map associating points to the vertices of `tmesh`}
|
||||
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
|
||||
|
|
@ -77,14 +96,6 @@ namespace Polygon_mesh_processing {
|
|||
* \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{vertex_is_constrained_map}
|
||||
* \cgalParamDescription{a property map containing the constrained-or-not status of each vertex of `tmesh`.}
|
||||
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
|
||||
* as key type and `bool` as value type. It must be default constructible.}
|
||||
* \cgalParamDefault{a default property map where no vertex is constrained}
|
||||
* \cgalParamExtra{A constrained vertex cannot be modified at all during smoothing.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{sparse_linear_solver}
|
||||
* \cgalParamDescription{an instance of the sparse linear solver used for smoothing}
|
||||
* \cgalParamType{a class model of `SparseLinearAlgebraWithFactorTraits_d`}
|
||||
|
|
@ -97,9 +108,10 @@ namespace Polygon_mesh_processing {
|
|||
*
|
||||
* @warning This function involves linear algebra, that is computed using non-exact, floating-point arithmetic.
|
||||
*
|
||||
* @see `smooth_mesh()`
|
||||
* @see `angle_and_area_smoothing()`
|
||||
*/
|
||||
template<typename TriangleMesh, typename FaceRange, typename NamedParameters = parameters::Default_named_parameters>
|
||||
template<typename TriangleMesh, typename FaceRange,
|
||||
typename NamedParameters = parameters::Default_named_parameters>
|
||||
void smooth_shape(const FaceRange& faces,
|
||||
TriangleMesh& tmesh,
|
||||
const double time,
|
||||
|
|
@ -125,6 +137,7 @@ void smooth_shape(const FaceRange& faces,
|
|||
VCMap vcmap = choose_parameter(get_parameter(np, internal_np::vertex_is_constrained),
|
||||
Static_boolean_property_map<vertex_descriptor, false>());
|
||||
const unsigned int nb_iterations = choose_parameter(get_parameter(np, internal_np::number_of_iterations), 1);
|
||||
const bool scale_after_smoothing = choose_parameter(get_parameter(np, internal_np::do_scale), true);
|
||||
|
||||
#if defined(CGAL_EIGEN3_ENABLED)
|
||||
#if EIGEN_VERSION_AT_LEAST(3,2,0)
|
||||
|
|
@ -161,11 +174,11 @@ void smooth_shape(const FaceRange& faces,
|
|||
Eigen_vector bx(n), by(n), bz(n), Xx(n), Xy(n), Xz(n);
|
||||
std::vector<CGAL::Triple<std::size_t, std::size_t, double> > stiffness;
|
||||
|
||||
internal::Shape_smoother<TriangleMesh, VertexPointMap, VCMap, Sparse_solver, GeomTraits> smoother(tmesh, vpmap, vcmap, gt);
|
||||
internal::Shape_smoother<TriangleMesh, VertexPointMap, VCMap, Sparse_solver, GeomTraits> smoother(tmesh, vpmap, vcmap, scale_after_smoothing, gt);
|
||||
|
||||
smoother.init_smoothing(faces);
|
||||
|
||||
// For robustness reasons, the laplacian coefficients are computed only once (only the mass
|
||||
// For robustness reasons, the Laplacian coefficients are computed only once (only the mass
|
||||
// matrix is updated at every iteration). See Kazdhan et al. "Can Mean-Curvature Flow Be Made Non-Singular?".
|
||||
smoother.calculate_stiffness_matrix_elements(stiffness);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||
#include <CGAL/Polygon_mesh_processing/smooth_shape.h>
|
||||
|
||||
#include <CGAL/utility.h>
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
#include <vector>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef Kernel::FT FT;
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef CGAL::Surface_mesh<Point> SurfaceMesh;
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Mesh_with_id;
|
||||
|
|
@ -38,7 +40,7 @@ void test_implicit_constrained_devil(Mesh mesh)
|
|||
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
|
||||
typename boost::property_map<Mesh, CGAL::vertex_point_t>::type vpmap = get(CGAL::vertex_point, mesh);
|
||||
|
||||
// z max is 20 in the devil
|
||||
// max 'z' is 20 in the devil
|
||||
std::set<vertex_descriptor> selected_vertices;
|
||||
for(vertex_descriptor v : vertices(mesh))
|
||||
{
|
||||
|
|
@ -47,6 +49,8 @@ void test_implicit_constrained_devil(Mesh mesh)
|
|||
selected_vertices.insert(v);
|
||||
}
|
||||
|
||||
std::cout << selected_vertices.size() << " constrained vertices" << std::endl;
|
||||
|
||||
CGAL::Boolean_property_map<std::set<vertex_descriptor> > vcmap(selected_vertices);
|
||||
|
||||
std::vector<Point> fixed_points(selected_vertices.size());
|
||||
|
|
@ -124,6 +128,29 @@ void test_implicit_constrained_elephant(Mesh mesh)
|
|||
#endif
|
||||
}
|
||||
|
||||
template <typename Mesh>
|
||||
void test_implicit_unscaled_elephant(Mesh mesh)
|
||||
{
|
||||
#ifdef CGAL_PMP_SMOOTHING_DEBUG
|
||||
std::cout << "-- test_implicit_unscaled_elephant --" << std::endl;
|
||||
#endif
|
||||
|
||||
const FT ivol = PMP::volume(mesh);
|
||||
std::cout << "Input volume is " << ivol << std::endl;
|
||||
|
||||
Mesh mesh_cpy(mesh);
|
||||
const double time_step = 0.001;
|
||||
PMP::smooth_shape(mesh_cpy, time_step, CGAL::parameters::number_of_iterations(5).do_scale(true));
|
||||
|
||||
FT ovol = PMP::volume(mesh_cpy);
|
||||
std::cout << "With scaling, output volume is " << ovol << std::endl;
|
||||
assert(equal_doubles(ivol, ovol, 1e-10));
|
||||
|
||||
PMP::smooth_shape(mesh, time_step, CGAL::parameters::number_of_iterations(5).do_scale(false));
|
||||
ovol = PMP::volume(mesh);
|
||||
std::cout << "Without scaling, output volume is " << ovol << std::endl;
|
||||
}
|
||||
|
||||
template <typename Mesh>
|
||||
void test_curvature_flow_time_step(Mesh mesh)
|
||||
{
|
||||
|
|
@ -167,8 +194,8 @@ int main(int, char**)
|
|||
SurfaceMesh mesh_devil;
|
||||
if(!input1 || !(input1 >> mesh_devil))
|
||||
{
|
||||
std::cerr << "Error: can not read file.";
|
||||
return 1;
|
||||
std::cerr << "Error: cannot read file " << filename_devil << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
input1.close();
|
||||
|
||||
|
|
@ -176,8 +203,8 @@ int main(int, char**)
|
|||
SurfaceMesh mesh_elephant;
|
||||
if(!input2 || !(input2 >> mesh_elephant))
|
||||
{
|
||||
std::cerr << "Error: can not read file.";
|
||||
return 1;
|
||||
std::cerr << "Error: cannot read file " << filename_elephant << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
input2.close();
|
||||
|
||||
|
|
@ -185,11 +212,12 @@ int main(int, char**)
|
|||
test_curvature_flow<SurfaceMesh>(mesh_elephant);
|
||||
test_implicit_constrained_elephant<SurfaceMesh>(mesh_elephant);
|
||||
test_implicit_constrained_devil<SurfaceMesh>(mesh_devil);
|
||||
test_implicit_unscaled_elephant<SurfaceMesh>(mesh_elephant);
|
||||
|
||||
input1.open(filename_devil);
|
||||
Mesh_with_id pl_mesh_devil;
|
||||
if(!input1 || !(input1 >> pl_mesh_devil)){
|
||||
std::cerr << "Error: can not read file.";
|
||||
std::cerr << "Error: cannot read file " << filename_devil << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
input1.close();
|
||||
|
|
@ -200,7 +228,7 @@ int main(int, char**)
|
|||
Mesh_with_id pl_mesh_elephant;
|
||||
if(!input2 || !(input2 >> pl_mesh_elephant))
|
||||
{
|
||||
std::cerr << "Error: can not read file.";
|
||||
std::cerr << "Error: cannot read file " << filename_elephant << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
input2.close();
|
||||
|
|
@ -212,6 +240,7 @@ int main(int, char**)
|
|||
test_curvature_flow<Mesh_with_id>(pl_mesh_elephant);
|
||||
test_implicit_constrained_elephant<Mesh_with_id>(pl_mesh_elephant);
|
||||
test_implicit_constrained_devil<Mesh_with_id>(pl_mesh_devil);
|
||||
test_implicit_unscaled_elephant<Mesh_with_id>(pl_mesh_elephant);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,12 +277,16 @@ void Mesh_3_plugin::mesh_3_volume()
|
|||
mesh_3(Mesh_type::VOLUME);
|
||||
}
|
||||
|
||||
boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const {
|
||||
boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
|
||||
{
|
||||
using boost::get;
|
||||
items = {};
|
||||
features_protection_available = false;
|
||||
item = nullptr;
|
||||
for (int ind : scene->selectionIndices()) {
|
||||
Scene_polylines_item* polylines_item = nullptr;
|
||||
|
||||
for (int ind : scene->selectionIndices())
|
||||
{
|
||||
try {
|
||||
if (auto sm_item =
|
||||
qobject_cast<Scene_surface_mesh_item*>(scene->item(ind))) {
|
||||
|
|
@ -313,9 +317,11 @@ boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
|
|||
return tr("An image items cannot be mixed with other items type");
|
||||
}
|
||||
# endif
|
||||
else if (auto polylines_item =
|
||||
qobject_cast<Scene_polylines_item*>(scene->item(ind))) {
|
||||
if (!items) items = Polyhedral_mesh_items{};
|
||||
else if ((polylines_item =
|
||||
qobject_cast<Scene_polylines_item*>(scene->item(ind))))
|
||||
{
|
||||
if (!items)
|
||||
continue;
|
||||
auto poly_items_ptr = get<Polyhedral_mesh_items>(&*items);
|
||||
if(poly_items_ptr) {
|
||||
if (poly_items_ptr->polylines_item) {
|
||||
|
|
@ -323,12 +329,16 @@ boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
|
|||
} else {
|
||||
poly_items_ptr->polylines_item = polylines_item;
|
||||
}
|
||||
} else {
|
||||
auto image_items = get<Image_mesh_items>(*items);
|
||||
if (image_items.polylines_item) {
|
||||
return tr("Only one polyline item is accepted");
|
||||
} else {
|
||||
image_items.polylines_item = polylines_item;
|
||||
}
|
||||
else {
|
||||
if(auto image_items_ptr = get<Image_mesh_items>(&*items))
|
||||
{
|
||||
if (image_items_ptr->polylines_item) {
|
||||
return tr("Only one polyline item is accepted");
|
||||
}
|
||||
else {
|
||||
image_items_ptr->polylines_item = polylines_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -341,6 +351,20 @@ boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
|
|||
}
|
||||
} catch (const boost::bad_get&) { return tr("Wrong selection of items"); }
|
||||
} // end for loop on selected items
|
||||
|
||||
//attach polylines_item to one or the other item
|
||||
//if it could not be done in the for loop
|
||||
//because of selection order
|
||||
if (polylines_item != nullptr && items != boost::none)
|
||||
{
|
||||
auto poly_items_ptr = get<Polyhedral_mesh_items>(&*items);
|
||||
auto image_items_ptr = get<Image_mesh_items>(&*items);
|
||||
if(poly_items_ptr && poly_items_ptr == nullptr)
|
||||
poly_items_ptr->polylines_item = polylines_item;
|
||||
else if(image_items_ptr && image_items_ptr == nullptr)
|
||||
image_items_ptr->polylines_item = polylines_item;
|
||||
}
|
||||
|
||||
if (!items) { return tr("Selected objects can't be meshed"); }
|
||||
item = nullptr;
|
||||
features_protection_available = false;
|
||||
|
|
@ -428,6 +452,8 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
|
|||
get<Polyhedral_mesh_items>(&*items)
|
||||
? get<Polyhedral_mesh_items>(&*items)->polylines_item
|
||||
: nullptr;
|
||||
if (polylines_item == nullptr && get<Image_mesh_items>(&*items) != nullptr)
|
||||
polylines_item = get<Image_mesh_items>(&*items)->polylines_item;
|
||||
Scene_implicit_function_item* function_item =
|
||||
get<Implicit_mesh_items>(&*items)
|
||||
? get<Implicit_mesh_items>(&*items)->function_item.get()
|
||||
|
|
@ -571,18 +597,28 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
|
|||
ui.edgeLabel->setEnabled(ui.noEdgeSizing->isChecked());
|
||||
ui.edgeSizing->setEnabled(ui.noEdgeSizing->isChecked());
|
||||
|
||||
const QString sharp_and_boundary("Sharp and Boundary edges");
|
||||
const QString boundary_only("Boundary edges only");
|
||||
const QString sharp_edges("Sharp edges");
|
||||
const QString input_polylines("Input polylines");
|
||||
const QString on_cube("Polylines on cube");
|
||||
const QString triple_lines("Triple+ lines");
|
||||
if (features_protection_available) {
|
||||
if (items->which() == POLYHEDRAL_MESH_ITEMS) {
|
||||
if (mesh_type == Mesh_type::SURFACE_ONLY) {
|
||||
ui.protectEdges->addItem(QString("Sharp and Boundary edges"));
|
||||
ui.protectEdges->addItem(QString("Boundary edges only"));
|
||||
ui.protectEdges->addItem(sharp_and_boundary);
|
||||
ui.protectEdges->addItem(boundary_only);
|
||||
} else
|
||||
ui.protectEdges->addItem(QString("Sharp edges"));
|
||||
ui.protectEdges->addItem(sharp_edges);
|
||||
} else if (items->which() == IMAGE_MESH_ITEMS) {
|
||||
if (polylines_item != nullptr)
|
||||
ui.protectEdges->addItem(QString("Input polylines"));
|
||||
if (polylines_item != nullptr) {
|
||||
ui.protectEdges->addItem(QString(input_polylines).append(" only"));
|
||||
ui.protectEdges->addItem(QString(on_cube).append(" and input polylines"));
|
||||
ui.protectEdges->addItem(QString(triple_lines).append(" and input polylines"));
|
||||
}
|
||||
else {
|
||||
ui.protectEdges->addItem(QString("Polylines on cube"));
|
||||
ui.protectEdges->addItem(on_cube);
|
||||
ui.protectEdges->addItem(triple_lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -629,10 +665,15 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
|
|||
approx = !ui.noApprox->isChecked() ? 0 : ui.approx->value();
|
||||
tets_shape = !ui.noTetShape->isChecked() ? 0 : ui.tetShape->value();
|
||||
tets_sizing = !ui.noTetSizing->isChecked() ? 0 : ui.tetSizing->value();
|
||||
protect_features =
|
||||
ui.protect->isChecked() && (ui.protectEdges->currentIndex() == 0);
|
||||
protect_borders =
|
||||
ui.protect->isChecked() && (ui.protectEdges->currentIndex() == 1);
|
||||
|
||||
const int pe_ci = ui.protectEdges->currentIndex();
|
||||
protect_borders = ui.protect->isChecked()
|
||||
&& ( pe_ci == ui.protectEdges->findText(on_cube, Qt::MatchContains)
|
||||
|| pe_ci == ui.protectEdges->findText(boundary_only, Qt::MatchContains));
|
||||
protect_features = ui.protect->isChecked()
|
||||
&& ( pe_ci == ui.protectEdges->findText(triple_lines, Qt::MatchContains)
|
||||
|| pe_ci == ui.protectEdges->findText(sharp_and_boundary, Qt::MatchContains));
|
||||
|
||||
const bool detect_connected_components = ui.detectComponents->isChecked();
|
||||
const int manifold = (ui.manifoldCheckBox->isChecked() ? 1 : 0) +
|
||||
(ui.facetTopology->isChecked() ? 2 : 0);
|
||||
|
|
@ -728,7 +769,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
|
|||
}
|
||||
break;
|
||||
}//end case POLYHEDRAL_MESH_ITEMS
|
||||
// Image
|
||||
// Implicit functions
|
||||
# ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS
|
||||
case IMPLICIT_MESH_ITEMS: {
|
||||
const Implicit_function_interface* pFunction = function_item->function();
|
||||
|
|
@ -747,11 +788,15 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
|
|||
manifold,
|
||||
mesh_type == Mesh_type::SURFACE_ONLY);
|
||||
break;
|
||||
}
|
||||
}//end case IMPLICIT_MESH_ITEMS
|
||||
# endif
|
||||
// Images
|
||||
# ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES
|
||||
case IMAGE_MESH_ITEMS: {
|
||||
const Image* pImage = image_item->image();
|
||||
auto& image_items = get<Image_mesh_items>(*items);
|
||||
const auto img_polylines_item = image_items.polylines_item;
|
||||
|
||||
if (nullptr == pImage) {
|
||||
QMessageBox::critical(mw, tr(""), tr("ERROR: no data in selected item"));
|
||||
return;
|
||||
|
|
@ -773,7 +818,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
|
|||
|
||||
thread = cgal_code_mesh_3(
|
||||
pImage,
|
||||
(polylines_item == nullptr) ? plc : polylines_item->polylines,
|
||||
(img_polylines_item == nullptr) ? plc : img_polylines_item->polylines,
|
||||
angle,
|
||||
facets_sizing,
|
||||
approx,
|
||||
|
|
@ -781,6 +826,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
|
|||
edges_sizing,
|
||||
tets_shape,
|
||||
protect_features,
|
||||
protect_borders,
|
||||
manifold,
|
||||
mesh_type == Mesh_type::SURFACE_ONLY,
|
||||
detect_connected_components,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
#include "Mesh_function.h"
|
||||
#include "Facet_extra_criterion.h"
|
||||
|
||||
#include <CGAL/Mesh_3/Detect_features_in_image.h>
|
||||
#include <CGAL/Mesh_3/Detect_features_on_image_bbox.h>
|
||||
|
||||
using namespace CGAL::Three;
|
||||
|
||||
|
|
@ -291,7 +293,8 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
|
|||
const double tet_sizing,
|
||||
const double edge_size,
|
||||
const double tet_shape,
|
||||
bool protect_features,
|
||||
bool protect_features, //detect_polylines
|
||||
const bool protect_borders,//polylines on bbox
|
||||
const int manifold,
|
||||
const bool surface_only,
|
||||
bool detect_connected_components,
|
||||
|
|
@ -303,11 +306,9 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
|
|||
{
|
||||
if (nullptr == pImage) { return nullptr; }
|
||||
|
||||
if(! polylines.empty()){
|
||||
protect_features = true; // so that it will be passed in make_mesh_3
|
||||
}
|
||||
Mesh_parameters param;
|
||||
param.protect_features = protect_features;
|
||||
param.protect_features
|
||||
= protect_features || protect_borders || !polylines.empty();
|
||||
param.detect_connected_components = detect_connected_components;
|
||||
param.facet_angle = facet_angle;
|
||||
param.facet_sizing = facet_sizing;
|
||||
|
|
@ -343,7 +344,7 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
|
|||
{
|
||||
namespace p = CGAL::parameters;
|
||||
|
||||
Image_mesh_domain* p_domain;
|
||||
Image_mesh_domain* p_domain = nullptr;
|
||||
#ifdef CGAL_USE_ITK
|
||||
if(nullptr != pWeights)
|
||||
{
|
||||
|
|
@ -359,35 +360,57 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
|
|||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
p_domain = new Image_mesh_domain
|
||||
(Image_mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = *pImage,
|
||||
p::relative_error_bound = 1e-6,
|
||||
p::construct_surface_patch_index =
|
||||
[](int i, int j) { return (i * 1000 + j); }
|
||||
)
|
||||
);
|
||||
}
|
||||
if (protect_features)
|
||||
{
|
||||
p_domain = new Image_mesh_domain
|
||||
(Image_mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = *pImage,
|
||||
p::relative_error_bound = 1e-6,
|
||||
p::construct_surface_patch_index =
|
||||
[](int i, int j) { return (i * 1000 + j); },
|
||||
p::features_detector = CGAL::Mesh_3::Detect_features_in_image(),
|
||||
p::input_features = std::cref(polylines)
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (protect_borders)//protect polylines on image Bbox
|
||||
{
|
||||
p_domain = new Image_mesh_domain
|
||||
(Image_mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = *pImage,
|
||||
p::relative_error_bound = 1e-6,
|
||||
p::construct_surface_patch_index =
|
||||
[](int i, int j) { return (i * 1000 + j); },
|
||||
p::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox(),
|
||||
p::input_features = std::cref(polylines)
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (!polylines.empty())
|
||||
{
|
||||
p_domain = new Image_mesh_domain
|
||||
(Image_mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = *pImage,
|
||||
p::relative_error_bound = 1e-6,
|
||||
p::construct_surface_patch_index =
|
||||
[](int i, int j) { return (i * 1000 + j); },
|
||||
p::input_features = std::cref(polylines)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if(protect_features && polylines.empty()){
|
||||
std::vector<std::vector<Bare_point> > polylines_on_bbox;
|
||||
if (p_domain == nullptr)
|
||||
{
|
||||
p_domain = new Image_mesh_domain
|
||||
(Image_mesh_domain::create_labeled_image_mesh_domain
|
||||
(p::image = *pImage,
|
||||
p::relative_error_bound = 1e-6,
|
||||
p::construct_surface_patch_index =
|
||||
[](int i, int j) { return (i * 1000 + j); }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
CGAL_IMAGE_IO_CASE(pImage->image(),
|
||||
{
|
||||
typedef Word Image_word_type;
|
||||
(CGAL::polylines_to_protect<
|
||||
Bare_point,
|
||||
Image_word_type>(*pImage, polylines_on_bbox));
|
||||
p_domain->add_features(polylines_on_bbox.begin(),
|
||||
polylines_on_bbox.end());
|
||||
}
|
||||
);
|
||||
}
|
||||
if(! polylines.empty()){
|
||||
// Insert edge in domain
|
||||
p_domain->add_features(polylines.begin(), polylines.end());
|
||||
}
|
||||
typedef ::Mesh_function<Image_mesh_domain,
|
||||
Mesh_fnt::Labeled_image_domain_tag> Mesh_function;
|
||||
Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(),
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ Meshing_thread* cgal_code_mesh_3(const CGAL::Image_3* pImage,
|
|||
const double edge_size,
|
||||
const double tet_shape,
|
||||
bool protect_features,
|
||||
const bool protect_borders,
|
||||
const int manifold,
|
||||
const bool surface_only,
|
||||
bool detect_connected_components,
|
||||
|
|
|
|||
|
|
@ -640,7 +640,7 @@ public:
|
|||
but are isolated from the complex at the end of the meshing process.
|
||||
|
||||
This function removes these so-called \em isolated vertices, that belong to the
|
||||
triangulation but not to any cell of the `C3T3`, from the triangulation.
|
||||
triangulation but not to any simplex of the `C3T3`, from the triangulation.
|
||||
*/
|
||||
void remove_isolated_vertices()
|
||||
{
|
||||
|
|
@ -669,7 +669,8 @@ public:
|
|||
std::vector<Vertex_handle> isolated;
|
||||
for (Vertex_handle v : tr.finite_vertex_handles())
|
||||
{
|
||||
if (v->meshing_info() == 0.)
|
||||
if (v->meshing_info() == 0.
|
||||
&& (v->in_dimension() > 1 || v->in_dimension() < 0))
|
||||
isolated.push_back(v);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -670,7 +670,7 @@ void clear();
|
|||
bool owns(const_iterator pos);
|
||||
|
||||
/*!
|
||||
* returns whether `pos` is in the range `[cc.begin(), cc`.end())` (`cc.end()` excluded).
|
||||
* returns whether `pos` is in the range `[cc.begin(), cc.end())` (`cc.end()` excluded).
|
||||
*/
|
||||
bool owns_dereferenceable(const_iterator pos);
|
||||
|
||||
|
|
|
|||
|
|
@ -294,8 +294,8 @@ complexity. No exception is thrown.
|
|||
/// returns whether `pos` is in the range `[ccc.begin(), ccc.end()]` (`ccc.end()` included).
|
||||
bool owns(const_iterator pos);
|
||||
/// returns whether `pos` is in the range `[ccc.begin(), ccc.end())` (`ccc.end()` excluded).
|
||||
bool owns_dereferenceable(const_iterator pos);
|
||||
|
||||
bool owns_dereferencable(const_iterator pos);
|
||||
/// @}
|
||||
|
||||
/// \name Merging
|
||||
|
|
|
|||
|
|
@ -149,12 +149,12 @@ CGAL_add_named_parameter(mesh_facet_angle_t, mesh_facet_angle, mesh_facet_angle)
|
|||
CGAL_add_named_parameter(mesh_facet_distance_t, mesh_facet_distance, mesh_facet_distance)
|
||||
CGAL_add_named_parameter(mesh_facet_topology_t, mesh_facet_topology, mesh_facet_topology)
|
||||
CGAL_add_named_parameter(polyline_constraints_t, polyline_constraints, polyline_constraints)
|
||||
CGAL_add_named_parameter(do_scale_t, do_scale, do_scale)
|
||||
CGAL_add_named_parameter(vertex_corner_map_t, vertex_corner_map, vertex_corner_map)
|
||||
CGAL_add_named_parameter(patch_normal_map_t, patch_normal_map, patch_normal_map)
|
||||
CGAL_add_named_parameter(region_primitive_map_t, region_primitive_map, region_primitive_map)
|
||||
CGAL_add_named_parameter(postprocess_regions_t, postprocess_regions, postprocess_regions)
|
||||
|
||||
|
||||
// List of named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)
|
||||
CGAL_add_named_parameter(get_placement_policy_t, get_placement_policy, get_placement)
|
||||
|
|
@ -333,6 +333,8 @@ CGAL_add_named_parameter_with_compatibility(rng_t, rng, p_rng)
|
|||
CGAL_add_named_parameter_with_compatibility(null_subdomain_index_param_t,null_subdomain_index_param, null_subdomain_index)
|
||||
CGAL_add_named_parameter_with_compatibility(surface_patch_index_t, surface_patch_index, construct_surface_patch_index)
|
||||
CGAL_add_named_parameter_with_compatibility_ref_only(weights_param_t, weights_param, weights)
|
||||
CGAL_add_named_parameter_with_compatibility(features_detector_param_t, features_detector_param, features_detector)
|
||||
CGAL_add_named_parameter_with_compatibility(input_features_param_t, input_features_param, input_features)
|
||||
|
||||
CGAL_add_named_parameter_with_compatibility(edge_size_param_t, edge_size_param, edge_size)
|
||||
CGAL_add_named_parameter_with_compatibility_ref_only(edge_sizing_field_param_t, edge_sizing_field_param, edge_sizing_field)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
#!/bin/bash
|
||||
echo "| repo | workflow | branch | event | runs on | status of last run | state | annotation | date | date since last runs | file |"
|
||||
echo "| :--: | :--------: | :----: | :---: | :------: | :------------------: | :---: | :--------: | :----: | :------------------: | :----: |"
|
||||
actualdate=$EPOCHSECONDS
|
||||
for repo in $(gh api orgs/CGAL/repos --jq '.[].full_name' | grep -v dev )
|
||||
do
|
||||
if [ "$repo" != "CGAL/CNRS" ] && [ "$repo" != "CGAL/GeometryFactory" ]
|
||||
then
|
||||
default_branch=$(gh api repos/$repo --jq '.default_branch')
|
||||
workflows=$(gh api repos/$repo/actions/workflows)
|
||||
workflows_count=$(jq '.total_count' <<< "$workflows")
|
||||
for ((i=0;i<workflows_count;i++))
|
||||
do
|
||||
workflow_id=$(jq '.workflows['$i'].id' <<< "$workflows")
|
||||
workflows_state=$(jq '.workflows['$i'].state' <<< "$workflows")
|
||||
if [ "$workflows_state" == "\"disabled\"" -o "$workflows_state" == "\"disabled_manually\"" ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
workflow_runs=$(gh api repos/$repo/actions/workflows/$workflow_id/runs)
|
||||
workflows_name=$(jq -e '.workflow_runs[0].name' <<< "$workflow_runs")
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
workflows_status=$(jq -r '.workflow_runs[0].status' <<< "$workflow_runs")
|
||||
workflows_conclusion=$(jq -r '.workflow_runs[0].conclusion' <<< "$workflow_runs")
|
||||
workflows_start=$(jq -r '.workflow_runs[0].run_started_at' <<< "$workflow_runs")
|
||||
workflows_date=$( date --date="$workflows_start" +%s )
|
||||
workflows_on=$(jq -r '.workflow_runs[0].event' <<< "$workflow_runs")
|
||||
workflows_path=$(jq -r '.workflow_runs[0].path' <<< "$workflow_runs")
|
||||
workflows_branch=$(jq -r '.workflow_runs[0].head_branch' <<< "$workflow_runs")
|
||||
workflows_checksuite_id=$(jq -r '.workflow_runs[0].check_suite_id' <<< "$workflow_runs")
|
||||
workflows_check_runs=$(gh api repos/$repo/check-suites/$workflows_checksuite_id/check-runs)
|
||||
workflows_check_runs_id=$(jq -r '.check_runs[0].id' <<< "$workflows_check_runs")
|
||||
workflows_check_runs_annotation=$(gh api repos/$repo/check-runs/$workflows_check_runs_id/annotations)
|
||||
worfklows_annotation_level=$(jq -r '.[].annotation_level' <<< "$workflows_check_runs_annotation" | tr '\n' ' ')
|
||||
if [ "$worfklows_annotation_level" == "" ]
|
||||
then
|
||||
worfklows_annotation_level+="-"
|
||||
fi
|
||||
workflows_event=""
|
||||
for trigger in $(curl --silent https://raw.githubusercontent.com/$repo/$default_branch/$workflows_path | yq '.on' | grep -v ' .*'); do
|
||||
if [ "${trigger}" != "-" ]
|
||||
then
|
||||
workflows_event+=${trigger}
|
||||
workflows_event+="<br/>"
|
||||
fi
|
||||
done
|
||||
echo "| $repo | $workflows_name | $workflows_branch | $workflows_event | $workflows_on | $workflows_status - $workflows_conclusion | $workflows_state | ***$worfklows_annotation_level*** | $workflows_start | $(((actualdate - workflows_date) / 86400 )) days | $repo/$workflows_path"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "| repo | dependabot |"
|
||||
echo "| :--: | :--------: |"
|
||||
for repo in $(gh api orgs/CGAL/repos --jq '.[].full_name' | grep -v dev )
|
||||
do
|
||||
if [ "$repo" != "CGAL/CNRS" ] && [ "$repo" != "CGAL/GeometryFactory" ]
|
||||
then
|
||||
default_branch=$(gh api repos/$repo --jq '.default_branch')
|
||||
workflows=$(gh api repos/$repo/actions/workflows)
|
||||
workflows_count=$(jq '.total_count' <<< "$workflows")
|
||||
if [ $workflows_count != 0 ]
|
||||
then
|
||||
dependabot=$(curl --silent https://raw.githubusercontent.com/$repo/$default_branch/.github/dependabot.yml)
|
||||
dependabotexist=""
|
||||
if [ "$dependabot" != "404: Not Found" ]
|
||||
then
|
||||
dependabotexist="yes"
|
||||
else
|
||||
dependabotexist="no"
|
||||
fi
|
||||
echo "| $repo | $dependabotexist |"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
|
@ -39,7 +39,7 @@ int main( int argc, char* argv[] )
|
|||
for(Polygon_with_holes::Hole_const_iterator it = input.holes_begin();
|
||||
it != input.holes_end();
|
||||
++it){
|
||||
assert(it->is_counterclockwise_oriented());
|
||||
assert(it->is_clockwise_oriented());
|
||||
}
|
||||
|
||||
double lOffset = 0.25 ;
|
||||
|
|
@ -75,13 +75,13 @@ int main( int argc, char* argv[] )
|
|||
else
|
||||
{
|
||||
std::cerr << "Computes the interior offset of a polygon with holes and draws the result in an EPS file." << std::endl
|
||||
<< std::endl
|
||||
<< "Usage: show_offset_polygon <input_file> [output_eps_file]" << std::endl
|
||||
<< std::endl
|
||||
<< "Usage: show_offset_polygon <intput_file> [offset_distance] [output_eps_file]" << std::endl
|
||||
<< std::endl
|
||||
<< " intput_file Text file describing the input polygon with holes." << std::endl
|
||||
<< " (See inputfile_format.txt for details)" << std::endl
|
||||
<< " offset_distance [default=0.25]." << std::endl
|
||||
<< " output_file [default='innput_file.offset.eps']" << std::endl ;
|
||||
<< " input_file Text file describing the input polygon with holes." << std::endl
|
||||
<< " (See input_file_format.txt for details" << std::endl
|
||||
<< " or use input_file_example.txt)" << std::endl
|
||||
<< " output_file [default='input_file.offset.eps']" << std::endl ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ int main( int argc, char* argv[] )
|
|||
for(Polygon_with_holes::Hole_const_iterator it = input.holes_begin();
|
||||
it != input.holes_end();
|
||||
++it){
|
||||
assert(it->is_counterclockwise_oriented());
|
||||
assert(it->is_clockwise_oriented());
|
||||
}
|
||||
|
||||
//check the validity of the input and fix orientation
|
||||
|
|
@ -51,8 +51,6 @@ int main( int argc, char* argv[] )
|
|||
std::cerr << "ERROR: outer boundary is not simple.";
|
||||
return 1;
|
||||
}
|
||||
if ( input.outer_boundary().is_clockwise_oriented() )
|
||||
input.outer_boundary().reverse_orientation();
|
||||
int k=0;
|
||||
for (Polygon_with_holes::Hole_iterator it = input.holes_begin();
|
||||
it!=input.holes_end(); ++it, ++k)
|
||||
|
|
@ -62,8 +60,6 @@ int main( int argc, char* argv[] )
|
|||
std::cerr << "ERROR: hole "<< k << " is not simple.\n";
|
||||
return 1;
|
||||
}
|
||||
if (it->is_counterclockwise_oriented())
|
||||
it->reverse_orientation();
|
||||
}
|
||||
|
||||
Straight_skeleton_ptr ss = CGAL::create_interior_straight_skeleton_2(input);
|
||||
|
|
@ -99,11 +95,12 @@ int main( int argc, char* argv[] )
|
|||
{
|
||||
std::cerr << "Computes the straight skeleton in the interior of a polygon with holes and draws it in an EPS file." << std::endl
|
||||
<< std::endl
|
||||
<< "Usage: show_straight_skeleton <intput_file> [output_eps_file]" << std::endl
|
||||
<< "Usage: show_straight_skeleton <input_file> [output_eps_file]" << std::endl
|
||||
<< std::endl
|
||||
<< " intput_file Text file describing the input polygon with holes." << std::endl
|
||||
<< " (See input_file_format.txt for details)" << std::endl
|
||||
<< " output_file [default='innput_file.skeleton.eps']" << std::endl ;
|
||||
<< " input_file Text file describing the input polygon with holes." << std::endl
|
||||
<< " (See input_file_format.txt for details" << std::endl
|
||||
<< " or use input_file_example.txt)" << std::endl
|
||||
<< " output_file [default='input_file.skeleton.eps']" << std::endl ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
4
|
||||
0 0
|
||||
1 0
|
||||
1 1
|
||||
0 1
|
||||
1
|
||||
4
|
||||
0.125 0.125
|
||||
0.125 0.875
|
||||
0.875 0.875
|
||||
0.875 0.125
|
||||
|
|
@ -39,12 +39,21 @@ The page \ref bgl_namedparameters describes their usage.
|
|||
- `DQQMask_3`
|
||||
- `Sqrt3Mask_3`
|
||||
|
||||
\cgalCRPSection{Functions}
|
||||
- `CGAL::Subdivision_method_3::PQQ()`
|
||||
- `CGAL::Subdivision_method_3::PTQ()`
|
||||
- `CGAL::Subdivision_method_3::DQQ()`
|
||||
- `CGAL::Subdivision_method_3::Sqrt3()`
|
||||
- `CGAL::Subdivision_method_3::CatmullClark_subdivision()`
|
||||
- `CGAL::Subdivision_method_3::Loop_subdivision()`
|
||||
- `CGAL::Subdivision_method_3::DooSabin_subdivision()`
|
||||
- `CGAL::Subdivision_method_3::Sqrt3_subdivision()`
|
||||
|
||||
\cgalCRPSection{Classes}
|
||||
- `CGAL::Subdivision_method_3`
|
||||
- `CGAL::CatmullClark_mask_3<PolygonMesh>`
|
||||
- `CGAL::Loop_mask_3<PolygonMesh>`
|
||||
- `CGAL::DooSabin_mask_3<PolygonMesh>`
|
||||
- `CGAL::Sqrt3_mask_3<PolygonMesh>`
|
||||
- `CGAL::Linear_mask_3<PolygonMesh>`
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
\example Subdivision_method_3/Customized_subdivision.cpp
|
||||
\example Subdivision_method_3/CatmullClark_subdivision.cpp
|
||||
\example Subdivision_method_3/DooSabin_subdivision.cpp
|
||||
\example Subdivision_method_3/Linear_subdivision.cpp
|
||||
\example Subdivision_method_3/Loop_subdivision.cpp
|
||||
\example Subdivision_method_3/Sqrt3_subdivision.cpp
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
|
||||
#include <CGAL/subdivision_method_3.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef CGAL::Surface_mesh<Kernel::Point_3> Surface_mesh;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/quad.off");
|
||||
|
||||
Surface_mesh mesh;
|
||||
if(!PMP::IO::read_polygon_mesh(filename, mesh))
|
||||
{
|
||||
std::cerr << "Invalid input." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
CGAL::Linear_mask_3<Surface_mesh> mask(&mesh);
|
||||
CGAL::Subdivision_method_3::PQQ(mesh, mask, CGAL::parameters::number_of_iterations(1));
|
||||
|
||||
std::ofstream out("out.off");
|
||||
out << mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -81,6 +81,7 @@ void PQQ_1step(Poly& p, VertexPointMap vpm, Mask mask) {
|
|||
int i=0;
|
||||
std::unordered_map<vertex_descriptor,int> v_index;
|
||||
for(vertex_descriptor vh : p_vertices){
|
||||
vertex_point_buffer[i] = get(vpm, vh);
|
||||
v_index[vh]= i++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public:
|
|||
|
||||
public:
|
||||
Linear_mask_3(Mesh* pmesh)
|
||||
: Base(pmesh, get(vertex_point, pmesh))
|
||||
: Base(pmesh, get(vertex_point, *pmesh))
|
||||
{ }
|
||||
|
||||
Linear_mask_3(Mesh* pmesh, VertexPointMap vpmap)
|
||||
|
|
@ -118,7 +118,7 @@ public:
|
|||
}
|
||||
|
||||
void border_node(halfedge_descriptor edge, Point& ept, Point& /*vpt*/){
|
||||
edge_node(edge, ept);
|
||||
edge_node(edge, ept);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ Catmull-Clark subdivision.
|
|||
\sa `CGAL::DooSabin_mask_3<PolygonMesh`
|
||||
\sa `CGAL::Loop_mask_3<PolygonMesh`
|
||||
\sa `CGAL::Sqrt3_mask_3<PolygonMesh>`
|
||||
\sa `CGAL::Linear_mask_3<PolygonMesh>`
|
||||
*/
|
||||
/// @{
|
||||
|
||||
|
|
@ -121,7 +122,6 @@ void CatmullClark_subdivision(PolygonMesh& pmesh, int step) {
|
|||
* \cgalParamNEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* \pre `pmesh` must be a triangle mesh.
|
||||
**/
|
||||
template <class PolygonMesh, class NamedParameters = parameters::Default_named_parameters>
|
||||
void CatmullClark_subdivision(PolygonMesh& pmesh, const NamedParameters& np = parameters::default_values()) {
|
||||
|
|
@ -179,6 +179,8 @@ void Loop_subdivision(PolygonMesh& pmesh, int step) {
|
|||
* \cgalParamDefault{`1`}
|
||||
* \cgalParamNEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* \pre `pmesh` must be a triangle mesh.
|
||||
**/
|
||||
template <class PolygonMesh, class NamedParameters = parameters::Default_named_parameters>
|
||||
void Loop_subdivision(PolygonMesh& pmesh, const NamedParameters& np = parameters::default_values()) {
|
||||
|
|
|
|||
|
|
@ -77,11 +77,20 @@ they were created must be used to obtain this information.
|
|||
|
||||
\subsection usage_example Example
|
||||
|
||||
The following example shows how to create a very simple `Surface_mesh`
|
||||
The first example shows how to create a very simple `Surface_mesh`
|
||||
by adding 2 faces, and how to check that a face is correctly added
|
||||
to the mesh.
|
||||
|
||||
\cgalExample{Surface_mesh/check_orientation.cpp}
|
||||
|
||||
The second example shows how to access the points associated
|
||||
to the vertices, either for an individual vertex, or as
|
||||
the range of points of the entire mesh. Such a range can
|
||||
be accessed in a for-loop or passed to functions that expect
|
||||
a range of points as input.
|
||||
|
||||
\cgalExample{Surface_mesh/sm_points.cpp}
|
||||
|
||||
\section sectionSurfaceMeshConnectivity Connectivity
|
||||
|
||||
A surface mesh is an edge-centered data structure capable of
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Algebraic_foundations
|
|||
BGL
|
||||
Box_intersection_d
|
||||
Circulator
|
||||
Convex_hull_3
|
||||
HalfedgeDS
|
||||
Kernel_23
|
||||
Miscellany
|
||||
|
|
@ -11,4 +12,3 @@ Polyhedron
|
|||
Polygon_mesh_processing
|
||||
STL_Extension
|
||||
Stream_support
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*!
|
||||
\example Surface_mesh/check_orientation.cpp
|
||||
\example Surface_mesh/sm_points.cpp
|
||||
\example Surface_mesh/sm_iterators.cpp
|
||||
\example Surface_mesh/sm_circulators.cpp
|
||||
\example Surface_mesh/sm_properties.cpp
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ project(Surface_mesh_Examples)
|
|||
#CGAL_Qt5 is needed for the drawing.
|
||||
find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5)
|
||||
|
||||
create_single_source_cgal_program("sm_points.cpp")
|
||||
create_single_source_cgal_program("sm_derivation.cpp")
|
||||
create_single_source_cgal_program("sm_join.cpp")
|
||||
create_single_source_cgal_program("sm_aabbtree.cpp")
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ int main()
|
|||
|
||||
// or with boost::tie, as the CGAL range derives from std::pair
|
||||
for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb){
|
||||
std::cout << *vb << std::endl;
|
||||
// Print vertex index and vertex coordinates
|
||||
std::cout << *vb << " " << m.point(*vb) << std::endl;
|
||||
}
|
||||
|
||||
// Instead of the classical for loop one can use
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
typedef Mesh::Vertex_index vertex_descriptor;
|
||||
typedef Mesh::Face_index face_descriptor;
|
||||
|
||||
int main()
|
||||
{
|
||||
Mesh m;
|
||||
vertex_descriptor v0 = m.add_vertex(K::Point_3(0,0,0));
|
||||
vertex_descriptor v1 = m.add_vertex(K::Point_3(1,0,0));
|
||||
vertex_descriptor v2 = m.add_vertex(K::Point_3(0,1,0));
|
||||
vertex_descriptor v3 = m.add_vertex(K::Point_3(0,0,1));
|
||||
|
||||
face_descriptor fd = m.add_face(v0, v1, v2);
|
||||
m.add_face(v1, v0, v3);
|
||||
|
||||
// Access the point for a given vertex
|
||||
for(vertex_descriptor vd : vertices_around_face(m.halfedge(fd), m)){
|
||||
std ::cout << m.point(vd) << std::endl;
|
||||
}
|
||||
|
||||
// Access the range of all points of the mesh
|
||||
for( const K::Point_3& p : m.points()){
|
||||
std::cout << p << std::endl;
|
||||
}
|
||||
|
||||
Mesh ch;
|
||||
CGAL::convex_hull_3(m.points().begin(), m.points().end(), ch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/boost/graph/generators.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
|
|
@ -25,7 +26,7 @@ int main()
|
|||
// give each vertex a name, the default is empty
|
||||
Mesh::Property_map<vertex_descriptor,std::string> name;
|
||||
bool created;
|
||||
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","");
|
||||
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","m1");
|
||||
assert(created);
|
||||
// add some names to the vertices
|
||||
name[v0] = "hello";
|
||||
|
|
@ -51,14 +52,34 @@ int main()
|
|||
std::cout << name[vd] << " @ " << location[vd] << std::endl;
|
||||
}
|
||||
|
||||
Mesh m2;
|
||||
CGAL::make_triangle(K::Point_3(0,0,1), K::Point_3(1,0,1),K::Point_3(0,1,1), m2);
|
||||
|
||||
m2.add_property_map<vertex_descriptor,std::string>("v:name","m2");
|
||||
Mesh::Property_map<vertex_descriptor,int> index;
|
||||
index = m2.add_property_map<vertex_descriptor,int>("v:index",-1).first;
|
||||
int i = 0;
|
||||
for (auto v : vertices(m2)) {
|
||||
index[v] = i++;
|
||||
}
|
||||
|
||||
std::cout << "properties of m1:" << std::endl;
|
||||
std::vector<std::string> props = m.properties<vertex_descriptor>();
|
||||
for(std::string p : props){
|
||||
std::cout << p << std::endl;
|
||||
}
|
||||
|
||||
m.join(m2);
|
||||
std::cout << "properties of m1 after join:" << std::endl;
|
||||
for(std::string p : m.properties<vertex_descriptor>()){
|
||||
std::cout << p << std::endl;
|
||||
}
|
||||
|
||||
for (auto v : vertices(m)) {
|
||||
std::cout << name[v] << std::endl;
|
||||
}
|
||||
// delete the string property again
|
||||
m.remove_property_map(name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1215,6 +1215,10 @@ public:
|
|||
fprops_.resize(nfaces);
|
||||
}
|
||||
|
||||
/// copies the simplices from `other`, and copies values of
|
||||
/// properties that already exist under the same name in `*this`.
|
||||
/// In case `*this` has a property that does not exist in `other`
|
||||
/// the copied simplices get the default value of the property.
|
||||
bool join(const Surface_mesh& other)
|
||||
{
|
||||
// increase capacity
|
||||
|
|
|
|||
|
|
@ -191,8 +191,6 @@ Inserts the line segment between the points `c.first` and `c.second` as a const
|
|||
/*!
|
||||
Inserts the line segment whose endpoints are the vertices `va` and
|
||||
`vb` as a constraint in the triangulation.
|
||||
\pre `va` != `vb`.
|
||||
|
||||
*/
|
||||
void insert_constraint(Vertex_handle va, Vertex_handle vb);
|
||||
|
||||
|
|
@ -224,7 +222,10 @@ std::size_t insert_constraints(ConstraintIterator first, ConstraintIterator last
|
|||
Same as above except that each constraints is given as a pair of indices of the points
|
||||
in the range [points_first, points_last). The indices must go from 0 to `std::distance(points_first, points_last)`
|
||||
\tparam PointIterator is an `InputIterator` with the value type `Point`.
|
||||
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int, Int>` where `Int` is an integral type implicitly convertible to `std::size_t`
|
||||
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int,Int>`
|
||||
where `Int` is an integral type implicitly convertible to `std::size_t`
|
||||
\note points are inserted even if they are not endpoint of a constraint.
|
||||
\return the number of inserted points.
|
||||
*/
|
||||
template <class PointIterator, class IndicesIterator>
|
||||
std::size_t insert_constraints(PointIterator points_first, PointIterator points_last,
|
||||
|
|
|
|||
|
|
@ -22,11 +22,17 @@ point.
|
|||
|
||||
|
||||
The data structure maintains for each input constraint
|
||||
the sequence of vertices on this constraint. These vertices are
|
||||
the sequence of vertices on this constraint. Note that there is
|
||||
not a one-to-one correspondence between an input constraint and
|
||||
the sequence of vertices. These vertices are
|
||||
either vertices of the input constraint or intersection points.
|
||||
Also consecutive identical points in the input constraint
|
||||
result in a single vertex in the sequence of vertices on this
|
||||
constraint. In case of an input constraint being degenerate
|
||||
to a point, this point is inserted but there will not be a
|
||||
zero length constraint.
|
||||
|
||||
\todo The following description does not match the code
|
||||
Two consecutive vertices of an input constraint form a *subconstraint*.
|
||||
Two consecutive vertices of a constraint form a *subconstraint*.
|
||||
A subconstraint is a pair of vertex handles and corresponds to a constrained edge of the
|
||||
triangulation, which is a pair of a face handle and an index.
|
||||
|
||||
|
|
@ -36,7 +42,8 @@ It further enables the retrieval of the set of input constraints that induce a s
|
|||
As it is straightforward to obtain a subconstraint from a constrained edge `e`,
|
||||
one can obtain the input constraints which induce `e`.
|
||||
|
||||
\tparam Tr must be either a CGAL::Constrained_triangulation_2 or a CGAL::Constrained_Delaunay_triangulation_2
|
||||
|
||||
\tparam Tr must be either a `CGAL::Constrained_triangulation_2` or a `CGAL::Constrained_Delaunay_triangulation_2`
|
||||
|
||||
\sa `CGAL::Constrained_triangulation_2<Traits,Tds>`
|
||||
\sa `CGAL::Constrained_Delaunay_triangulation_2<Traits,Tds>`
|
||||
|
|
@ -242,12 +249,14 @@ insert(PointIterator first, PointIterator last);
|
|||
/*!
|
||||
inserts the constraint segment `ab` in the triangulation.
|
||||
If the two points are equal the point is inserted but no constraint,
|
||||
and the default constructed `Constraint_id` is returned.
|
||||
and a default constructed `Constraint_id` is returned.
|
||||
*/
|
||||
Constraint_id insert_constraint(Point a, Point b);
|
||||
|
||||
/*!
|
||||
inserts the constraint `c`.
|
||||
inserts the constraint `c` in the triangulation.
|
||||
If the two points are equal the point is inserted but no constraint,
|
||||
and a default constructed `Constraint_id` is returned.
|
||||
*/
|
||||
void push_back(const std::pair<Point,Point>& c);
|
||||
|
||||
|
|
@ -255,7 +264,7 @@ inserts the constraint `c`.
|
|||
inserts a constraint whose endpoints are the vertices
|
||||
pointed by `va` and `vb` in the triangulation.
|
||||
If the two vertex handles are equal no constraint is inserted,
|
||||
and the default constructed `Constraint_id` is returned.
|
||||
and a default constructed `Constraint_id` is returned.
|
||||
*/
|
||||
Constraint_id insert_constraint(Vertex_handle va, Vertex_handle vb);
|
||||
|
||||
|
|
@ -264,9 +273,10 @@ inserts a polyline defined by the points in the range `[first,last)`
|
|||
and returns the constraint id.
|
||||
The polyline is considered as a closed curve if the first and last point are equal or if `close == true`. This enables for example passing the vertex range of a `Polygon_2`.
|
||||
When traversing the vertices of a closed polyline constraint with a `Vertices_in_constraint_iterator` the first and last vertex are the same.
|
||||
In case the range is empty `Constraint_id()` is returned.
|
||||
In case all points are equal the point is inserted but no constraint,
|
||||
and `Constraint_id()` is returned.
|
||||
In case the range is empty a default constructed `Constraint_id` is returned.
|
||||
In case the range contains only one point or all points are equal the point is inserted but no constraint,
|
||||
and a default constructed `Constraint_id` is returned.
|
||||
|
||||
\tparam PointIterator must be an `InputIterator` with the value type `Point`.
|
||||
*/
|
||||
template < class PointIterator>
|
||||
|
|
@ -280,9 +290,12 @@ is used to improve efficiency.
|
|||
More precisely, all endpoints are inserted prior to the segments and according to the order provided by the spatial sort.
|
||||
Once endpoints have been inserted, the segments are inserted in the order of the input iterator,
|
||||
using the vertex handles of its endpoints.
|
||||
In case the constraints are degenerate the points are inserted, but no
|
||||
constraints.
|
||||
|
||||
\tparam ConstraintIterator must be an `InputIterator` with the value type `std::pair<Point,Point>` or `Segment`.
|
||||
|
||||
\return the number of inserted points.
|
||||
\tparam ConstraintIterator must be an `InputIterator` with the value type `std::pair<Point,Point>` or `Segment`.
|
||||
*/
|
||||
template <class ConstraintIterator>
|
||||
std::size_t insert_constraints(ConstraintIterator first, ConstraintIterator last);
|
||||
|
|
@ -291,7 +304,11 @@ std::size_t insert_constraints(ConstraintIterator first, ConstraintIterator last
|
|||
Same as above except that each constraint is given as a pair of indices of the points
|
||||
in the range [points_first, points_last). The indices must go from 0 to `std::distance(points_first, points_last)`
|
||||
\tparam PointIterator is an `InputIterator` with the value type `Point`.
|
||||
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int, Int>` where `Int` is an integral type implicitly convertible to `std::size_t`
|
||||
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int,
|
||||
Int>` where `Int` is an integral type implicitly convertible to
|
||||
`std::size_t`
|
||||
\note points are inserted even if they are not endpoint of a constraint.
|
||||
\return the number of inserted points.
|
||||
*/
|
||||
template <class PointIterator, class IndicesIterator>
|
||||
std::size_t insert_constraints(PointIterator points_first, PointIterator points_last,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ are described in Chapter \ref PkgTDS2Ref "2D Triangulation Data Structure".
|
|||
|
||||
- `CGAL::Triangulation_cw_ccw_2`
|
||||
|
||||
\cgalCRPSection{Functions}
|
||||
|
||||
- `CGAL::mark_domain_in_triangulation()`
|
||||
|
||||
\cgalCRPSection{Enum}
|
||||
- \link CGAL::Triangulation_2::Locate_type `CGAL::Triangulation_2<Traits,Tds>::Locate_type` \endlink
|
||||
|
||||
|
|
|
|||
|
|
@ -431,6 +431,9 @@ public:
|
|||
IndicesIterator indices_first,
|
||||
IndicesIterator indices_beyond)
|
||||
{
|
||||
if(indices_first == indices_beyond){
|
||||
return insert(points_first, points_beyond);
|
||||
}
|
||||
std::vector<Point> points(points_first, points_beyond);
|
||||
return internal::insert_constraints(*this,points, indices_first, indices_beyond);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -828,6 +828,9 @@ insert_constraint(Vertex_handle vaa, Vertex_handle vbb)
|
|||
// if a vertex vc of t lies on segment ab
|
||||
// or if ab intersect some constrained edges
|
||||
{
|
||||
if(vaa == vbb){
|
||||
return;
|
||||
}
|
||||
std::stack<std::pair<Vertex_handle, Vertex_handle> > stack;
|
||||
stack.push(std::make_pair(vaa,vbb));
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace CGAL {
|
|||
IndicesIterator indices_beyond )
|
||||
{
|
||||
if(indices_first == indices_beyond){
|
||||
return 0;
|
||||
return t.insert(points.begin(), points.end());
|
||||
}
|
||||
typedef typename T::Vertex_handle Vertex_handle;
|
||||
typedef typename T::Face_handle Face_handle;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue