Merge branch 'Classification-GF-old' into Classification-GF

This commit is contained in:
Simon Giraudot 2016-11-23 08:55:57 +01:00
commit 310d81864e
97 changed files with 66944 additions and 17 deletions

View File

@ -18,7 +18,7 @@ int main(int argc, char* argv[])
std::ifstream in((argc>1)?argv[1]:"data/prim.off");
in >> sm;
Mesh::Property_map<vertex_descriptor,int> ccmap;
CGAL::Properties::Property_map<vertex_descriptor,int> ccmap;
ccmap = sm.add_property_map<vertex_descriptor,int>("v:CC").first;
int num = connected_components(sm, ccmap);

View File

@ -19,7 +19,7 @@ int main(int, char* argv[])
//std::cin >> P;
std::ifstream in(argv[1]);
in >> P;
Mesh::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
CGAL::Properties::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
predecessor = P.add_property_map<vertex_descriptor,vertex_descriptor>("v:predecessor").first;
boost::prim_minimum_spanning_tree(P, predecessor, boost::root_vertex(*vertices(P).first));

View File

@ -68,7 +68,7 @@ int main(int argc, char* argv[])
}
// the storage of a property map is in primal
Mesh::Property_map<face_descriptor,int> fccmap;
CGAL::Properties::Property_map<face_descriptor,int> fccmap;
fccmap = primal.add_property_map<face_descriptor,int>("f:CC").first;
int num = connected_components(finite_dual, fccmap);
@ -77,7 +77,7 @@ int main(int argc, char* argv[])
std::cout << f << " in connected component " << fccmap[f] << std::endl;
}
Mesh::Property_map<vertex_descriptor,int> vccmap;
CGAL::Properties::Property_map<vertex_descriptor,int> vccmap;
vccmap = primal.add_property_map<vertex_descriptor,int>("v:CC").first;
num = connected_components(primal, vccmap);

View File

@ -0,0 +1,256 @@
namespace CGAL {
/*!
\mainpage User Manual
\anchor Chapter_Classification
\cgalAutoToc
\author Simon Giraudot
This component implements a generalization of the algorithm described in \cgalCite{cgal:lm-clscm-12}. It classifies a data set into a user-defined set of classes (such as ground, vegetation, buildings, etc.). A flexible API is provided so that the user can classify any type of data, compute its own local attributes on the point cloud and define its own classes based on these attributes.
\section Classification_Organization Package Organization
%Classification of point sets is achieved as follows:
- some analysis is performed on the input point set;
- attributes are computed based on this analysis;
- a set of classification types (for example: ground, building, vegetation) is defined by the user;
- attributes are given weights and each pair of attribute/type is assigned a relationship;
- classification is computed pointwise by minimizing an energy defined as the sum of the values taken by attributes on input points (which depend on the attribute/type relationship)
- additional regularization can be used by smoothing either locally or globally through an Alpha Expansion approach.
This package is designed to be easily extended by the user: more specifically, attributes and types can be defined by the user to handle any data he/she needs to classify (although \cgal provides a predefined framework for common urban scenes).
\cgalFigureBegin{Classification_Organization,organization.png}
Organization of the package.
\cgalFigureEnd
\section Classification_structures Data Structures
\subsection Classification_analysis Analysis
%Classification is based on the computation of local attributes of points. These attributes often require precomputed analysis structures: such data structures might be shared by several attributes and are therefore computed separately.
\cgal provides the following structures:
- `CGAL::Classification::Point_set_neighborhood` stores spatial searching structures and provides adapted queries for points;
- `CGAL::Classification::Local_eigen_analysis` precomputes covariance matrices on local neighborhood of points and stores the associated eigenvectors and eigenvalues;
- `CGAL::Classification::Planimetric_grid` is a 2D grid used for digital terrain modeling.
The following code snippet shows how to instantiate such data structures from an input PLY point set (the full example is given at the end of the manual).
\snippet Classification/example_point_set_classification.cpp Analysis
\subsection Classification_attributes Attributes
Attributes are defined as scalar fields that associate each input point with a specific value. In the \cgal classification framework, an abstract class `CGAL::Classification::Attribute` defines what method the attribute must provide. All attributes must inherit this class. The attributes provided by \cgal are generally sufficient to handle most cases. However, the user may want to define its own attributes, especially if the input point set comes with additional properties that were not anticipated by \cgal. A user-defined attribute must inherit `CGAL::Classification::Attribute` and provide a method `value()` that associate a scalar value to each input point.
Attributes are accessed through `Handle` objects, `CGAL::Classification::Attribute_handle`.
\cgal provides some predefined attributes that make sense in urban scene classification:
- `CGAL::Classification::Attribute_distance_to_plane` measures how far away a point is from a locally estimated plane
- `CGAL::Classification::Attribute_elevation` estimates the local distance to an estimated ground
- `CGAL::Classification::Attribute_vertical_dispersion` computes how noisy the point set is on a local Z-cylinder
- `CGAL::Classification::Attribute_verticality` compares the local normal vector to the vertical vector.
For more details about how these different attributes can help identifying one classification type or the other, please refer to their associated reference manual pages. In addition, \cgal also provides attributes solely based on the local eigen values \cgalCite{cgal:mbrsh-raofw-11}. Such attributes are less easy to relate to a specific classification type but can still be useful:
- `CGAL::Classification::Attribute_anisotropy`
- `CGAL::Classification::Attribute_eigentropy`
- `CGAL::Classification::Attribute_linearity`
- `CGAL::Classification::Attribute_omnivariance`
- `CGAL::Classification::Attribute_planarity`
- `CGAL::Classification::Attribute_sphericity`
- `CGAL::Classification::Attribute_sum_eigenvalues`
- `CGAL::Classification::Attribute_surface_variation`.
Finally, if the input point set has additional properties, these can also be used as attributes. For example, \cgal provides the following attributes:
- `CGAL::Classification::Attribute_echo_scatter` uses the number of returns (echo) provided by most LIDAR scanners if available
- `CGAL::Classification::Attribute_hsv` uses input color information if available.
In the following code snippet, a subset of these attributes are instantiated, their weights are set and they are added to a newly created classification object:
\snippet Classification/example_point_set_classification.cpp Attributes
\subsection Classification_types Classification Types
A classification type represents how a point should be classified, for example: vegetation, building, road, etc. It is defined by the values the attributes are expected to take for a specific type. For example, vegetation is expected to have a high distance to plane and have a color close to green (if colors are available); facades have a low distance to plane and a low verticality; etc.
\cgal provides a class `CGAL::Classification::Type` to define such a set of attribute effects, along with the associated `Handle` object: `CGAL::Classification::Type_handle`. Each type may define how a specific attribute affects it:
- `FAVORED_ATT`: the type is favored by high values of the attribute
- `NEUTRAL_ATT`: the type is not affected by the attribute
- `PENALIZED_ATT`: the type is favored by low values of the attribute
Let \f$x=(x_i)_{i=1..N_c}\f$ be a potential classification result with \f$N_c\f$ the number of input points and \f$x_i\f$ the class of the \f$i^{th}\f$ point (for example: vegetation, ground, etc.). Let \f$a_j(i)\f$ be the raw value of the \f$j^{th}\f$ attribute at the \f$i^{th}\f$ point and \f$w_j\f$ be the weight of this attribute. We define the normalized value of the \f$j^{th}\f$ attribute at the \f$i^{th}\f$ point as follows:
\f{eqnarray*}{
A_j(x_i) = & (1 - \min(\max(0,\frac{a_j(i)}{w_j}), 1)) & \mbox{if } a_j \mbox{ favors } x_i \\
& 0.5 & \mbox{if } a_j \mbox{ is neutral for } x_i \\
& \min(\max(0,\frac{a_j(i)}{w_j}), 1) & \mbox{if } a_j \mbox{ penalizes } x_i
\f}
The following code snippet shows how to add types to the classification object and how to set the effects of the attributes on these types:
\snippet Classification/example_point_set_classification.cpp Classification Types
\subsection Classification_regularization Regularization
%Classification is performed by minizing an energy over the input point set. This energy can be regularized with different methods. \cgal provides 3 different methods for classification, ranging from high speed / low quality to low speed / high quality:
- `CGAL::Point_set_classification::run()`
- `CGAL::Point_set_classification::run_with_local_smoothing()`
- `CGAL::Point_set_classification::run_with_graphcut()`
On a point set of 3 millions points, the first method takes about 4 seconds, the second about 40 seconds and the third about 2 minutes.
\cgalFigureBegin{Classification_image,classif.png}
Top-Left: input point set. Top-Right: raw output classification represented by a set of colors (ground is orange, facades are blue, roofs are pink and vegetation is green). Bottom-Left: output classification using local smoothing. Bottom-Right: output classification using graphcut.
\cgalFigureEnd
Mathematical details are provided hereafter.
\subsubsection Classification_regularized_no No Regularization
- `CGAL::Point_set_classification::run()`: this is the fastest method
that provides acceptable but usually noisy results (see Figure
\cgalFigureRef{Classification_image}, top-right).
Let \f$x=(x_i)_{i=1..N_c}\f$ be a potential classification result with \f$N_c\f$ the number of input points and \f$x_i\f$ the class of the \f$i^{th}\f$ point (for example: vegetation, ground, etc.). The classification is performed by minimizing the following energy:
\f[
E(x) = \sum_{i = 1..N_c} E_{di}(x_i)
\f]
This energy is a sum of pointwise energies and involves no regularization. Let \f$A=(A_j)_{j=1..N_a}\f$ be the set of normalized attributes
(see \ref Classification_types). The pointwise energy measures the coherence of the class \f$x_i\f$ at the \f$i^{th}\f$ point and is defined as:
\f[
E_{di}(x_i) = \sum_{j = 1..N_a} A_j(x_i)
\f]
\subsubsection Classification_regularized_local Local Smoothing
- `CGAL::Point_set_classification::run_with_local_smoothing()`: this
method is a tradeoff between quality and efficiency (see Figure
\cgalFigureRef{Classification_image}, bottom-left). The minimized
energy is defined as follows:
\f[
E(x) = \sum_{i = 1..N_c} E_{di}(x_i)
\f]
The pointwise energy \f$E_{di}(x_i)\f$ is replaced by
\f$E_{si}(x_i)\f$ defined on a small local neighborhood \f$N(i)\f$ of
the \f$i^{th}\f$ point:
\f[
E_{si}(x_i) = \sum_{j = 1..N_a} \frac{\sum_{k \in N(i)} A_j(x_k)}{\left| N(i) \right|}
\f]
This allows to eliminate local noisy variations of assigned
classification types. Increasing the size of the neighborhood
increases the noise reduction at the cost of higher computation times.
\subsubsection Classification_regularized_graphcut Global Regularization (Graph Cut)
- `CGAL::Point_set_classification::run_with_graphcut()`: this method
offers the best quality but requires longer computation time (see
Figure \cgalFigureRef{Classification_image}, bottom-right). The
total energy that is minimized is the sum of the partial data term
\f$E_{di}(x_i)\f$ and of a pairwise interaction energy defined by the
standard Potts model:
\f[
E(x) = \sum_{i = 1..N_c} E_{di}(x_i) + \gamma \sum_{i \sim j} \mathbf{1}_{x_i \neq x_j}
\f]
where \f$\gamma>0\f$ is the parameter of the Potts model that
quantifies the strengh of the regularization, \f$i \sim j\f$
represents the pairs of neighboring points and
\f$\mathbf{1}_{\{.\}}\f$ the characteristic function.
A Graph Cut based algorithm (Alpha Expansion) is used to quickly reach
an approximate solution close to the global optimum of this energy.
This method allows to consistently segment the input point set in
piecewise constant parts and to eliminate global variations of
assigned classification types. Increasing \f$\gamma\f$ produces more
regular result with a constant computation time.
\subsection Classification_example Example
The following example:
- reads an input file (LIDAR point set in PLY format);
- computes useful structures from this input;
- computes segmentation attributes from the input and the precomputed structures;
- defines 3 classification types (vegetation, ground and roof) along with the effects of attributes on them;
- classifies the point set;
- saves the result in a colored PLY format.
\cgalExample{Classification/example_point_set_classification.cpp}
\section Classification_helper Helper
The classification algorithm is designed to be as flexible as possible: the user may define its own attributes and classification types. Nevertheless, \cgal provides a predefined framework that should work correctly on common urban point sets. The class `CGAL::Classification::Helper` is designed to make it easier for the user to classify its input point set:
- it takes care of generating all needed analysis structure;
- it generates all possible attributes (among all the \cgal predefined ones) based on which property maps are available (it uses colors if available, etc.);
- multiple scales can be used to increase the quality of the results
- input/ouput methods are provided to save and recover a specific configuration (with all attributes, types and relationships between them).
- classification can be saved as a PLY format with colors and labels.
\section Classification_training Training
%Classification is based on relationships between attributes and types. Each attribute has a specific weight and each pair of attribute/type has a specific effect. This means that the number of parameters to set up becomes rapidly large: if 6 attributes are used to classify between 4 classification types, 30 parameters have to be set up.
Though it is possible to set them one by one, \cgal also provides a training algorithm that requires a small set of ground truth points provided by the user. More specifically, the user must provide, for each classification type he/she wants to classify, a set of known inliers among the input point set (for example, selecting one roof, one tree, one section of the ground). The training algorithm works as follows:
- for each attribute, a range of weights is tested: the effects each attribute have on each type is estimated. For a given weight, if an attribute has the same effect on each type, it is non-relevant for classification. The range of weights such that the attribute is relevant is estimated;
- for each attribute, uniformly picked weight values are tested and their effects estimated;
- each ground truth points provided by the user is classified using this set of weights and effects;
- for each classification type, the ratio of correctly classified ground truth points is computed. The minimum of this ratios is used as a score for this set of weights and effects: a ratio of 0.8 means that for each classification type, at least 80\% of the provided ground truth point were correctly classified;
- the same mechanism is repeated until all attributes' ranges have been tested. Weights are only changed one by one, the other ones kept to the previous value that gave the best score.
This usually converges to a satisfying solution. The number of trials is user defined, set to 300 by default. Using at least 10 times the number of attributes is advised. If the solution is not satisfying, more ground truth points can be selected,for example, in a region that the user identifies as misclassified with the current configuration. The training algorithm keeps the best weights found as initialization and carries on trying new weights by taking new ground truth points into account.
\cgalFigureBegin{Classification_training_fig,classif_training.png}
Example of evolution of training score. Purple curve is the score computed at the current iteration, green curve is the best score found so far. Iterations where better solutions are found are marked by vertical gray lines.
\cgalFigureEnd
\subsection Classification_helper_example Example with Helper and Training
The following example:
- reads a point set with a training set (embedded as a PLY attribute _label_);
- uses the helper to generate attributes on 5 scales;
- trains the algorithm using 800 trials;
- runs the algorithm using the graphcut regularization;
- saves the output using the helper.
\cgalExample{Classification/example_helper.cpp}
\section Classification_history History
This package is based on a research code by Florent Lafarge that was generalized, extended and packaged by Simon Giraudot.
*/
} /* namespace CGAL */

View File

@ -0,0 +1,5 @@
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Classification"
INPUT = ${CMAKE_SOURCE_DIR}/Classification/doc/Classification/ \
${CMAKE_SOURCE_DIR}/Classification/include/CGAL/Classification/ \
${CMAKE_SOURCE_DIR}/Classification/include/CGAL/Classifier.h

View File

@ -0,0 +1,73 @@
/*!
\defgroup PkgClassification Classification Reference
\defgroup PkgClassificationConcepts Concepts
\ingroup PkgClassification
\defgroup PkgClassificationShapes Shapes
\ingroup PkgClassification
\addtogroup PkgClassification
\cgalPkgDescriptionBegin{Classification, PkgClassificationSummary}
\cgalPkgPicture{data_classif.png}
\cgalPkgSummaryBegin
\cgalPkgAuthors{Simon Giraudot}
\cgalPkgDesc{This component implements an algorithm that classifies a data set into a user-defined set of classes (such as ground, vegetation, buildings, etc.). A flexible API is provided so that the user can classify any type of data, compute its own local attributes on the data set and define its own classes based on these attributes.}
\cgalPkgManuals{Chapter_Classification, PkgClassification}
\cgalPkgSummaryEnd
\cgalPkgShortInfoBegin
\cgalPkgSince{4.9}
\cgalPkgBib{cgal:ovja-pssd}
\cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgDemo{Operations on Polyhedra,polyhedron_3.zip}
\cgalPkgShortInfoEnd
\cgalPkgDescriptionEnd
\cgalClassifedRefPages
## Concepts ##
- `CGAL::NeighborQuery`
## Classification ##
- `CGAL::Classifier<RandomAccessIterator, ItemMap>`
## Data Structures ##
- `CGAL::Classification::Helper<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Point_set_neighborhood<Kernel, RandomAccessIterator, PointMap>`
- `CGAL::Classification::Local_eigen_analysis<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap>`
## Classification Type ##
- `CGAL::Classification::Type`
- `CGAL::Classification::Type_handle`
## Attribute ##
- `CGAL::Classification::Attribute`
- `CGAL::Classification::Attribute_handle`
## Predefined Attributes ##
- `CGAL::Classification::Attribute_anisotropy<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_distance_to_plane<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_echo_scatter<Kernel, RandomAccessIterator, PointMap, EchoMap>`
- `CGAL::Classification::Attribute_eigentropy<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_elevation<Kernel, RandomAccessIterator, PointMap>`
- `CGAL::Classification::Attribute_hsv<Kernel, RandomAccessIterator, ColorMap>`
- `CGAL::Classification::Attribute_linearity<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_omnivariance<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_planarity<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_sphericity<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_sum_eigenvalues<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_surface_variation<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
- `CGAL::Classification::Attribute_vertical_dispersion<Kernel, RandomAccessIterator, PointMap>`
- `CGAL::Classification::Attribute_verticality<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
*/

View File

@ -0,0 +1,6 @@
Manual
Kernel_23
STL_Extension
Algebraic_foundations
Circulator
Stream_support

View File

@ -0,0 +1,4 @@
/*!
\example Classification/example_point_set_classification.cpp
\example Classification/example_helper.cpp
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

View File

@ -0,0 +1,48 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
project( Classification )
cmake_minimum_required(VERSION 2.8.11)
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
# include helper file
include( ${CGAL_USE_FILE} )
# Boost and its components
find_package( Boost REQUIRED )
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
# include for local directory
include_directories( BEFORE include )
# include for local package
include_directories( BEFORE ../../include )
# Creating entries for all C++ files with "main" routine
# ##########################################################
include( CGAL_CreateSingleSourceCGALProgram )
create_single_source_cgal_program( "example_point_set_classification.cpp" )
create_single_source_cgal_program( "example_helper.cpp" )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,136 @@
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Classifier.h>
#include <CGAL/Classification/Helper.h>
#include <CGAL/IO/read_ply_points.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Iso_cuboid_3 Iso_cuboid_3;
typedef std::vector<Point>::iterator Iterator;
typedef CGAL::Identity_property_map<Point> Pmap;
typedef CGAL::Classifier<Iterator, Pmap> Classification;
typedef CGAL::Classification::Helper<Kernel, Iterator, Pmap> Helper;
/*
This interpreter is used to read a PLY input that contains training
attributes (with the PLY "label" property).
*/
class My_ply_interpreter
{
std::vector<Point>& points;
std::vector<int>& labels;
public:
My_ply_interpreter (std::vector<Point>& points,
std::vector<int>& labels)
: points (points), labels (labels)
{ }
// Init and test if input file contains the right properties
bool is_applicable (CGAL::Ply_reader& reader)
{
return reader.does_tag_exist<double> ("x")
&& reader.does_tag_exist<double> ("y")
&& reader.does_tag_exist<double> ("z")
&& reader.does_tag_exist<int> ("label");
}
// Describes how to process one line (= one point object)
void process_line (CGAL::Ply_reader& reader)
{
double x = 0., y = 0., z = 0.;
int l = 0;
reader.assign (x, "x");
reader.assign (y, "y");
reader.assign (z, "z");
reader.assign (l, "label");
points.push_back (Point (x, y, z));
labels.push_back(l);
}
};
int main (int argc, char** argv)
{
std::string filename (argc > 1 ? argv[1] : "data/b9_training.ply");
std::ifstream in (filename.c_str());
std::vector<Point> pts;
std::vector<int> labels;
std::cerr << "Reading input" << std::endl;
My_ply_interpreter interpreter (pts, labels);
if (!in
|| !(CGAL::read_ply_custom_points (in, interpreter, Kernel())))
{
std::cerr << "Error: cannot read " << filename << std::endl;
return EXIT_FAILURE;
}
Classification psc (pts.begin (), pts.end(), Pmap());
std::cerr << "Generating attributes" << std::endl;
Helper helper (pts.begin(), pts.end(), Pmap(),
5); // Using 5 scales
helper.generate_attributes (psc, pts.begin(), pts.end(), Pmap());
// Add types to PSC
CGAL::Classification::Type_handle ground
= psc.add_classification_type ("ground");
CGAL::Classification::Type_handle vege
= psc.add_classification_type ("vegetation");
CGAL::Classification::Type_handle roof
= psc.add_classification_type ("roof");
// Set training sets
for (std::size_t i = 0; i < labels.size(); ++ i)
{
switch (labels[i])
{
case 0:
psc.add_training_index(ground, i);
break;
case 1:
psc.add_training_index(vege, i);
break;
case 2:
psc.add_training_index(roof, i);
break;
default:
break;
}
}
std::cerr << "Training" << std::endl;
psc.training(800); // 800 trials
psc.run_with_graphcut (helper.neighborhood().k_neighbor_query(12), 0.5);
// Save the output in a colored PLY format
std::ofstream f ("classification.ply");
f.precision(18);
std::vector<CGAL::Classification::RGB_Color> colors;
colors.push_back(CGAL::make_array ((unsigned char)245, 180, 0)); // Ground
colors.push_back(CGAL::make_array ((unsigned char)0, 255, 27)); // Vegetation
colors.push_back(CGAL::make_array ((unsigned char)255, 0, 170)); // Roof
helper.write_ply (f, pts.begin(), pts.end(), Pmap(), psc, &colors);
/// Save the configuration to be able to reload it later
helper.save ("config.xml", psc);
std::cerr << "All done" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,187 @@
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Classifier.h>
#include <CGAL/Classification/Point_set_neighborhood.h>
#include <CGAL/Classification/Planimetric_grid.h>
#include <CGAL/Classification/Attribute.h>
#include <CGAL/Classification/Attributes_eigen.h>
#include <CGAL/Classification/Attribute_distance_to_plane.h>
#include <CGAL/Classification/Attribute_vertical_dispersion.h>
#include <CGAL/Classification/Attribute_elevation.h>
#include <CGAL/IO/read_ply_points.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Iso_cuboid_3 Iso_cuboid_3;
typedef std::vector<Point>::iterator Iterator;
typedef CGAL::Identity_property_map<Point> Pmap;
typedef CGAL::Classifier<Iterator, Pmap> Classification;
typedef CGAL::Classification::Planimetric_grid<Kernel, Iterator, Pmap> Planimetric_grid;
typedef CGAL::Classification::Point_set_neighborhood<Kernel, Iterator, Pmap> Neighborhood;
typedef CGAL::Classification::Local_eigen_analysis<Kernel, Iterator, Pmap> Local_eigen_analysis;
typedef CGAL::Classification::Type_handle Type_handle;
typedef CGAL::Classification::Attribute_handle Attribute_handle;
typedef CGAL::Classification::Attribute_distance_to_plane<Kernel, Iterator, Pmap> Distance_to_plane;
typedef CGAL::Classification::Attribute_linearity<Kernel, Iterator, Pmap> Linearity;
typedef CGAL::Classification::Attribute_omnivariance<Kernel, Iterator, Pmap> Omnivariance;
typedef CGAL::Classification::Attribute_planarity<Kernel, Iterator, Pmap> Planarity;
typedef CGAL::Classification::Attribute_surface_variation<Kernel, Iterator, Pmap> Surface_variation;
typedef CGAL::Classification::Attribute_elevation<Kernel, Iterator, Pmap> Elevation;
typedef CGAL::Classification::Attribute_vertical_dispersion<Kernel, Iterator, Pmap> Dispersion;
///////////////////////////////////////////////////////////////////
//! [Analysis]
int main (int argc, char** argv)
{
std::string filename (argc > 1 ? argv[1] : "data/b9.ply");
std::ifstream in (filename.c_str());
std::vector<Point> pts;
std::cerr << "Reading input" << std::endl;
if (!in
|| !(CGAL::read_ply_points (in, std::back_inserter (pts))))
{
std::cerr << "Error: cannot read " << filename << std::endl;
return EXIT_FAILURE;
}
double grid_resolution = 0.34;
double radius_neighbors = 1.7;
double radius_dtm = 15.0;
std::cerr << "Computing useful structures" << std::endl;
Iso_cuboid_3 bbox = CGAL::bounding_box (pts.begin(), pts.end());
Planimetric_grid grid (pts.begin(), pts.end(), Pmap(), bbox, grid_resolution);
Neighborhood neighborhood (pts.begin(), pts.end(), Pmap());
double garbage;
Local_eigen_analysis eigen (pts.begin(), pts.end(), Pmap(), neighborhood.k_neighbor_query(6), garbage);
//! [Analysis]
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//! [Attributes]
std::cerr << "Computing attributes" << std::endl;
Attribute_handle d2p (new Distance_to_plane (pts.begin(), pts.end(), Pmap(), eigen));
Attribute_handle lin (new Linearity (pts.begin(), pts.end(), eigen));
Attribute_handle omni (new Omnivariance (pts.begin(), pts.end(), eigen));
Attribute_handle plan (new Planarity (pts.begin(), pts.end(), eigen));
Attribute_handle surf (new Surface_variation (pts.begin(), pts.end(), eigen));
Attribute_handle disp (new Dispersion (pts.begin(), pts.end(), Pmap(), grid,
grid_resolution,
radius_neighbors));
Attribute_handle elev (new Elevation (pts.begin(), pts.end(), Pmap(), grid,
grid_resolution,
radius_dtm));
std::cerr << "Setting weights" << std::endl;
d2p->weight = 6.75e-2;
lin->weight = 1.19;
omni->weight = 1.34e-1;
plan->weight = 7.32e-1;
surf->weight = 1.36e-1;
disp->weight = 5.45e-1;
elev->weight = 1.47e1;
// Add attributes to classification object
Classification psc (pts.begin (), pts.end(), Pmap());
psc.add_attribute (d2p);
psc.add_attribute (lin);
psc.add_attribute (omni);
psc.add_attribute (plan);
psc.add_attribute (surf);
psc.add_attribute (disp);
psc.add_attribute (elev);
//! [Attributes]
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//! [Classification Types]
std::cerr << "Setting up classification types" << std::endl;
// Create classification type and define how attributes affect them
Type_handle ground = psc.add_classification_type ("ground");
ground->set_attribute_effect (d2p, CGAL::Classification::Type::NEUTRAL_ATT);
ground->set_attribute_effect (lin, CGAL::Classification::Type::PENALIZED_ATT);
ground->set_attribute_effect (omni, CGAL::Classification::Type::NEUTRAL_ATT);
ground->set_attribute_effect (plan, CGAL::Classification::Type::FAVORED_ATT);
ground->set_attribute_effect (surf, CGAL::Classification::Type::PENALIZED_ATT);
ground->set_attribute_effect (disp, CGAL::Classification::Type::NEUTRAL_ATT);
ground->set_attribute_effect (elev, CGAL::Classification::Type::PENALIZED_ATT);
Type_handle vege = psc.add_classification_type ("vegetation");
vege->set_attribute_effect (d2p, CGAL::Classification::Type::FAVORED_ATT);
vege->set_attribute_effect (lin, CGAL::Classification::Type::NEUTRAL_ATT);
vege->set_attribute_effect (omni, CGAL::Classification::Type::FAVORED_ATT);
vege->set_attribute_effect (plan, CGAL::Classification::Type::NEUTRAL_ATT);
vege->set_attribute_effect (surf, CGAL::Classification::Type::NEUTRAL_ATT);
vege->set_attribute_effect (disp, CGAL::Classification::Type::FAVORED_ATT);
vege->set_attribute_effect (elev, CGAL::Classification::Type::NEUTRAL_ATT);
Type_handle roof = psc.add_classification_type ("roof");
roof->set_attribute_effect (d2p, CGAL::Classification::Type::NEUTRAL_ATT);
roof->set_attribute_effect (lin, CGAL::Classification::Type::PENALIZED_ATT);
roof->set_attribute_effect (omni, CGAL::Classification::Type::FAVORED_ATT);
roof->set_attribute_effect (plan, CGAL::Classification::Type::FAVORED_ATT);
roof->set_attribute_effect (surf, CGAL::Classification::Type::PENALIZED_ATT);
roof->set_attribute_effect (disp, CGAL::Classification::Type::NEUTRAL_ATT);
roof->set_attribute_effect (elev, CGAL::Classification::Type::FAVORED_ATT);
//! [Classification Types]
///////////////////////////////////////////////////////////////////
// Run classification
psc.run_with_graphcut (neighborhood.k_neighbor_query(12), 0.2);
// Save the output in a colored PLY format
std::ofstream f ("classification.ply");
f << "ply" << std::endl
<< "format ascii 1.0" << std::endl
<< "element vertex " << pts.size() << std::endl
<< "property float x" << std::endl
<< "property float y" << std::endl
<< "property float z" << std::endl
<< "property uchar red" << std::endl
<< "property uchar green" << std::endl
<< "property uchar blue" << std::endl
<< "end_header" << std::endl;
for (std::size_t i = 0; i < pts.size(); ++ i)
{
f << pts[i] << " ";
Type_handle type = psc.classification_type_of (i);
if (type == ground)
f << "245 180 0" << std::endl;
else if (type == vege)
f << "0 255 27" << std::endl;
else if (type == roof)
f << "255 0 170" << std::endl;
else
{
f << "0 0 0" << std::endl;
std::cerr << "Error: unknown classification type" << std::endl;
}
}
std::cerr << "All done" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,120 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_H
#include <vector>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Abstract class describing a classification attribute.
A classification attribute associates a scalar value to each item
of the classification input.
*/
class Attribute
{
public:
double weight; ///< Weight of the attribute between 0 and +&infin;.
/// \cond SKIP_IN_MANUAL
double mean;
double max;
virtual ~Attribute() { }
/// \endcond
/*!
\brief Returns the ID of the attribute.
This method returns _abstract\_attribute_ and should be overloaded
by a child class with a specific ID.
*/
virtual std::string id() { return "abstract_attribute"; }
/*!
\brief Returns the value taken by the attribute on the given item.
This method must be implemented by inherited classes.
\param index Index of the input item.
\return the value of the attribute on the item of index `index`
*/
virtual double value (std::size_t index) = 0;
/// \cond SKIP_IN_MANUAL
virtual double normalized (std::size_t index)
{
return (std::max) (0., (std::min) (1., value(index) / weight));
}
virtual double favored (std::size_t index) { return (1. - normalized (index)); }
virtual double penalized (std::size_t index) { return normalized (index); }
// virtual double ignored (std::size_t index) { return (std::min) (favored(index), penalized(index)); }
virtual double ignored (std::size_t) { return 0.5; }
void compute_mean_max (std::vector<double>& vect, double& mean, double& max)
{
mean = 0.;
max = -std::numeric_limits<double>::max();
double min = std::numeric_limits<double>::max();
for (std::size_t i = 0; i < vect.size(); ++ i)
{
mean += vect[i];
if (vect[i] > max)
max = vect[i];
if (vect[i] < min)
min = vect[i];
}
// std::cerr << id() << " Min/max = " << min << " / " << max << std::endl;
mean /= vect.size();
}
/// \endcond
};
#ifdef DOXYGEN_RUNNING
/*!
\ingroup PkgClassification
\brief Handle to a classification `Attribute`.
\cgalModels Handle
*/
class Attribute_handle { };
#else
typedef boost::shared_ptr<Attribute> Attribute_handle;
#endif
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_H

View File

@ -0,0 +1,112 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
#include <vector>
#include <CGAL/Classification/Color.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Attribute based on HSV colorimetric information.
If the input point cloud has colorimetric information, it can be
used for classification purposes. This attribute is based on
Gaussian probabilistic model on one of the three HSV channels
(hue, saturation or value).
It computes the probability of the color of the input point to
match this specific color channel defined by a mean and a standard
deviation.
For example, such an attribute using the channel 0 (hue) with a
mean of 90 (which corresponds to a green hue) can help identifying
trees.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam ColorMap is a model of `ReadablePropertyMap` with value type `CGAL::Classification::RGB_Color`.A
*/
template <typename Kernel, typename RandomAccessIterator, typename ColorMap>
class Attribute_hsv : public Attribute
{
typedef typename Classification::RGB_Color RGB_Color;
typedef typename Classification::HSV_Color HSV_Color;
std::vector<double> color_attribute;
std::string m_id;
public:
/*!
\brief Constructs an attribute based on the given color channel,
mean and standard deviation.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param color_map Property map to access the colors of the input points
\param channel Chosen HSV channel (0 for hue, 1 for saturation, 2 for value).
\param mean Mean value of the specified channel
\param sd Standard deviation of the specified channel
*/
Attribute_hsv (RandomAccessIterator begin,
RandomAccessIterator end,
ColorMap color_map,
std::size_t channel,
double mean, double sd)
{
this->weight = 1.;
for(std::size_t i = 0; i < (std::size_t)(end - begin);i++)
{
HSV_Color c = Classification::rgb_to_hsv (get(color_map, begin[i]));
color_attribute.push_back (std::exp (-(c[channel] - mean) * (c[channel] - mean) / (2. * sd * sd)));
}
this->compute_mean_max (color_attribute, this->mean, this->max);
std::ostringstream oss;
if (channel == 0) oss << "hue";
else if (channel == 1) oss << "saturation";
else if (channel == 2) oss << "value";
oss << "_" << mean;
m_id = oss.str();
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return color_attribute[pt_index];
}
virtual std::string id() { return m_id; }
/// \endcond
};
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H

View File

@ -0,0 +1,92 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot, Florent Lafarge
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_DISTANCE_TO_PLANE_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_DISTANCE_TO_PLANE_H
#include <vector>
#include <CGAL/Classifier.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Attribute based on local distance to a fitted plane.
Characterizing a level of non-planarity can help identify noisy
parts of the input such as vegetation. This attribute computes the
distance of a point to a locally fitted plane.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_distance_to_plane : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> distance_to_plane_attribute;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param point_map Property map to access the input points
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_distance_to_plane (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const Local_eigen_analysis& eigen)
{
this->weight = 1.;
for(std::size_t i = 0; i < (std::size_t)(end - begin); i++)
distance_to_plane_attribute.push_back
(CGAL::sqrt (CGAL::squared_distance (get(point_map, begin[i]), eigen.plane(i))));
this->compute_mean_max (distance_to_plane_attribute, this->mean, this->max);
// max *= 2;
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return distance_to_plane_attribute[pt_index];
}
virtual std::string id() { return "distance_to_plane"; }
/// \endcond
};
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_DISTANCE_TO_PLANE_H

View File

@ -0,0 +1,124 @@
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_ECHO_SCATTER_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_ECHO_SCATTER_H
#include <vector>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Attribute based on echo scatter.
The number of returns (echo number) is a useful information
provided by most LIDAR sensor. It can help identifying trees.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam EchoMap is a model of `ReadablePropertyMap` with value type `std::size_t`.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap, typename EchoMap>
class Attribute_echo_scatter : public Attribute
{
typedef Classification::Image<float> Image_float;
typedef Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
std::vector<double> echo_scatter;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param echo_map Property map to access the echo values of the input points
\param grid Precomputed `Planimetric_grid`
\param grid_resolution Resolution of the planimetric grid
\param radius_neighbors Radius of local neighborhoods
*/
Attribute_echo_scatter (RandomAccessIterator begin,
RandomAccessIterator end,
EchoMap echo_map,
Grid& grid,
const double grid_resolution,
double radius_neighbors = 1.)
{
this->weight = 1.;
Image_float Scatter(grid.width(), grid.height());
for (std::size_t j = 0; j < grid.height(); j++)
for (std::size_t i = 0; i < grid.width(); i++)
Scatter(i,j)=0;
std::size_t square = (std::size_t)(0.5 * radius_neighbors / grid_resolution) + 1;
for (std::size_t j = 0; j < grid.height(); j++){
for (std::size_t i = 0; i < grid.width(); i++){
if(grid.mask(i,j)){
std::size_t squareXmin = (i < square ? 0 : i - square);
std::size_t squareXmax = (std::min) (grid.width()-1, i + square);
std::size_t squareYmin = (j < square ? 0 : j - square);
std::size_t squareYmax = (std::min) (grid.height()-1, j + square);
std::size_t NB_echo_sup=0;
std::size_t NB_echo_total=0;
for(std::size_t k = squareXmin; k <= squareXmax; k++){
for(std::size_t l = squareYmin; l <= squareYmax; l++){
if(CGAL::sqrt(pow((double)k-i,2)+pow((double)l-j,2))<=(double)0.5*radius_neighbors/grid_resolution){
if(grid.indices(k,l).size()>0){
for(std::size_t t=0; t<grid.indices(k,l).size();t++){
std::size_t ip = grid.indices(k,l)[t];
if(get(echo_map, begin[ip]) > 1)
NB_echo_sup++;
}
NB_echo_total=NB_echo_total+grid.indices(k,l).size();
}
}
}
}
Scatter(i,j)=(float)NB_echo_sup/NB_echo_total;
}
}
}
for(std::size_t i = 0; i < (std::size_t)(end - begin); i++){
std::size_t I= grid.x(i);
std::size_t J= grid.y(i);
echo_scatter.push_back((double)Scatter(I,J));
}
this->compute_mean_max (echo_scatter, this->mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return echo_scatter[pt_index];
}
virtual std::string id() { return "echo_scatter"; }
/// \endcond
};
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_ECHO_SCATTER_H

View File

@ -0,0 +1,167 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_ELEVATION_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_ELEVATION_H
#include <vector>
#include <CGAL/Classification/Attribute.h>
#include <CGAL/Classification/Image.h>
#include <CGAL/Classification/Planimetric_grid.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Attribute based on local elevation.
The local position of the ground can be computed for urban
scenes. This attribute computes the distance to the local
estimation of the ground.
It is useful to discriminate the ground from horizontal roofs.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
class Attribute_elevation : public Attribute
{
typedef typename Kernel::Iso_cuboid_3 Iso_cuboid_3;
typedef Image<float> Image_float;
typedef Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
std::vector<double> elevation_attribute;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param point_map Property map to access the input points
\param grid Precomputed `Planimetric_grid`
\param grid_resolution Resolution of the planimetric grid
\param radius_dtm Radius for digital terrain modeling (must be bigger than the size of a building)
*/
Attribute_elevation (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const Grid& grid,
const double grid_resolution,
double radius_dtm = -1.)
{
this->weight = 1.;
if (radius_dtm < 0.)
radius_dtm = 100. * grid_resolution;
//DEM
Image_float dem(grid.width(),grid.height());
for (std::size_t j = 0; j < grid.height(); ++ j)
for (std::size_t i = 0; i < grid.width(); ++ i)
{
if (grid.indices(i,j).empty())
continue;
double mean = 0.;
for (std::size_t k = 0; k < grid.indices(i,j).size(); ++ k)
mean += get(point_map, begin[grid.indices(i,j)[k]]).z();
mean /= grid.indices(i,j).size();
dem(i,j) = mean;
}
std::size_t square = (std::size_t)(0.5 * radius_dtm / grid_resolution) + 1;
Image_float dtm_x(grid.width(),grid.height());
for (std::size_t j = 0; j < grid.height(); ++ j)
{
for (std::size_t i = 0; i < grid.width(); ++ i)
{
std::size_t squareXmin = (i < square ? 0 : i - square);
std::size_t squareXmax = (std::min)(grid.width() - 1, i + square);
std::vector<double> z;
z.reserve(squareXmax - squareXmin +1 );
for(std::size_t k = squareXmin; k <= squareXmax; k++)
if (dem(k,j) != 0.)
z.push_back (dem(k,j));
if (z.empty())
continue;
std::nth_element (z.begin(), z.begin() + (z.size() / 10), z.end());
dtm_x(i,j) = z[z.size() / 10];
}
}
dem.free();
Image_float dtm(grid.width(),grid.height());
for (std::size_t i = 0; i < grid.width(); ++ i)
{
for (std::size_t j = 0; j < grid.height(); ++ j)
{
std::size_t squareYmin = (j < square ? 0 : j - square);
std::size_t squareYmax = (std::min)(grid.height() - 1, j + square);
std::vector<double> z;
z.reserve(squareYmax - squareYmin +1 );
for(std::size_t l = squareYmin; l <= squareYmax; l++)
if (dtm_x(i,l) != 0.)
z.push_back (dtm_x(i,l));
if (z.empty())
continue;
std::nth_element (z.begin(), z.begin() + (z.size() / 10), z.end());
dtm(i,j) = z[z.size() / 10];
}
}
dtm_x.free();
elevation_attribute.reserve(end - begin);
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++){
std::size_t I = grid.x(i);
std::size_t J = grid.y(i);
elevation_attribute.push_back ((double)(get(point_map, begin[i]).z()-dtm(I,J)));
}
this->compute_mean_max (elevation_attribute, this->mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return elevation_attribute[pt_index];
}
virtual std::string id() { return "elevation"; }
/// \endcond
};
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_ELEVATION_H

View File

@ -0,0 +1,159 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_VERTICAL_DISPERSION_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_VERTICAL_DISPERSION_H
#include <vector>
#include <CGAL/Classification/Image.h>
#include <CGAL/Classification/Planimetric_grid.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Attribute based on local vertical dispersion of points.
Urban scenes can often be decomposed as a set of 2D regions with
different heights. While these heights are usually piecewise
constant or piecewise linear, on some specific parts of the scene
such as vegetation, they can become extremely unstable. This
attribute quantifies the vertical dispersion of the points on a
local Z-cylinder around the points.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
class Attribute_vertical_dispersion : public Attribute
{
typedef Classification::Image<float> Image_float;
typedef Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
std::vector<double> vertical_dispersion;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param point_map Property map to access the input points
\param grid Precomputed `Planimetric_grid`
\param grid_resolution Resolution of the planimetric grid
\param radius_neighbors Radius of local neighborhoods
*/
Attribute_vertical_dispersion (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const Grid& grid,
const double grid_resolution,
double radius_neighbors = -1.)
{
this->weight = 1.;
if (radius_neighbors < 0.)
radius_neighbors = 5. * grid_resolution;
Image_float Dispersion(grid.width(), grid.height());
for (std::size_t j = 0; j < grid.height(); j++)
for (std::size_t i = 0; i < grid.width(); i++)
Dispersion(i,j)=0;
std::size_t square = (std::size_t)(0.5 * radius_neighbors / grid_resolution) + 1;
typename Kernel::Vector_3 verti (0., 0., 1.);
for (std::size_t j = 0; j < grid.height(); j++){
for (std::size_t i = 0; i < grid.width(); i++){
if(!(grid.mask(i,j)))
continue;
std::vector<double> hori;
std::size_t squareXmin = (i < square ? 0 : i - square);
std::size_t squareXmax = (std::min) (grid.width()-1, i + square);
std::size_t squareYmin = (j < square ? 0 : j - square);
std::size_t squareYmax = (std::min) (grid.height()-1, j + square);
for(std::size_t k = squareXmin; k <= squareXmax; k++)
for(std::size_t l = squareYmin; l <= squareYmax; l++)
if(CGAL::sqrt(pow((double)k-i,2)+pow((double)l-j,2))
<=(double)0.5*radius_neighbors/grid_resolution
&& (grid.indices(k,l).size()>0))
for(std::size_t t=0; t<grid.indices(k,l).size();t++)
{
std::size_t ip = grid.indices(k,l)[t];
hori.push_back (get(point_map, begin[ip]).z());
}
if (hori.empty())
continue;
std::sort (hori.begin(), hori.end());
std::size_t nb_layers = 1;
std::vector<bool> occupy (1 + (std::size_t)((hori.back() - hori.front()) / grid_resolution), false);
std::size_t last_index = 0;
for (std::size_t k = 0; k < hori.size(); ++ k)
{
std::size_t index = (std::size_t)((hori[k] - hori.front()) / grid_resolution);
occupy[index] = true;
if (index > last_index + 1)
++ nb_layers;
last_index = index;
}
std::size_t nb_occ = 0;
for (std::size_t k = 0; k < occupy.size(); ++ k)
if (occupy[k])
++ nb_occ;
Dispersion(i,j)= 1.f - (nb_occ / (float)(occupy.size()));
}
}
for (std::size_t i = 0; i < (std::size_t)(end - begin);i++)
{
std::size_t I= grid.x(i);
std::size_t J= grid.y(i);
vertical_dispersion.push_back((double)Dispersion(I,J));
}
this->compute_mean_max (vertical_dispersion, this->mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return vertical_dispersion[pt_index];
}
virtual std::string id() { return "vertical_dispersion"; }
/// \endcond
};
}
}
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_VERTICAL_DISPERSION_H

View File

@ -0,0 +1,121 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_VERTICALITY_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_VERTICALITY_H
#include <vector>
#include <CGAL/Classification/Local_eigen_analysis.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Attribute based on local verticality.
The orientation of the best fitting plane of a local neighborhood
of the considered point can be useful to discriminate facades from
the ground.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_verticality : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> verticality_attribute;
public:
/*!
\brief Constructs the attribute using local eigen analysis.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_verticality (RandomAccessIterator begin,
RandomAccessIterator end,
const Local_eigen_analysis& eigen)
{
this->weight = 1.;
typename Kernel::Vector_3 vertical (0., 0., 1.);
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++)
{
typename Kernel::Vector_3 normal = eigen.normal_vector(i);
normal = normal / CGAL::sqrt (normal * normal);
verticality_attribute.push_back (1. - CGAL::abs(normal * vertical));
}
this->compute_mean_max (verticality_attribute, this->mean, this->max);
// max *= 2;
}
/*!
\brief Constructs the attribute using provided normals of points.
\tparam VectorMap is a model of `ReadablePropertyMap` with value type `Vector_3<Kernel>`.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param normal_map Property map to access the normal vectors of the input points.
*/
template <typename VectorMap>
Attribute_verticality (const RandomAccessIterator& begin,
const RandomAccessIterator& end,
VectorMap normal_map)
{
this->weight = 1.;
typename Kernel::Vector_3 vertical (0., 0., 1.);
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++)
{
typename Kernel::Vector_3 normal = get(normal_map, begin[i]);
normal = normal / CGAL::sqrt (normal * normal);
verticality_attribute.push_back (1. - std::fabs(normal * vertical));
}
this->compute_mean_max (verticality_attribute, this->mean, this->max);
// max *= 2;
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return verticality_attribute[pt_index];
}
virtual std::string id() { return "verticality"; }
/// \endcond
};
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_VERTICALITY_H

View File

@ -0,0 +1,500 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTES_EIGEN_H
#define CGAL_CLASSIFICATION_ATTRIBUTES_EIGEN_H
#include <vector>
#include <CGAL/Classification/Local_eigen_analysis.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
Linearity is defined, for the 3 eigenvalues \f$\lambda_1 \ge
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
\frac{\lambda_1 - \lambda_2}{\lambda_1}
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_linearity : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_linearity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
{
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
if (ev[2] < 1e-15)
attrib.push_back (0.);
else
attrib.push_back ((ev[2] - ev[1]) / ev[2]);
}
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "linearity"; }
/// \endcond
};
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
Planarity is defined, for the 3 eigenvalues \f$\lambda_1 \ge
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
\frac{\lambda_2 - \lambda_3}{\lambda_1}
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_planarity : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_planarity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
{
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
if (ev[2] < 1e-15)
attrib.push_back (0.);
else
attrib.push_back ((ev[1] - ev[0]) / ev[2]);
}
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "planarity"; }
/// \endcond
};
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
Sphericity is defined, for the 3 eigenvalues \f$\lambda_1 \ge
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
\frac{\lambda_3}{\lambda_1}
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_sphericity : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_sphericity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
{
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
if (ev[2] < 1e-15)
attrib.push_back (0.);
else
attrib.push_back (ev[0] / ev[2]);
}
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "sphericity"; }
/// \endcond
};
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
Omnivariance is defined, for the 3 eigenvalues \f$\lambda_1 \ge
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
(\lambda_1 \times \lambda_2 \times \lambda_3)^{\frac{1}{3}}
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_omnivariance : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_omnivariance (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
{
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
attrib.push_back (std::pow (std::fabs(ev[0] * ev[1] * ev[2]), 0.333333333));
}
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "omnivariance"; }
/// \endcond
};
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
Anisotropy is defined, for the 3 eigenvalues \f$\lambda_1 \ge
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
\frac{\lambda_1 - \lambda_3}{\lambda_1}
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_anisotropy : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_anisotropy (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
{
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
if (ev[2] < 1e-15)
attrib.push_back (0.);
else
attrib.push_back ((ev[2] - ev[0]) / ev[2]);
}
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "anisotropy"; }
/// \endcond
};
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
Eigentropy is defined, for the 3 eigenvalues \f$\lambda_1 \ge
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
- \sum_{i=1}^3 \lambda_i \times \log{\lambda_i}
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_eigentropy : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_eigentropy (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
{
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
if (ev[0] < 1e-15
|| ev[1] < 1e-15
|| ev[2] < 1e-15)
attrib.push_back (0.);
else
attrib.push_back (- ev[0] * std::log(ev[0])
- ev[1] * std::log(ev[1])
- ev[2] * std::log(ev[2]));
}
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "eigentropy"; }
/// \endcond
};
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
The sum of the eigenvalues is defined, for the 3 eigenvalues
\f$\lambda_1 \ge \lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
\lambda_1 + \lambda_2 + \lambda_3
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_sum_eigenvalues : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_sum_eigenvalues (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
attrib.push_back (eigen.sum_eigenvalues(i));
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "sum_eigen"; }
/// \endcond
};
/*!
\ingroup PkgClassification
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
Surface variation is defined, for the 3 eigenvalues \f$\lambda_1
\ge \lambda_2 \ge \lambda_3 \ge 0\f$, as:
\f[
\frac{\lambda_3}{\lambda_1 + \lambda_2 + \lambda_3}
\f]
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_surface_variation : public Attribute
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
\brief Constructs the attribute.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_surface_variation (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
{
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
if (ev[0] + ev[1] + ev[2] < 1e-15)
attrib.push_back (0.);
else
attrib.push_back (ev[0] / (ev[0] + ev[1] + ev[2]));
}
this->compute_mean_max (attrib, mean, this->max);
}
/// \cond SKIP_IN_MANUAL
virtual double value (std::size_t pt_index)
{
return attrib[pt_index];
}
virtual std::string id() { return "surface_variation"; }
/// \endcond
};
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTES_EIGEN_H

View File

@ -0,0 +1,136 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_COLOR_H
#define CGAL_CLASSIFICATION_COLOR_H
#include <CGAL/array.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassificationColor
Color described in red/green/blue space. Each component is stored
as an unsigned char ranging from 0 (no color) to 255 (
*/
typedef CGAL::cpp11::array<unsigned char, 3> RGB_Color;
/*!
\ingroup PkgClassificationColor
Color described in hue/saturation/value space. Each component is stored
as a double:
- `hue` ranges from 0° to 360° (corresponding to the color tint)
- `saturation` ranges from 0.0 (gray) to 100.0 (full saturation)
- `value` ranges from 0.0 (black) to 100.0 (white)
*/
typedef CGAL::cpp11::array<double, 3> HSV_Color;
/// \cond SKIP_IN_MANUAL
inline HSV_Color rgb_to_hsv (const RGB_Color& c)
{
double r = (double)(c[0]) / 255.;
double g = (double)(c[1]) / 255.;
double b = (double)(c[2]) / 255.;
double Cmax = (std::max) (r, (std::max) (g, b));
double Cmin = (std::min) (r, (std::min) (g, b));
double delta = Cmax - Cmin;
double H = 0.;
if (delta != 0.)
{
if (Cmax == r)
H = 60. * ((g - b) / delta);
else if (Cmax == g)
H = 60. * (((b - r) / delta) + 2.);
else
H = 60. * (((r - g) / delta) + 4.);
}
if (H < 0.) H += 360.;
double S = (Cmax == 0. ? 0. : 100. * (delta / Cmax));
double V = 100. * Cmax;
HSV_Color out = {{ H, S, V }};
return out;
}
inline RGB_Color hsv_to_rgb (const HSV_Color& c)
{
double h = c[0];
double s = c[1];
double v = c[2];
s /= 100.;
v /= 100.;
double C = v*s;
int hh = (int)(h/60.);
double X = C * (1-CGAL::abs (hh % 2 - 1));
double r = 0, g = 0, b = 0;
if( hh>=0 && hh<1 )
{
r = C;
g = X;
}
else if( hh>=1 && hh<2 )
{
r = X;
g = C;
}
else if( hh>=2 && hh<3 )
{
g = C;
b = X;
}
else if( hh>=3 && hh<4 )
{
g = X;
b = C;
}
else if( hh>=4 && hh<5 )
{
r = X;
b = C;
}
else
{
r = C;
b = X;
}
double m = v-C;
r += m;
g += m;
b += m;
r *= 255.0;
g *= 255.0;
b *= 255.0;
RGB_Color out = {{ (unsigned char)r, (unsigned char)g, (unsigned char)b }};
return out;
}
/// \endcond
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_COLOR_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_IMAGE_H
#define CGAL_CLASSIFICATION_IMAGE_H
namespace CGAL {
namespace Classification {
/// \cond SKIP_IN_MANUAL
template <typename Type>
class Image
{
std::size_t m_width;
std::size_t m_height;
Type* m_raw;
public:
Image () : m_width(0), m_height(0), m_raw (NULL)
{
}
Image (std::size_t width, std::size_t height)
: m_width (width),
m_height (height)
{
if (m_width * m_height > 0)
m_raw = new Type[width * height]();
else
m_raw = NULL;
}
~Image ()
{
free();
}
void free()
{
if (m_raw != NULL)
delete[] m_raw;
m_raw = NULL;
}
Image (const Image& other)
: m_width (other.width()),
m_height (other.height())
{
if (m_width * m_height > 0)
{
m_raw = new Type[m_width * m_height];
std::copy (other.m_raw, other.m_raw + (m_width * m_height), this->m_raw);
}
else
m_raw = NULL;
}
Image& operator= (const Image& other)
{
if (m_raw != NULL)
delete[] m_raw;
m_raw = NULL;
m_width = other.width();
m_height = other.height();
if (m_width * m_height > 0)
{
m_raw = new Type[m_width * m_height];
std::copy (other.m_raw, other.m_raw + (m_width * m_height), this->m_raw);
}
return *this;
}
std::size_t width() const { return m_width; }
std::size_t height() const { return m_height; }
Type& operator() (const std::size_t& x, const std::size_t& y)
{
// return m_raw[y * m_width + x];
return m_raw[x * m_height + y];
}
const Type& operator() (const std::size_t& x, const std::size_t& y) const
{
// return m_raw[y * m_width + x];
return m_raw[x * m_height + y];
}
};
/// \endcond
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_IMAGE_H

View File

@ -0,0 +1,185 @@
#ifndef CGAL_CLASSIFICATION_LOCAL_EIGEN_ANALYSIS_H
#define CGAL_CLASSIFICATION_LOCAL_EIGEN_ANALYSIS_H
#include <vector>
#include <CGAL/Search_traits_3.h>
#include <CGAL/Fuzzy_sphere.h>
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/Default_diagonalize_traits.h>
#include <CGAL/centroid.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Class that precomputes and stored the eigenvectors and
eigenvalues of the covariance matrices of all points of a point
set, using a local neighborhood.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Local_eigen_analysis
{
public:
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
typedef typename Kernel::Plane_3 Plane;
typedef CGAL::cpp11::array<double, 3> Eigenvalues; ///< Eigenvalues (sorted in ascending order)
private:
std::vector<Eigenvalues> m_eigenvalues;
std::vector<double> m_sum_eigenvalues;
std::vector<Point> m_centroids;
std::vector<Vector> m_smallest_eigenvectors;
std::vector<Vector> m_middle_eigenvectors;
std::vector<Vector> m_largest_eigenvectors;
public:
/// \cond SKIP_IN_MANUAL
Local_eigen_analysis () { }
/// \endcond
/*!
\brief Computes the local eigen analysis of an input range based
on a local neighborhood.
\tparam NeighborQuery is a model of `NeighborQuery`
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param point_map Property map to access the input points
\param neighbor_query Object used to access neighborhoods of points
\param mean_range The mean value of the range corresponding to the
`knn` number of neighbors is returned by the constructor through
this reference.
*/
template <typename NeighborQuery>
Local_eigen_analysis (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const NeighborQuery& neighbor_query,
double& mean_range)
{
std::size_t size = end - begin;
m_eigenvalues.reserve (size);
m_centroids.reserve (size);
m_smallest_eigenvectors.reserve (size);
m_middle_eigenvectors.reserve (size);
m_largest_eigenvectors.reserve (size);
mean_range = 0.;
for (std::size_t i = 0; i < size; i++)
{
std::vector<std::size_t> neighbors;
neighbor_query (get(point_map, begin[i]), std::back_inserter (neighbors));
std::vector<Point> neighbor_points;
for (std::size_t j = 0; j < neighbors.size(); ++ j)
neighbor_points.push_back (get(point_map, begin[neighbors[j]]));
mean_range += CGAL::sqrt (CGAL::squared_distance (get(point_map, begin[i]),
get(point_map, begin[neighbors.back()])));
compute (get(point_map, begin[i]), neighbor_points);
}
mean_range /= size;
}
/*!
\brief Returns the estimated normal vector of the indexed point.
*/
const Vector& normal_vector (std::size_t index) const { return m_smallest_eigenvectors[index]; }
/*!
\brief Returns the estimated local tangent plane of the index point.
*/
Plane plane (std::size_t index) const { return Plane (m_centroids[index], m_smallest_eigenvectors[index]); }
/*!
\brief Returns the normalized eigenvalues of the index point.
*/
const Eigenvalues& eigenvalue (std::size_t index) const { return m_eigenvalues[index]; }
/*!
\brief Returns the sum of eigenvalues of the index point.
*/
const double& sum_eigenvalues (std::size_t index) const { return m_sum_eigenvalues[index]; }
private:
void compute (const Point& query, std::vector<Point>& neighbor_points)
{
if (neighbor_points.size() == 0)
{
Eigenvalues v = {{ 0., 0., 0. }};
m_eigenvalues.push_back (v);
m_centroids.push_back (query);
m_smallest_eigenvectors.push_back (Vector (0., 0., 1.));
m_middle_eigenvectors.push_back (Vector (0., 1., 0.));
m_largest_eigenvectors.push_back (Vector (1., 0., 0.));
return;
}
Point centroid = CGAL::centroid (neighbor_points.begin(), neighbor_points.end());
m_centroids.push_back (centroid);
CGAL::cpp11::array<double, 6> covariance = {{ 0., 0., 0., 0., 0., 0. }};
for (std::size_t i = 0; i < neighbor_points.size(); ++ i)
{
Vector d = neighbor_points[i] - centroid;
covariance[0] += d.x () * d.x ();
covariance[1] += d.x () * d.y ();
covariance[2] += d.x () * d.z ();
covariance[3] += d.y () * d.y ();
covariance[4] += d.y () * d.z ();
covariance[5] += d.z () * d.z ();
}
Eigenvalues evalues = {{ 0., 0., 0. }};
CGAL::cpp11::array<double, 9> evectors = {{ 0., 0., 0.,
0., 0., 0.,
0., 0., 0. }};
DiagonalizeTraits::diagonalize_selfadjoint_covariance_matrix
(covariance, evalues, evectors);
// Normalize
double sum = evalues[0] + evalues[1] + evalues[2];
if (sum > 0.)
for (std::size_t i = 0; i < 3; ++ i)
evalues[i] = evalues[i] / sum;
m_sum_eigenvalues.push_back(sum);
m_eigenvalues.push_back (evalues);
m_smallest_eigenvectors.push_back (Vector (evectors[0], evectors[1], evectors[2]));
m_middle_eigenvectors.push_back (Vector (evectors[3], evectors[4], evectors[5]));
m_largest_eigenvectors.push_back (Vector (evectors[6], evectors[7], evectors[8]));
}
};
}
}
#endif // CGAL_CLASSIFICATION_LOCAL_EIGEN_ANALYSIS_H

View File

@ -0,0 +1,103 @@
#ifndef CGAL_CLASSIFICATION_PLANIMETRIC_GRID_H
#define CGAL_CLASSIFICATION_PLANIMETRIC_GRID_H
#include <vector>
#include <CGAL/Classification/Image.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Class that precomputes a 2D planimetric grid used for
digital terrain modeling.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
class Planimetric_grid
{
public:
typedef typename Kernel::Point_3 Point_3;
typedef typename Kernel::Iso_cuboid_3 Iso_cuboid_3;
private:
typedef Image<std::vector<std::size_t> > Image_indices;
typedef Image<bool> Image_bool;
Image_indices m_grid;
std::vector<std::size_t> m_x;
std::vector<std::size_t> m_y;
public:
/// \cond SKIP_IN_MANUAL
Planimetric_grid () { }
/// \endcond
/*
\brief Constructs a planimetric grid based on the input range.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param point_map Property map to access the input points
\param bbox The bounding box of the input range
\param grid_resolution Resolution of the planimetric grid
*/
Planimetric_grid (const RandomAccessIterator& begin,
const RandomAccessIterator& end,
PointMap point_map,
const Iso_cuboid_3& bbox,
const double grid_resolution)
{
std::size_t size = (std::size_t)(end - begin);
std::size_t width = (std::size_t)((bbox.xmax() - bbox.xmin()) / grid_resolution) + 1;
std::size_t height = (std::size_t)((bbox.ymax() - bbox.ymin()) / grid_resolution) + 1;
m_grid = Image_indices (width, height);
for (std::size_t i = 0; i < size; ++ i)
{
const Point_3& p = get(point_map, begin[i]);
m_x.push_back ((std::size_t)((p.x() - bbox.xmin()) / grid_resolution));
m_y.push_back ((std::size_t)((p.y() - bbox.ymin()) / grid_resolution));
m_grid(m_x.back(), m_y.back()).push_back (i);
}
}
std::size_t width() const { return m_grid.width(); }
std::size_t height() const { return m_grid.height(); }
/*!
\brief Returns the indices of points lying in the given indexed cell.
*/
const std::vector<std::size_t>& indices(std::size_t x, std::size_t y) const { return m_grid(x,y); }
/*!
\brief Returns `true` if the indexed cell is to be used for classification.
*/
bool mask(std::size_t x, std::size_t y) const { return (!(m_grid(x,y).empty())); }
/*!
\brief Returns the `x` coordinate of the indexed point in the grid.
*/
std::size_t x(std::size_t index) const { return m_x[index]; }
/*!
\brief Returns the `y` coordinate of the indexed point in the grid.
*/
std::size_t y(std::size_t index) const { return m_y[index]; }
};
}
}
#endif // CGAL_CLASSIFICATION_PLANIMETRIC_GRID_H

View File

@ -0,0 +1,291 @@
#ifndef CGAL_CLASSIFICATION_POINT_SET_NEIGHBORHOOD_H
#define CGAL_CLASSIFICATION_POINT_SET_NEIGHBORHOOD_H
#include <vector>
#include <boost/iterator/counting_iterator.hpp>
#include <CGAL/Search_traits_3.h>
#include <CGAL/Fuzzy_sphere.h>
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/Default_diagonalize_traits.h>
#include <CGAL/centroid.h>
#include <CGAL/grid_simplify_point_set.h>
#include <CGAL/Classification/Image.h>
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Class that precomputes spatial searching structures and
gives easy access to local neighborhoods of points.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
class Point_set_neighborhood
{
typedef typename Kernel::FT FT;
typedef typename Kernel::Point_3 Point;
class My_point_property_map{
RandomAccessIterator begin;
PointMap point_map;
public:
typedef Point value_type;
typedef const value_type& reference;
typedef std::size_t key_type;
typedef boost::lvalue_property_map_tag category;
My_point_property_map () { }
My_point_property_map (RandomAccessIterator begin, PointMap point_map)
: begin (begin), point_map (point_map) { }
reference operator[] (key_type k) const { return get(point_map, begin[k]); }
friend inline reference get (const My_point_property_map& ppmap, key_type i)
{ return ppmap[i]; }
};
typedef Search_traits_3<Kernel> SearchTraits_3;
typedef Search_traits_adapter <std::size_t, My_point_property_map, SearchTraits_3> Search_traits;
typedef Sliding_midpoint<Search_traits> Splitter;
typedef Distance_adapter<std::size_t, My_point_property_map, Euclidean_distance<SearchTraits_3> > Distance;
typedef Kd_tree<Search_traits, Splitter, Tag_true> Tree;
typedef Fuzzy_sphere<Search_traits> Sphere;
typedef Orthogonal_k_neighbor_search<Search_traits, Distance, Splitter, Tree> Knn;
Tree* m_tree;
Distance m_distance;
std::vector<std::vector<std::size_t> > m_precomputed_neighbors;
public:
/*!
Functor that returns a neighborhood with a fixed number of points.
\cgalModels NeighborQuery
*/
class K_neighbor_query
{
public:
typedef Point_set_neighborhood::Point value_type; ///<
private:
const Point_set_neighborhood& neighborhood;
std::size_t k;
public:
/*!
\brief Constructs a K neighbor query object.
\param neighborhood The point set neighborhood structure.
\param k The number of neighbors per query.
*/
K_neighbor_query (const Point_set_neighborhood& neighborhood, std::size_t k)
: neighborhood (neighborhood), k(k) { }
/// \cond SKIP_IN_MANUAL
template <typename OutputIterator>
void operator() (const value_type& query, OutputIterator output) const
{
neighborhood.k_neighbors (query, k, output);
}
/// \endcond
};
/*!
Functor that returns a neighborhood with a fixed radius.
\cgalModels NeighborQuery
*/
class Range_neighbor_query
{
public:
typedef Point_set_neighborhood::Point value_type; ///<
private:
const Point_set_neighborhood& neighborhood;
double radius;
public:
/*!
\brief Constructs a range neighbor query object.
\param neighborhood The point set neighborhood structure.
\param radius The radius of the neighbor query.
*/
Range_neighbor_query (const Point_set_neighborhood& neighborhood, double radius)
: neighborhood (neighborhood), radius(radius) { }
/// \cond SKIP_IN_MANUAL
template <typename OutputIterator>
void operator() (const value_type& query, OutputIterator output) const
{
neighborhood.range_neighbors (query, radius, output);
}
/// \endcond
};
friend class K_neighbor_query;
friend class Range_neighbor_query;
/// \cond SKIP_IN_MANUAL
Point_set_neighborhood () : m_tree (NULL) { }
/// \endcond
/*!
\brief Constructs a neighborhood object based on the input range.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param point_map Property map to access the input points
*/
Point_set_neighborhood (const RandomAccessIterator& begin,
const RandomAccessIterator& end,
PointMap point_map)
: m_tree (NULL)
{
std::size_t size = end - begin;
My_point_property_map pmap (begin, point_map);
m_tree = new Tree (boost::counting_iterator<std::size_t> (0),
boost::counting_iterator<std::size_t> (size),
Splitter(),
Search_traits (pmap));
m_distance = Distance (pmap);
m_tree->build();
}
/*!
\brief Constructs a simplified neighborhood object based on the input range.
This method first computes a simplified version of the input point
set by voxelization: a 3D grid is defined and for each subset
present in one cell, only the point closest to the centroid of
this subset is used.
\param begin Iterator to the first input object
\param end Past-the-end iterator
\param point_map Property map to access the input points
\param voxel_size
*/
Point_set_neighborhood (const RandomAccessIterator& begin,
const RandomAccessIterator& end,
PointMap point_map,
double voxel_size)
: m_tree (NULL)
{
// First, simplify
std::size_t size = end - begin;
std::vector<std::size_t> indices (size);
for (std::size_t i = 0; i < indices.size(); ++ i)
indices[i] = i;
My_point_property_map pmap (begin, point_map);
voxelize_point_set(indices, pmap, voxel_size);
m_tree = new Tree (indices.begin(), indices.end(),
Splitter(),
Search_traits (pmap));
m_distance = Distance (pmap);
m_tree->build();
}
/// \cond SKIP_IN_MANUAL
~Point_set_neighborhood ()
{
if (m_tree != NULL)
delete m_tree;
}
/// \endcond
/*!
\brief Returns a neighbor query object with fixed number of neighbors `k`.
*/
K_neighbor_query k_neighbor_query (const std::size_t k) const
{
return K_neighbor_query (*this, k);
}
/*!
\brief Returns a neighbor query object with fixed radius `radius`.
*/
Range_neighbor_query range_neighbor_query (const double radius) const
{
return Range_neighbor_query (*this, radius);
}
private:
template <typename OutputIterator>
void range_neighbors (const Point& query, const FT radius_neighbors, OutputIterator output) const
{
CGAL_assertion (m_tree != NULL);
Sphere fs (query, radius_neighbors, 0, m_tree->traits());
m_tree->search (output, fs);
}
template <typename OutputIterator>
void k_neighbors (const Point& query, const std::size_t k, OutputIterator output) const
{
CGAL_assertion (m_tree != NULL);
Knn search (*m_tree, query, (unsigned int)k, 0, true, m_distance);
for (typename Knn::iterator it = search.begin(); it != search.end(); ++ it)
*(output ++) = it->first;
}
/// \cond SKIP_IN_MANUAL
template <typename Map>
void voxelize_point_set (std::vector<std::size_t>& indices, Map point_map,
double voxel_size)
{
std::map<Point, std::vector<std::size_t> > grid;
for (std::size_t i = 0; i < indices.size(); ++ i)
{
const Point& p = get(point_map, indices[i]);
Point ref (std::floor(p.x() / voxel_size),
std::floor(p.y() / voxel_size),
std::floor(p.z() / voxel_size));
typename std::map<Point, std::vector<std::size_t> >::iterator it;
boost::tie (it, boost::tuples::ignore)
= grid.insert (std::make_pair (ref, std::vector<std::size_t>()));
it->second.push_back (indices[i]);
}
indices.clear();
for (typename std::map<Point, std::vector<std::size_t> >::iterator
it = grid.begin(); it != grid.end(); ++ it)
{
const std::vector<std::size_t>& pts = it->second;
Point centroid = CGAL::centroid (boost::make_transform_iterator
(pts.begin(),
CGAL::Property_map_to_unary_function<Map>(point_map)),
boost::make_transform_iterator
(pts.end(),
CGAL::Property_map_to_unary_function<Map>(point_map)));
std::size_t chosen = 0;
double min_dist = (std::numeric_limits<double>::max)();
for (std::size_t i = 0; i < pts.size(); ++ i)
{
double dist = CGAL::squared_distance(get(point_map, pts[i]), centroid);
if (dist < min_dist)
{
min_dist = dist;
chosen = pts[i];
}
}
indices.push_back (chosen);
}
}
/// \endcond
};
}
}
#endif // CGAL_CLASSIFICATION_POINT_SET_POINT_SET_NEIGHBORHOOD_H

View File

@ -0,0 +1,108 @@
#ifndef CGAL_CLASSIFICATION_TYPE_H
#define CGAL_CLASSIFICATION_TYPE_H
namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\brief Classification type.
A type is what is sought after when performing classification on an
input set (for example: vegetation, ground, etc.). It is defined
as a set of relationship with classification attributes.
*/
class Type
{
public:
enum Attribute_effect /// Defines how an attribute affects this type.
{
FAVORED_ATT = 0, ///< High values of the attribute favor this type
NEUTRAL_ATT = 1, ///< The attribute has no effect on this type
PENALIZED_ATT = 2 ///< Low values of the attribute favor this type
};
private:
/// \cond SKIP_IN_MANUAL
std::string m_id;
std::map<Attribute_handle, Attribute_effect> m_attribute_effects;
/// \endcond
public:
/*!
\param id The name of the classification type
(e.g. vegetation).
*/
Type (std::string id) : m_id (id) { }
/*!
\brief Sets how an attribute affects the classification type.
\param att Attribute whose effect on the classification type is set
\param effect The effect the attribute has on the classification type
*/
void set_attribute_effect (Attribute_handle att, Attribute_effect effect)
{
m_attribute_effects[att] = effect;
}
/*!
\brief Returns the effect of attribute `att` on the classification type.
*/
Attribute_effect attribute_effect (Attribute_handle att)
{
std::map<Attribute_handle, Attribute_effect>::iterator
search = m_attribute_effects.find (att);
return (search == m_attribute_effects.end () ? NEUTRAL_ATT : search->second);
}
/*!
\brief Returns the ID of the classification type.
*/
const std::string& id() const { return m_id; }
/// \cond SKIP_IN_MANUAL
void info()
{
std::cerr << "Attribute " << m_id << ": ";
for (std::map<Attribute_handle, Attribute_effect>::iterator it = m_attribute_effects.begin();
it != m_attribute_effects.end(); ++ it)
{
if (it->second == NEUTRAL_ATT)
continue;
std::cerr << it->first;
if (it->second == FAVORED_ATT) std::cerr << " (favored), ";
else if (it->second == PENALIZED_ATT) std::cerr << " (penalized), ";
}
std::cerr << std::endl;
}
/// \endcond
};
#ifdef DOXYGEN_RUNNING
/*!
\ingroup PkgClassification
\brief Handle to a classification `Type`.
\cgalModels Handle
*/
class Type_handle { };
#else
typedef boost::shared_ptr<Type> Type_handle;
#endif
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_TYPE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
project( Classification )
cmake_minimum_required(VERSION 2.8.11)
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
# include helper file
include( ${CGAL_USE_FILE} )
# Boost and its components
find_package( Boost REQUIRED )
# Use Eigen
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif()
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
# include for local directory
include_directories( BEFORE include )
# include for local package
include_directories( BEFORE ../../include )
# Creating entries for all C++ files with "main" routine
# ##########################################################
include( CGAL_CreateSingleSourceCGALProgram )
#add_definitions("-DCGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE")
create_single_source_cgal_program( "test_features.cpp" )
create_single_source_cgal_program( "test_graphcut.cpp" )

View File

@ -0,0 +1,72 @@
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
//#include <CGAL/Simple_cartesian.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Classifier.h>
#include <CGAL/Classification/Helper.h>
#include <CGAL/IO/read_ply_points.h>
#include <CGAL/Timer.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>
//typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Point_set_3<Point> Point_set;
typedef Point_set::iterator Iterator;
typedef Point_set::Point_map Pmap;
typedef CGAL::Classifier<Iterator, Pmap> Classification;
typedef CGAL::Classification::Helper<Kernel, Iterator, Pmap> Helper;
int main (int argc, char** argv)
{
std::string filename (argc > 1 ? argv[1] : "data/portland_mini.ply");
std::ifstream in (filename.c_str());
Point_set pts;
std::cerr << "[READING INPUT]" << std::endl;
if (!in
|| !(CGAL::read_ply_point_set (in, pts)))
{
std::cerr << "Error: cannot read " << filename << std::endl;
return EXIT_FAILURE;
}
std::string configname (argc > 2 ? argv[2] : "data/portland_mini.xml");
std::cerr << "[LOADING CONFIG]" << std::endl;
Classification psc (pts.begin (), pts.end(), pts.point_map());
Helper helper (configname.c_str(), // load XML config
psc,
pts.begin(), pts.end(), pts.point_map());
std::cerr << "[RUNNING WITH GRAPHCUT]" << std::endl;
CGAL::Timer t;
t.start();
psc.run_with_graphcut (helper.neighborhood(), 0.5);
t.stop();
std::cerr << "Grapcut computed in " << t.time() << " second(s)" << std::endl;
std::cerr << std::endl << "[WRITING OUTPUT]" << std::endl;
std::ofstream f ("output.ply");
f.precision(18);
srand (time (NULL)); // to get different colors everytime
helper.write_ply (f, pts.begin(), pts.end(), pts.point_map(), psc);
std::cerr << "[ALL DONE]" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -66,6 +66,7 @@ Three
Triangulation_3
Triangulation
Ridges_3
Point_set_3
Point_set_processing_3
Point_set_shape_detection_3
Polyline_simplification_2
@ -95,6 +96,6 @@ Barycentric_coordinates_2
Surface_mesh
Surface_mesh_shortest_path
Polygon_mesh_processing
Classification

View File

@ -115,9 +115,11 @@ h1 {
\package_listing{Surface_mesh_skeletonization}
\package_listing{Ridges_3}
\package_listing{Jet_fitting_3}
\package_listing{Point_set_3}
\package_listing{Point_set_processing_3}
\package_listing{Point_set_shape_detection_3}
\package_listing{Stream_lines_2}
\package_listing{Classification}
\section PartSearchStructures Spatial Searching and Sorting

View File

@ -1060,6 +1060,16 @@ note = {\url{ttp://hal.inria.fr/inria-00090522}}
annote = {map,generalized map},
}
@article{cgal:lm-clscm-12,
author = {Lafarge, Florent and Mallet, Clement},
title = {{Creating large-scale city models from 3D-point clouds: a robust approach with hybrid representation}},
journal = {International Journal of Computer Vision},
volume = {99},
number = {1},
pages = {69-85},
year = {2012},
}
@inproceedings{ cgal:lt-fmeps-98,
author = "Peter Lindstrom and Greg Turk",
title = "Fast and memory efficient polygonal simplification",
@ -1295,6 +1305,20 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio
update = "09.11 penarand"
}
@article{cgal:mbrsh-raofw-11,
title = "Relevance assessment of full-waveform lidar data for urban area classification ",
journal = "\{ISPRS\} Journal of Photogrammetry and Remote Sensing ",
volume = "66",
number = "6, Supplement",
pages = "S71 - S84",
year = "2011",
note = "Advances in \{LIDAR\} Data Processing and Applications ",
issn = "0924-2716",
doi = "http://dx.doi.org/10.1016/j.isprsjprs.2011.09.008",
url = "http://www.sciencedirect.com/science/article/pii/S0924271611001055",
author = "Clément Mallet and Frédéric Bretar and Michel Roux and Uwe Soergel and Christian Heipke"
}
@article{cgal:ml-cfsg-00
, author = "G. Medioni and M. Lee and C. Tang"
, title = "A Computational Framework for Segmentation and Grouping"

View File

@ -262,6 +262,13 @@ and <code>src/</code> directories).
This API was deprecated since CGAL 4.4.
</li>
</ul>
<h3>3D Point Set</h3>
<ul>
<li>New package providing a flexible data
structure <code>CGAL::Point_set_3</code> that allows the user to
easily handle point sets with an arbitrary number of attributes
(such as normal vectors, colors, labeling, etc.).</li>
</ul>
<h3>Point Set Processing</h3>
<ul>
<li>New function <code>CGAL::read_ply_custom_points()</code> that
@ -478,6 +485,13 @@ and <code>src/</code> directories).
<code>CGAL::write_ply_points()</code>
and <code>CGAL::write_ply_points_and_normals()</code>.</li>
</ul>
<h3>Point Set Shape Detection</h3>
<ul>
<li>New post-processing
algorithm: <code>CGAL::regularize_planes()</code>. This allows the user
to favor parallelism, orthogonality, coplanarity and/or axial
symmetry between detected planes.</li>
</ul>
<h3>Surface Mesh Parameterization</h3>
<ul>
<li><code>LSCM_parameterizer_3</code> now uses by default Eigen

View File

@ -0,0 +1,2 @@
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Point Set"

View File

@ -0,0 +1,70 @@
/*!
\defgroup PkgPointSet3 3D Point Set Reference
\cgalPkgDescriptionBegin{3D Point Set, PkgPointSet3Summary}
\cgalPkgPicture{point_set_3.png}
\cgalPkgSummaryBegin
\cgalPkgAuthors{Simon Giraudot}
\cgalPkgDesc{This component provides the user with a flexible 3D point set data structure. The user can define any additional property needed such as normal vectors, colors or labels. \cgal algorithms can be easily applied to this data structure.}
\cgalPkgManuals{Chapter_Point_Set_3, PkgPointSet3}
\cgalPkgSummaryEnd
\cgalPkgShortInfoBegin
\cgalPkgSince{4.10}
\cgalPkgBib{cgal:g-ps}
\cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgDemo{Operations on Polyhedra,polyhedron_3.zip}
\cgalPkgShortInfoEnd
\cgalPkgDescriptionEnd
\cgalClassifedRefPages
## Class ##
- `CGAL::Point_set_3<Point,Vector>`
\defgroup PkgPointSet3PointSetProcessing3 Point Set Processing
\ingroup PkgPointSet3
\brief This module offers convenience overloads of functions available in the
\ref PkgPointSetProcessingSummary package. These overloads allow the
user to call point set processing algorithms without having to handle
manually property maps and iterators.
The overloads, available after including
`CGAL/Point_set_3/Point_set_processing_3.h`, all follow the same
pattern based on the original point set processing functions:
- Iterators and property maps of the original functions are replaced
with a single parameter `CGAL::Point_set_3<Point,Vector>`
- The other parameters (and their potential default values) are
following in the same order as the original function.
For a complete documentation of these functions, please refer to the
\ref PkgPointSetProcessing manual.
\defgroup PkgPointSet3IO Input/Output
\ingroup PkgPointSet3
\brief This module offers convenience overloads of input/ouput
functions available in the \ref PkgPointSetProcessingSummary package.
These overloads, available after including `CGAL/Point_set_3/IO.h`,
allow the user to call point set processing algorithms without having
to handle manually property maps and iterators.
Input functions instanciate all the necessary property maps:
- if found in the input, normal vectors are stored in the usual
`CGAL::Point_set_3` property `normal` with template type `Vector`
- for PLY input only, other properties are stored as properties in the
`Point_set_3` class with the name and type given by the PLY header
For a complete documentation of these functions, please refer to the
\ref PkgPointSetProcessing manual.
*/

View File

@ -0,0 +1,178 @@
namespace CGAL {
/*!
\mainpage User Manual
\anchor Chapter_Point_Set_3
\cgalAutoToc
\author Simon Giraudot
\cgal provides several algorithms for processing point sets, ranging from
\ref Chapter_Point_Set_Shape_Detection "Shape Detection" to
\ref Chapter_Advancing_Front_Surface_Reconstruction "Surface Reconstruction"
through standard \ref Chapter_Point_Set_Processing "Point Set Processing" tools.
While these algorithms do not impose specific data structures to work
on, \cgal provides a 3D point set structure to make it easier for the
user to handle additional properties such as normal vectors, colors,
labels, and to call \cgal algorithms on them.
\section Point_set_3_Principle General Principle
`CGAL::Point_set_3<Point,Vector>` is a vector based data structure
that contains by default a property named _point_ with template
`Point` type.
Any property the user needs can be easily added, modified and
removed. A property is identified by a unique name and a
type. Convenience methods are provided to handle the property named
_normal_ with template type `Vector` that is a very common property on
point sets.
Reordering is achieved by swapping index values: this guarantees that
these operations have a constant complexity no matter how many
properties are defined. To avoid frequent memory allocation and
deallocation, removal of points is also handled by swapping the index
values, putting the points marked as removed at the back of the index
property and keeping track of the number of points marked as
removed. If the user needs memory to be deallocated, the element
marked as removed can be actually deleted from memory.
\section Point_set_3_Usage Simple Usage
The data structure is designed to be easy to use despite its potential
complexity when using properties. Several convenience methods are
provided to handle points and normals without having to handle
properties directly.
The following example shows how to fill a point set with points, add a
normal property, set the normal values, add or remove an item, etc.
\cgalExample{Point_set_3/point_set.cpp}
\section Point_set_3_Properties Using Additional Properties
Every information in the point set is a property. A raw point set
comes with a _point_ property only. As we saw in the previous section,
the user can easily add a _normal_ property. But this mechanism is
generalized to any type of property.
The following example shows how to define a color property and an
intensity property, and how to modify the point set according to this.
\cgalExample{Point_set_3/point_set_property.cpp}
\section Point_set_3_Algorithms Applying CGAL Algorithms
Most \cgal algorithms let the user free to choose whatever data
structures he/she needs: the points and attributes are then access
through iterators and property maps. The `CGAL::Point_set_3`
structure directly provides these iterators and property maps so that
applying \cgal algorithms to it is straightforward.
In addition, all functions of the package
\ref Chapter_Point_Set_Processing "Point Set Processing" are overloaded so
that the user only has to call them with the `CGAL::Point_set_3`
object as a parameter to replace all property maps and iterators.
\subsection Point_set_3_PSP Point Set Processing
The following example shows how to apply some algorithms from the
\cgal library using a point set object:
- generating a point set around a sphere
- estimating the normals with `CGAL::jet_estimate_normals()`
- simplifying the point set with `CGAL::grid_simplify_point_set()`
- detecting the sphere shape with `CGAL::Shape_detection_3::Efficient_RANSAC`
\cgalExample{Point_set_3/point_set_algo.cpp}
\subsection Point_set_3_IO Input/Output
The following example reads a point set in the XYZ format, normalizes
and inverts the normal vectors and write the result in the OFF
format.
\cgalExample{Point_set_3/point_set_read_xyz.cpp}
The PLY format is the usual choice when storing an arbitrary number of
additional properties of points is needed. \cgal provides a function
`read_ply_point_set()` that allows the user to recover any PLY
property he/she wants, provided the adapted PLY interpreter is
implemented.
The `CGAL::Point_set_3` object is filled with all readable properties
of a PLY input. Each PLY property is read and stored into a point set
property with similar name and type.
For example, if the following line is found in the PLY header:
> property uchar red
Then a property named _red_ and with type `boost::uint8_t` (`boost`
types are used because of their fixed memory size) will be
instantiated in the point set and filled with the corresponding
values.
Only points and normals are recovered as properties with complex class
types (namely the template types `Point` and `Vector`). Other
properties are stored with simple number types. For example, if a
color is given with integer red, green and blue values, 3 integer
properties _red_, _green_ and _blue_ will be instantiated. A
user-defined interpreter must be implemented if such properties should
be stored all together (a unique property _color_ of type
`CGAL::cpp11::array` for example).
The following example shows how to use this interpreter and how to
recover a specific property afterwards:
\cgalExample{Point_set_3/point_set_read_ply.cpp}
\subsection Point_set_3_Avdanced Advanced Usage
Using functions of \cgal to read files requires a slightly different
behavior because, internally, the properties of an item are defined
_before_ this item is inserted into the point set (which is not
possible with `CGAL::Point_set_3`). Although using the provided
overloads presented in the previous subsection should cover most
usages, we document the specific back inserters and property maps that
are used internally:
- `CGAL::Point_set_3::index_back_inserter()` is used as an output iterator that creates
new item
- `CGAL::Point_set_3::point_push_map()` is a property map that is allowed to create a
new item if it was not yet created by the back inserter
- `CGAL::Point_set_3::normal_push_map()` works similarly
Such _push property maps_ are also available for other user-defined
properties (see `CGAL::Point_set_3::push_property_map()`).
The following example shows how to read OFF point without using the
overload provided for `CGAL::Point_set_3`:
\cgalExample{Point_set_3/point_set_advanced.cpp}
\section Point_set_3_History History
This package has been created to fill the need for a practical data
structure that handles points with a user-defined set of
properties. This property mechanism was already implemented in the
\ref Chapter_3D_Surface_mesh "Surface Mesh" package: all the classes
dedicated to the management of properties were extracted so that they
can be used in this _3D Point Set_
package. `CGAL::Surface_mesh<Point>` and
`CGAL::Point_set_3<Point,Vector>` follow a similar API for property
management.
*/
} /* namespace CGAL */

View File

@ -0,0 +1,10 @@
Manual
Kernel_23
STL_Extension
Algebraic_foundations
Circulator
Stream_support
Point_set_processing_3
Point_set_shape_detection_3
Advancing_front_surface_reconstruction
Surface_mesh

View File

@ -0,0 +1,8 @@
/*!
\example Point_set_3/point_set.cpp
\example Point_set_3/point_set_property.cpp
\example Point_set_3/point_set_algo.cpp
\example Point_set_3/point_set_read_xyz.cpp
\example Point_set_3/point_set_read_ply.cpp
\example Point_set_3/point_set_advanced.cpp
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -0,0 +1,64 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
project( Point_set_3 )
cmake_minimum_required(VERSION 2.8.11)
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
# include helper file
include( ${CGAL_USE_FILE} )
# Boost and its components
find_package( Boost REQUIRED )
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
# include for local directory
include_directories( BEFORE include )
# include for local package
include_directories( BEFORE ../../include )
# Creating entries for all C++ files with "main" routine
# ##########################################################
include( CGAL_CreateSingleSourceCGALProgram )
create_single_source_cgal_program( "point_set.cpp" )
create_single_source_cgal_program( "point_set_property.cpp" )
create_single_source_cgal_program( "point_set_read_xyz.cpp" )
create_single_source_cgal_program( "point_set_read_ply.cpp" )
create_single_source_cgal_program( "point_set_advanced.cpp" )
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
if (NOT EIGEN3_FOUND)
find_package(LAPACK)
if(LAPACK_FOUND)
include( ${LAPACK_USE_FILE} )
endif(LAPACK_FOUND)
else()
include( ${EIGEN3_USE_FILE} )
create_single_source_cgal_program( "point_set_algo.cpp" )
endif()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
ply
format ascii 1.0
comment Example for CGAL PLY reader
element vertex 3
property double x
property double y
property double z
property double nx
property double ny
property double nz
property uchar red
property uchar green
property uchar blue
property double intensity
property int label
end_header
0.0 0.0 0.0 0.0 0.0 1.0 255 0 0 0.8 1
0.0 0.0 1.0 0.0 0.0 1.0 0 255 0 0.76 0
0.0 1.0 0.0 0.0 0.0 1.0 0 0 255 0.99 1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
void print_point_set (const Point_set& point_set)
{
std::cerr << "Content of point set:" << std::endl;
for (Point_set::const_iterator it = point_set.begin();
it != point_set.end(); ++ it)
std::cerr << "* Point " << *it
<< ": " << point_set.point(*it) // or point_set[it]
<< " with normal " << point_set.normal(*it)
<< std::endl;
}
int main (int, char**)
{
Point_set point_set;
// Add points
point_set.insert (Point (0., 0., 0.));
point_set.insert (Point (0., 0., 1.));
point_set.insert (Point (0., 1., 0.));
point_set.add_normal_map();
print_point_set(point_set); // Normals have default values
// Change normal values
Point_set::iterator it = point_set.begin();
point_set.normal(*(it++)) = Vector (1., 0., 0.);
point_set.normal(*(it++)) = Vector (0., 1., 0.);
point_set.normal(*(it++)) = Vector (0., 0., 1.);
// Add point + normal
point_set.insert (Point (1., 2., 3.), Vector (4., 5., 6.));
print_point_set(point_set);
// Add new item
Point_set::iterator new_item = point_set.insert(Point (7., 8., 9.));
point_set.normal(*new_item) = Vector (10., 11., 12.);
print_point_set(point_set); // New item has default values
point_set.remove (point_set.begin() + 2,
point_set.begin() + 4);
print_point_set(point_set); // New item has default values
// Display information
std::cerr << "Number of removed points: " <<point_set.number_of_removed_points() << std::endl;
point_set.collect_garbage();
// Display information (garbage should be gone)
std::cerr << "After garbage collection: " <<point_set.number_of_removed_points() << std::endl;
return 0;
}

View File

@ -0,0 +1,33 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/IO/read_off_points.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
int main (int argc, char** argv)
{
std::ifstream f (argc > 1 ? argv[1] : "data/camel.off");
Point_set point_set;
point_set.add_normal_map();
// Reading input in OFF format
if (!f || !CGAL::read_off_points_and_normals
(f,
point_set.index_back_inserter(), // OutputIterator
point_set.point_push_map(),
point_set.normal_push_map()))
{
std::cerr << "Can't read input file " << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,74 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/Point_set_processing_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <CGAL/grid_simplify_point_set.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/Shape_detection_3.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Random_points_on_sphere_3<Point> Point_generator;
typedef CGAL::Point_set_3<Point> Point_set;
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits
<Kernel, Point_set, Point_set::Point_map, Point_set::Vector_map> Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits> Efficient_ransac;
typedef CGAL::Shape_detection_3::Sphere<Traits> Sphere;
int main (int, char**)
{
Point_set point_set;
// Generate points on a unit sphere
Point_generator generator(1.);
std::size_t nb_pts = 10000;
point_set.reserve (nb_pts);
for (std::size_t i = 0; i < nb_pts; ++ i)
point_set.insert (*(generator ++));
// Add normal property and estimate normal values
CGAL::jet_estimate_normals<CGAL::Sequential_tag> (point_set,
12); // Number of neighbors
// Simplify point set
CGAL::grid_simplify_point_set (point_set,
0.1); // Size of grid cell
std::vector<std::string> properties = point_set.properties();
std::cerr << "Properties:" << std::endl;
for (std::size_t i = 0; i < properties.size(); ++ i)
std::cerr << " * " << properties[i] << std::endl;
// Detect sphere with RANSAC
Efficient_ransac ransac;
ransac.set_input(point_set,
point_set.point_map(), // Call built-in property map
point_set.normal_map()); // Call built-in property map
ransac.add_shape_factory<Sphere>();
Efficient_ransac::Parameters parameters;
parameters.probability = 0.05;
parameters.min_points = point_set.size() / 3.;
parameters.epsilon = 0.01;
parameters.cluster_epsilon = 0.5;
parameters.normal_threshold = 0.9;
ransac.detect(parameters);
BOOST_FOREACH(boost::shared_ptr<Efficient_ransac::Shape> shape, ransac.shapes())
if (Sphere* sphere = dynamic_cast<Sphere*>(shape.get()))
std::cerr << "Detected sphere of center " << sphere->center() // Center should be approx 0, 0, 0
<< " and of radius " << sphere->radius() << std::endl; // Radius should be approx 1
return 0;
}

View File

@ -0,0 +1,79 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::cpp11::array<unsigned char, 3> Color;
typedef CGAL::Point_set_3<Point> Point_set;
typedef Point_set::Property_map<Color> Color_map;
typedef Point_set::Property_map<FT> FT_map;
void print_point_set (const Point_set& point_set)
{
Color_map color;
boost::tie (color, boost::tuples::ignore) = point_set.property_map<Color>("color");
FT_map intensity;
boost::tie (intensity, boost::tuples::ignore) = point_set.property_map<FT>("intensity");
std::cerr << "Content of point set:" << std::endl;
for (Point_set::const_iterator it = point_set.begin();
it != point_set.end(); ++ it)
std::cerr << "* Point " << point_set.point(*it) // or point_set[it]
<< " with color [" << (int)(color[*it][0])
<< " " << (int)(color[*it][1])
<< " " << (int)(color[*it][2])
<< "] and intensity " << intensity[*it]
<< std::endl;
}
int main (int, char**)
{
srand (time (NULL));
Point_set point_set;
Color black = {{ 0, 0, 0 }};
bool success = false;
Color_map color;
boost::tie (color, success) = point_set.add_property_map<Color> ("color", black);
assert (success);
FT_map intensity;
boost::tie (intensity, success) = point_set.add_property_map<FT> ("intensity", 0.);
assert (success);
point_set.reserve (10); // For memory optimization
for (std::size_t i = 0; i < 10; ++ i)
{
Point_set::iterator it = point_set.insert (Point (i, i, i));
Color c = {{ (unsigned char)(rand() % 256),
(unsigned char)(rand() % 256),
(unsigned char)(rand() % 256) }};
color[*it] = c;
intensity[*it] = rand() / (double)(RAND_MAX);
}
print_point_set (point_set);
// Remove points with intensity less than 0.5
Point_set::iterator it = point_set.begin();
while (it != point_set.end())
{
if (intensity[*it] < 0.5)
point_set.remove(it);
else
++ it;
}
print_point_set (point_set); // point set is filtered
return 0;
}

View File

@ -0,0 +1,48 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
int main (int argc, char** argv)
{
std::ifstream f (argc > 1 ? argv[1] : "data/example.ply");
Point_set point_set;
if (!f || !CGAL::read_ply_point_set (f, point_set))
{
std::cerr << "Can't read input file " << std::endl;
}
// Shows which properties are defined
std::vector<std::string> properties = point_set.properties();
std::cerr << "Properties:" << std::endl;
for (std::size_t i = 0; i < properties.size(); ++ i)
std::cerr << " * " << properties[i] << std::endl;
// Recover "label" property of type int
Point_set::Property_map<boost::int32_t> label_prop;
bool found = false;
boost::tie (label_prop, found) = point_set.property_map<boost::int32_t> ("label");
if (found)
{
std::cerr << "Point set has an integer \"label\" property with values:" << std::endl;
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
std::cerr << " * " << label_prop[*it] << std::endl;
}
std::ofstream out ("out.ply");
CGAL::write_ply_point_set (out, point_set);
return 0;
}

View File

@ -0,0 +1,47 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
int main (int argc, char** argv)
{
std::ifstream f (argc > 1 ? argv[1] : "data/oni.xyz");
Point_set point_set;
// Reading input in XYZ format
if (!f || !CGAL::read_xyz_point_set (f, point_set))
{
std::cerr << "Can't read input file " << std::endl;
return EXIT_FAILURE;
}
if (point_set.has_normal_map())
{
// Normalization + inversion of normal vectors
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
{
Vector n = point_set.normal(*it);
n = - n / std::sqrt (n * n);
point_set.normal(*it) = n;
}
}
// Writing result in OFF format
std::ofstream out("normalized_normals.off");
if (!out || !CGAL::write_off_point_set (out, point_set))
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,232 @@
// Copyright (c) 2016 Geometry Factory
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Simon Giraudot
#ifndef CGAL_READ_PLY_POINT_SET_3_H
#define CGAL_READ_PLY_POINT_SET_3_H
#include <CGAL/Point_set_3.h>
/// \cond SKIP_IN_MANUAL
namespace CGAL
{
/*!
\ingroup PkgPointSet3
\brief PLY interpreter designed to fill a `CGAL::Point_set_3` object.
This interpreter will instanciate any number of property needed to
store all PLY properties read in the header:
- points and normals are stored as usual `CGAL::Point_set_3`
properties (property "point" of type `CGAL::Point_3` and property
"normal" of type `CGAL::Vector_3`)
- other PLY properties are stored on point set properties with the
name and type given by the PLY header
\tparam Point Point type.
\tparam Vector Normal vector type.
\cgalModels `PlyInterpreter`
*/
template <typename Point,
typename Vector = typename Kernel_traits<Point>::Kernel::Vector_3>
class Ply_interpreter_point_set_3
{
public:
typedef Point_set_3<Point> Point_set;
private:
struct Abstract_ply_property_to_point_set_property
{
virtual void assign (Ply_reader& reader, typename Point_set::Index index) = 0;
};
template <typename Type>
class Ply_property_to_point_set_property : public Abstract_ply_property_to_point_set_property
{
typedef typename Point_set::template Property_map<Type> Map;
typedef typename Point_set::template Push_property_map<Map> Pmap;
Map m_map;
Pmap m_pmap;
std::string m_name;
public:
Ply_property_to_point_set_property (Point_set& ps, const std::string& name)
: m_name (name)
{
boost::tie (m_map, boost::tuples::ignore) = ps.add_property_map(name, Type());
m_pmap = ps.push_property_map (m_map);
}
virtual void assign (Ply_reader& reader, typename Point_set::Index index)
{
Type t;
reader.assign (t, m_name.c_str());
put(m_pmap, index, t);
}
};
Point_set& m_point_set;
bool m_use_floats;
std::vector<Abstract_ply_property_to_point_set_property*> m_properties;
public:
Ply_interpreter_point_set_3 (Point_set& point_set)
: m_point_set (point_set), m_use_floats (false)
{ }
bool is_applicable (Ply_reader& reader)
{
const std::vector<internal::Ply_read_number*>& readers
= reader.readers();
bool has_normal[3] = { false, false, false };
for (std::size_t i = 0; i < readers.size(); ++ i)
{
const std::string& name = readers[i]->name();
if (name == "x" ||
name == "y" ||
name == "z")
{
if (dynamic_cast<internal::Ply_read_typed_number<float>*>(readers[i]))
m_use_floats = true;
continue;
}
if (name == "nx")
{
has_normal[0] = true;
continue;
}
if (name == "ny")
{
has_normal[1] = true;
continue;
}
if (name == "nz")
{
has_normal[2] = true;
continue;
}
if (dynamic_cast<internal::Ply_read_typed_number<boost::int8_t>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<boost::int8_t>(m_point_set,
name));
}
else if (dynamic_cast<internal::Ply_read_typed_number<boost::uint8_t>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<boost::uint8_t>(m_point_set,
name));
}
else if (dynamic_cast<internal::Ply_read_typed_number<boost::int16_t>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<boost::int16_t>(m_point_set,
name));
}
else if (dynamic_cast<internal::Ply_read_typed_number<boost::uint16_t>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<boost::uint16_t>(m_point_set,
name));
}
else if (dynamic_cast<internal::Ply_read_typed_number<boost::int32_t>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<boost::int32_t>(m_point_set,
name));
}
else if (dynamic_cast<internal::Ply_read_typed_number<boost::uint32_t>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<boost::uint32_t>(m_point_set,
name));
}
else if (dynamic_cast<internal::Ply_read_typed_number<float>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<float>(m_point_set,
name));
}
else if (dynamic_cast<internal::Ply_read_typed_number<double>*>(readers[i]))
{
m_properties.push_back
(new Ply_property_to_point_set_property<double>(m_point_set,
name));
}
}
if (has_normal[0] && has_normal[1] && has_normal[2])
m_point_set.add_normal_map();
return (reader.does_tag_exist<float> ("x") || reader.does_tag_exist<double> ("x"))
&& (reader.does_tag_exist<float> ("y") || reader.does_tag_exist<double> ("y"))
&& (reader.does_tag_exist<float> ("z") || reader.does_tag_exist<double> ("z"));
}
void process_line (Ply_reader& reader)
{
m_point_set.insert();
if (m_use_floats)
process_line<float>(reader);
else
process_line<double>(reader);
for (std::size_t i = 0; i < m_properties.size(); ++ i)
m_properties[i]->assign (reader, *(m_point_set.end() - 1));
}
template <typename FT>
void process_line (Ply_reader& reader)
{
FT x = (FT)0.,y = (FT)0., z = (FT)0.,
nx = (FT)0., ny = (FT)0., nz = (FT)0.;
reader.assign (x, "x");
reader.assign (y, "y");
reader.assign (z, "z");
Point point (x, y, z);
m_point_set.point(*(m_point_set.end() - 1)) = point;
if (m_point_set.has_normal_map())
{
reader.assign (nx, "nx");
reader.assign (ny, "ny");
reader.assign (nz, "nz");
Vector normal (nx, ny, nz);
m_point_set.normal(*(m_point_set.end() - 1)) = normal;
}
}
};
}
/// \endcond
#endif // CGAL_READ_PLY_POINT_SET_3_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,400 @@
// Copyright (c) 2016 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Simon Giraudot
#ifndef CGAL_POINT_SET_3_IO
#define CGAL_POINT_SET_3_IO
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/read_off_points.h>
#include <CGAL/IO/read_ply_points.h>
#include <CGAL/IO/read_ply_point_set_3.h>
#include <CGAL/IO/write_xyz_points.h>
#include <CGAL/IO/write_off_points.h>
#include <CGAL/IO/write_ply_points.h>
namespace CGAL {
/*!
\ingroup PkgPointSet3IO
*/
template <typename Point, typename Vector>
bool
read_xyz_point_set(
std::istream& stream, ///< input stream.
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
point_set.add_normal_map();
bool out = CGAL::read_xyz_points_and_normals
(stream,
point_set.index_back_inserter(),
point_set.point_push_map(),
point_set.normal_push_map());
bool has_normals = false;
for (typename CGAL::Point_set_3<Point, Vector>::const_iterator it = point_set.begin();
it != point_set.end(); ++ it)
if (point_set.normal(*it) != CGAL::NULL_VECTOR)
{
has_normals = true;
break;
}
if (!has_normals)
point_set.remove_normal_map();
return out;
}
/*!
\ingroup PkgPointSet3IO
*/
template <typename Point, typename Vector>
bool
read_off_point_set(
std::istream& stream, ///< input stream.
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
point_set.add_normal_map();
bool out = CGAL::read_off_points_and_normals
(stream,
point_set.index_back_inserter(),
point_set.point_push_map(),
point_set.normal_push_map());
bool has_normals = false;
for (typename CGAL::Point_set_3<Point, Vector>::const_iterator it = point_set.begin();
it != point_set.end(); ++ it)
if (point_set.normal(*it) != CGAL::NULL_VECTOR)
{
has_normals = true;
break;
}
if (!has_normals)
point_set.remove_normal_map();
return out;
}
/*!
\ingroup PkgPointSet3IO
*/
template <typename Point, typename Vector>
bool
read_ply_point_set(
std::istream& stream, ///< input stream.
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
CGAL::Ply_interpreter_point_set_3<Point, Vector> interpreter (point_set);
return CGAL::read_ply_custom_points
(stream, interpreter,
typename Kernel_traits<Point>::Kernel());
}
/*!
\ingroup PkgPointSet3IO
*/
template <typename Point, typename Vector>
bool
write_xyz_point_set(
std::ostream& stream, ///< output stream.
const CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
if (point_set.has_normal_map())
return CGAL::write_xyz_points_and_normals
(stream, point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map());
return CGAL::write_xyz_points
(stream, point_set.begin(), point_set.end(),
point_set.point_map());
}
/*!
\ingroup PkgPointSet3IO
*/
template <typename Point, typename Vector>
bool
write_off_point_set(
std::ostream& stream, ///< output stream.
const CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
if (point_set.has_normal_map())
return CGAL::write_off_points_and_normals
(stream, point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map());
return CGAL::write_off_points
(stream, point_set.begin(), point_set.end(),
point_set.point_map());
}
/*!
\ingroup PkgPointSet3IO
*/
template <typename Point, typename Vector>
bool
write_ply_point_set(
std::ostream& stream, ///< output stream.
const CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
stream << point_set;
return true;
// if (point_set.has_normal_map())
// return CGAL::write_ply_points_and_normals
// (stream, point_set.begin(), point_set.end(),
// point_set.point_map(), point_set.normal_map());
// return CGAL::write_ply_points
// (stream, point_set.begin(), point_set.end(),
// point_set.point_map());
}
/*!
\ingroup PkgPointSet3IO
\brief Reads the point set from an input stream that can be either:
- XYZ
- OFF
- PLY
The format is detected from the stream. If the stream contains
normal vectors, the normal map is added to the point set. For PLY
input, all point properties found in the header are added.
\relates Point_set_3
*/
template <typename Point, typename Vector>
std::istream& operator>>(std::istream& is,
CGAL::Point_set_3<Point, Vector>& ps)
{
// Check format identifier on first line
std::string line;
if (!getline(is, line))
return is;
is.seekg(0);
if (line == "OFF" || line == "NOFF")
CGAL::read_off_point_set (is, ps);
else if (line == "ply")
CGAL::read_ply_point_set (is, ps);
else
CGAL::read_xyz_point_set (is, ps);
return is;
}
/// \cond SKIP_IN_MANUAL
namespace internal
{
template <typename Point, typename Vector>
class Abstract_property_printer
{
public:
virtual std::string get_string(const typename CGAL::Point_set_3<Point,Vector>::Index& index) = 0;
};
template <typename Point, typename Vector, typename Type>
class Property_printer : public Abstract_property_printer<Point, Vector>
{
typedef typename CGAL::Point_set_3<Point, Vector> Point_set;
typedef typename Point_set::template Property_map<Type> Pmap;
Pmap m_pmap;
public:
Property_printer (const Pmap& pmap) : m_pmap (pmap)
{
}
virtual std::string get_string(const typename CGAL::Point_set_3<Point,Vector>::Index& index)
{
std::ostringstream oss;
oss.precision (std::numeric_limits<double>::digits10 + 2);
oss << get(m_pmap, index);
return oss.str();
}
};
template <typename Point, typename Vector, typename Type>
class Char_property_printer : public Abstract_property_printer<Point, Vector>
{
typedef typename CGAL::Point_set_3<Point, Vector> Point_set;
typedef typename Point_set::template Property_map<Type> Pmap;
Pmap m_pmap;
public:
Char_property_printer (const Pmap& pmap) : m_pmap (pmap)
{
}
virtual std::string get_string(const typename CGAL::Point_set_3<Point,Vector>::Index& index)
{
std::ostringstream oss;
oss << (int)(get(m_pmap, index));
return oss.str();
}
};
}
/// \endcond
/*!
\ingroup PkgPointSet3IO
\brief Inserts the point set in an output stream in ASCII PLY
format. All properties are inserted in their instantiation order.
\relates Point_set_3
*/
template <typename Point, typename Vector>
std::ostream& operator<<(std::ostream& os,
const CGAL::Point_set_3<Point, Vector>& ps)
{
typedef CGAL::Point_set_3<Point, Vector> Point_set;
os << "ply" << std::endl
<< "format ascii 1.0" << std::endl
<< "comment Generated by the CGAL library" << std::endl
<< "element vertex " << ps.number_of_points() << std::endl;
std::vector<std::string> prop = ps.base().properties();
std::vector<internal::Abstract_property_printer<Point, Vector>*> printers;
for (std::size_t i = 0; i < prop.size(); ++ i)
{
if (prop[i] == "index")
continue;
if (prop[i] == "point")
{
os << "property double x" << std::endl
<< "property double y" << std::endl
<< "property double z" << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,Point>(ps.point_map()));
continue;
}
if (prop[i] == "normal")
{
os << "property double nx" << std::endl
<< "property double ny" << std::endl
<< "property double nz" << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,Vector>(ps.normal_map()));
continue;
}
bool okay = false;
{
typename Point_set::template Property_map<boost::int8_t> pmap;
boost::tie (pmap, okay) = ps.template property_map<boost::int8_t>(prop[i]);
if (okay)
{
os << "property char " << prop[i] << std::endl;
printers.push_back (new internal::Char_property_printer<Point,Vector,boost::int8_t>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::uint8_t> pmap;
boost::tie (pmap, okay) = ps.template property_map<boost::uint8_t>(prop[i]);
if (okay)
{
os << "property uchar " << prop[i] << std::endl;
printers.push_back (new internal::Char_property_printer<Point,Vector,boost::uint8_t>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::int16_t> pmap;
boost::tie (pmap, okay) = ps.template property_map<boost::int16_t>(prop[i]);
if (okay)
{
os << "property short " << prop[i] << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,boost::int16_t>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::uint16_t> pmap;
boost::tie (pmap, okay) = ps.template property_map<boost::uint16_t>(prop[i]);
if (okay)
{
os << "property ushort " << prop[i] << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,boost::uint16_t>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::int32_t> pmap;
boost::tie (pmap, okay) = ps.template property_map<boost::int32_t>(prop[i]);
if (okay)
{
os << "property int " << prop[i] << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,boost::int32_t>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<float> pmap;
boost::tie (pmap, okay) = ps.template property_map<float>(prop[i]);
if (okay)
{
os << "property float " << prop[i] << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,float>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<double> pmap;
boost::tie (pmap, okay) = ps.template property_map<double>(prop[i]);
if (okay)
{
os << "property double " << prop[i] << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,double>(pmap));
continue;
}
}
}
os << "end_header" << std::endl;
for (typename Point_set::const_iterator it = ps.begin(); it != ps.end(); ++ it)
{
for (std::size_t i = 0; i < printers.size(); ++ i)
os << printers[i]->get_string(*it) << " ";
os << std::endl;
}
return os;
}
} // namespace CGAL
#endif // CGAL_POINT_SET_3_IO

View File

@ -0,0 +1,304 @@
// Copyright (c) 2016 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Simon Giraudot
#ifndef CGAL_POINT_SET_3_POINT_SET_PROCESSING_3_H
#define CGAL_POINT_SET_3_POINT_SET_PROCESSING_3_H
#include <CGAL/bilateral_smooth_point_set.h>
#include <CGAL/compute_average_spacing.h>
#include <CGAL/edge_aware_upsample_point_set.h>
#include <CGAL/grid_simplify_point_set.h>
#include <CGAL/hierarchy_simplify_point_set.h>
#include <CGAL/jet_estimate_normals.h>
#include <CGAL/jet_smooth_point_set.h>
#include <CGAL/mst_orient_normals.h>
#include <CGAL/pca_estimate_normals.h>
#include <CGAL/random_simplify_point_set.h>
#include <CGAL/remove_outliers.h>
#include <CGAL/vcm_estimate_normals.h>
#include <CGAL/wlop_simplify_and_regularize_point_set.h>
namespace CGAL {
/*!
\ingroup PkgPointSet3PointSetProcessing3
*/
template <typename Concurrency_tag,
typename Point,
typename Vector>
double
bilateral_smooth_point_set(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
const unsigned int k, ///< number of neighbors.
double sharpness_angle) ///< control sharpness(0-90)
{
return CGAL::bilateral_smooth_point_set<Concurrency_tag>
(point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map(),
k, sharpness_angle);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
*/
template <typename Concurrency_tag,
typename Point, typename Vector>
double
compute_average_spacing(
const CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
unsigned int k) ///< number of neighbors.
{
return CGAL::compute_average_spacing<Concurrency_tag>
(point_set.begin(), point_set.end(), point_set.point_map(), k);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
*/
template <typename Concurrency_tag,
typename Point, typename Vector>
void
edge_aware_upsample_point_set(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
double sharpness_angle = 30, ///< control sharpness(0-90)
double edge_sensitivity = 1, ///< edge sensitivity(0-5)
double neighbor_radius = -1, ///< initial size of neighbors.
const std::size_t number_of_output_points = 1000)///< number of output points.
{
CGAL::edge_aware_upsample_point_set<Concurrency_tag>
(point_set.begin(), point_set.end(),
point_set.point_back_inserter(),
point_set.point_map(), point_set.normal_map(),
sharpness_angle, edge_sensitivity, neighbor_radius, number_of_output_points);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note No iterator is returned, points simplified are directly
removed from the point set.
*/
template <typename Point, typename Vector>
void grid_simplify_point_set(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
double epsilon) ///< tolerance value when merging 3D points.
{
point_set.remove_from
(CGAL::grid_simplify_point_set
(point_set.begin(), point_set.end(), point_set.point_map(), epsilon));
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note No iterator is returned, points simplified are directly
removed from the point set.
*/
template <typename Point, typename Vector>
void hierarchy_simplify_point_set(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
const unsigned int size = 10, ///< maximum cluster size
const double var_max = 0.333) ///< maximal surface variation
{
point_set.remove_from
(CGAL::hierarchy_simplify_point_set
(point_set.begin(), point_set.end(), point_set.point_map(), size, var_max,
CGAL::Default_diagonalize_traits<double, 3>()));
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note This function adds a normal map to the point set.
*/
template <typename Concurrency_tag,
typename Point, typename Vector>
void
jet_estimate_normals(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
unsigned int k, ///< number of neighbors.
unsigned int degree_fitting = 2) ///< fitting degree
{
point_set.add_normal_map();
CGAL::jet_estimate_normals<Concurrency_tag>
(point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map(),
k, degree_fitting);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
*/
template <typename Concurrency_tag,
typename Point, typename Vector>
void
jet_smooth_point_set(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
unsigned int k, ///< number of neighbors.
unsigned int degree_fitting = 2, ///< fitting degree
unsigned int degree_monge = 2) ///< Monge degree
{
CGAL::jet_smooth_point_set<Concurrency_tag>
(point_set.begin(), point_set.end(), point_set.point_map(),
k, degree_fitting, degree_monge);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
*/
template <typename Point, typename Vector>
typename CGAL::Point_set_3<Point, Vector>::iterator
mst_orient_normals(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
unsigned int k) ///< number of neighbors
{
return CGAL::mst_orient_normals
(point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map(), k);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note This function adds a normal map to the point set.
*/
template <typename Concurrency_tag,
typename Point, typename Vector>
void
pca_estimate_normals(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
unsigned int k) ///< number of neighbors.
{
point_set.add_normal_map();
CGAL::pca_estimate_normals<Concurrency_tag>
(point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map(),
k);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note No iterator is returned, points simplified are directly
removed from the point set.
*/
template <typename Point, typename Vector>
void random_simplify_point_set(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
double removed_percentage) ///< percentage of points to remove
{
point_set.remove_from
(CGAL::random_simplify_point_set
(point_set.begin(), point_set.end(), point_set.point_map(), removed_percentage));
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note No iterator is returned, points simplified are directly
removed from the point set.
*/
template <typename Point, typename Vector>
void remove_outliers(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
unsigned int k, ///< number of neighbors.
double threshold_percent) ///< percentage of points to remove
{
point_set.remove_from
(CGAL::remove_outliers
(point_set.begin(), point_set.end(), point_set.point_map(), k, threshold_percent));
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note This function adds a normal map to the point set.
*/
template <typename Point, typename Vector>
void
vcm_estimate_normals(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
double offset_radius, ///< offset radius.
double convolution_radius) ///< convolution radius.
{
point_set.add_normal_map();
CGAL::vcm_estimate_normals
(point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map(),
offset_radius, convolution_radius);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
\note This function adds a normal map to the point set.
*/
template <typename Point, typename Vector>
void
vcm_estimate_normals(
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
double offset_radius, ///< offset radius.
unsigned int nb_neighbors_convolve) ///< number of neighbors used during the convolution.
{
point_set.add_normal_map();
CGAL::vcm_estimate_normals
(point_set.begin(), point_set.end(),
point_set.point_map(), point_set.normal_map(),
offset_radius, nb_neighbors_convolve);
}
/*!
\ingroup PkgPointSet3PointSetProcessing3
*/
template <typename Concurrency_tag,
typename Point, typename Vector>
void
wlop_simplify_and_regularize_point_set(
const CGAL::Point_set_3<Point, Vector>& input_point_set, ///< input point set
CGAL::Point_set_3<Point, Vector>& output_point_set, ///< output point set
const double select_percentage = 5, ///< percentage of points to retain
double neighbor_radius = -1, ///< size of neighbors.
const unsigned int max_iter_number = 35, ///< number of iterations.
const bool require_uniform_sampling = false ///< if needed to compute density
/// to generate more rugularized result.
)
{
CGAL::wlop_simplify_and_regularize_point_set
(input_point_set.begin(), input_point_set.end(),
output_point_set.point_back_inserter(),
input_point_set.point_map(),
neighbor_radius, max_iter_number, require_uniform_sampling);
}
} // namespace CGAL
#endif // CGAL_POINT_SET_3_POINT_SET_PROCESSING_3_H

View File

@ -0,0 +1 @@
GeometryFactory (France)

View File

@ -0,0 +1 @@
GPL (v3 or later)

View File

@ -0,0 +1 @@
Simon Giraudot (simon.giraudot@geometryfactory.com)

View File

@ -0,0 +1,48 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
project( Point_set_3 )
cmake_minimum_required(VERSION 2.8.11)
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
# include helper file
include( ${CGAL_USE_FILE} )
# Boost and its components
find_package( Boost REQUIRED )
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
# include for local directory
# include for local package
include_directories( BEFORE ../../include )
# Creating entries for all C++ files with "main" routine
# ##########################################################
include( CGAL_CreateSingleSourceCGALProgram )
create_single_source_cgal_program( "point_set_test.cpp" )
create_single_source_cgal_program( "point_set_test_join.cpp" )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,123 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/Point_set_processing_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <CGAL/grid_simplify_point_set.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
typedef CGAL::cpp11::array<unsigned char, 3> Color;
std::size_t nb_test = 0;
std::size_t nb_success = 0;
void test (bool expr, const char* msg)
{
++ nb_test;
if (!expr)
std::cerr << "Error on test " << nb_test << ": " << msg << std::endl;
else
++ nb_success;
}
int main (int, char**)
{
Point_set point_set;
test (!(point_set.has_normal_map()), "point set shouldn't have normals.");
point_set.add_normal_map();
test (point_set.has_normal_map(), "point set should have normals.");
std::ifstream f ("data/oni.pwn");
CGAL::read_xyz_point_set(f, point_set);
f.close ();
Point_set::iterator
first_to_remove = CGAL::grid_simplify_point_set (point_set.begin(),
point_set.end(),
point_set.point_map(),
0.1);
std::size_t size = point_set.size ();
point_set.remove_from (first_to_remove);
test ((point_set.size() + point_set.garbage_size() == size), "sizes before and after removal do not match.");
Point_set::Point_range
range = point_set.points();
{
Point_set::const_iterator psit = point_set.begin();
bool range_okay = true;
for (Point_set::Point_range::const_iterator it = range.begin(); it != range.end(); ++ it)
{
if (*it != point_set.point (*psit))
{
range_okay = false;
break;
}
++ psit;
}
test (range_okay, "range access does not follow property map based access.");
}
test (point_set.has_garbage(), "point set should have garbage.");
point_set.collect_garbage();
test (!(point_set.has_garbage()), "point set shouldn't have garbage.");
test (!(point_set.has_property_map<Color> ("color")), "point set shouldn't have colors.");
typename Point_set::Property_map<Color> color_prop;
bool garbage;
boost::tie (color_prop, garbage) = point_set.add_property_map ("color", Color());
test (point_set.has_property_map<Color> ("color"), "point set should have colors.");
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
{
Color c = {{ static_cast<unsigned char>(rand() % 255),
static_cast<unsigned char>(rand() % 255),
static_cast<unsigned char>(rand() % 255) }};
put (color_prop, *it, c);
test ((get (color_prop, *it) == c), "recovered color is incorrect.");
}
typename Point_set::Property_map<Color> color_prop_2;
boost::tie (color_prop_2, garbage) = point_set.property_map<Color>("color");
test ((color_prop_2 == color_prop), "color property not recovered correctly.");
point_set.remove_normal_map ();
test (!(point_set.has_normal_map()), "point set shouldn't have normals.");
test (point_set.has_property_map<Color> ("color"), "point set should have colors.");
point_set.remove_property_map<Color> (color_prop);
test (!(point_set.has_property_map<Color> ("color")), "point set shouldn't have colors.");
point_set.add_property_map<int> ("label", 0);
point_set.add_property_map<double> ("intensity", 0.0);
test (point_set.base().n_properties() == 4, "point set should have 4 properties.");
Point p_before = *(point_set.points().begin());
point_set.clear_properties();
test (point_set.base().n_properties() == 2, "point set should have 2 properties.");
test (!(point_set.has_property_map<int>("label")), "point set shouldn' have labels.");
test (!(point_set.has_property_map<double>("intensity")), "point set shouldn' have intensity.");
test (!(point_set.empty()), "point set shouldn' be empty.");
Point p_after = *(point_set.points().begin());
test (p_before == p_after, "points should not change when clearing properties.");
std::cerr << nb_success << "/" << nb_test << " test(s) succeeded." << std::endl;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,66 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/write_xyz_points.h>
#include <CGAL/grid_simplify_point_set.h>
#include <fstream>
#include <limits>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
typedef CGAL::cpp11::array<unsigned char, 3> Color;
std::size_t nb_test = 0;
std::size_t nb_success = 0;
void test (bool expr, const char* msg)
{
++ nb_test;
if (!expr)
std::cerr << "Error on test " << nb_test << ": " << msg << std::endl;
else
++ nb_success;
}
void print_point_set (const Point_set& ps, const char* msg)
{
std::cerr << msg << std::endl;
if (ps.has_normal_map())
for (Point_set::const_iterator it = ps.begin(); it != ps.end(); ++ it)
std::cerr << *it << ": " << ps.point(*it)
<< ", normal " << ps.normal(*it) << std::endl;
else
for (Point_set::const_iterator it = ps.begin(); it != ps.end(); ++ it)
std::cerr << *it << ": " << ps.point(*it) << std::endl;
}
int main (int, char**)
{
Point_set ps1, ps2;
ps1.add_normal_map();
for (std::size_t i = 0; i < 5; ++ i)
ps1.insert (Point (i, i, i), Vector (i, i, i));
ps1.remove (ps1.end() - 3);
for (std::size_t i = 5; i < 10; ++ i)
ps2.insert (Point (i, i, i));
ps2.remove (ps2.end() - 3);
print_point_set (ps1, "PS1 = ");
print_point_set (ps2, "PS2 = ");
ps1 += ps2;
print_point_set (ps1, "JOINT PS1 = ");
return EXIT_SUCCESS;
};

View File

@ -24,6 +24,7 @@
#include <CGAL/value_type_traits.h>
#include <CGAL/point_set_processing_assertions.h>
#include <CGAL/Kernel_traits.h>
#include <CGAL/IO/io.h>
#include <boost/version.hpp>
#include <boost/cstdint.hpp>
@ -82,7 +83,17 @@ namespace internal {
stream >> s;
c = static_cast<unsigned char>(s);
}
void read_ascii (std::istream& stream, float& t) const
{
stream >> iformat(t);
}
void read_ascii (std::istream& stream, double& t) const
{
stream >> iformat(t);
}
// Default template when Type is not a char type
template <typename Type>
void read_ascii (std::istream& stream, Type& t) const
@ -90,6 +101,7 @@ namespace internal {
stream >> t;
}
template <typename Type>
Type read (std::istream& stream) const
{

View File

@ -234,7 +234,7 @@ jet_smooth_point_set(
{
for(it = first; it != beyond; it++)
{
typename boost::property_traits<PointPMap>::reference p = get(point_pmap, *it);
const typename boost::property_traits<PointPMap>::reference p = get(point_pmap, *it);
put(point_pmap, *it ,
internal::jet_smooth_point<Kernel, SvdTraits>(
p,tree,k,degree_fitting,degree_monge) );

View File

@ -242,6 +242,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
add_item(scene_polyhedron_selection_item Scene_polyhedron_selection_item.cpp)
target_link_libraries(scene_polyhedron_selection_item scene_polyhedron_item_decorator scene_polyhedron_item_k_ring_selection)
add_item(scene_point_set_classification_item Scene_point_set_classification_item.cpp)
target_link_libraries(scene_point_set_classification_item scene_points_with_normal_item scene_color_ramp)
add_item(scene_polyhedron_shortest_path_item Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp)
add_item(scene_surface_mesh_item Scene_surface_mesh_item.cpp)
@ -270,9 +273,6 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
target_link_libraries( demo_framework gl_splat)
foreach( lib
demo_framework
scene_basic_objects

View File

@ -57,3 +57,13 @@ target_link_libraries(xyz_plugin scene_points_with_normal_item)
polyhedron_demo_plugin(ply_to_xyz_plugin PLY_to_xyz_io_plugin)
target_link_libraries(ply_to_xyz_plugin scene_points_with_normal_item)
find_package(libLAS)
if (libLAS_FOUND)
include_directories(${libLAS_INCLUDE_DIRS})
polyhedron_demo_plugin(las_to_xyz_plugin LAS_to_xyz_io_plugin)
target_link_libraries(las_to_xyz_plugin scene_points_with_normal_item ${libLAS_LIBRARIES})
else()
message(STATUS "NOTICE : the las IO plugin needs LAS libraries and will not be compiled.")
endif()

View File

@ -0,0 +1,63 @@
#include "Scene_points_with_normal_item.h"
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
#include "read_las_point_set.h"
#include <fstream>
class Polyhedron_demo_las_to_xyz_plugin :
public QObject,
public CGAL::Three::Polyhedron_demo_io_plugin_interface
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_io_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.0")
public:
QString name() const { return "las_to_xyz_plugin"; }
QString nameFilters() const { return "LAS files as Point set (*.las);;Compressed LAZ files as Point set (*.laz)"; }
bool canLoad() const;
CGAL::Three::Scene_item* load(QFileInfo fileinfo);
bool canSave(const CGAL::Three::Scene_item*);
bool save(const CGAL::Three::Scene_item*, QFileInfo fileinfo);
};
bool Polyhedron_demo_las_to_xyz_plugin::canLoad() const {
return true;
}
CGAL::Three::Scene_item*
Polyhedron_demo_las_to_xyz_plugin::load(QFileInfo fileinfo) {
std::ifstream in(fileinfo.filePath().toUtf8(), std::ios_base::binary);
if(!in)
std::cerr << "Error!\n";
Scene_points_with_normal_item* item;
item = new Scene_points_with_normal_item();
if(!read_las_point_set(in, *(item->point_set())) || item->isEmpty())
{
delete item;
return 0;
}
item->point_set()->check_colors();
std::cerr << item->point_set()->info();
item->setName(fileinfo.completeBaseName());
return item;
}
bool Polyhedron_demo_las_to_xyz_plugin::canSave(const CGAL::Three::Scene_item*)
{
// No save function yet
return false;
}
bool Polyhedron_demo_las_to_xyz_plugin::save(const CGAL::Three::Scene_item*, QFileInfo)
{
return false;
}
#include "LAS_to_xyz_io_plugin.moc"

View File

@ -10,3 +10,6 @@ polyhedron_demo_plugin(trivial_plugin Trivial_plugin)
polyhedron_demo_plugin(create_bbox_mesh_plugin Create_bbox_mesh_plugin)
target_link_libraries(create_bbox_mesh_plugin scene_polyhedron_item)
polyhedron_demo_plugin(recenter_plugin Recenter_plugin)
target_link_libraries(recenter_plugin scene_points_with_normal_item)

View File

@ -0,0 +1,81 @@
#include "config.h"
#include "Scene_points_with_normal_item.h"
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/centroid.h>
#include <QObject>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
#include <QtPlugin>
#include <QMessageBox>
using namespace CGAL::Three;
class Polyhedron_demo_recenter_plugin :
public QObject,
public Polyhedron_demo_plugin_helper
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
private:
QAction* actionRecenter;
public:
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
scene = scene_interface;
mw = mainWindow;
actionRecenter = new QAction(tr("Recenter"), mainWindow);
actionRecenter->setObjectName("actionRecenter");
autoConnectActions();
}
QList<QAction*> actions() const {
return QList<QAction*>() << actionRecenter;
}
//! Applicable if the currently selected item is a
//! points_with_normal_item (can be extended to other items).
bool applicable(QAction*) const {
return qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
}
public Q_SLOTS:
void on_actionRecenter_triggered();
}; // end Polyhedron_demo_recenter_plugin
void Polyhedron_demo_recenter_plugin::on_actionRecenter_triggered()
{
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_points_with_normal_item* item =
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
if(item)
{
Point_set* points = item->point_set();
if(points == NULL)
return;
QApplication::setOverrideCursor(Qt::WaitCursor);
Kernel::Point_3 centroid = CGAL::centroid (points->points().begin(),
points->points().end());
Kernel::Vector_3 recenter (centroid, CGAL::ORIGIN);
std::cerr << "Recenter by " << recenter << std::endl;
for (Point_set::iterator it = points->begin(); it != points->end(); ++ it)
points->point(*it) = points->point(*it) + recenter;
QApplication::restoreOverrideCursor();
points->invalidate_bounds();
item->invalidateOpenGLBuffers();
scene->itemChanged(index);
}
}
#include "Recenter_plugin.moc"

View File

@ -39,6 +39,10 @@ endif()
polyhedron_demo_plugin(point_set_selection_plugin Point_set_selection_plugin ${point_set_selectionUI_FILES})
target_link_libraries(point_set_selection_plugin scene_points_with_normal_item scene_polylines_item)
qt5_wrap_ui( point_set_classificationUI_FILES Point_set_classification_widget.ui)
polyhedron_demo_plugin(point_set_classification_plugin Point_set_classification_plugin ${point_set_classificationUI_FILES})
target_link_libraries(point_set_classification_plugin scene_point_set_classification_item scene_points_with_normal_item scene_polylines_item scene_polygon_soup_item)
qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui)
polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES})
target_link_libraries(point_set_shape_detection_plugin scene_polyhedron_item scene_points_with_normal_item scene_polygon_soup_item)

View File

@ -0,0 +1,894 @@
#include <QtCore/qglobal.h>
#include <QFileDialog>
#include <QColorDialog>
#include <fstream>
#include "opengl_tools.h"
#include "Messages_interface.h"
#include "Scene_points_with_normal_item.h"
#include "Scene_point_set_classification_item.h"
#include "Scene_polylines_item.h"
#include "Scene_polygon_soup_item.h"
#include <CGAL/Three/Scene_interface.h>
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/Random.h>
#include "ui_Point_set_classification_widget.h"
#include <QAction>
#include <QMainWindow>
#include <QApplication>
#include <QCheckBox>
#include <QInputDialog>
#include <QSlider>
#include <map>
#include <boost/graph/adjacency_list.hpp>
#include <CGAL/boost/graph/split_graph_into_polylines.h>
using namespace CGAL::Three;
class Polyhedron_demo_point_set_classification_plugin :
public QObject,
public Polyhedron_demo_plugin_helper
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
struct ClassRow
{
QLabel* label;
QPushButton* color_button;
QPushButton* train;
QPushButton* remove;
QColor color;
QLabel* label2;
QComboBox* effect;
ClassRow (QWidget* parent, const char* name, const QColor& color)
: color (color)
{
label = new QLabel (name, parent);
color_button = new QPushButton ("", parent);
QString s("background: #"
+ QString(color.red() < 16? "0" : "") + QString::number(color.red(),16)
+ QString(color.green() < 16? "0" : "") + QString::number(color.green(),16)
+ QString(color.blue() < 16? "0" : "") + QString::number(color.blue(),16) + ";");
color_button->setStyleSheet(s);
train = new QPushButton ("Add selection");
remove = new QPushButton ("Remove");
label2 = new QLabel (name, parent);
effect = new QComboBox;
effect->addItem("Penalized");
effect->addItem("Neutral");
effect->addItem("Favored");
}
~ClassRow ()
{
}
void change_color (const QColor& color)
{
this->color = color;
QString s("background: #"
+ QString(color.red() < 16? "0" : "") + QString::number(color.red(),16)
+ QString(color.green() < 16? "0" : "") + QString::number(color.green(),16)
+ QString(color.blue() < 16? "0" : "") + QString::number(color.blue(),16) + ";");
color_button->setStyleSheet(s);
color_button->update();
}
};
public:
bool applicable(QAction*) const {
return
qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
}
void print_message(QString message) { messages->information(message); }
QList<QAction*> actions() const { return QList<QAction*>() << actionPointSetClassification; }
using Polyhedron_demo_plugin_helper::init;
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* m) {
mw = mainWindow;
scene = scene_interface;
messages = m;
actionPointSetClassification = new QAction(tr("Point Set Classification"), mw);
connect(actionPointSetClassification, SIGNAL(triggered()), this, SLOT(point_set_classification_action()));
dock_widget = new QDockWidget("Point Set Classification", mw);
dock_widget->setVisible(false);
ui_widget.setupUi(dock_widget);
addDockWidget(dock_widget);
color_att = QColor (75, 75, 77);
connect(ui_widget.create_from_item, SIGNAL(clicked()), this,
SLOT(on_create_from_item_button_clicked()));
connect(ui_widget.compute_features, SIGNAL(clicked()), this,
SLOT(on_compute_features_button_clicked()));
connect(ui_widget.display, SIGNAL(currentIndexChanged(int)), this,
SLOT(on_display_button_clicked(int)));
connect(ui_widget.run, SIGNAL(clicked()), this,
SLOT(on_run_button_clicked()));
connect(ui_widget.save_config, SIGNAL(clicked()), this,
SLOT(on_save_config_button_clicked()));
connect(ui_widget.load_config, SIGNAL(clicked()), this,
SLOT(on_load_config_button_clicked()));
connect(ui_widget.run_smoothed, SIGNAL(clicked()), this,
SLOT(on_run_smoothed_button_clicked()));
connect(ui_widget.run_graphcut, SIGNAL(clicked()), this,
SLOT(on_run_graphcut_button_clicked()));
connect(ui_widget.smoothingDoubleSpinBox, SIGNAL(valueChanged(double)), this,
SLOT(on_smoothing_value_changed(double)));
connect(ui_widget.save, SIGNAL(clicked()), this,
SLOT(on_save_button_clicked()));
connect(ui_widget.generate_point_set_items, SIGNAL(clicked()), this,
SLOT(on_generate_point_set_items_button_clicked()));
connect(ui_widget.numberOfScalesSpinBox, SIGNAL(valueChanged(int)), this,
SLOT(on_update_nb_scales()));
connect(ui_widget.number_of_trials, SIGNAL(valueChanged(int)), this,
SLOT(on_update_number_of_trials()));
connect(ui_widget.add_new_class, SIGNAL(clicked()), this,
SLOT(on_add_new_class_clicked()));
connect(ui_widget.reset_training_sets, SIGNAL(clicked()), this,
SLOT(on_reset_training_sets_clicked()));
connect(ui_widget.validate_selection, SIGNAL(clicked()), this,
SLOT(on_validate_selection_clicked()));
connect(ui_widget.train, SIGNAL(clicked()), this,
SLOT(on_train_clicked()));
connect(ui_widget.selected_attribute, SIGNAL(currentIndexChanged(int)), this,
SLOT(on_selected_attribute_changed(int)));
connect(ui_widget.attribute_weight, SIGNAL(valueChanged(int)), this,
SLOT(on_attribute_weight_changed(int)));
QObject* scene_obj = dynamic_cast<QObject*>(scene_interface);
if(scene_obj)
{
connect(scene_obj, SIGNAL(itemAboutToBeDestroyed(CGAL::Three::Scene_item*)), this,
SLOT(item_about_to_be_destroyed(CGAL::Three::Scene_item*)));
connect(scene_obj, SIGNAL(itemIndexSelected(int)), this,
SLOT(update_plugin(int)));
}
}
virtual void closure()
{
dock_widget->hide();
}
public Q_SLOTS:
void item_about_to_be_destroyed(CGAL::Three::Scene_item* scene_item) {
// if points item
Scene_points_with_normal_item* points_item = qobject_cast<Scene_points_with_normal_item*>(scene_item);
if(points_item)
{
Item_map::iterator it = item_map.find(points_item);
if (it != item_map.end())
{
Scene_point_set_classification_item* classif_item = it->second;
item_map.erase(it); // first erase from map, because scene->erase will cause a call to this function
scene->erase( scene->item_id(classif_item) );
}
}
// if classification item
Scene_point_set_classification_item* classif_item = qobject_cast<Scene_point_set_classification_item*>(scene_item);
if(classif_item)
item_map.erase (classif_item->points_item());
}
void point_set_classification_action()
{
dock_widget->show();
dock_widget->raise();
Scene_points_with_normal_item* points_item = getSelectedItem<Scene_points_with_normal_item>();
if (item_map.find(points_item) == item_map.end())
on_create_from_item_button_clicked();
}
void update_plugin(int)
{
update_plugin_from_item(get_classification_item());
}
void disable_everything ()
{
ui_widget.load_config->setEnabled(false);
ui_widget.save_config->setEnabled(false);
ui_widget.compute_features->setEnabled(false);
ui_widget.numberOfScalesSpinBox->setEnabled(false);
ui_widget.display->setEnabled(false);
ui_widget.tabWidget->setEnabled(false);
ui_widget.run->setEnabled(false);
ui_widget.run_smoothed->setEnabled(false);
ui_widget.frame->setEnabled(false);
ui_widget.save->setEnabled(false);
ui_widget.generate_point_set_items->setEnabled(false);
}
void enable_computation()
{
ui_widget.load_config->setEnabled(true);
ui_widget.compute_features->setEnabled(true);
ui_widget.numberOfScalesSpinBox->setEnabled(true);
ui_widget.display->setEnabled(true);
}
void enable_classif()
{
ui_widget.save_config->setEnabled(true);
ui_widget.tabWidget->setEnabled(true);
ui_widget.run->setEnabled(true);
ui_widget.run_smoothed->setEnabled(true);
ui_widget.frame->setEnabled(true);
ui_widget.save->setEnabled(true);
ui_widget.generate_point_set_items->setEnabled(true);
}
void update_plugin_from_item(Scene_point_set_classification_item* item)
{
if (item == NULL) // Deactivate plugin
{
disable_everything();
ui_widget.tabWidget->setCurrentIndex(0);
}
else
{
disable_everything();
enable_computation();
ui_widget.numberOfScalesSpinBox->setValue((int)(item->nb_scales()));
ui_widget.number_of_trials->setValue((int)(item->number_of_trials()));
ui_widget.smoothingDoubleSpinBox->setValue((int)(item->smoothing()));
// Clear class types
for (std::size_t i = 0; i < class_rows.size(); ++ i)
{
ui_widget.gridLayout_3->removeWidget (class_rows[i].label);
delete class_rows[i].label;
ui_widget.gridLayout_3->removeWidget (class_rows[i].color_button);
delete class_rows[i].color_button;
ui_widget.gridLayout_3->removeWidget (class_rows[i].train);
delete class_rows[i].train;
ui_widget.gridLayout_3->removeWidget (class_rows[i].remove);
delete class_rows[i].remove;
ui_widget.gridLayout->removeWidget (class_rows[i].label2);
delete class_rows[i].label2;
ui_widget.gridLayout->removeWidget (class_rows[i].effect);
delete class_rows[i].effect;
}
class_rows.clear();
// Add types
for (std::size_t i = 0; i < item->types().size(); ++ i)
add_new_class (ClassRow (dock_widget, item->types()[i].first->id().c_str(),
item->types()[i].second));
// Enabled classif if features computed
if (!(item->features_computed()))
ui_widget.tabWidget->setCurrentIndex(0);
else
enable_classif();
int index = ui_widget.display->currentIndex();
ui_widget.display->clear();
ui_widget.display->addItem("Real colors");
ui_widget.display->addItem("Classification");
ui_widget.display->addItem("Training sets");
ui_widget.selected_attribute->clear();
item->fill_display_combo_box(ui_widget.display, ui_widget.selected_attribute);
if (index >= ui_widget.display->count())
ui_widget.display->setCurrentIndex(1);
else
ui_widget.display->setCurrentIndex(index);
ui_widget.selected_attribute->setCurrentIndex(0);
}
}
void on_update_nb_scales()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
return;
classification_item->nb_scales() = ui_widget.numberOfScalesSpinBox->value();
}
void on_update_number_of_trials()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
return;
classification_item->number_of_trials() = ui_widget.number_of_trials->value();
}
Scene_point_set_classification_item* get_classification_item()
{
Scene_point_set_classification_item* out =
qobject_cast<Scene_point_set_classification_item*>(scene->item(scene->mainSelectionIndex()));
if (out)
return out;
Scene_points_with_normal_item* points_item =
qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
if (!points_item)
return NULL;
Item_map::iterator it = item_map.find(points_item);
if (it != item_map.end())
return it->second;
return NULL;
}
void on_create_from_item_button_clicked()
{
Scene_points_with_normal_item* points_item = getSelectedItem<Scene_points_with_normal_item>();
if(!points_item)
{
print_message("Error: there is no selected point set item!");
return;
}
if (item_map.find(points_item) != item_map.end())
return;
QApplication::setOverrideCursor(Qt::WaitCursor);
Scene_point_set_classification_item* new_item
= new Scene_point_set_classification_item (points_item);
scene->addItem(new_item);
new_item->setName(QString("%1 (classification)").arg(points_item->name()));
points_item->setVisible (false);
item_map.insert (std::make_pair (points_item, new_item));
QApplication::restoreOverrideCursor();
connect(points_item, &Scene_points_with_normal_item::itemChanged,
new_item, &Scene_point_set_classification_item::invalidateOpenGLBuffers);
update_plugin_from_item(new_item);
}
void run (Scene_point_set_classification_item* classification_item, int method)
{
classification_item->run (method);
}
void on_compute_features_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
time.start();
classification_item->compute_features ();
// run (classification_item, 0);
std::cerr << "Features computed in " << time.elapsed() / 1000 << " second(s)" << std::endl;
update_plugin_from_item(classification_item);
QApplication::restoreOverrideCursor();
scene->itemChanged(classification_item);
}
void on_save_config_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QString filename = QFileDialog::getSaveFileName(mw,
tr("Save classification configuration"),
QString("config.xml"),
"Config file (*.xml);;");
if (filename == QString())
return;
QApplication::setOverrideCursor(Qt::WaitCursor);
classification_item->save_config (filename.toStdString().c_str());
QApplication::restoreOverrideCursor();
}
void on_load_config_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QString filename = QFileDialog::getOpenFileName(mw,
tr("Open classification configuration"),
".",
"Config file (*.xml);;All Files (*)");
if (filename == QString())
return;
QApplication::setOverrideCursor(Qt::WaitCursor);
classification_item->load_config (filename.toStdString().c_str());
update_plugin_from_item(classification_item);
run (classification_item, 0);
QApplication::restoreOverrideCursor();
scene->itemChanged(classification_item);
}
void on_display_button_clicked(int index)
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
return;
classification_item->change_color (index);
scene->itemChanged(classification_item);
}
void on_run_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
run (classification_item, 0);
QApplication::restoreOverrideCursor();
scene->itemChanged(classification_item);
}
void on_run_smoothed_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
time.start();
run (classification_item, 1);
std::cerr << "Smoothed classification computed in " << time.elapsed() / 1000 << " second(s)" << std::endl;
QApplication::restoreOverrideCursor();
scene->itemChanged(classification_item);
}
void on_run_graphcut_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
time.start();
run (classification_item, 2);
std::cerr << "Graphcut classification computed in " << time.elapsed() / 1000 << " second(s)" << std::endl;
QApplication::restoreOverrideCursor();
scene->itemChanged(classification_item);
}
void on_smoothing_value_changed(double v)
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
return;
classification_item->smoothing() = v;
}
void on_save_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QString filename = QFileDialog::getSaveFileName(mw,
tr("Save PLY classified point set"),
QString("%1.ply").arg(classification_item->name()),
"PLY point set (*.ply);;");
if (filename == QString())
return;
std::ofstream out(filename.toUtf8());
QApplication::setOverrideCursor(Qt::WaitCursor);
classification_item->write_ply_point_set (out);
QApplication::restoreOverrideCursor();
out.close();
}
void on_generate_point_set_items_button_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
std::vector<Scene_points_with_normal_item*> new_items;
classification_item->generate_point_set_items<Scene_points_with_normal_item>
(new_items, classification_item->points_item()->name().toStdString().c_str());
for (std::size_t i = 0; i < new_items.size(); ++ i)
{
if (new_items[i]->point_set()->empty())
delete new_items[i];
else
scene->addItem (new_items[i]);
}
QApplication::restoreOverrideCursor();
}
void on_add_new_class_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
bool ok;
QString name =
QInputDialog::getText((QWidget*)mw,
tr("Add new classification type"), // dialog title
tr("Name:"), // field label
QLineEdit::Normal,
tr("type%1").arg(class_rows.size() + 1),
&ok);
if (!ok)
return;
add_new_class (ClassRow (dock_widget, name.toStdString().c_str(),
QColor (192 + rand() % 60,
192 + rand() % 60,
192 + rand() % 60)));
classification_item->add_new_type (class_rows.back().label->text().toStdString().c_str(),
class_rows.back().color);
}
void on_reset_training_sets_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
classification_item->reset_training_sets();
}
void on_validate_selection_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
classification_item->validate_selection();
}
void on_train_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
std::vector<std::string> classes;
std::vector<QColor> colors;
for (std::size_t i = 0; i < class_rows.size(); ++ i)
{
classes.push_back (class_rows[i].label->text().toStdString());
colors.push_back (class_rows[i].color);
}
QApplication::setOverrideCursor(Qt::WaitCursor);
classification_item->train();
QApplication::restoreOverrideCursor();
update_plugin_from_item(classification_item);
}
void add_new_class (const ClassRow& class_row)
{
class_rows.push_back (class_row);
int position = static_cast<int>(class_rows.size());
ui_widget.gridLayout_3->addWidget (class_rows.back().label, position, 0);
ui_widget.gridLayout_3->addWidget (class_rows.back().color_button, position, 1);
ui_widget.gridLayout_3->addWidget (class_rows.back().train, position, 3);
ui_widget.gridLayout_3->addWidget (class_rows.back().remove, position, 5);
connect(class_rows.back().remove, SIGNAL(clicked()), this,
SLOT(on_remove_class_clicked()));
connect(class_rows.back().color_button, SIGNAL(clicked()), this,
SLOT(on_color_changed_clicked()));
connect(class_rows.back().train, SIGNAL(clicked()), this,
SLOT(on_add_selection_to_training_set_clicked()));
ui_widget.gridLayout->addWidget (class_rows.back().label2, position, 0);
ui_widget.gridLayout->addWidget (class_rows.back().effect, position, 2);
connect(class_rows.back().effect, SIGNAL(currentIndexChanged(int)), this,
SLOT(on_effect_changed(int)));
}
void on_remove_class_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
int index = ui_widget.gridLayout_3->indexOf(qobject_cast<QWidget*>(QObject::sender()));
int row_index, column_index, row_span, column_span;
ui_widget.gridLayout_3->getItemPosition(index, &row_index, &column_index, &row_span, &column_span);
--row_index;
classification_item->remove_type (class_rows[row_index].label->text().toStdString().c_str());
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].label);
delete class_rows[row_index].label;
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].color_button);
delete class_rows[row_index].color_button;
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].train);
delete class_rows[row_index].train;
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].remove);
delete class_rows[row_index].remove;
ui_widget.gridLayout->removeWidget (class_rows[row_index].label2);
delete class_rows[row_index].label2;
ui_widget.gridLayout->removeWidget (class_rows[row_index].effect);
delete class_rows[row_index].effect;
if (class_rows.size() > 1)
for (std::size_t i = row_index + 1; i < class_rows.size(); ++ i)
{
ui_widget.gridLayout_3->addWidget (class_rows[i].label, (int)i, 0);
ui_widget.gridLayout_3->addWidget (class_rows[i].color_button, (int)i, 1);
ui_widget.gridLayout_3->addWidget (class_rows[i].train, (int)i, 3);
ui_widget.gridLayout_3->addWidget (class_rows[i].remove, (int)i, 5);
ui_widget.gridLayout->addWidget (class_rows[i].label2, (int)i, 0);
ui_widget.gridLayout->addWidget (class_rows[i].effect, (int)i, 2);
}
class_rows.erase (class_rows.begin() + row_index);
scene->itemChanged(classification_item);
}
void on_color_changed_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
QPushButton* color_button = qobject_cast<QPushButton*>(QObject::sender());
int index = ui_widget.gridLayout_3->indexOf(color_button);
int row_index, column_index, row_span, column_span;
ui_widget.gridLayout_3->getItemPosition(index, &row_index, &column_index, &row_span, &column_span);
-- row_index;
QColor color = class_rows[row_index].color;
color = QColorDialog::getColor(color, (QWidget*)mw, "Change of color of classification type");
class_rows[row_index].change_color (color);
classification_item->change_type_color (class_rows[row_index].label->text().toStdString().c_str(),
color);
scene->itemChanged(classification_item);
}
void on_add_selection_to_training_set_clicked()
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
int index = ui_widget.gridLayout_3->indexOf(qobject_cast<QWidget*>(QObject::sender()));
int row_index, column_index, row_span, column_span;
ui_widget.gridLayout_3->getItemPosition(index, &row_index, &column_index, &row_span, &column_span);
--row_index;
classification_item->add_selection_to_training_set
(class_rows[row_index].label->text().toStdString().c_str());
}
void on_selected_attribute_changed(int v)
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
if (classification_item->number_of_attributes() <= (std::size_t)v)
return;
Scene_point_set_classification_item::Attribute_handle
att = classification_item->attribute(v);
if (att == Scene_point_set_classification_item::Attribute_handle())
return;
// std::cerr << att->weight
// << " " << (int)(1001. * 2. * std::atan(att->weight) / CGAL_PI) << std::endl;
ui_widget.attribute_weight->setValue ((int)(1001. * 2. * std::atan(att->weight) / CGAL_PI));
for (std::size_t i = 0; i < classification_item->types().size(); ++ i)
{
CGAL::Classification::Type::Attribute_effect
eff = classification_item->types()[i].first->attribute_effect(att);
if (eff == CGAL::Classification::Type::PENALIZED_ATT)
class_rows[i].effect->setCurrentIndex(0);
else if (eff == CGAL::Classification::Type::NEUTRAL_ATT)
class_rows[i].effect->setCurrentIndex(1);
else
class_rows[i].effect->setCurrentIndex(2);
}
}
void on_attribute_weight_changed(int v)
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
Scene_point_set_classification_item::Attribute_handle
att = classification_item->attribute(ui_widget.selected_attribute->currentIndex());
if (att == Scene_point_set_classification_item::Attribute_handle())
return;
att->weight = std::tan ((CGAL_PI/2.) * v / 1001.);
// std::cerr << att->weight << std::endl;
for (std::size_t i = 0; i < class_rows.size(); ++ i)
class_rows[i].effect->setEnabled(att->weight != 0.);
}
void on_effect_changed (int v)
{
Scene_point_set_classification_item* classification_item
= get_classification_item();
if(!classification_item)
{
print_message("Error: there is no point set classification item!");
return;
}
Scene_point_set_classification_item::Attribute_handle
att = classification_item->attribute(ui_widget.selected_attribute->currentIndex());
if (att == Scene_point_set_classification_item::Attribute_handle())
return;
QComboBox* combo = qobject_cast<QComboBox*>(QObject::sender());
for (std::size_t i = 0;i < class_rows.size(); ++ i)
if (class_rows[i].effect == combo)
{
// std::cerr << att->id() << " is ";
if (v == 0)
{
classification_item->types()[i].first->set_attribute_effect
(att, CGAL::Classification::Type::PENALIZED_ATT);
// std::cerr << " penalized for ";
}
else if (v == 1)
{
classification_item->types()[i].first->set_attribute_effect
(att, CGAL::Classification::Type::NEUTRAL_ATT);
// std::cerr << " neutral for ";
}
else
{
classification_item->types()[i].first->set_attribute_effect
(att, CGAL::Classification::Type::FAVORED_ATT);
// std::cerr << " favored for ";
}
// std::cerr << classification_item->types()[i].first->id() << std::endl;
break;
}
}
private:
Messages_interface* messages;
QAction* actionPointSetClassification;
QDockWidget* dock_widget;
std::vector<ClassRow> class_rows;
Ui::PointSetClassification ui_widget;
QColor color_att;
typedef std::map<Scene_points_with_normal_item*, Scene_point_set_classification_item*> Item_map;
Item_map item_map;
}; // end Polyhedron_demo_point_set_classification_plugin
#include "Point_set_classification_plugin.moc"

View File

@ -0,0 +1,722 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PointSetClassification</class>
<widget class="QDockWidget" name="PointSetClassification">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>960</height>
</rect>
</property>
<property name="windowTitle">
<string>Point set classification</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<spacer name="verticalSpacer_12">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QPushButton" name="create_from_item">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Create classification item</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="load_config">
<property name="text">
<string>Load config</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="save_config">
<property name="text">
<string>Save config</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QPushButton" name="compute_features">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Compute features</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="numberOfScalesSpinBox">
<property name="suffix">
<string> scale(s)</string>
</property>
<property name="prefix">
<string>using </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>View:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="display">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Real colors</string>
</property>
</item>
<item>
<property name="text">
<string>Classification</string>
</property>
</item>
<item>
<property name="text">
<string>Training sets</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_classif">
<attribute name="title">
<string>Classification</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Classes</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<layout class="QGridLayout" name="gridLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item row="0" column="1">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Color</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_12">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Training set</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Name</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="5">
<widget class="QPushButton" name="add_new_class">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Add new</string>
</property>
</widget>
</item>
<item row="0" column="4">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Training</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QPushButton" name="train">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Train</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="number_of_trials">
<property name="suffix">
<string> trials</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>300</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="reset_training_sets">
<property name="text">
<string>Reset training sets</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="validate_selection">
<property name="text">
<string>Validate selection for training</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_11">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_advanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Advanced</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,2">
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Attribute:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="selected_attribute">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_10">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSlider" name="attribute_weight">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="pageStep">
<number>50</number>
</property>
<property name="value">
<number>500</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBothSides</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Class type</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Effect</string>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_9">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>41</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="run">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Run (quick)</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="run_smoothed">
<property name="text">
<string>Run (smoothed)</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QPushButton" name="run_graphcut">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Run (graphcut)</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="smoothingDoubleSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Smoothing strenght</string>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.500000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="save">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Save classified point set</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="generate_point_set_items">
<property name="text">
<string>Generate point set items</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_14">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -406,6 +406,7 @@ protected:
(points->begin() + unselected.size());
}
point_set_item->invalidateOpenGLBuffers();
point_set_item->itemChanged();
}

View File

@ -0,0 +1,547 @@
#include "Scene_point_set_classification_item.h"
#include "Color_ramp.h"
#include <CGAL/Timer.h>
#include <CGAL/Memory_sizer.h>
#include <CGAL/Three/Viewer_interface.h>
#include <QObject>
#include <QMenu>
#include <QGLViewer/manipulatedCameraFrame.h>
#include <set>
#include <stack>
#include <algorithm>
#include <boost/array.hpp>
Scene_point_set_classification_item::Scene_point_set_classification_item(PSC* psc)
: Scene_item(NbOfVbos,NbOfVaos),
m_points (NULL),
m_psc (psc),
m_helper (NULL)
{
setRenderingMode(PointsPlusNormals);
m_nb_scales = 5;
m_nb_trials = 300;
m_smoothing = 0.5;
m_index_color = 1;
is_selected = true;
nb_points = 0;
nb_lines = 0;
}
Scene_point_set_classification_item::Scene_point_set_classification_item(Scene_points_with_normal_item* points)
: Scene_item(NbOfVbos,NbOfVaos),
m_points (points),
m_psc (NULL),
m_helper (NULL)
{
setRenderingMode(PointsPlusNormals);
m_nb_scales = 5;
m_index_color = 1;
m_nb_trials = 300;
m_smoothing = 0.5;
reset_indices();
m_psc = new PSC(m_points->point_set()->begin(), m_points->point_set()->end(), m_points->point_set()->point_map());
Type_handle ground = m_psc->add_classification_type("ground");
Type_handle vegetation = m_psc->add_classification_type("vegetation");
Type_handle roof = m_psc->add_classification_type("roof");
Type_handle facade = m_psc->add_classification_type("facade");
m_types.push_back (std::make_pair(ground, QColor(245, 180, 0)));
m_types.push_back (std::make_pair(vegetation, QColor(0, 255, 27)));
m_types.push_back (std::make_pair(roof, QColor(255, 0, 170)));
m_types.push_back (std::make_pair(facade, QColor(100, 0, 255)));
is_selected = true;
nb_points = 0;
nb_lines = 0;
}
// Copy constructor
Scene_point_set_classification_item::Scene_point_set_classification_item(const Scene_point_set_classification_item&)
:Scene_item(NbOfVbos,NbOfVaos), // do not call superclass' copy constructor
m_points (NULL),
m_psc (NULL),
m_helper (NULL)
{
setRenderingMode(PointsPlusNormals);
m_nb_scales = 5;
m_index_color = 1;
m_nb_trials = 300;
m_smoothing = 0.5;
nb_points = 0;
invalidateOpenGLBuffers();
}
Scene_point_set_classification_item::~Scene_point_set_classification_item()
{
if (m_psc != NULL)
delete m_psc;
if (m_helper != NULL)
delete m_helper;
}
void Scene_point_set_classification_item::initializeBuffers(CGAL::Three::Viewer_interface *viewer) const
{
compute_normals_and_vertices();
//vao for the edges
{
program = getShaderProgram(PROGRAM_NO_SELECTION, viewer);
program->bind();
vaos[Edges]->bind();
buffers[Edges_vertices].bind();
buffers[Edges_vertices].allocate(positions_lines.data(),
static_cast<int>(positions_lines.size()*sizeof(double)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex",GL_DOUBLE,0,3);
buffers[Edges_vertices].release();
vaos[Edges]->release();
nb_lines = positions_lines.size();
positions_lines.resize(0);
std::vector<double>(positions_lines).swap(positions_lines);
program->release();
}
//vao for the points
{
program = getShaderProgram(PROGRAM_NO_SELECTION, viewer);
program->bind();
vaos[ThePoints]->bind();
buffers[Points_vertices].bind();
buffers[Points_vertices].allocate(positions_points.data(),
static_cast<int>(positions_points.size()*sizeof(double)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex",GL_DOUBLE,0,3);
buffers[Points_vertices].release();
if (!(colors_points.empty()))
{
buffers[Points_colors].bind();
buffers[Points_colors].allocate (colors_points.data(),
static_cast<int>(colors_points.size()*sizeof(double)));
program->enableAttributeArray("colors");
program->setAttributeBuffer("colors",GL_DOUBLE,0,3);
buffers[Points_colors].release();
std::vector<double>(colors_points).swap(colors_points);
}
vaos[ThePoints]->release();
nb_points = positions_points.size();
positions_points.resize(0);
std::vector<double>(positions_points).swap(positions_points);
program->release();
}
are_buffers_filled = true;
}
void Scene_point_set_classification_item::compute_normals_and_vertices() const
{
int index_color = real_index_color();
positions_lines.resize(0);
positions_points.resize(0);
colors_points.resize(0);
if (index_color == 9) // Show clusters centroids
{
// positions_points.reserve(m_psc->clusters().size() * 3);
// colors_points.reserve(m_psc->clusters().size() * 3);
// for (std::size_t i = 0; i < m_psc->clusters().size(); ++ i)
// {
// const Kernel::Point_3& p = m_psc->clusters()[i].centroid;
// positions_points.push_back(p.x());
// positions_points.push_back(p.y());
// positions_points.push_back(p.z());
// for (std::set<std::size_t>::iterator it = m_psc->clusters()[i].neighbors.begin ();
// it != m_psc->clusters()[i].neighbors.end (); ++ it)
// {
// const Kernel::Point_3& q = m_psc->clusters()[*it].centroid;
// positions_lines.push_back(p.x());
// positions_lines.push_back(p.y());
// positions_lines.push_back(p.z());
// positions_lines.push_back(q.x());
// positions_lines.push_back(q.y());
// positions_lines.push_back(q.z());
// }
// }
}
else // Show points
{
positions_points.reserve(m_points->point_set()->size() * 3);
colors_points.reserve(m_points->point_set()->size() * 3);
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->end(); ++ it)
{
const Kernel::Point_3& p = m_points->point_set()->point(*it);
positions_points.push_back(p.x());
positions_points.push_back(p.y());
positions_points.push_back(p.z());
}
}
// Colors
static Color_ramp ramp;
ramp.build_red();
if (index_color == -1) // item color
{
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
colors_points.push_back (color().redF());
colors_points.push_back (color().greenF());
colors_points.push_back (color().blueF());
}
}
else if (index_color == 0) // real colors
{
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
colors_points.push_back ((double)(m_points->point_set()->red(*it)) / 255.);
colors_points.push_back ((double)(m_points->point_set()->green(*it)) / 255.);
colors_points.push_back ((double)(m_points->point_set()->blue(*it)) / 255.);
}
}
else if (index_color == 1) // classif
{
std::map<Type_handle, QColor> map_colors;
for (std::size_t i = 0; i < m_types.size(); ++ i)
map_colors.insert (m_types[i]);
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
QColor color (0, 0, 0);
Type_handle c = m_psc->classification_type_of(*it);
if (c != Type_handle())
color = map_colors[c];
colors_points.push_back ((double)(color.red()) / 255.);
colors_points.push_back ((double)(color.green()) / 255.);
colors_points.push_back ((double)(color.blue()) / 255.);
}
}
else if (index_color == 2) // training
{
std::map<Type_handle, QColor> map_colors;
for (std::size_t i = 0; i < m_types.size(); ++ i)
map_colors.insert (m_types[i]);
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
QColor color (0, 0, 0);
Type_handle c = m_psc->training_type_of(*it);
Type_handle c2 = m_psc->classification_type_of(*it);
if (c != Type_handle())
color = map_colors[c];
double div = 255.;
if (c != c2)
div = 400.;
colors_points.push_back ((double)(color.red()) / div);
colors_points.push_back ((double)(color.green()) / div);
colors_points.push_back ((double)(color.blue()) / div);
}
}
else
{
Attribute_handle att = m_psc->get_attribute(index_color - 3);
double weight = att->weight;
att->weight = att->max;
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
colors_points.push_back (ramp.r(att->normalized(*it)));
colors_points.push_back (ramp.g(att->normalized(*it)));
colors_points.push_back (ramp.b(att->normalized(*it)));
}
att->weight = weight;
}
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
it != m_points->point_set()->end(); ++ it)
{
colors_points.push_back (1.);
colors_points.push_back (0.);
colors_points.push_back (0.);
}
}
// Duplicates scene item
Scene_point_set_classification_item*
Scene_point_set_classification_item::clone() const
{
return new Scene_point_set_classification_item(*this);
}
// Write point set to .PLY file
bool Scene_point_set_classification_item::write_ply_point_set(std::ostream& stream)
{
if (m_helper == NULL)
return false;
stream.precision (std::numeric_limits<double>::digits10 + 2);
reset_indices();
std::vector<Color> colors;
for (std::size_t i = 0; i < m_types.size(); ++ i)
{
Color c = {{ (unsigned char)(m_types[i].second.red()),
(unsigned char)(m_types[i].second.green()),
(unsigned char)(m_types[i].second.blue()) }};
colors.push_back (c);
}
m_helper->write_ply (stream,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
*m_psc,
&colors);
return true;
}
QString
Scene_point_set_classification_item::toolTip() const
{
return QObject::tr("<p><b>%1</b><br />"
"<i>Point set classification</i></p>"
"<p>Number of points: %2</p>")
.arg(name())
.arg(m_points->point_set()->size());
}
bool Scene_point_set_classification_item::supportsRenderingMode(RenderingMode m) const
{
return m==PointsPlusNormals;
}
void Scene_point_set_classification_item::drawSplats(CGAL::Three::Viewer_interface*) const
{
}
void Scene_point_set_classification_item::drawEdges(CGAL::Three::Viewer_interface* viewer) const
{
if(!are_buffers_filled)
initializeBuffers(viewer);
vaos[Edges]->bind();
program=getShaderProgram(PROGRAM_NO_SELECTION);
attribBuffers(viewer,PROGRAM_NO_SELECTION);
program->bind();
program->setAttributeValue("colors", this->color());
viewer->glDrawArrays(GL_LINES, 0,
static_cast<GLsizei>((nb_lines)/3));
vaos[Edges]->release();
program->release();
}
void Scene_point_set_classification_item::drawPoints(CGAL::Three::Viewer_interface* viewer) const
{
if(!are_buffers_filled)
initializeBuffers(viewer);
GLfloat point_size;
viewer->glGetFloatv(GL_POINT_SIZE, &point_size);
if (m_index_color == 9)
viewer->glPointSize(15.f);
else
viewer->glPointSize(3.f);
vaos[ThePoints]->bind();
program=getShaderProgram(PROGRAM_NO_SELECTION);
attribBuffers(viewer,PROGRAM_NO_SELECTION);
program->bind();
if (colors_points.empty())
program->setAttributeValue("colors", this->color());
viewer->glDrawArrays(GL_POINTS, 0,
static_cast<GLsizei>(((std::size_t)(nb_points)/3)));
vaos[ThePoints]->release();
program->release();
viewer->glPointSize(point_size);
}
bool
Scene_point_set_classification_item::isEmpty() const
{
return false;
}
void
Scene_point_set_classification_item::compute_bbox() const
{
if (m_points->point_set()->empty())
return;
double xmin = std::numeric_limits<double>::max();
double ymin = std::numeric_limits<double>::max();
double zmin = std::numeric_limits<double>::max();
double xmax = -std::numeric_limits<double>::max();
double ymax = -std::numeric_limits<double>::max();
double zmax = -std::numeric_limits<double>::max();
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->end(); ++ it)
{
const Kernel::Point_3& p = m_points->point_set()->point(*it);
xmin = (std::min)(xmin, p.x());
ymin = (std::min)(ymin, p.y());
zmin = (std::min)(zmin, p.z());
xmax = (std::max)(xmax, p.x());
ymax = (std::max)(ymax, p.y());
zmax = (std::max)(zmax, p.z());
}
_bbox = Bbox(xmin,ymin,zmin,
xmax,ymax,zmax);
}
QMenu* Scene_point_set_classification_item::contextMenu()
{
QMenu* menu = Scene_item::contextMenu();
return menu;
}
void Scene_point_set_classification_item::setRenderingMode(RenderingMode m)
{
Scene_item::setRenderingMode(m);
}
void Scene_point_set_classification_item::invalidateOpenGLBuffers()
{
are_buffers_filled = false;
compute_bbox();
}
void Scene_point_set_classification_item::change_color (int index)
{
m_index_color = index;
invalidateOpenGLBuffers();
}
int Scene_point_set_classification_item::real_index_color() const
{
int out = m_index_color;
if (out == 0 && !(m_points->point_set()->has_colors()))
out = -1;
return out;
}
void Scene_point_set_classification_item::reset_indices ()
{
Point_set::Property_map<Point_set::Index> indices;
boost::tie (indices, boost::tuples::ignore)
= m_points->point_set()->property_map<Point_set::Index>("index");
m_points->point_set()->unselect_all();
Point_set::Index idx;
++ idx;
for (std::size_t i = 0; i < m_points->point_set()->size(); ++ i)
*(indices.begin() + i) = idx ++;
}
void Scene_point_set_classification_item::compute_features ()
{
Q_ASSERT (!(m_points->point_set()->empty()));
Q_ASSERT (m_psc != NULL);
m_psc->clear_attributes();
reset_indices();
std::cerr << "Computing features with " << m_nb_scales << " scale(s)" << std::endl;
compute_bbox();
if (m_helper != NULL) delete m_helper;
m_helper = new Helper (m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
m_nb_scales);
m_helper->generate_point_based_attributes (*m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map());
if (m_points->point_set()->has_normal_map())
m_helper->generate_normal_based_attributes (*m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->normal_map());
else
m_helper->generate_normal_based_attributes (*m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end());
Point_set::Property_map<boost::uint8_t> echo_map;
bool okay;
boost::tie (echo_map, okay) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
if (okay)
m_helper->generate_echo_based_attributes (*m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
echo_map);
if (m_points->point_set()->has_colors())
m_helper->generate_color_based_attributes (*m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
Color_map(m_points->point_set()));
}
void Scene_point_set_classification_item::train()
{
if (m_helper == NULL)
{
std::cerr << "Error: features not computed" << std::endl;
return;
}
m_psc->training(m_nb_trials);
m_psc->run();
m_helper->info();
}
bool Scene_point_set_classification_item::run (int method)
{
if (m_helper == NULL)
{
std::cerr << "Error: features not computed" << std::endl;
return false;
}
reset_indices();
if (method == 0)
m_psc->run();
else if (method == 1)
m_psc->run_with_local_smoothing (m_helper->neighborhood().range_neighbor_query(m_helper->radius_neighbors()));
else if (method == 2)
m_psc->run_with_graphcut (m_helper->neighborhood().k_neighbor_query(12), m_smoothing);
invalidateOpenGLBuffers();
Q_EMIT itemChanged();
return true;
}

View File

@ -0,0 +1,405 @@
#ifndef POINT_SET_CLASSIFICATION_ITEM_H
#define POINT_SET_CLASSIFICATION_ITEM_H
#include <CGAL/Three/Scene_item.h>
#include <CGAL/Classifier.h>
#include <CGAL/Classification/Attribute.h>
#include <CGAL/Classification/Attribute_vertical_dispersion.h>
#include <CGAL/Classification/Attribute_elevation.h>
#include <CGAL/Classification/Attribute_verticality.h>
#include <CGAL/Classification/Attribute_distance_to_plane.h>
#include <CGAL/Classification/Attribute_color.h>
#include <CGAL/Classification/Attribute_echo_scatter.h>
#include <CGAL/Classification/Attributes_eigen.h>
#include <CGAL/Classification/Helper.h>
#include "Scene_point_set_classification_item_config.h"
#include "Scene_points_with_normal_item.h"
#include "Polyhedron_type_fwd.h"
#include "Kernel_type.h"
#include "Point_set_3.h"
#include <iostream>
class QMenu;
class QAction;
// This class represents a point set in the OpenGL scene
class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_item
: public CGAL::Three::Scene_item
{
Q_OBJECT
template <typename PointSet>
class Point_set_color_map
{
public:
typedef CGAL::Classification::RGB_Color Color;
typedef typename PointSet::Index key_type;
typedef Color value_type;
typedef value_type& reference;
typedef boost::lvalue_property_map_tag category;
PointSet* ps;
Point_set_color_map(PointSet* ps = NULL)
: ps(ps) { }
friend value_type get (const Point_set_color_map& pm, const key_type& i)
{
Color out = {{ pm.ps->red(i),
pm.ps->green(i),
pm.ps->blue(i) }};
return out;
}
};
public:
typedef Kernel::Point_3 Point_3;
typedef Kernel::Vector_3 Vector_3;
typedef CGAL::Classification::RGB_Color Color;
typedef Point_set::iterator Iterator;
typedef Point_set::Point_map Point_map;
typedef Point_set::Vector_map Vector_map;
typedef Point_set_color_map<Point_set> Color_map;
typedef CGAL::Classifier<Iterator, Point_map> PSC;
typedef CGAL::Classification::Helper<Kernel, Iterator, Point_map> Helper;
typedef CGAL::Classification::Type_handle Type_handle;
typedef CGAL::Classification::Attribute_handle Attribute_handle;
typedef CGAL::Classification::Attribute_vertical_dispersion<Kernel, Iterator, Point_map> Dispersion;
typedef CGAL::Classification::Attribute_elevation<Kernel, Iterator, Point_map> Elevation;
typedef CGAL::Classification::Attribute_verticality<Kernel, Iterator, Point_map> Verticality;
typedef CGAL::Classification::Attribute_distance_to_plane<Kernel, Iterator, Point_map> Distance_to_plane;
public:
Scene_point_set_classification_item(PSC* psc = NULL);
Scene_point_set_classification_item(Scene_points_with_normal_item* points);
Scene_point_set_classification_item(const Scene_point_set_classification_item& toCopy);
~Scene_point_set_classification_item();
Scene_point_set_classification_item* clone() const;
// Function to override the context menu
QMenu* contextMenu();
// IO
bool write_ply_point_set(std::ostream& out);
// Function for displaying meta-data of the item
virtual QString toolTip() const;
virtual void invalidateOpenGLBuffers();
// Indicate if rendering mode is supported
virtual bool supportsRenderingMode(RenderingMode m) const;
virtual void drawEdges(CGAL::Three::Viewer_interface* viewer) const;
virtual void drawPoints(CGAL::Three::Viewer_interface*) const;
virtual void drawSplats(CGAL::Three::Viewer_interface*) const;
// Gets dimensions
virtual bool isFinite() const { return true; }
virtual bool isEmpty() const;
virtual void compute_bbox() const;
virtual void setRenderingMode(RenderingMode m);
void change_color (int index);
int real_index_color() const;
void reset_indices();
void compute_features ();
bool run (int method);
template <typename Item>
void generate_point_set_items(std::vector<Item*>& items,
const char* name)
{
std::map<Type_handle, std::size_t> map_types;
for (std::size_t i = 0; i < m_types.size(); ++ i)
{
items.push_back (new Item);
items.back()->setName (QString("%1 (%2)").arg(name).arg(m_types[i].first->id().c_str()));
items.back()->setColor (m_types[i].second);
map_types[m_types[i].first] = i;
}
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->end(); ++ it)
{
Type_handle c = m_psc->classification_type_of(*it);
if (c != Type_handle())
items[map_types[c]]->point_set()->insert (m_points->point_set()->point(*it));
}
}
Scene_points_with_normal_item* points_item() { return m_points; }
void reset_training_sets()
{
m_psc->prepare_classification();
m_psc->reset_training_sets();
invalidateOpenGLBuffers();
Q_EMIT itemChanged();
}
void train();
void callback()
{
invalidateOpenGLBuffers();
Q_EMIT itemChanged();
}
Type_handle get_classification_type (const char* name)
{
for (std::size_t i = 0; i < m_types.size(); ++ i)
if (m_types[i].first->id() == name)
return m_types[i].first;
return Type_handle();
}
void add_selection_to_training_set (const char* name)
{
Type_handle class_type = get_classification_type (name);
if (!(m_psc->classification_prepared()))
m_psc->prepare_classification();
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
it != m_points->point_set()->end(); ++ it)
m_psc->set_classification_type_of(*it, class_type);
m_psc->add_training_set(class_type,
m_points->point_set()->first_selected(),
m_points->point_set()->end());
m_points->resetSelection();
}
void validate_selection ()
{
if (!(m_psc->classification_prepared()))
m_psc->prepare_classification();
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
it != m_points->point_set()->end(); ++ it)
{
Type_handle t = m_psc->classification_type_of(*it);
m_psc->add_training_index (t, *it);
}
m_points->resetSelection();
}
double& smoothing() { return m_smoothing; }
std::size_t& nb_scales() { return m_nb_scales; }
std::size_t& number_of_trials() { return m_nb_trials; }
bool features_computed() const { return (m_helper != NULL); }
std::vector<std::pair<Type_handle, QColor> >& types() { return m_types; }
std::size_t number_of_attributes() const { return m_psc->number_of_attributes(); }
Attribute_handle attribute(std::size_t i) { return m_psc->get_attribute(i); }
void add_new_type (const char* name, const QColor& color)
{
m_types.push_back (std::make_pair (m_psc->add_classification_type(name),
color));
}
void remove_type (const char* name)
{
for (std::size_t i = 0; i < m_types.size(); ++ i)
if (m_types[i].first->id() == name)
{
m_psc->remove_classification_type (m_types[i].first);
m_types.erase (m_types.begin() + i);
break;
}
invalidateOpenGLBuffers();
Q_EMIT itemChanged();
}
void change_type_color (const char* name, const QColor& color)
{
for (std::size_t i = 0; i < m_types.size(); ++ i)
if (m_types[i].first->id() == name)
{
m_types[i].second = color;
break;
}
}
template <typename ComboBox>
void fill_display_combo_box (ComboBox* cb, ComboBox* cb1)
{
for (std::size_t i = 0; i < m_psc->number_of_attributes(); ++ i)
{
std::size_t scale = m_helper->scale_of_attribute(m_psc->get_attribute(i));
std::ostringstream oss;
oss << "Attribute " << m_psc->get_attribute(i)->id() << "_" << scale;
cb->addItem (oss.str().c_str());
cb1->addItem (oss.str().c_str());
}
}
void save_config(const char* filename)
{
if (m_helper == NULL)
{
std::cerr << "Error: features not computed" << std::endl;
return;
}
m_helper->save (filename, *m_psc);
}
void load_config(const char* filename)
{
if (m_helper != NULL)
delete m_helper;
m_psc->clear_classification_types();
m_psc->clear_attributes();
reset_indices();
bool normals = m_points->point_set()->has_normal_map();
bool colors = m_points->point_set()->has_colors();
Point_set::Property_map<boost::uint8_t> echo_map;
bool echo;
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
if (!normals && !colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map());
else if (!normals && !colors && echo)
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
CGAL::Empty_property_map<Iterator, Vector_3>(),
CGAL::Empty_property_map<Iterator, Color>(),
echo_map);
else if (!normals && colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
CGAL::Empty_property_map<Iterator, Vector_3>(),
Color_map(m_points->point_set()));
else if (!normals && colors && echo)
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
CGAL::Empty_property_map<Iterator, Vector_3>(),
Color_map(m_points->point_set()),
echo_map);
else if (normals && !colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
m_points->point_set()->normal_map());
else if (normals && !colors && echo)
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
m_points->point_set()->normal_map(),
CGAL::Empty_property_map<Iterator, Color>(),
echo_map);
else if (normals && colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
m_points->point_set()->normal_map(),
CGAL::Empty_property_map<Iterator, Color>());
else
m_helper = new Helper (filename, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
m_points->point_set()->normal_map(),
Color_map(m_points->point_set()),
echo_map);
std::vector<std::pair<Type_handle, QColor> > new_types;
for (std::size_t i = 0; i < m_psc->number_of_classification_types(); ++ i)
{
Type_handle t = m_psc->get_classification_type(i);
QColor color (192 + rand() % 60,
192 + rand() % 60,
192 + rand() % 60);
for (std::size_t j = 0; j < m_types.size(); ++ j)
if (t->id() == m_types[j].first->id())
{
color = m_types[j].second;
break;
}
new_types.push_back (std::make_pair (t, color));
}
m_types.swap (new_types);
}
public Q_SLOTS:
// Data
private:
Scene_points_with_normal_item* m_points;
PSC* m_psc;
Helper* m_helper;
std::size_t m_nb_scales;
std::vector<std::pair<Type_handle, QColor> > m_types;
std::size_t m_nb_trials;
double m_smoothing;
int m_index_color;
enum VAOs {
Edges=0,
ThePoints,
NbOfVaos = ThePoints+1
};
enum VBOs {
Edges_vertices = 0,
Points_vertices,
Points_colors,
NbOfVbos = Points_colors+1
};
mutable std::vector<double> positions_lines;
mutable std::vector<double> positions_points;
mutable std::vector<double> colors_points;
mutable std::size_t nb_points;
mutable std::size_t nb_lines;
mutable QOpenGLShaderProgram *program;
using CGAL::Three::Scene_item::initializeBuffers;
void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const;
void compute_normals_and_vertices() const;
}; // end class Scene_point_set_classification_item
#endif // POINT_SET_CLASSIFICATION_ITEM_H

View File

@ -0,0 +1,10 @@
#ifndef SCENE_POINT_SET_CLASSIFICATION_ITEM_CONFIG_H
#define SCENE_POINT_SET_CLASSIFICATION_ITEM_CONFIG_H
#ifdef scene_point_set_classification_item_EXPORTS
# define SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Q_DECL_EXPORT
#else
# define SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Q_DECL_IMPORT
#endif
#endif // SCENE_POINT_SET_CLASSIFICATION_ITEM_CONFIG_H

View File

@ -0,0 +1,87 @@
#ifndef READ_LAS_POINT_SET_H
#define READ_LAS_POINT_SET_H
#include <liblas/liblas.hpp>
template <typename Point, typename Vector>
bool read_las_point_set(
std::istream& stream, ///< input stream.
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
typename CGAL::Point_set_3<Point, Vector> Point_set;
liblas::ReaderFactory f;
liblas::Reader reader = f.CreateWithStream(stream);
Point_set::Property_map<unsigned char> echo_map;
boost::tie(echo_map, boost::tuples::ignore)
= point_set.template add_property_map<unsigned char>("echo", 0);
Point_set::Property_map<unsigned char> red_map;
boost::tie(red_map, boost::tuples::ignore)
= point_set.template add_property_map<unsigned char>("red", 0);
Point_set::Property_map<unsigned char> green_map;
boost::tie(green_map, boost::tuples::ignore)
= point_set.template add_property_map<unsigned char>("green", 0);
Point_set::Property_map<unsigned char> blue_map;
boost::tie(blue_map, boost::tuples::ignore)
= point_set.template add_property_map<unsigned char>("blue", 0);
unsigned int bit_short_to_char = 0;
while (reader.ReadNextPoint())
{
const liblas::Point& p = reader.GetPoint();
Point_set::iterator it = point_set.insert (Kernel::Point_3 (p.GetX(), p.GetY(), p.GetZ()));
put(echo_map, *it, p.GetReturnNumber());
const liblas::Color& c = p.GetColor();
if (bit_short_to_char == 0
&& (c[0] > 255 || c[1] > 255 || c[2] > 255))
{
// if a value is above 255, shorts are used (that should be
// default but not always the case, hence this test)
bit_short_to_char = 8;
for (Point_set::iterator it2 = point_set.begin(); it2 != it; ++ it2)
{
// Correct previously added values
put(red_map, *it2, ((get(red_map, *it2)) >> 8));
put(green_map, *it2, ((get(green_map, *it2)) >> 8));
put(blue_map, *it2, ((get(blue_map, *it2)) >> 8));
}
}
put(red_map, *it, (c.GetRed() >> bit_short_to_char));
put(green_map, *it, (c.GetGreen() >> bit_short_to_char));
put(blue_map, *it, (c.GetBlue() >> bit_short_to_char));
}
bool remove_echo = true;
bool remove_colors = true;
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
{
if (get(echo_map, *it) != 0)
remove_echo = false;
if (get(red_map, *it) != 0 ||
get(green_map, *it) != 0 ||
get(blue_map, *it) != 0)
remove_colors = false;
if (!remove_echo && !remove_colors)
break;
}
if (remove_echo)
point_set.remove_property_map(echo_map);
if (remove_colors)
{
point_set.remove_property_map(red_map);
point_set.remove_property_map(green_map);
point_set.remove_property_map(blue_map);
}
return true;
}
#endif // READ_LAS_POINT_SET_H

View File

@ -348,6 +348,23 @@ make_property_map(const std::vector<T>& v)
return make_property_map(&v[0]);
}
/// Empty property map that only returns the default value type
///
/// \cgalModels `ReadablePropertyMap`
///
/// \endcond
template<class InputIterator, class ValueType>
struct Empty_property_map{
typedef typename InputIterator::value_type key_type;
typedef boost::readable_property_map_tag category;
/// Free function to use a get the value from an iterator using Input_iterator_property_map.
inline friend ValueType
get (const Empty_property_map&, const key_type&){ return ValueType(); }
};
} // namespace CGAL
#endif // CGAL_POINT_SET_PROPERTY_MAP_H

View File

@ -174,6 +174,59 @@ public:
return is;
}
};
template <>
class Input_rep<float> {
float& t;
public:
//! initialize with a reference to \a t.
Input_rep( float& tt) : t(tt) {}
std::istream& operator()( std::istream& is) const
{
typedef std::istream istream;
typedef istream::char_type char_type;
typedef istream::int_type int_type;
typedef istream::traits_type traits_type;
std::string buffer;
buffer.reserve(32);
char_type c;
do {
const int_type i = is.get();
if(i == traits_type::eof()) {
return is;
}
c = static_cast<char_type>(i);
}while (std::isspace(c));
if(c == '-'){
buffer += '-';
} else if(c != '+'){
is.unget();
}
do {
const int_type i = is.get();
if(i == traits_type::eof()) {
is.clear(is.rdstate() & ~std::ios_base::failbit);
break;
}
c = static_cast<char_type>(i);
if(std::isdigit(c) || (c =='.') || (c =='E') || (c =='e') || (c =='+') || (c =='-')){
buffer += c;
}else{
is.unget();
break;
}
}while(true);
if(sscanf(buffer.c_str(), "%f", &t) != 1) {
// if a 'buffer' does not contain a double, set the fail bit.
is.setstate(std::ios_base::failbit);
}
return is;
}
};
#endif
/*! \relates Input_rep

View File

@ -21,7 +21,7 @@ int main(int /* argc */, char* argv[])
Mesh sm;
std::ifstream in(argv[1]);
in >> sm;
Mesh::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
CGAL::Properties::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
predecessor = sm.add_property_map<vertex_descriptor,vertex_descriptor>("v:predecessor").first;
boost::prim_minimum_spanning_tree(sm, predecessor, boost::root_vertex(*vertices(sm).first));

View File

@ -19,7 +19,7 @@ int main(int argc, char* argv[])
std::ifstream in2((argc>2)?argv[2]:"data/quad.off");
Mesh::Property_map<vertex_descriptor,std::string> name1, name2;
CGAL::Properties::Property_map<vertex_descriptor,std::string> name1, name2;
bool created;
sm1.add_property_map<vertex_descriptor,int>("v:weight",7812);
boost::tie(name1, created) = sm1.add_property_map<vertex_descriptor,std::string>("v:name","hello");

View File

@ -31,7 +31,7 @@ int main()
}
// The status of being used or removed is stored in a property map
Mesh::Property_map<Mesh::Vertex_index,bool> removed
CGAL::Properties::Property_map<Mesh::Vertex_index,bool> removed
= m.property_map<Mesh::Vertex_index,bool>("v:removed").first;

View File

@ -26,7 +26,7 @@ int main()
// give each vertex a name, the default is empty
Mesh::Property_map<vertex_descriptor,std::string> name;
CGAL::Properties::Property_map<vertex_descriptor,std::string> name;
bool created;
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","");
assert(created);
@ -36,20 +36,20 @@ int main()
{
// You get an existing property, and created will be false
Mesh::Property_map<vertex_descriptor,std::string> name;
CGAL::Properties::Property_map<vertex_descriptor,std::string> name;
bool created;
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name", "");
assert(! created);
}
// You can't get a property that does not exist
Mesh::Property_map<face_descriptor,std::string> gnus;
CGAL::Properties::Property_map<face_descriptor,std::string> gnus;
bool found;
boost::tie(gnus, found) = m.property_map<face_descriptor,std::string>("v:gnus");
assert(! found);
// retrieve the point property for which exists a convenience function
Mesh::Property_map<vertex_descriptor, K::Point_3> location = m.points();
CGAL::Properties::Property_map<vertex_descriptor, K::Point_3> location = m.points();
BOOST_FOREACH( vertex_descriptor vd, m.vertices()) {
std::cout << name[vd] << " @ " << location[vd] << std::endl;
}

View File

@ -396,7 +396,12 @@ public:
parrays_[i]->swap(i0, i1);
}
// swap content with other Property_container
void swap (Property_container& other)
{
this->parrays_.swap (other.parrays_);
}
private:
std::vector<Base_property_array*> parrays_;
size_t size_;

View File

@ -1748,4 +1748,6 @@ inline Graph::termtype Graph::what_segment(node_id i)
return SINK;
}
#undef last_node
#endif