From dc3c56335bbce3aa78c505da8efc24c67fb71469 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 28 Apr 2011 09:50:28 +0000 Subject: [PATCH 02/65] almost ready --- .gitattributes | 21 + .../Spatial_sorting/PkgDescription.tex | 4 +- .../Spatial_sorting/fig/Hilbert-median.gif | Bin 0 -> 11995 bytes .../Spatial_sorting/fig/Hilbert-median.pdf | Bin 0 -> 8054 bytes .../Spatial_sorting/fig/Hilbert-middle.gif | Bin 0 -> 28980 bytes .../Spatial_sorting/fig/Hilbert-middle.pdf | Bin 0 -> 17537 bytes .../doc_tex/Spatial_sorting/fig/Hilbert8.gif | Bin 0 -> 10599 bytes .../doc_tex/Spatial_sorting/fig/Hilbert8.pdf | Bin 0 -> 8261 bytes .../doc_tex/Spatial_sorting/main.tex | 3 +- .../Spatial_sorting/spatial_sorting.tex | 213 +++++++-- .../Spatial_sorting/spatial_sorting_def.tex | 16 - .../Hilbert_policy_tags.tex | 112 +++++ .../Spatial_sorting_ref/Hilbert_sort_2.tex | 6 +- .../Spatial_sorting_ref/Hilbert_sort_3.tex | 7 +- .../Spatial_sorting_ref/Hilbert_sort_d.tex | 29 ++ .../SpatialSortingTraits_2.tex | 20 +- .../SpatialSortingTraits_3.tex | 30 +- .../SpatialSortingTraits_d.tex | 61 +++ .../Spatial_sorting_ref/hilbert_sort.tex | 19 +- .../doc_tex/Spatial_sorting_ref/intro.tex | 17 +- .../doc_tex/Spatial_sorting_ref/main.tex | 3 + .../Spatial_sorting_ref/spatial_sort.tex | 34 +- .../Spatial_sorting/example_delaunay_2.cpp | 86 +++- .../examples/Spatial_sorting/hilbert.cpp | 22 + .../Spatial_sorting/hilbert_policies.cpp | 24 + .../examples/Spatial_sorting/myPoint.cpp | 62 --- .../small_example_delaunay_2.cpp | 40 ++ .../examples/Spatial_sorting/sort_indices.cpp | 102 ++-- .../include/CGAL/Hilbert_policy_tags.h | 40 ++ Spatial_sorting/include/CGAL/Hilbert_sort_2.h | 114 +---- Spatial_sorting/include/CGAL/Hilbert_sort_3.h | 136 +----- .../include/CGAL/Hilbert_sort_base.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_d.h | 54 +++ .../include/CGAL/Hilbert_sort_median_2.h | 122 +++++ .../include/CGAL/Hilbert_sort_median_3.h | 144 ++++++ .../include/CGAL/Hilbert_sort_median_d.h | 169 +++++++ .../include/CGAL/Hilbert_sort_middle_2.h | 137 ++++++ .../include/CGAL/Hilbert_sort_middle_3.h | 185 ++++++++ .../include/CGAL/Hilbert_sort_middle_base.h | 43 ++ .../include/CGAL/Hilbert_sort_middle_d.h | 187 ++++++++ .../include/CGAL/Multiscale_sort.h | 2 +- Spatial_sorting/include/CGAL/hilbert_sort.h | 72 ++- Spatial_sorting/include/CGAL/spatial_sort.h | 109 ++++- .../package_info/Spatial_sorting/maintainer | 2 +- .../test/Spatial_sorting/test_hilbert.cpp | 437 +++++++++++++++++- .../test/Spatial_sorting/test_multiscale.cpp | 43 +- 46 files changed, 2417 insertions(+), 512 deletions(-) create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.gif create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.pdf create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-middle.gif create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-middle.pdf create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert8.gif create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert8.pdf delete mode 100644 Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting_def.tex create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex create mode 100644 Spatial_sorting/examples/Spatial_sorting/hilbert.cpp create mode 100644 Spatial_sorting/examples/Spatial_sorting/hilbert_policies.cpp delete mode 100644 Spatial_sorting/examples/Spatial_sorting/myPoint.cpp create mode 100644 Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp create mode 100644 Spatial_sorting/include/CGAL/Hilbert_policy_tags.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_d.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_median_2.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_median_3.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h create mode 100644 Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h diff --git a/.gitattributes b/.gitattributes index 57670b1248d..f406df7841c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3300,12 +3300,33 @@ Spatial_searching/doc_tex/Spatial_searching/windowQuery.png -text Spatial_searching/include/CGAL/internal/K_neighbor_search.h -text Spatial_searching/include/CGAL/internal/bounded_priority_queue.h -text Spatial_searching/test/Spatial_searching/Compare_methods.cpp -text +Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.gif -text +Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.pdf -text +Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-middle.gif -text +Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-middle.pdf -text +Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert8.gif -text +Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert8.pdf -text Spatial_sorting/doc_tex/Spatial_sorting/fig/hilbert.png -text Spatial_sorting/doc_tex/Spatial_sorting/fig/hilbertLarge.jpg -text +Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex -text +Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex -text +Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex -text Spatial_sorting/dont_submit -text Spatial_sorting/examples/Spatial_sorting/data/input.cin -text Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cmd -text +Spatial_sorting/examples/Spatial_sorting/hilbert.cpp -text +Spatial_sorting/examples/Spatial_sorting/hilbert_policies.cpp -text +Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp -text Spatial_sorting/examples/Spatial_sorting/sort_indices.cmd -text +Spatial_sorting/include/CGAL/Hilbert_policy_tags.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_d.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_median_2.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_median_3.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h -text +Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h -text Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_0.poly -text svneol=unset#application/octet-stream Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_1.poly -text svneol=unset#application/octet-stream Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_2.poly -text svneol=unset#application/octet-stream diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/PkgDescription.tex b/Spatial_sorting/doc_tex/Spatial_sorting/PkgDescription.tex index d35536380eb..959a556c9ca 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/PkgDescription.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/PkgDescription.tex @@ -1,8 +1,8 @@ \begin{ccPkgDescription}{Spatial Sorting \label{Pkg:SpatialSorting}} -\ccPkgHowToCiteCgal{cgal:d-ss-11} +\ccPkgHowToCiteCgal{cgal:d-ss-10} \ccPkgSummary{This package provides functions -for sorting geometric objects in two and three dimensions, in order to improve +for sorting geometric objects in two, three and higher dimensions, in order to improve efficiency of incremental geometric algorithms.} \ccPkgIntroducedInCGAL{3.3} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.gif b/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.gif new file mode 100644 index 0000000000000000000000000000000000000000..cadcba5cdd6808562ab2bb2bf13844f8f4391ca7 GIT binary patch literal 11995 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 literal 0 HcmV?d00001 diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.pdf b/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ddd7002eed63eeb23de6294dbcb396e6b9fc66a9 GIT binary patch literal 8054 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 FKL9K}YX1NL literal 0 HcmV?d00001 diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-middle.gif b/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-middle.gif new file mode 100644 index 0000000000000000000000000000000000000000..d8f7c1296f12fa9e136a78c6ff7b66a20aafba78 GIT binary patch literal 28980 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 literal 0 HcmV?d00001 diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert8.gif b/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert8.gif new file mode 100644 index 0000000000000000000000000000000000000000..d737b6951b472f0fbaf18bda3f55e79ee5320242 GIT binary patch literal 10599 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 U3I2O)paOi{0464BWf{Q#04ih0EC2ui literal 0 HcmV?d00001 diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/main.tex b/Spatial_sorting/doc_tex/Spatial_sorting/main.tex index 442b704f4ef..c184c024ddb 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/main.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/main.tex @@ -1,12 +1,11 @@ \ccUserChapter{Spatial Sorting \label{chap:spatial_sorting}} -\ccChapterAuthor{Christophe Delage} +\ccChapterAuthor{Christophe Delage \and Olivier Devillers} \input{Spatial_sorting/PkgDescription} \minitoc -\input{Spatial_sorting/spatial_sorting_def} \input{Spatial_sorting/spatial_sorting} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index 7c0a371fba6..807db95b739 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -1,61 +1,176 @@ -%\begin{ccHtmlOnly} -%
-% -%
-%\end{ccHtmlOnly} -% -%\begin{ccTexOnly} -%\begin{center} -%\includegraphics[width=6.5cm]{Convex_hull_2/saarhull} -%%\leavevmode\epsfxsize8cm\epsffile{Convex_hull_2/saarhull.eps} -%\end{center} -%\end{ccTexOnly} + +\section{Introduction} + +Many geometric algorithms implemented in \cgal\ are incremental, and thus their +speed is dependent on the order of insertion. This package provides sorting +algorithms that may considerably improve running times of such +algorithms. + +The rationale is to sort objects along a space-filling curve +so that two +objects close geometrically will be close in the insertion order with high +probability. That way, parts of a data structure that will be looked at during +an insertion will probably have been looked at in a recent insertion, and thus +probably will be in cache memory instead of main memory. +As another side-effect, these sorting functions usually improve memory locality +of the data structures produced by incremental algorithms, sometimes leading to +speed ups in other algorithm using these data structures. + +Some algorithms have a good complexity under randomized hypotheses which +contradicts the idea of sorting the input using any sorting criterion. +In such a case, it is possible to introduce just a bit of randomness +to be able to combine the good randomized complexity and the +good effects of locality \cite{acr-icb-03}. + + +The only predicates used by this package are comparisons between coordinates, +thus there is no robustness issues involved here, for example to choose the +arithmetic of the kernel. + + + +\begin{ccTexOnly} +\newpage +\end{ccTexOnly} + + +\begin{figure} +\begin{ccHtmlOnly} +
+ +
+\end{ccHtmlOnly} +\begin{ccTexOnly} +\begin{center} +\includegraphics[width=11.5cm]{Spatial_sorting/fig/Hilbert8} +\end{center} +\end{ccTexOnly} +\caption{Hilbert mapping +\label{Spatial_sorting_fig_Hilbert8}} +\end{figure} + +\section{Hilbert Sorting\label{sec:hilbert_sorting}} + + +In 2D, one can construct a space filling curve, that is a mapping $f$ of $[0,1]$ +to the unit square $[0,1]^2$, such that $f(0)=(0,0)$ and $f(1)=(1,0)$ + in the following way: +the unit square is subdivided in four such that\\ +\begin{quote} +$f([0,\frac{1}{4}])=[0,\frac{1}{2}]^2$, +$f([\frac{1}{4},\frac{1}{2}])=[0,\frac{1}{2}]\times[\frac{1}{2},1]$, +$f([\frac{1}{2},\frac{3}{4}])=[\frac{1}{2},1]^2$, +and +$f([\frac{3}{4},1])=[\frac{1}{2},1]\times[0,\frac{1}{2}].$\\ +$f(\frac{1}{4})=(0,\frac{1}{2})$\\ +$f(\frac{1}{2})=(\frac{1}{2},\frac{1}{2})$, and +$f(\frac{3}{4})=(1,\frac{1}{2})$. +\end{quote} + +Then each square is subdivided in the same way recursively. +Figure~\ref{Spatial_sorting_fig_Hilbert8} illustrates this process. + +Now given a set of 2D points, they can be sorted in the order they have on such +a space filling curve as illustrated on Figure~\ref{Spatial_sorting_fig_Hilbert_middle} : + +\begin{figure}[h] +\begin{ccHtmlOnly} +
+ +
+\end{ccHtmlOnly} +\begin{ccTexOnly} +\begin{center} +\includegraphics[width=6.5cm]{Spatial_sorting/fig/Hilbert-middle} +\end{center} +\end{ccTexOnly} +\caption{Hilbert sort with middle policy +\label{Spatial_sorting_fig_Hilbert_middle}} +\end{figure} + +\begin{ccTexOnly} +\newpage +\end{ccTexOnly} + +\subsection{Examples} + +The code to use Hilbert sort is as simple as the following example: + +\ccIncludeExampleCode{Spatial_sorting/hilbert.cpp} + + +\begin{figure}[t] +\begin{ccHtmlOnly} +
+ +
+\end{ccHtmlOnly} +\begin{ccTexOnly} +\begin{center} +\includegraphics[width=6.5cm]{Spatial_sorting/fig/Hilbert-median} +\end{center} +\end{ccTexOnly} +\caption{Hilbert sort with median policy +\label{Spatial_sorting_fig_Hilbert_median}} +\end{figure} + +If instead of subdividing the square in a fixed way at its middle point, + as above, we subdivide it +by splitting at the median point (in $x$ or $y$ directions alternating), +we construct a 2-d tree adapted to the point set. This tree can be visited in a +similar manner and we get also a suitable ordering of the points +(see Figure~\ref{Spatial_sorting_fig_Hilbert_median}). + + + + + + +\cgal\ provides Hilbert sorting for points in 2D, 3D and higher dimensions, +in the middle and the median policies. + +The median policy seems interesting in practice and his invariant to +scaling, while the middle policy is easier to analyze. Most +theoretical results are using the middle policy +\cite{acr-icb-03,other-references}.. + + +This other example illustrates the use of the two different policies + + +\ccIncludeExampleCode{Spatial_sorting/hilbert_policies.cpp} + \section{Spatial Sorting\label{sec:spatial_sorting}} -\cgal\ provides a small set of sorting algorithms, currently implemented only for 2D and 3D points, although it is easy to extend them to other objects through a traits mechanism. +Hilbert sort cannot be used directly before feeding a randomized algorithm. +Thus, the trick is to organize the point set in random buckets of increasing +sizes, Hilbert sort being used only inside a bucket. -Given an iterator range of points, the function \ccc{hilbert_sort} sorts them -along the space-filling Hilbert curve. -Combined with a \ccc{std::random_shuffle}, the function \ccc{spatial_sort} will -sort points in a way keeping enough randomness to retain theoretical optimality -for some algorithms\footnote{in fact, this has only been proved for Delaunay triangulation}, -and close enough to a space-filling curve to speed-up algorithms. - -The 2D and 3D triangulation classes of \cgal\ internally sort points as described -above, when the points are passed as an iterator range to a constructor or the -\ccc{insert} method. +It has been proved, in the context of Delaunay triangulation, that +such an order provides enough randomness to combine the advantages of a random + order and a space filling curve order \cite{acr-icb-03}. -\section{Examples} +\cgal\ provides spatial sorting for points in 2D, 3D and higher dimensions, +with the middle and the median policies for Hilbert sort in the buckets. -In the following three examples you will see how to apply -spatial sort to \cgal\ points, or on the indices into -a container with points, or on a user defined point class. +\subsection{Examples} -\subsection{Sorting Points} +The following example shows that, on particular input, spatial sort +runs much faster than a bad order or than Hilbert sort (below results +with release mode compilation on a 1.8GHz processor). +\begin{verbatim} +$ ./small_example_delaunay_2 +10000 points on a parabola + Delaunay without spatial sort... done in 6.33443 seconds. + Delaunay with median hilbert sort... done in 0.822975 seconds. + Delaunay with median spatial sort... done in 0.022415 seconds. +\end{verbatim} -When you construct a triangulation from an iterator range of -points, the points get spatially sorted internally. +\ccIncludeExampleCode{Spatial_sorting/small_example_delaunay_2.cpp} -If you have a need for inserting the points one by one -you might sort them yourself. - -\ccIncludeExampleCode{Spatial_sorting/example_delaunay_2.cpp} - - -\subsection{Sorting Indices} - -If you do not want to reorder your input, you can -sort indices in your input instead. +Next example describes how a traits class different than CGAL Kernel can be +used to sort a container of handle on points instead of points directly. \ccIncludeExampleCode{Spatial_sorting/sort_indices.cpp} - - -\subsection{Sorting User Defined Points} - -If you want to sort points of your own point type, -you only have to provide functors that compare -the \ccc{x} and \ccc{y} coordinates of your points. - -\ccIncludeExampleCode{Spatial_sorting/myPoint.cpp} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting_def.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting_def.tex deleted file mode 100644 index 4de45ea4e99..00000000000 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting_def.tex +++ /dev/null @@ -1,16 +0,0 @@ -\section{Introduction} - -Many geometric algorithms implemented in \cgal\ are incremental, and thus their -speed is dependent on the order of insertion. This package provides sorting -algorithms that may considerably improve running times of such -algorithms. - -The rationale is to sort objects along a space-filling curve so that two -objects close geometrically will be close in the insertion order with high -probability. That way, parts of a data structure that will be looked at during -an insertion will probably have been looked at in a recent insertion, and thus -probably will be in cache memory instead of main memory. - -As another side-effect, these sorting functions usually improve memory locality -of the data structures produced by incremental algorithms, sometimes leading to -speed ups in other algorithm using these data structures. diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex new file mode 100644 index 00000000000..a9dd3231f55 --- /dev/null +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex @@ -0,0 +1,112 @@ +\begin{ccRefClass}{Median} + +\ccDefinition +\ccRefName\ is a tag class. It can be used to parameterize a strategy policy +in order to specify the strategy for spatial sorting. +\ccc{Hilbert_policy} can be passed to +as parameter to +\ccc{hilbert_sort} to choose the sorting policy. + +\ccInclude{CGAL/Hilbert_policy_tags.h} + +\ccIsModel +\ccc{DefaultConstructible, CopyConstructible} + +\ccSeeAlso +\ccc{Middle} \\ +\ccc{Hilbert_policy} \\ +\ccc{Hilbert_sort__median_policy} \\ +\ccc{Hilbert_sort__middle_policy} + +\end{ccRefClass} + + +\begin{ccRefClass}{Middle} + +\ccDefinition +\ccRefName\ is a tag class. It can be used to parameterize a strategy policy +in order to specify the strategy for spatial sorting. +\ccc{Hilbert_policy} can be passed to +as parameter to +\ccc{hilbert_sort} to choose the sorting policy. + +\ccInclude{CGAL/Hilbert_policy_tags.h} + +\ccIsModel +\ccc{DefaultConstructible, CopyConstructible} + + +\ccSeeAlso +\ccc{Median} \\ +\ccc{Hilbert_policy} \\ +\ccc{Hilbert_sort__median_policy} \\ +\ccc{Hilbert_sort__middle_policy} + +\end{ccRefClass} + + +\begin{ccRefClass}{Hilbert_policy} + +\ccDefinition +\ccRefName\ is a policy class which can be used to parameterize a strategy policy +in order to specify the strategy for spatial sorting. +\ccc{Hilbert_policy} +or +\ccc{Hilbert_policy} +can be passed to +as parameter to +\ccc{hilbert_sort} to choose the sorting policy. + +\ccInclude{CGAL/Hilbert_policy_tags.h} + + + +\ccParameters + +\ccc{Tag} can only be either \ccc{Median} or \ccc{Middle} currently. + +\ccIsModel +\ccc{DefaultConstructible, CopyConstructible} + +\ccSeeAlso +\ccc{Median} \\ +\ccc{Middle} \\ +\ccc{Hilbert_sort__median_policy} \\ +\ccc{Hilbert_sort__middle_policy} + +\end{ccRefClass} + + +\begin{ccRefClass}{Hilbert_sort_median_policy} + +\ccDefinition +A typedef to \ccc{Hilbert_policy}. + +\ccInclude{CGAL/Hilbert_policy_tags.h} + + +\ccSeeAlso +\ccc{Median} \\ +\ccc{Middle} \\ +\ccc{Hilbert_policy} \\ +\ccc{Hilbert_sort__middle_policy} + + +\end{ccRefClass} + + +\begin{ccRefClass}{Hilbert_sort_middle_policy} + +\ccDefinition +A typedef to \ccc{Hilbert_policy}. + +\ccInclude{CGAL/Hilbert_policy_tags.h} + + +\ccSeeAlso +\ccc{Median} \\ +\ccc{Middle} \\ +\ccc{Hilbert_sort__median_policy} \\ +\ccc{Hilbert_policy} + +\end{ccRefClass} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_2.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_2.tex index 3d07eb3e062..26bb805c768 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_2.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_2.tex @@ -2,9 +2,11 @@ % | Reference manual page: Hilbert_sort_2.tex % +------------------------------------------------------------------------+ -\begin{ccRefFunctionObjectClass}{Hilbert_sort_2} +\begin{ccRefFunctionObjectClass}{Hilbert_sort_2} \ccDefinition The function object \ccRefName\ sorts iterator ranges of -\ccc{Traits::Point_2} along a Hilbert curve. +\ccc{Traits::Point_2} along a Hilbert curve by recursively subdividing +at the median +or the middle depending on the \ccc{PolicyTag}. \ccRequirements \ccc{Traits} is a model for \ccc{SpatialSortingTraits}. diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_3.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_3.tex index 9f696e750bc..1b548776765 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_3.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_3.tex @@ -1,10 +1,11 @@ % +------------------------------------------------------------------------+ -% | Reference manual page: Hilbert_sort_2.tex +% | Reference manual page: Hilbert_sort_3.tex % +------------------------------------------------------------------------+ -\begin{ccRefFunctionObjectClass}{Hilbert_sort_3} +\begin{ccRefFunctionObjectClass}{Hilbert_sort_3} \ccDefinition The function object \ccRefName\ sorts iterator ranges of -\ccc{Traits::Point_3} along a Hilbert curve. +\ccc{Traits::Point_3} along a Hilbert curve by recursively subdividing at the median +or the middle depending on the \ccc{PolicyTag}. \ccRequirements \ccc{Traits} is a model for \ccc{SpatialSortingTraits_3}. diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex new file mode 100644 index 00000000000..2eecab74e04 --- /dev/null +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex @@ -0,0 +1,29 @@ +% +------------------------------------------------------------------------+ +% | Reference manual page: Hilbert_sort_d.tex +% +------------------------------------------------------------------------+ + +\begin{ccRefFunctionObjectClass}{Hilbert_sort_d} +\ccDefinition The function object \ccRefName\ sorts iterator ranges of +\ccc{Traits::Point_d} along a Hilbert curve by recursively subdividing at the median +or the middle depending on the \ccc{PolicyTag}. + +\ccRequirements \ccc{Traits} is a model for \ccc{SpatialSortingTraits_d}. + +\ccTagFullDeclarations +\ccCreationVariable{o} +\ccCreation +\ccConstructor{Hilbert_sort_d(const Traits &traits = Traits())}{constructs an instance with \ccc{traits} as traits class instance.} +\ccOperations +\ccThree{void;;}{A}{} + +\ccMethod{template void operator() (RandomAccessIterator begin, RandomAccessIterator end) const;}{sorts the range [\ccc{begin}, \ccc{end}). + \ccRequire \ccc{RandomAccessIterator::value_type} equals to \ccc{Traits::Point_d}.} + + \ccTagDefaults + +\end{ccRefFunctionObjectClass} +% +------------------------------------------------------------------------+ +%%RefPage: end of main body, begin of footer +% EOF +% +------------------------------------------------------------------------+ + diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex index ea4b1a1b82d..df1d1f53ad0 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex @@ -15,12 +15,26 @@ functions and functors. \ccTypes \ccAutoIndexingOff -\ccSetTwoColumns{SpatialSortingTraits_2::Less_x_2}{} +\ccSetTwoColumns{SpatialSortingTraits_2::Compute_x_2}{} \ccNestedType{Point_2}% {The point type on which the sorting algorithms operate.} +\ccNestedType{Compute_x_2}% + {Functor object type returning the $x$ coordinate of a \ccc{Point_2}. + Must provide + \ccc{FT operator()(Point_2 p)} where \ccc{FT} can be used as + argument of \ccc{CGAL::to_double}. + } + +\ccNestedType{Compute_y_2}% + {Functor object type returning the $y$ coordinate of a \ccc{Point_2}. + Must provide + \ccc{FT operator()(Point_2 p)} where \ccc{FT} can be used as + argument of \ccc{CGAL::to_double}. + } + \ccNestedType{Less_x_2}% {Binary predicate object type comparing \ccc{Point_2}s along the $x$ coordinate. @@ -55,6 +69,10 @@ The following member functions to create instances of the above predicate object types must exist. \setlength\parskip{0mm} +\ccMemberFunction{Compute_x_2 compute_x_2_object(); }{} +\ccGlue +\ccMemberFunction{Compute_y_2 compute_y_2_object(); }{} +\ccGlue \ccMemberFunction{Less_x_2 less_x_2_object(); }{} \ccGlue \ccMemberFunction{Less_y_2 less_y_2_object(); }{} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex index 2741ee9ed3e..18f90121d0c 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex @@ -15,12 +15,34 @@ functions and functors. \ccTypes \ccAutoIndexingOff -\ccSetTwoColumns{SpatialSortingTraits_3::Less_x_3}{} +\ccSetTwoColumns{SpatialSortingTraits_3::Compute_x_3}{} \ccNestedType{Point_3}% {The point type on which the sorting algorithms operate.} +\ccNestedType{Compute_x_3}% + {Functor object type returning the $x$ coordinate of a \ccc{Point_3}. + Must provide + \ccc{FT operator()(Point_3 p)} where \ccc{FT} can be used as + argument of \ccc{CGAL::to_double}. + } + +\ccNestedType{Compute_y_3}% + {Functor object type returning the $y$ coordinate of a \ccc{Point_3}. + Must provide + \ccc{FT operator()(Point_3 p)} where \ccc{FT} can be used as + argument of \ccc{CGAL::to_double}. + } + +\ccNestedType{Compute_z_3}% + {Functor object type returning the $z$ coordinate of a \ccc{Point_3}. + Must provide + \ccc{FT operator()(Point_3 p)} where \ccc{FT} can be used as + argument of \ccc{CGAL::to_double}. + } + + \ccNestedType{Less_x_3}% {Binary predicate object type comparing \ccc{Point_3}s along the $x$ coordinate. @@ -65,6 +87,12 @@ The following member functions to create instances of the above predicate object types must exist. \setlength\parskip{0mm} +\ccMemberFunction{Compute_x_3 compute_x_3_object(); }{} +\ccGlue +\ccMemberFunction{Compute_y_3 compute_y_3_object(); }{} +\ccGlue +\ccMemberFunction{Compute_z_3 compute_z_3_object(); }{} +\ccGlue \ccMemberFunction{Less_x_3 less_x_3_object(); }{} \ccGlue \ccMemberFunction{Less_y_3 less_y_3_object(); }{} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex new file mode 100644 index 00000000000..92f718dbe74 --- /dev/null +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex @@ -0,0 +1,61 @@ +% +------------------------------------------------------------------------+ +% | Reference manual page: SpatialSortingTraits_d.tex +% +------------------------------------------------------------------------+ + + +\begin{ccRefConcept}{SpatialSortingTraits_d} + +\ccDefinition + +All higher dimensional spatial sorting algorithms provided in \cgal{} are parameterized +by a traits class \ccStyle{Traits}, which defines the +primitives (objects and predicates) that the sorting algorithms use. +\ccRefName\ defines the complete set of primitives required in these +functions and functors. + +\ccTypes +\ccAutoIndexingOff +\ccSetTwoColumns{SpatialSortingTraits_3::Compute_coordinate_d}{} + +\ccNestedType{Point_d}% + {The point type on which the sorting algorithms operate. + } + + +\ccNestedType{Compute_coordinate_d(}% + {Functor object type returning the coordinates of a \ccc{Point_d}. + Must provide + \ccc{FT operator()(Point_d p, int i)} returning the $i$th + coordinate of $p$. \ccc{FT} is a type that can be compared by + operator \ccc{<} and \ccc{<=} and can be used as + argument of \ccc{CGAL::to_double}. + } + +\ccCreation +\ccCreationVariable{traits} %% choose variable name + +Only a copy constructor is required. + +\ccConstructor{SpatialSortingTraits_d(const SpatialSortingTraits_d& t);}{} + +\ccOperations + +The following member functions to create instances of the above predicate +object types must exist. + +\setlength\parskip{0mm} +\ccMemberFunction{Compute_coordinate_d compute_coordinate_d_object(); }{} + +\ccParDims +\ccHasModels + +Any \cgal{} $d$ dimensional kernel. + +\ccParDims +\end{ccRefConcept} + +% +------------------------------------------------------------------------+ +%%RefPage: end of main body, begin of footer +% EOF +% +------------------------------------------------------------------------+ + diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/hilbert_sort.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/hilbert_sort.tex index 7980faf7ff7..1cdfa31e3f4 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/hilbert_sort.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/hilbert_sort.tex @@ -21,27 +21,34 @@ along a Hilbert curve. \ccInclude{CGAL/hilbert_sort.h} -\ccGlobalFunction{template +\ccGlobalFunction{template void hilbert_sort( RandomAccessIterator begin, RandomAccessIterator end, - const Traits& traits = Default_traits);}% + const Traits& traits = Default_traits, + PolicyTag policy = Default_policy);} {sorts the range [\ccc{begin},\ccc{end}) in place.} The default traits class \ccc{Default_traits} is the kernel in which the type \ccc{RandomAccessIterator::value_type} is defined. +The default policy is \ccc{Hilbert_sort_median_policy()} and the +other option is \ccc{Hilbert_sort_middle_policy()}. \ccHeading{Requirements} \begin{enumerate} \item \ccc{RandomAccessIterator::value_type} is convertible to -\ccc{Traits::Point_2} or \ccc{Traits::Point_3}. -\item \ccc{Traits} is a model for concept \ccc{SpatialSortingTraits_2} or \ccc{SpatialSortingTraits_3}. +\ccc{Traits::Point_2}, \ccc{Traits::Point_3}, or \ccc{Traits::Point_d}. +\item \ccc{Traits} is a model for concept \ccc{SpatialSortingTraits_2}, + \ccc{SpatialSortingTraits_3}, or \ccc{SpatialSortingTraits_d}. \end{enumerate} \ccImplementation -Creates an instance of \ccc{Hilbert_sort_2} or -\ccc{Hilbert_sort_3} and calls its \ccc{operator()}. +Creates an instance of +\ccc{Hilbert_sort_2}, +\ccc{Hilbert_sort_3}, or +\ccc{Hilbert_sort_d} +and calls its \ccc{operator()}. %\ccc{Some_other_class}, %\ccc{some_other_function}. diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex index 932eb8ad57c..ad4c5be5b83 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex @@ -7,7 +7,7 @@ \ccRefChapter{Spatial Sorting\label{chap:spatialsortingref}} -\ccChapterAuthor{Christophe Delage} +\ccChapterAuthor{Christophe Delage \and Olivier Devillers} \ccHeading{Functions} @@ -17,11 +17,22 @@ \ccHeading{Function Objects} \ccRefIdfierPage{CGAL::Multiscale_sort} \\ -\ccRefIdfierPage{CGAL::Hilbert_sort_2} \\ -\ccRefIdfierPage{CGAL::Hilbert_sort_3} \\ +\ccRefIdfierPage{CGAL::Hilbert_sort_2} \\ +\ccRefIdfierPage{CGAL::Hilbert_sort_3} \\ +\ccRefIdfierPage{CGAL::Hilbert_sort_d} \\ \ccHeading{Concepts} \ccRefIdfierPage{SpatialSortingTraits_2} \\ \ccRefIdfierPage{SpatialSortingTraits_3} \\ +\ccRefIdfierPage{SpatialSortingTraits_d} \\ + + +\ccHeading{Utilities} + +\ccRefIdfierPage{CGAL::Median}\\ +\ccRefIdfierPage{CGAL::Middle}\\ +\ccRefIdfierPage{CGAL::Hilbert_policy}\\ +\ccRefIdfierPage{CGAL::Hilbert_sort_median_policy}\\ +\ccRefIdfierPage{CGAL::Hilbert_sort_middle_policy} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex index 1b92cc657c0..029a4dc5cf4 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex @@ -13,6 +13,9 @@ \input{Spatial_sorting_ref/Hilbert_sort_2.tex} \input{Spatial_sorting_ref/SpatialSortingTraits_3.tex} \input{Spatial_sorting_ref/Hilbert_sort_3.tex} +\input{Spatial_sorting_ref/SpatialSortingTraits_d.tex} +\input{Spatial_sorting_ref/Hilbert_sort_d.tex} \input{Spatial_sorting_ref/Multiscale_sort.tex} +\input{Spatial_sorting_ref/Hilbert_policy_tags.tex} %% EOF diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/spatial_sort.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/spatial_sort.tex index fe348ab6aa5..3a88692347a 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/spatial_sort.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/spatial_sort.tex @@ -23,28 +23,50 @@ of being close in the order. \ccInclude{CGAL/spatial_sort.h} -\ccGlobalFunction{template +\ccGlobalFunction{template void spatial_sort( RandomAccessIterator begin, RandomAccessIterator end, - const Traits& traits = Default_traits);}% + const Traits& traits = Default_traits, + PolicyTag policy = Default_policy, + std::ptrdiff_t threshold_hilbert=default, + std::ptrdiff_t threshold_multiscale=default, + double ratio=default);}% {sorts the range [\ccc{begin},\ccc{end}) in place.} The default traits class \ccc{Default_traits} is the kernel in which the type \ccc{RandomAccessIterator::value_type} is defined. +The default policy is \ccc{Hilbert_sort_median_policy()} and the +other option is \ccc{Hilbert_sort_middle_policy()}. + +The default values for the thresholds and the ratio depends on the dimension. + + \ccHeading{Requirements} \begin{enumerate} \item \ccc{RandomAccessIterator::value_type} is convertible to -\ccc{Traits::Point_2} or \ccc{Traits::Point_3}. -\item \ccc{Traits} is a model for concept \ccc{SpatialSortingTraits_2} or \ccc{SpatialSortingTraits_3}. +\ccc{Traits::Point_2}, \ccc{Traits::Point_3}, or \ccc{Traits::Point_d}. +\item \ccc{Traits} is a model for concept \ccc{SpatialSortingTraits_2}, + \ccc{SpatialSortingTraits_3}, or \ccc{SpatialSortingTraits_d}. \end{enumerate} \ccImplementation -Creates an instance of \ccc{Multiscale_sort>} -or \ccc{Multiscale_sort>} and calls its \ccc{operator()}. +Creates an instance of \ccc{Multiscale_sort} +where \ccStyle{Hilbert_sort} is an Hilbert sorting object, +and calls its \ccc{operator()}. + +The \ccStyle{threshold_hilbert} is the minimal size of a point set to be +subdivided recursively during Hilbert sorting, otherwise random order is used. + The \ccStyle{threshold_multiscale} value is the minimal size for a sample to +call Hilbert sort, otherwise random order is used. +The \ccStyle{ratio} value is used to split the original set in two subsets, +spatial sort is applied on the first subset of size +\ccStyle{ratio} +times the original size of the set, Hilbert sort is applied on the +second subset. %\ccc{Some_other_class}, %\ccc{some_other_function}. diff --git a/Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cpp b/Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cpp index 42994ea2baf..e421604778f 100644 --- a/Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include #include #include @@ -9,31 +12,68 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Delaunay_triangulation_2 DT; +typedef K::Point_2 Point; +typedef CGAL::Creator_uniform_2 Creator_2; + +void compute_delaunay(std::vector::iterator it, + std::vector::iterator e){ + DT dt; + DT::Face_handle hint; + for( ;it!=e; ++it) hint = dt.insert(*it, hint)->face(); + return; +} + +void test_orders(std::vector::iterator b, + std::vector::iterator e){ + CGAL::Timer cost; + + cost.reset();cost.start(); + std::cout << " Delaunay without spatial sort... "<< std::flush; + compute_delaunay(b,e);cost.stop(); + std::cout << "done in "< v; +{ int size1 = 1000,size2=100000; + std::vector v,w; + v.reserve(size1);w.reserve(size2); - std::cout << "Reading..." << std::endl; - std::istream_iterator begin(std::cin), end; - std::copy(begin, end, std::back_inserter(v)); + std::cout <::const_iterator p = v.begin(); p != v.end(); ++p) - f = dt.insert(*p, f)->face(); - - std::cout << "Delaunay is_valid()..." << std::endl; - dt.is_valid(); - - std::cout << "Ok." << std::endl; - - return 0; + CGAL::Random random (42); + CGAL::Random_points_in_square_2 gen (1.0, random); + std::cout < +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_2 Point; +typedef CGAL::Creator_uniform_2 Creator; + +int main () +{ + std::size_t size = 16; + std::vector v; v.reserve(size); + CGAL::points_on_square_grid_2(3.0, size, // generate points + std::back_inserter(v), Creator()); + + CGAL::hilbert_sort (v.begin(), v.end()); // sort + + for(int i=0; i +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_2 Point; + +int main () +{ + std::vector v; v.reserve(4); + v.push_back( Point(0.0,0.0)) ; + v.push_back( Point(1.0,1.0)) ; + v.push_back( Point(0.1,0.1)) ; + v.push_back( Point(0.2,0.8)) ; + + std::cout << "Hilbert sort (middle policy)." << std::endl; + CGAL::hilbert_sort (v.begin(), v.end(), CGAL::Hilbert_sort_middle_policy()); + std::cout< - -struct MyPoint { - double x,y; - - MyPoint() - : x(0), y(0) - {} - - MyPoint(double x, double y) - : x(x), y(y) - {} -}; - - -struct MyLessX { - - bool operator()(const MyPoint& p, const MyPoint& q) const - { - return p.x < q.x; - } - -}; - -struct MyLessY { - - bool operator()(const MyPoint& p, const MyPoint& q) const - { - return p.y < q.y; - } - -}; - -struct MySpatialSortingTraits { - - typedef MyPoint Point_2; - - typedef MyLessX Less_x_2; - typedef MyLessY Less_y_2; - - Less_x_2 less_x_2_object() const - { - return Less_x_2(); - } - - Less_y_2 less_y_2_object() const - { - return Less_y_2(); - } -}; - -int main() -{ - MyPoint points[2]; - - points[0] = MyPoint(78,12); - points[1] = MyPoint(3,121); - MySpatialSortingTraits sst; - CGAL::spatial_sort(points, points+2, sst); - std::cerr << "done" << std::endl; - return 0; -} diff --git a/Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp b/Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp new file mode 100644 index 00000000000..a38465e54ae --- /dev/null +++ b/Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Delaunay_triangulation_2 DT; +void compute_delaunay(std::vector::iterator it, + std::vector::iterator e){ + DT dt; + DT::Face_handle hint; + for( ;it!=e; ++it) hint = dt.insert(*it, hint)->face(); +} +int main () +{ int size = 1000; + std::vector v; + v.reserve(size); + CGAL::Timer cost; + std::cout < +#include #include - - -typedef CGAL::Simple_cartesian K; -typedef K::Point_2 Point_2; -typedef std::vector::iterator Point_iterator; - - - +#include +// Below is a traits class that allow to dereference before comparing +// coordinates. Requirements are to define in the traits class : +// Point_2, Less_x_2, less_x_2_object, Less_y_2, and less_y_2_object template -struct Sort_traits_2 { - +struct Dereference_traits_2 { Kernel k; - - Sort_traits_2 (const Kernel &kernel = Kernel()) - : k (kernel) - {} - + Dereference_traits_2 (const Kernel &kernel = Kernel()) : k (kernel) {} typedef Iterator Point_2; - struct Less_x_2 { Kernel k; - Less_x_2 (const Kernel &kernel = Kernel()) - : k (kernel) - {} + Less_x_2 (const Kernel &kernel = Kernel()): k (kernel) {} bool operator() (const Point_2 &p, const Point_2 &q) const - { + { // dereference then compare return k.less_x_2_object() (*p, *q); } }; - - Less_x_2 - less_x_2_object() const - { - return Less_x_2(k); - } - - struct Less_y_2 { + Less_x_2 less_x_2_object() const { return Less_x_2(k); } + struct Less_y_2 { // Same stuff for y direction Kernel k; - Less_y_2 (const Kernel &kernel = Kernel()) - : k (kernel) - {} - bool operator() (const Point_2 &p, const Point_2 &q) const - { - return k.less_y_2_object() (*p, *q); - } + Less_y_2 (const Kernel &kernel = Kernel()): k (kernel) {} + bool operator() (const Point_2 &p, const Point_2 &q) const + { return k.less_y_2_object() (*p, *q); } }; - - - Less_y_2 - less_y_2_object() const - { - return Less_y_2(k); - } + Less_y_2 less_y_2_object() const { return Less_y_2(k); } }; - - -typedef CGAL::Hilbert_sort_2 > Hilbert_sort_2; -typedef CGAL::Multiscale_sort Spatial_sort_2; - - - - +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_2 Point; +typedef std::vector::iterator Point_it; +typedef CGAL::Hilbert_sort_2 > H_sort; +typedef CGAL::Multiscale_sort My_sort; int main () { - Spatial_sort_2 sort_2; + My_sort my_sort; + std::size_t size = 10; + std::vector points; points.reserve(size); + std::vector iterators; iterators.reserve(size); + CGAL::Random_points_in_square_2 gen (10.0); - std::vector points; - std::vector iterators; - - Point_2 p; - while(std::cin >> p){ - points.push_back(p); - } - - iterators.reserve(points.size()); - for(Point_iterator it = points.begin(); it != points.end(); ++it){ + for (int i = 0; i < size; ++i) points.push_back (*gen++); + for(Point_it it = points.begin(); it != points.end(); ++it) iterators.push_back(it); - } - - sort_2(iterators.begin(), iterators.end()); - - for(std::vector::iterator i = iterators.begin(); - i != iterators.end(); i++) - { - std::cout << **i << std::endl; - } - + my_sort(iterators.begin(), iterators.end()); + for(std::vector::iterator i = iterators.begin(); + i != iterators.end(); i++) std::cout << **i << std::endl; return 0; } diff --git a/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h b/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h new file mode 100644 index 00000000000..b8aeb45c765 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h @@ -0,0 +1,40 @@ +// Copyright (c) 2009 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.6-branch/Spatial_sorting/include/CGAL/hilbert_sort.h $ +// $Id: hilbert_sort.h 53867 2010-01-28 12:18:19Z lrineau $ +// +// Author(s) : Olivier Devillers + +#ifndef CGAL_HILBERT_POLICY_H +#define CGAL_HILBERT_POLICY_H + + +namespace CGAL { + +struct Middle {}; +struct Median {}; + + +// A policy to select the sorting strategy. + +template < typename Tag > +struct Hilbert_policy {}; + +typedef Hilbert_policy Hilbert_sort_middle_policy; +typedef Hilbert_policy Hilbert_sort_median_policy; + +} // namespace CGAL + +#endif // CGAL_HILBERT_POLICY_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h index 2f1a8d8065d..17ad03613b3 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h @@ -15,108 +15,40 @@ // $URL$ // $Id$ // -// Author(s) : Christophe Delage +// Author(s) : Olivier Devillers #ifndef CGAL_HILBERT_SORT_2_H #define CGAL_HILBERT_SORT_2_H -#include -#include -#include -#include +#include +#include +#include namespace CGAL { -namespace internal { - template struct Hilbert_cmp_2; +template + class Hilbert_sort_2; - template - struct Hilbert_cmp_2 - : public std::binary_function - { - typedef typename K::Point_2 Point; - K k; - Hilbert_cmp_2 (const K &_k = K()) : k(_k) {} - bool operator() (const Point &p, const Point &q) const - { - return Hilbert_cmp_2 (k) (q, p); - } - }; - - template - struct Hilbert_cmp_2 - : public std::binary_function - { - typedef typename K::Point_2 Point; - K k; - Hilbert_cmp_2 (const K &_k = K()) : k(_k) {} - bool operator() (const Point &p, const Point &q) const - { - return k.less_x_2_object() (p, q); - } - }; - - template - struct Hilbert_cmp_2 - : public std::binary_function - { - typedef typename K::Point_2 Point; - K k; - Hilbert_cmp_2 (const K &_k = K()) : k(_k) {} - bool operator() (const Point &p, const Point &q) const - { - return k.less_y_2_object() (p, q); - } - }; -} - -template -class Hilbert_sort_2 +template + class Hilbert_sort_2 + : public Hilbert_sort_median_2 { -public: - typedef K Kernel; - typedef typename Kernel::Point_2 Point; - -private: - Kernel _k; - std::ptrdiff_t _limit; - - template struct Cmp : public internal::Hilbert_cmp_2 - { Cmp (const Kernel &k) : internal::Hilbert_cmp_2 (k) {} }; - -public: - Hilbert_sort_2 (const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) - : _k(k), _limit (limit) + public: + Hilbert_sort_2 (const K &k , std::ptrdiff_t limit=1 ) + : Hilbert_sort_median_2 (k,limit) {} - - template - void sort (RandomAccessIterator begin, RandomAccessIterator end) const - { - const int y = (x + 1) % 2; - if (end - begin <= _limit) return; - - RandomAccessIterator m0 = begin, m4 = end; - - RandomAccessIterator m2 = internal::hilbert_split (m0, m4, Cmp< x, upx> (_k)); - RandomAccessIterator m1 = internal::hilbert_split (m0, m2, Cmp< y, upy> (_k)); - RandomAccessIterator m3 = internal::hilbert_split (m2, m4, Cmp< y, !upy> (_k)); - - sort (m0, m1); - sort (m1, m2); - sort (m2, m3); - sort (m3, m4); - } - - template - void operator() (RandomAccessIterator begin, RandomAccessIterator end) const - { - sort <0, false, false> (begin, end); - } }; -} //namespace CGAL +template + class Hilbert_sort_2 + : public Hilbert_sort_middle_2 +{ + public: + Hilbert_sort_2 (const K &k , std::ptrdiff_t limit=1 ) + : Hilbert_sort_middle_2 (k,limit) + {} +}; + +} // namespace CGAL #endif//CGAL_HILBERT_SORT_2_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_3.h b/Spatial_sorting/include/CGAL/Hilbert_sort_3.h index 68d606db2a9..9d59a93e874 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_3.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_3.h @@ -15,130 +15,40 @@ // $URL$ // $Id$ // -// Author(s) : Christophe Delage +// Author(s) : Olivier Devillers #ifndef CGAL_HILBERT_SORT_3_H #define CGAL_HILBERT_SORT_3_H -#include -#include -#include -#include +#include +#include +#include namespace CGAL { -namespace internal { - template struct Hilbert_cmp_3; +template + class Hilbert_sort_3; - template - struct Hilbert_cmp_3 - : public std::binary_function - { - typedef typename K::Point_3 Point; - K k; - Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} - bool operator() (const Point &p, const Point &q) const - { - return Hilbert_cmp_3 (k) (q, p); - } - }; - - template - struct Hilbert_cmp_3 - : public std::binary_function - { - typedef typename K::Point_3 Point; - K k; - Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} - bool operator() (const Point &p, const Point &q) const - { - return k.less_x_3_object() (p, q); - } - }; - - template - struct Hilbert_cmp_3 - : public std::binary_function - { - typedef typename K::Point_3 Point; - K k; - Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} - bool operator() (const Point &p, const Point &q) const - { - return k.less_y_3_object() (p, q); - } - }; - - template - struct Hilbert_cmp_3 - : public std::binary_function - { - typedef typename K::Point_3 Point; - K k; - Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} - bool operator() (const Point &p, const Point &q) const - { - return k.less_z_3_object() (p, q); - } - }; -} - -template -class Hilbert_sort_3 +template + class Hilbert_sort_3 + : public Hilbert_sort_median_3 { -public: - typedef K Kernel; - typedef typename Kernel::Point_3 Point; - -private: - Kernel _k; - std::ptrdiff_t _limit; - - template struct Cmp : public internal::Hilbert_cmp_3 - { Cmp (const Kernel &k) : internal::Hilbert_cmp_3 (k) {} }; - -public: - Hilbert_sort_3 (const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) - : _k(k), _limit (limit) + public: + Hilbert_sort_3 (const K &k , std::ptrdiff_t limit=1 ) + : Hilbert_sort_median_3 (k,limit) {} - - template - void sort (RandomAccessIterator begin, RandomAccessIterator end) const - { - const int y = (x + 1) % 3, z = (x + 2) % 3; - if (end - begin <= _limit) return; - - RandomAccessIterator m0 = begin, m8 = end; - - RandomAccessIterator m4 = internal::hilbert_split (m0, m8, Cmp< x, upx> (_k)); - RandomAccessIterator m2 = internal::hilbert_split (m0, m4, Cmp< y, upy> (_k)); - RandomAccessIterator m1 = internal::hilbert_split (m0, m2, Cmp< z, upz> (_k)); - RandomAccessIterator m3 = internal::hilbert_split (m2, m4, Cmp< z, !upz> (_k)); - RandomAccessIterator m6 = internal::hilbert_split (m4, m8, Cmp< y, !upy> (_k)); - RandomAccessIterator m5 = internal::hilbert_split (m4, m6, Cmp< z, upz> (_k)); - RandomAccessIterator m7 = internal::hilbert_split (m6, m8, Cmp< z, !upz> (_k)); - - sort (m0, m1); - sort (m1, m2); - sort (m2, m3); - sort (m3, m4); - sort (m4, m5); - sort (m5, m6); - sort (m6, m7); - sort (m7, m8); - } - - template - void operator() (RandomAccessIterator begin, RandomAccessIterator end) const - { - sort <0, false, false, false> (begin, end); - } }; -} //namespace CGAL +template + class Hilbert_sort_3 + : public Hilbert_sort_middle_3 +{ + public: + Hilbert_sort_3 (const K &k , std::ptrdiff_t limit=1 ) + : Hilbert_sort_middle_3 (k,limit) + {} +}; + +} // namespace CGAL #endif//CGAL_HILBERT_SORT_3_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_base.h b/Spatial_sorting/include/CGAL/Hilbert_sort_base.h index 6924700098d..462e989730f 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_base.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_base.h @@ -40,6 +40,6 @@ namespace internal { } } -} //namespace CGAL +} // namespace CGAL #endif//CGAL_HILBERT_SORT_BASE_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_d.h new file mode 100644 index 00000000000..8661af4d9ae --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_d.h @@ -0,0 +1,54 @@ +// Copyright (c) 2007 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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: svn+ssh://odevil@scm.gforge.inria.fr/svn/cgal/trunk/Spatial_sorting/include/CGAL/Hilbert_sort_d.h $ +// $Id: Hilbert_sort_d.h 51456 2009-08-24 17:10:04Z spion $ +// +// Author(s) : Olivier Devillers + +#ifndef CGAL_HILBERT_SORT_d_H +#define CGAL_HILBERT_SORT_d_H + +#include +#include +#include + +namespace CGAL { + +template + class Hilbert_sort_d; + +template + class Hilbert_sort_d + : public Hilbert_sort_median_d +{ + public: + Hilbert_sort_d (const K &k , std::ptrdiff_t limit=1 ) + : Hilbert_sort_median_d (k,limit) + {} +}; + +template + class Hilbert_sort_d + : public Hilbert_sort_middle_d +{ + public: + Hilbert_sort_d (const K &k , std::ptrdiff_t limit=1 ) + : Hilbert_sort_middle_d (k,limit) + {} +}; + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_d_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_2.h new file mode 100644 index 00000000000..832a54f19e6 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_2.h @@ -0,0 +1,122 @@ +// Copyright (c) 2007 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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: svn+ssh://odevil@scm.gforge.inria.fr/svn/cgal/trunk/Spatial_sorting/include/CGAL/Hilbert_sort_2.h $ +// $Id: Hilbert_sort_2.h 51456 2009-08-24 17:10:04Z spion $ +// +// Author(s) : Christophe Delage + +#ifndef CGAL_HILBERT_SORT_MEDIAN_2_H +#define CGAL_HILBERT_SORT_MEDIAN_2_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + template struct Hilbert_cmp_2; + + template + struct Hilbert_cmp_2 + : public std::binary_function + { + typedef typename K::Point_2 Point; + K k; + Hilbert_cmp_2 (const K &_k = K()) : k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return Hilbert_cmp_2 (k) (q, p); + } + }; + + template + struct Hilbert_cmp_2 + : public std::binary_function + { + typedef typename K::Point_2 Point; + K k; + Hilbert_cmp_2 (const K &_k = K()) : k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return k.less_x_2_object() (p, q); + } + }; + + template + struct Hilbert_cmp_2 + : public std::binary_function + { + typedef typename K::Point_2 Point; + K k; + Hilbert_cmp_2 (const K &_k = K()) : k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return k.less_y_2_object() (p, q); + } + }; +} + +template +class Hilbert_sort_median_2 +{ +public: + typedef K Kernel; + typedef typename Kernel::Point_2 Point; + +private: + Kernel _k; + std::ptrdiff_t _limit; + + template struct Cmp : public internal::Hilbert_cmp_2 + { Cmp (const Kernel &k) : internal::Hilbert_cmp_2 (k) {} }; + +public: + Hilbert_sort_median_2 (const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) + : _k(k), _limit (limit) + {} + + template + void sort (RandomAccessIterator begin, RandomAccessIterator end) const + { + const int y = (x + 1) % 2; + if (end - begin <= _limit) return; + + RandomAccessIterator m0 = begin, m4 = end; + + RandomAccessIterator m2 = internal::hilbert_split (m0, m4, Cmp< x, upx> (_k)); + RandomAccessIterator m1 = internal::hilbert_split (m0, m2, Cmp< y, upy> (_k)); + RandomAccessIterator m3 = internal::hilbert_split (m2, m4, Cmp< y, !upy> (_k)); + + sort (m0, m1); + sort (m1, m2); + sort (m2, m3); + sort (m3, m4); + } + + template + void operator() (RandomAccessIterator begin, RandomAccessIterator end) const + { + sort <0, false, false> (begin, end); + } +}; + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_MEDIAN_2_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_3.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_3.h new file mode 100644 index 00000000000..33b64a20eb8 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_3.h @@ -0,0 +1,144 @@ +// Copyright (c) 2007 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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: svn+ssh://odevil@scm.gforge.inria.fr/svn/cgal/trunk/Spatial_sorting/include/CGAL/Hilbert_sort_3.h $ +// $Id: Hilbert_sort_3.h 51456 2009-08-24 17:10:04Z spion $ +// +// Author(s) : Christophe Delage + +#ifndef CGAL_HILBERT_SORT_MEDIAN_3_H +#define CGAL_HILBERT_SORT_MEDIAN_3_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + template struct Hilbert_cmp_3; + + template + struct Hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return Hilbert_cmp_3 (k) (q, p); + } + }; + + template + struct Hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return k.less_x_3_object() (p, q); + } + }; + + template + struct Hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return k.less_y_3_object() (p, q); + } + }; + + template + struct Hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + Hilbert_cmp_3 (const K &_k = K()) : k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return k.less_z_3_object() (p, q); + } + }; +} + +template +class Hilbert_sort_median_3 +{ +public: + typedef K Kernel; + typedef typename Kernel::Point_3 Point; + +private: + Kernel _k; + std::ptrdiff_t _limit; + + template struct Cmp : public internal::Hilbert_cmp_3 + { Cmp (const Kernel &k) : internal::Hilbert_cmp_3 (k) {} }; + +public: + Hilbert_sort_median_3 (const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) + : _k(k), _limit (limit) + {} + + template + void sort (RandomAccessIterator begin, RandomAccessIterator end) const + { + const int y = (x + 1) % 3, z = (x + 2) % 3; + if (end - begin <= _limit) return; + + RandomAccessIterator m0 = begin, m8 = end; + + RandomAccessIterator m4 = internal::hilbert_split (m0, m8, Cmp< x, upx> (_k)); + RandomAccessIterator m2 = internal::hilbert_split (m0, m4, Cmp< y, upy> (_k)); + RandomAccessIterator m1 = internal::hilbert_split (m0, m2, Cmp< z, upz> (_k)); + RandomAccessIterator m3 = internal::hilbert_split (m2, m4, Cmp< z, !upz> (_k)); + RandomAccessIterator m6 = internal::hilbert_split (m4, m8, Cmp< y, !upy> (_k)); + RandomAccessIterator m5 = internal::hilbert_split (m4, m6, Cmp< z, upz> (_k)); + RandomAccessIterator m7 = internal::hilbert_split (m6, m8, Cmp< z, !upz> (_k)); + + sort (m0, m1); + sort (m1, m2); + sort (m2, m3); + sort (m3, m4); + sort (m4, m5); + sort (m5, m6); + sort (m6, m7); + sort (m7, m8); + } + + template + void operator() (RandomAccessIterator begin, RandomAccessIterator end) const + { + sort <0, false, false, false> (begin, end); + } +}; + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_MEDIAN_3_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h new file mode 100644 index 00000000000..b49bbe6d9d2 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -0,0 +1,169 @@ +// Copyright (c) 2010 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Olivier Devillers + +#ifndef CGAL_HILBERT_SORT_MEDIAN_d_H +#define CGAL_HILBERT_SORT_MEDIAN_d_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + + template + struct Hilbert_cmp_d + : public std::binary_function + { + typedef typename K::Point_d Point; + K k; + int axe; + bool orient; + Hilbert_cmp_d (int a, bool o, const K &_k = K()) + : axe(a), orient(o), k(_k) {} + bool operator() (const Point &p, const Point &q) const + { + return (orient ? (k.compute_coordinate_d_object() (p,axe) + > k.compute_coordinate_d_object() (q,axe)) + : (k.compute_coordinate_d_object() (p,axe) + < k.compute_coordinate_d_object() (q,axe)) ) ; + } + }; + +} + +template +class Hilbert_sort_median_d +{ +public: + typedef K Kernel; + typedef typename Kernel::Point_d Point; + typedef std::vector< bool > Starting_position; + +private: + Kernel _k; + std::ptrdiff_t _limit; + mutable int _dimension; + mutable int two_to_dim; + + struct Cmp : public internal::Hilbert_cmp_d + { Cmp (int a, bool dir, const Kernel &k) + : internal::Hilbert_cmp_d (a,dir,k) {} }; + +public: + Hilbert_sort_median_d(const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) + : _k(k), _limit (limit) + {} + + template + void sort (RandomAccessIterator begin, RandomAccessIterator end, + Starting_position start, int direction) const + { + if (end - begin <= _limit) return; + + int nb_directions = _dimension; + int nb_splits = two_to_dim; + + if ( (end-begin) < (two_to_dim/2) ) { // not many points + nb_splits = 1; + nb_directions = 0; + while ( (end-begin) > nb_splits) { + ++nb_directions; + nb_splits *= 2; // compute 2^nb_directions + } + } + + + std::vector places(nb_splits +1); + std::vector dir (nb_splits +1); + places[0]=begin; + places[nb_splits]=end; + + int last_dir = (direction + nb_directions) % _dimension; + int current_dir = direction; + int current_level_step =nb_splits; + do{ + int half_step = current_level_step/2; + int left=0; + int middle = half_step; + int right=current_level_step; + bool orient = start[current_dir]; + do{ + dir[middle] = current_dir; + places[middle] = internal::hilbert_split + (places[left], places[right], Cmp (current_dir,orient,_k)); + left =right; + right+=current_level_step; + middle+=current_level_step; + orient = ! orient; + }while( left< nb_splits); + current_level_step = half_step; + current_dir = (current_dir +1) % _dimension; + }while (current_dir != last_dir); + + if ( end-begin < two_to_dim) return; // less than 2^dim points + + /////////////start recursive calls + last_dir = (direction + _dimension -1) % _dimension; + // first step is special + sort( places[0], places[1], start, last_dir); + + for(int i=1; i + void operator() (RandomAccessIterator begin, RandomAccessIterator end) const + { + _dimension = begin->dimension(); + two_to_dim = 1; + Starting_position start(_dimension); + + + for (int i=0; i<_dimension; ++i) { + start[i]=false; // we start below in all coordinates + two_to_dim *= 2; // compute 2^_dimension + if (two_to_dim*2 <= 0) { + CGAL_assertion(end-begin < two_to_dim);//too many points in such dim + break; + } + } + + // we start with direction 0; + sort (begin, end, start, 0); + } +}; + + + + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_MEDIAN_d_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h new file mode 100644 index 00000000000..c0b0f34c6c4 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h @@ -0,0 +1,137 @@ +// Copyright (c) 2010 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Olivier Devillers + +#ifndef CGAL_HILBERT_SORT_MIDDLE_2_H +#define CGAL_HILBERT_SORT_MIDDLE_2_H + +#include +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + template struct Fixed_hilbert_cmp_2; + + template + struct Fixed_hilbert_cmp_2 + : public std::binary_function + { + typedef typename K::Point_2 Point; + K k; + double value; + Fixed_hilbert_cmp_2 (double v, const K &_k = K()) : k(_k),value(v) {} + bool operator() (const Point &p) const + { + return ! Fixed_hilbert_cmp_2 (value, k) (p); + } + }; + + template + struct Fixed_hilbert_cmp_2 + : public std::binary_function + { + typedef typename K::Point_2 Point; + K k; + double value; + Fixed_hilbert_cmp_2 (double v, const K &_k = K()) : k(_k),value(v) {} + bool operator() (const Point &p) const + { + return to_double(k.compute_x_2_object()(p)) < value; + } + }; + + template + struct Fixed_hilbert_cmp_2 + : public std::binary_function + { + typedef typename K::Point_2 Point; + K k; + double value; + Fixed_hilbert_cmp_2 (double v, const K &_k = K()) : k(_k),value(v) {} + bool operator() (const Point &p) const + { + return to_double(k.compute_y_2_object()(p)) < value; + } + }; +} + + +template +class Hilbert_sort_middle_2 +{ +public: + typedef K Kernel; + typedef typename Kernel::Point_2 Point; + +private: + Kernel _k; + std::ptrdiff_t _limit; + + template struct Cmp : public internal::Fixed_hilbert_cmp_2 + { Cmp (double v, const Kernel &k) : internal::Fixed_hilbert_cmp_2 (v, k) {} }; + +public: + Hilbert_sort_middle_2 (const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) + : _k(k), _limit (limit) + {} + + template + void sort (RandomAccessIterator begin, RandomAccessIterator end, + double xmin, double ymin, double xmax, double ymax) const + { + const int y = (x + 1) % 2; + if (end - begin <= _limit) return; + + double xmed= (xmin+xmax)/2; + double ymed= (ymin+ymax)/2; + + RandomAccessIterator m0 = begin, m4 = end; + + RandomAccessIterator m2 = + internal::fixed_hilbert_split (m0, m4, Cmp< x, upx> (xmed,_k)); + RandomAccessIterator m1 = + internal::fixed_hilbert_split (m0, m2, Cmp< y, upy> (ymed,_k)); + RandomAccessIterator m3 = + internal::fixed_hilbert_split (m2, m4, Cmp< y, !upy> (ymed,_k)); + + sort (m0, m1, ymin, xmin, ymed, xmed); + sort (m1, m2, xmin, ymed, xmed, ymax); + sort (m2, m3, xmed, ymed, xmax, ymax); + sort (m3, m4, ymed, xmax, ymin, xmed); + } + + template + void operator() (RandomAccessIterator begin, RandomAccessIterator end) const + { + Bbox_2 box=bbox_2(begin, end); + sort <0, false, false> (begin, end, + box.xmin(), box.ymin(), box.xmax(), box.ymax()); + } +}; + + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_MIDDLE_2_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h new file mode 100644 index 00000000000..d09fc96f665 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h @@ -0,0 +1,185 @@ +// Copyright (c) 2010 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Olivier Devillers + +#ifndef CGAL_HILBERT_SORT_MIDDLE_3_H +#define CGAL_HILBERT_SORT_MIDDLE_3_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + template struct Fixed_hilbert_cmp_3; + + template + struct Fixed_hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + double value; + Fixed_hilbert_cmp_3 (double v, const K &_k = K()) : k(_k),value(v) {} + bool operator() (const Point &p) const + { + return ! Fixed_hilbert_cmp_3 (value,k) (p); + } + }; + + template + struct Fixed_hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + double value; + Fixed_hilbert_cmp_3 (double v, const K &_k = K()) : k(_k),value(v) {} + bool operator() (const Point &p) const + { + return to_double(k.compute_x_3_object()(p)) < value; + } + }; + + template + struct Fixed_hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + double value; + Fixed_hilbert_cmp_3 (double v, const K &_k = K()) : k(_k),value(v) {} + bool operator() (const Point &p) const + { + return to_double(k.compute_y_3_object()(p)) < value; + } + }; + + template + struct Fixed_hilbert_cmp_3 + : public std::binary_function + { + typedef typename K::Point_3 Point; + K k; + double value; + Fixed_hilbert_cmp_3 (double v, const K &_k = K()) : k(_k),value(v) {} + bool operator() (const Point &p) const + { + return to_double(k.compute_z_3_object()(p)) < value ; + } + }; +} + +template +class Hilbert_sort_middle_3 +{ +public: + typedef K Kernel; + typedef typename Kernel::Point_3 Point; + +private: + Kernel _k; + std::ptrdiff_t _limit; + + template struct Cmp : public internal::Fixed_hilbert_cmp_3 + { Cmp (double v,const Kernel &k) : internal::Fixed_hilbert_cmp_3 (v,k) {} }; + +public: + Hilbert_sort_middle_3 (const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) + : _k(k), _limit (limit) + {} + + template + void sort (RandomAccessIterator begin, RandomAccessIterator end, + double xmin, double ymin, double zmin, + double xmax, double ymax, double zmax) const + { + const int y = (x + 1) % 3, z = (x + 2) % 3; + if (end - begin <= _limit) return; + + double xmed= (xmin+xmax)/2; + double ymed= (ymin+ymax)/2; + double zmed= (zmin+zmax)/2; + + + RandomAccessIterator m0 = begin, m8 = end; + + RandomAccessIterator m4 = + internal::fixed_hilbert_split (m0, m8, Cmp< x, upx> (xmed,_k)); + RandomAccessIterator m2 = + internal::fixed_hilbert_split (m0, m4, Cmp< y, upy> (ymed,_k)); + RandomAccessIterator m6 = + internal::fixed_hilbert_split (m4, m8, Cmp< y, !upy> (ymed,_k)); + RandomAccessIterator m1 = + internal::fixed_hilbert_split (m0, m2, Cmp< z, upz> (zmed,_k)); + RandomAccessIterator m3 = + internal::fixed_hilbert_split (m2, m4, Cmp< z, !upz> (zmed,_k)); + RandomAccessIterator m5 = + internal::fixed_hilbert_split (m4, m6, Cmp< z, upz> (zmed,_k)); + RandomAccessIterator m7 = + internal::fixed_hilbert_split (m6, m8, Cmp< z, !upz> (zmed,_k)); + + + sort (m0, m1, zmin, xmin, ymin, zmed, xmed, ymed); + sort (m1, m2, ymin, zmed, xmin, ymed, zmax, xmed); + sort (m2, m3, ymed, zmed, xmin, ymax, zmax, xmed); + sort (m3, m4, xmin, ymax, zmed, xmed, ymed, zmin); + sort (m4, m5, xmed, ymax, zmed, xmax, ymed, zmin); + sort (m5, m6, ymax, zmed, xmax, ymed, zmax, xmed); + sort (m6, m7, ymed, zmed, xmax, ymin, zmax, xmed); + sort (m7, m8, zmed, xmax, ymin, zmin, xmed, ymed); + } + + template + void operator() (RandomAccessIterator begin, RandomAccessIterator end) const + { + K k; + double xmin=to_double(k.compute_x_3_object()(*begin)), + ymin=to_double(k.compute_y_3_object()(*begin)), + zmin=to_double(k.compute_z_3_object()(*begin)), + xmax=xmin, + ymax=ymin, + zmax=zmin; + for(RandomAccessIterator it=begin+1; it xmax) + xmax = to_double(k.compute_x_3_object()(*it)); + if ( to_double(k.compute_y_3_object()(*it)) > ymax) + ymax = to_double(k.compute_y_3_object()(*it)); + if ( to_double(k.compute_z_3_object()(*it)) > zmax) + zmax = to_double(k.compute_z_3_object()(*it)); + } + + sort <0, false, false, false> (begin, end, xmin,ymin,zmin,xmax,ymax,zmax); + } +}; + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_MIDDLE_3_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h new file mode 100644 index 00000000000..0f19a50b825 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h @@ -0,0 +1,43 @@ +// Copyright (c) 2010 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Olivier Devillers + +#ifndef CGAL_HILBERT_SORT_MIDDLE_BASE_H +#define CGAL_HILBERT_SORT_MIDDLE_BASE_H + +#include +#include + +namespace CGAL { + +namespace internal { + + template + RandomAccessIterator + fixed_hilbert_split (RandomAccessIterator begin, RandomAccessIterator end, + Cmp cmp = Cmp ()) + { + if (begin >= end) return begin; + + return std::partition (begin, end, cmp); + } +} + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_MIDDLE_BASE_H diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h new file mode 100644 index 00000000000..97c4814d5ee --- /dev/null +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h @@ -0,0 +1,187 @@ +// Copyright (c) 2010 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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Olivier Devillers + +#ifndef CGAL_HILBERT_SORT_MIDDLE_d_H +#define CGAL_HILBERT_SORT_MIDDLE_d_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + + template + struct Fixed_hilbert_cmp_d + : public std::binary_function + { + typedef typename K::Point_d Point; + K k; + int axe; + bool orient; + double value; + Fixed_hilbert_cmp_d (int a, bool o, double v, const K &_k = K()) + : axe(a), orient(o), k(_k), value(v) {} + bool operator() (const Point &p) const + { + return (orient + ? ( to_double( k.compute_coordinate_d_object() (p,axe) ) > value) + : ( to_double( k.compute_coordinate_d_object() (p,axe) ) <= value)); + } + }; + +} + +template +class Hilbert_sort_middle_d +{ +public: + typedef K Kernel; + typedef typename Kernel::Point_d Point; + typedef std::vector< bool > Starting_position; + typedef std::vector< double > Corner; + +private: + Kernel _k; + std::ptrdiff_t _limit; + mutable int _dimension; + mutable int two_to_dim; + + struct Cmp : public internal::Fixed_hilbert_cmp_d + { Cmp (int a, bool dir, double v, const Kernel &k) + : internal::Fixed_hilbert_cmp_d (a,dir,v,k) {} }; + +public: + Hilbert_sort_middle_d (const Kernel &k = Kernel(), std::ptrdiff_t limit = 1) + : _k(k), _limit (limit) + {} + + template + void sort (RandomAccessIterator begin, RandomAccessIterator end, + Starting_position start, int direction, + Corner min, Corner max) const + { + if (end - begin <= _limit) return; + + Corner med(_dimension); + for( int i=0; i<_dimension; ++i) med[i]=(min[i]+max[i])/2; + Corner cmin=min,cmax=med; + + std::vector places(two_to_dim +1); + std::vector dir (two_to_dim +1); + places[0]=begin; + places[two_to_dim]=end; + + int last_dir = (direction + _dimension) % _dimension; + int current_dir = direction; + int current_level_step =two_to_dim; + do{ + int half_step = current_level_step/2; + int left=0; + int middle = half_step; + int right=current_level_step; + bool orient = start[current_dir]; + do{ + dir[middle] = current_dir; + places[middle] = internal::fixed_hilbert_split + (places[left], places[right], + Cmp (current_dir,orient,med[current_dir],_k)); + left =right; + right+=current_level_step; + middle+=current_level_step; + orient = ! orient; + }while( left< two_to_dim); + current_level_step = half_step; + current_dir = (current_dir +1) % _dimension; + }while (current_dir != last_dir); + + /////////////start recursive calls + last_dir = (direction + _dimension -1) % _dimension; + // first step is special + sort( places[0], places[1], start, last_dir,cmin,cmax); + cmin[last_dir] = med[last_dir]; + cmax[last_dir] = max[last_dir]; + + + for(int i=1; i + void operator() (RandomAccessIterator begin, RandomAccessIterator end) const + { + K k; + _dimension = begin->dimension(); + two_to_dim = 1; + Starting_position start(_dimension); + Corner min(_dimension),max(_dimension); + + for (int i=0; i<_dimension; ++i) + min[i]=max[i]=to_double( k.compute_coordinate_d_object() (*begin,i) ); + for(RandomAccessIterator it=begin+1; it max[i]) max[i] = d; + } + } + + + for (int i=0; i<_dimension; ++i) { + start[i]=false; // we start below in all coordinates + two_to_dim *= 2; // compute 2^_dimension + if (two_to_dim*2 <= 0) { + CGAL_assertion(end-begin < two_to_dim);//too many points in such dim + break; + } + } + + + + // we start with direction 0; + sort (begin, end, start, 0, min, max); + } +}; + + + + +} // namespace CGAL + +#endif//CGAL_HILBERT_SORT_MIDDLE_d_H diff --git a/Spatial_sorting/include/CGAL/Multiscale_sort.h b/Spatial_sorting/include/CGAL/Multiscale_sort.h index 1786858406e..51c5df33b5d 100644 --- a/Spatial_sorting/include/CGAL/Multiscale_sort.h +++ b/Spatial_sorting/include/CGAL/Multiscale_sort.h @@ -53,6 +53,6 @@ public: } }; -} //namespace CGAL +} // namespace CGAL #endif // CGAL_MULTISCALE_SORT_H diff --git a/Spatial_sorting/include/CGAL/hilbert_sort.h b/Spatial_sorting/include/CGAL/hilbert_sort.h index d7956c41699..2529325ca03 100644 --- a/Spatial_sorting/include/CGAL/hilbert_sort.h +++ b/Spatial_sorting/include/CGAL/hilbert_sort.h @@ -16,14 +16,17 @@ // $Id$ // // Author(s) : Christophe Delage +// : Olivier Devillers #ifndef CGAL_HILBERT_SORT_H #define CGAL_HILBERT_SORT_H #include +#include #include #include +#include #include #include @@ -32,50 +35,81 @@ namespace CGAL { + namespace internal { - template - void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, - const Kernel &k, typename Kernel::Point_2 *) + template + void hilbert_sort (RandomAccessIterator begin, + RandomAccessIterator end, + Policy policy, + const Kernel &k, typename Kernel::Point_2 *) { boost::rand48 random; boost::random_number_generator rng(random); std::random_shuffle(begin,end, rng); - (Hilbert_sort_2 (k)) (begin, end); + (Hilbert_sort_2 (k))(begin, end); } - - template - void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, - const Kernel &k, typename Kernel::Point_3 *) + + template + void hilbert_sort (RandomAccessIterator begin, + RandomAccessIterator end, + Policy policy, + const Kernel &k, typename Kernel::Point_3 *) { boost::rand48 random; boost::random_number_generator rng(random); std::random_shuffle(begin,end, rng); - (Hilbert_sort_3 (k)) (begin, end); + (Hilbert_sort_3 (k))(begin, end); } -} -template -void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, - const Kernel &k) -{ - typedef std::iterator_traits ITraits; - typedef typename ITraits::value_type value_type; + template + void hilbert_sort (RandomAccessIterator begin, + RandomAccessIterator end, + Policy policy, + const Kernel &k, typename Kernel::Point_d *) + { + boost::rand48 random; + boost::random_number_generator rng(random); + std::random_shuffle(begin,end, rng); + (Hilbert_sort_d (k))(begin, end); + } + + - internal::hilbert_sort (begin, end, k, static_cast (0)); } template void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end) +{ + hilbert_sort (begin, end, Hilbert_sort_median_policy()); +} + +template +void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, + Policy policy) { typedef std::iterator_traits ITraits; typedef typename ITraits::value_type value_type; typedef CGAL::Kernel_traits KTraits; typedef typename KTraits::Kernel Kernel; - hilbert_sort (begin, end, Kernel()); + internal::hilbert_sort(begin, end, policy, Kernel(), + static_cast (0)); } -} //namespace CGAL + +template +void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, + Policy policy, const Kernel &k ) +{ + typedef std::iterator_traits ITraits; + typedef typename ITraits::value_type value_type; + + internal::hilbert_sort(begin, end, + policy, k, static_cast (0)); +} + +} // namespace CGAL #endif//CGAL_HILBERT_SORT_H + diff --git a/Spatial_sorting/include/CGAL/spatial_sort.h b/Spatial_sorting/include/CGAL/spatial_sort.h index 3640c6492aa..1522edd3a7d 100644 --- a/Spatial_sorting/include/CGAL/spatial_sort.h +++ b/Spatial_sorting/include/CGAL/spatial_sort.h @@ -12,19 +12,18 @@ // 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$ +// $URL: +// $Id: // // Author(s) : Christophe Delage +// : Olivier Devillers #ifndef CGAL_SPATIAL_SORT_H #define CGAL_SPATIAL_SORT_H #include -#include -#include - +#include #include #include @@ -34,54 +33,120 @@ namespace CGAL { + namespace internal { - template - void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, - const Kernel &k, typename Kernel::Point_2 *) + template + void spatial_sort ( + RandomAccessIterator begin, RandomAccessIterator end, + Policy policy, + const Kernel &k, typename Kernel::Point_2 *, + std::ptrdiff_t threshold_hilbert, + std::ptrdiff_t threshold_multiscale, + double ratio) { - typedef Hilbert_sort_2 Sort; + typedef Hilbert_sort_2 Sort; boost::rand48 random; boost::random_number_generator rng(random); std::random_shuffle(begin,end,rng); - (Multiscale_sort (Sort (k, 4), 16, 0.25)) (begin, end); + if (threshold_hilbert==0) threshold_hilbert=4; + if (threshold_multiscale==0) threshold_multiscale=16; + if (ratio==0.0) ratio=0.25; + + (Multiscale_sort (Sort (k, threshold_hilbert), + threshold_multiscale, ratio)) (begin, end); } - template - void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, - const Kernel &k, typename Kernel::Point_3 *) + template + void spatial_sort ( + RandomAccessIterator begin, RandomAccessIterator end, + Policy policy, + const Kernel &k, typename Kernel::Point_3 *, + std::ptrdiff_t threshold_hilbert, + std::ptrdiff_t threshold_multiscale, + double ratio) { - typedef Hilbert_sort_3 Sort; + typedef Hilbert_sort_3 Sort; boost::rand48 random; boost::random_number_generator rng(random); std::random_shuffle(begin,end, rng); - (Multiscale_sort (Sort (k, 8), 64, 0.125)) (begin, end); + if (threshold_hilbert==0) threshold_hilbert=8; + if (threshold_multiscale==0) threshold_multiscale=64; + if (ratio==0.0) ratio=0.125; + + (Multiscale_sort (Sort (k, threshold_hilbert), + threshold_multiscale, ratio)) (begin, end); } + + template + void spatial_sort ( + RandomAccessIterator begin, RandomAccessIterator end, + Policy policy, + const Kernel &k, typename Kernel::Point_d *, + std::ptrdiff_t threshold_hilbert, + std::ptrdiff_t threshold_multiscale, + double ratio) + { + typedef Hilbert_sort_d Sort; + boost::rand48 random; + boost::random_number_generator rng(random); + std::random_shuffle(begin,end, rng); + + if (threshold_hilbert==0) threshold_hilbert=10; + if (threshold_multiscale==0) threshold_multiscale=500; + if (ratio==0.0) ratio=0.05; + + (Multiscale_sort (Sort (k, threshold_hilbert), + threshold_multiscale, ratio)) (begin, end); + } + } -template + +template void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, - const Kernel &k) + Policy policy, + const Kernel &k, + std::ptrdiff_t threshold_hilbert=0, + std::ptrdiff_t threshold_multiscale=0, + double ratio=0.0) { typedef std::iterator_traits ITraits; typedef typename ITraits::value_type value_type; - internal::spatial_sort (begin, end, k, static_cast (0)); + internal::spatial_sort(begin, end, policy, k, static_cast (0), + threshold_hilbert,threshold_multiscale,ratio); } -template -void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end) +template +void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, + Policy policy, + std::ptrdiff_t threshold_hilbert=0, + std::ptrdiff_t threshold_multiscale=0, + double ratio=0.0) { typedef std::iterator_traits ITraits; typedef typename ITraits::value_type value_type; typedef CGAL::Kernel_traits KTraits; typedef typename KTraits::Kernel Kernel; - spatial_sort (begin, end, Kernel()); + spatial_sort (begin, end, policy, Kernel(), + threshold_hilbert,threshold_multiscale,ratio); } -} //namespace CGAL +template +void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, + std::ptrdiff_t threshold_hilbert=0, + std::ptrdiff_t threshold_multiscale=0, + double ratio=0.0) +{ + spatial_sort (begin, end, + Hilbert_sort_median_policy(), + threshold_hilbert,threshold_multiscale,ratio); +} + +} // namespace CGAL #endif//CGAL_SPATIAL_SORT_H diff --git a/Spatial_sorting/package_info/Spatial_sorting/maintainer b/Spatial_sorting/package_info/Spatial_sorting/maintainer index 7e028c78627..99303a0d3ce 100644 --- a/Spatial_sorting/package_info/Spatial_sorting/maintainer +++ b/Spatial_sorting/package_info/Spatial_sorting/maintainer @@ -1 +1 @@ -cgal-develop +odevil diff --git a/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp b/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp index 33b7511ce28..7364d547d77 100644 --- a/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp +++ b/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp @@ -4,37 +4,47 @@ #include #include +#include #include #include #include +#include +#include #include #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef K::Point_2 Point_2; -typedef K::Point_3 Point_3; +#include -typedef CGAL::Creator_uniform_2 Creator_2; -typedef CGAL::Creator_uniform_3 Creator_3; +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_2 Point_2; +typedef K::Point_3 Point_3; +typedef CGAL::Creator_uniform_2 Creator_2; +typedef CGAL::Creator_uniform_3 Creator_3; + +typedef CGAL::Cartesian_d Kd; +typedef Kd::Point_d Point; +typedef CGAL::Creator_uniform_d::iterator, Point>Creator_d; int main () { - const int nb_points_2 = 50000, nb_points_3 = 50000; - CGAL::Random random (42); + int nb_points_2 = 5000, nb_points_3 = 5000, + nb_points_d=10000, small_nb_points_d=3; + CGAL::Random random (42); + CGAL::Timer cost; std::cout << "Testing Hilbert sort." << std::endl; { - std::cout << "Testing 2D: Generating points... " << std::flush; + std::cout << "Testing 2D: Generating "< v; v.reserve (nb_points_2); - CGAL::Random_points_in_square_2 gen (1.0, random); + CGAL::Random_points_in_square_2 gen (1.0, random); for (int i = 0; i < nb_points_2; ++i) v.push_back (*gen++); @@ -45,9 +55,11 @@ int main () std::cout << " Sorting points... " << std::flush; + cost.reset();cost.start(); CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); - std::cout << "done." << std::endl; + std::cout << "done in "< v; + v.reserve(size); + + CGAL::points_on_square_grid_2 (box_size, (std::size_t)size, + std::back_inserter(v), Creator_2() ); + + std::cout << "done." << std::endl; + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve (nb_points_2); + + CGAL::Random_points_in_square_2 gen (1.0, random); + + for (int i = 0; i < nb_points_2; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort(v.begin(),v.end(),CGAL::Hilbert_sort_middle_policy()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve(size); + + CGAL::points_on_square_grid_2 (box_size, (std::size_t)size, + std::back_inserter(v), Creator_2() ); + + std::cout << "done." << std::endl; + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort(v.begin(),v.end(),CGAL::Hilbert_sort_middle_policy()); + cost.stop(); + + std::cout << "done in "< v; v.reserve (nb_points_3); - CGAL::Random_points_in_cube_3 gen (1.0, random); + CGAL::Random_points_in_cube_3 gen (1.0, random); for (int i = 0; i < nb_points_3; ++i) v.push_back (*gen++); @@ -75,9 +174,11 @@ int main () std::cout << " Sorting points... " << std::flush; + cost.reset();cost.start(); CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); - std::cout << "done." << std::endl; + std::cout << "done in "< v; + v.reserve(size); + + CGAL::points_on_cube_grid_3 (box_size, (std::size_t)size, + std::back_inserter(v), Creator_3() ); + + std::cout << "done." << std::endl; + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve (nb_points_3); + + CGAL::Random_points_in_cube_3 gen (1.0, random); + + for (int i = 0; i < nb_points_3; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort(v.begin(),v.end(),CGAL::Hilbert_sort_middle_policy()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve(size); + + CGAL::points_on_cube_grid_3 (box_size, (std::size_t)size, + std::back_inserter(v), Creator_3() ); + + std::cout << "done." << std::endl; + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort(v.begin(),v.end(),CGAL::Hilbert_sort_middle_policy()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve (nb_points_d); + + CGAL::Random_points_in_cube_d gen (dim, 1.0, random); + + for (int i = 0; i < nb_points_d; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve (nb_points_d); + + CGAL::Random_points_in_cube_d gen (dim, 1.0, random); + + for (int i = 0; i < nb_points_d; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve (nb_points_d); + + CGAL::Random_points_in_cube_d gen (dim, 1.0, random); + + for (int i = 0; i < nb_points_d; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); + + std::cout << "done in "< v(size); + + CGAL::points_on_cube_grid_d (dim, box_size, (std::size_t)size, + v.begin(), Creator_d(dim) ); + + std::cout << "done." << std::endl; + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.begin()+size); + cost.stop(); + + std::cout << "done in "< v(size); + + CGAL::points_on_cube_grid_d (dim, box_size, (std::size_t)size, + v.begin(), Creator_d(dim) ); + + std::cout << "done." << std::endl; + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.begin()+size, + CGAL::Hilbert_sort_middle_policy()); + cost.stop(); + + std::cout << "done in "< v(size); + + CGAL::points_on_cube_grid_d (dim, box_size, (std::size_t)size, + v.begin(), Creator_d(dim) ); + + std::cout << "done." << std::endl; + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.begin()+size, + CGAL::Hilbert_sort_middle_policy()); + cost.stop(); + + std::cout << "done in "< v; + v.reserve (nb_points_d); + + CGAL::Random_points_in_cube_d gen (dim, 1.0, random); + + for (int i = 0; i < nb_points_d; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.end()); + cost.stop(); + + std::cout << "done in "< #include +#include #include #include #include +#include +#include #include #include @@ -21,9 +24,12 @@ typedef K::Point_3 Point_3; typedef CGAL::Creator_uniform_2 Creator_2; typedef CGAL::Creator_uniform_3 Creator_3; +typedef CGAL::Cartesian_d Kd; +typedef Kd::Point_d Point; + int main () { - const int nb_points_2 = 50000, nb_points_3 = 50000; + const int nb_points_2 = 50000, nb_points_3 = 50000, nb_points_d=50000; CGAL::Random random (42); std::cout << "Testing Multiscale sort." << std::endl; @@ -55,7 +61,7 @@ int main () std::sort (v2.begin(), v2.end(), K().less_xy_2_object()); assert(v == v2); - std::cout << "OK." << std::endl; + std::cout << "no points lost." << std::endl; } { @@ -85,7 +91,38 @@ int main () std::sort (v2.begin(), v2.end(), K().less_xyz_3_object()); assert(v == v2); - std::cout << "OK." << std::endl; + std::cout << "no points lost." << std::endl; + } + + { + int dim=5; + std::cout << "Testing "< v; + v.reserve (nb_points_d); + + CGAL::Random_points_in_cube_d gen (dim, 1.0, random); + + for (int i = 0; i < nb_points_d; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points... " << std::flush; + + CGAL::spatial_sort (v.begin(), v.end()); + + std::cout << "done." << std::endl; + + std::cout << " Checking... " << std::flush; + + std::sort (v.begin(), v.end(), Kd().less_lexicographically_d_object()); + std::sort (v2.begin(), v2.end(),Kd().less_lexicographically_d_object()); + assert(v == v2); + + std::cout << "no points lost." << std::endl; } return 0; From e451196060bd2fe694612b1eee60fe7a2ff19dcf Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 28 Apr 2011 10:14:34 +0000 Subject: [PATCH 03/65] add default parameter in constructors of Hilbert_sort_23d --- .gitattributes | 1 - .../examples/Spatial_sorting/example_delaunay_2.cmd | 1 - Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp | 5 +++-- Spatial_sorting/include/CGAL/Hilbert_sort_2.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_3.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_d.h | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cmd diff --git a/.gitattributes b/.gitattributes index f406df7841c..e31bbb8f9d6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3313,7 +3313,6 @@ Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex -text Spatial_sorting/dont_submit -text Spatial_sorting/examples/Spatial_sorting/data/input.cin -text -Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cmd -text Spatial_sorting/examples/Spatial_sorting/hilbert.cpp -text Spatial_sorting/examples/Spatial_sorting/hilbert_policies.cpp -text Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp -text diff --git a/Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cmd b/Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cmd deleted file mode 100644 index d391bf0a1c3..00000000000 --- a/Spatial_sorting/examples/Spatial_sorting/example_delaunay_2.cmd +++ /dev/null @@ -1 +0,0 @@ -< data/input.cin \ No newline at end of file diff --git a/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp b/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp index cc8c27bd085..3019d764a3c 100644 --- a/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp @@ -29,8 +29,9 @@ struct Dereference_traits_2 { typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_2 Point; typedef std::vector::iterator Point_it; -typedef CGAL::Hilbert_sort_2 > H_sort; -typedef CGAL::Multiscale_sort My_sort; +typedef CGAL::Hilbert_sort_2, + CGAL::Hilbert_sort_median_policy > H_sort; +typedef CGAL::Multiscale_sort My_sort; int main () { My_sort my_sort; diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h index 17ad03613b3..58dc3c4bade 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h @@ -34,7 +34,7 @@ template : public Hilbert_sort_median_2 { public: - Hilbert_sort_2 (const K &k , std::ptrdiff_t limit=1 ) + Hilbert_sort_2 (const K &k=K() , std::ptrdiff_t limit=1 ) : Hilbert_sort_median_2 (k,limit) {} }; @@ -44,7 +44,7 @@ template : public Hilbert_sort_middle_2 { public: - Hilbert_sort_2 (const K &k , std::ptrdiff_t limit=1 ) + Hilbert_sort_2 (const K &k=K() , std::ptrdiff_t limit=1 ) : Hilbert_sort_middle_2 (k,limit) {} }; diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_3.h b/Spatial_sorting/include/CGAL/Hilbert_sort_3.h index 9d59a93e874..876c5adbeb0 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_3.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_3.h @@ -34,7 +34,7 @@ template : public Hilbert_sort_median_3 { public: - Hilbert_sort_3 (const K &k , std::ptrdiff_t limit=1 ) + Hilbert_sort_3 (const K &k=K() , std::ptrdiff_t limit=1 ) : Hilbert_sort_median_3 (k,limit) {} }; @@ -44,7 +44,7 @@ template : public Hilbert_sort_middle_3 { public: - Hilbert_sort_3 (const K &k , std::ptrdiff_t limit=1 ) + Hilbert_sort_3 (const K &k=K() , std::ptrdiff_t limit=1 ) : Hilbert_sort_middle_3 (k,limit) {} }; diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_d.h index 8661af4d9ae..2ecc9184859 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_d.h @@ -34,7 +34,7 @@ template : public Hilbert_sort_median_d { public: - Hilbert_sort_d (const K &k , std::ptrdiff_t limit=1 ) + Hilbert_sort_d (const K &k=K() , std::ptrdiff_t limit=1 ) : Hilbert_sort_median_d (k,limit) {} }; @@ -44,7 +44,7 @@ template : public Hilbert_sort_middle_d { public: - Hilbert_sort_d (const K &k , std::ptrdiff_t limit=1 ) + Hilbert_sort_d (const K &k=K() , std::ptrdiff_t limit=1 ) : Hilbert_sort_middle_d (k,limit) {} }; From f03e3204764bc9d7da8c727cbad4d47176fdec2f Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 28 Apr 2011 13:06:37 +0000 Subject: [PATCH 04/65] solving some problems in default template parameters --- Spatial_sorting/include/CGAL/spatial_sort.h | 47 +++++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/Spatial_sorting/include/CGAL/spatial_sort.h b/Spatial_sorting/include/CGAL/spatial_sort.h index 1522edd3a7d..1d561149fba 100644 --- a/Spatial_sorting/include/CGAL/spatial_sort.h +++ b/Spatial_sorting/include/CGAL/spatial_sort.h @@ -39,8 +39,9 @@ namespace internal { template void spatial_sort ( RandomAccessIterator begin, RandomAccessIterator end, + const Kernel &k, Policy policy, - const Kernel &k, typename Kernel::Point_2 *, + typename Kernel::Point_2 *, std::ptrdiff_t threshold_hilbert, std::ptrdiff_t threshold_multiscale, double ratio) @@ -61,8 +62,9 @@ namespace internal { template void spatial_sort ( RandomAccessIterator begin, RandomAccessIterator end, + const Kernel &k, Policy policy, - const Kernel &k, typename Kernel::Point_3 *, + typename Kernel::Point_3 *, std::ptrdiff_t threshold_hilbert, std::ptrdiff_t threshold_multiscale, double ratio) @@ -83,8 +85,9 @@ namespace internal { template void spatial_sort ( RandomAccessIterator begin, RandomAccessIterator end, + const Kernel &k, Policy policy, - const Kernel &k, typename Kernel::Point_d *, + typename Kernel::Point_d *, std::ptrdiff_t threshold_hilbert, std::ptrdiff_t threshold_multiscale, double ratio) @@ -107,8 +110,8 @@ namespace internal { template void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, - Policy policy, const Kernel &k, + Policy policy, std::ptrdiff_t threshold_hilbert=0, std::ptrdiff_t threshold_multiscale=0, double ratio=0.0) @@ -116,13 +119,13 @@ void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, typedef std::iterator_traits ITraits; typedef typename ITraits::value_type value_type; - internal::spatial_sort(begin, end, policy, k, static_cast (0), + internal::spatial_sort(begin, end, k, policy, static_cast (0), threshold_hilbert,threshold_multiscale,ratio); } -template +template void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, - Policy policy, + Hilbert_sort_median_policy policy, std::ptrdiff_t threshold_hilbert=0, std::ptrdiff_t threshold_multiscale=0, double ratio=0.0) @@ -132,7 +135,35 @@ void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, typedef CGAL::Kernel_traits KTraits; typedef typename KTraits::Kernel Kernel; - spatial_sort (begin, end, policy, Kernel(), + spatial_sort (begin, end, Kernel(), policy, + threshold_hilbert,threshold_multiscale,ratio); +} +template +void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, + Hilbert_sort_middle_policy policy, + std::ptrdiff_t threshold_hilbert=0, + std::ptrdiff_t threshold_multiscale=0, + double ratio=0.0) +{ + typedef std::iterator_traits ITraits; + typedef typename ITraits::value_type value_type; + typedef CGAL::Kernel_traits KTraits; + typedef typename KTraits::Kernel Kernel; + + spatial_sort (begin, end, Kernel(), policy, + threshold_hilbert,threshold_multiscale,ratio); +} + + +template +void spatial_sort (RandomAccessIterator begin, RandomAccessIterator end, + const Kernel &k, + std::ptrdiff_t threshold_hilbert=0, + std::ptrdiff_t threshold_multiscale=0, + double ratio=0.0) +{ + spatial_sort (begin, end, k, + Hilbert_sort_median_policy(), threshold_hilbert,threshold_multiscale,ratio); } From 2afd39edc3c53c385a5dc2e9b63408827340206b Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Fri, 29 Apr 2011 14:31:48 +0000 Subject: [PATCH 05/65] adding predicate Less_coordinate_d --- Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex | 2 ++ Kernel_d/doc_tex/Kernel_d_ref/main.tex | 1 + Kernel_d/include/CGAL/Cartesian_d.h | 3 +++ Kernel_d/include/CGAL/Homogeneous_d.h | 3 +++ .../include/CGAL/Kernel_d/function_objectsCd.h | 13 +++++++++++++ .../include/CGAL/Kernel_d/function_objectsHd.h | 14 ++++++++++++++ .../Spatial_sorting_ref/SpatialSortingTraits_d.tex | 14 +++++++++++++- .../include/CGAL/Hilbert_sort_median_d.h | 6 ++---- 8 files changed, 51 insertions(+), 5 deletions(-) diff --git a/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex b/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex index ecdd47bdf6f..76d051ce30a 100644 --- a/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex +++ b/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex @@ -108,6 +108,8 @@ replacing operators, especially for equality testing. \ccGlue \ccNestedType{Less_or_equal_lexicographically_d}{} \ccGlue +\ccNestedType{Less_coordinate_d}{} +\ccGlue \ccNestedType{Lift_to_paraboloid_d}{} \ccGlue \ccNestedType{Linear_base_d}{} diff --git a/Kernel_d/doc_tex/Kernel_d_ref/main.tex b/Kernel_d/doc_tex/Kernel_d_ref/main.tex index 8bd81972aa0..7e481266a81 100644 --- a/Kernel_d/doc_tex/Kernel_d_ref/main.tex +++ b/Kernel_d/doc_tex/Kernel_d_ref/main.tex @@ -88,6 +88,7 @@ \input{Kernel_d_ref/Kernel_Intersect_d.tex} \input{Kernel_d_ref/Kernel_Less_lexicographically_d.tex} \input{Kernel_d_ref/Kernel_Less_or_equal_lexicographically_d.tex} +\input{Kernel_d_ref/Kernel_Less_coordinate_d.tex} \input{Kernel_d_ref/Kernel_Lift_to_paraboloid_d.tex} \input{Kernel_d_ref/Kernel_Linearly_independent_d.tex} \input{Kernel_d_ref/Kernel_Linear_base_d.tex} diff --git a/Kernel_d/include/CGAL/Cartesian_d.h b/Kernel_d/include/CGAL/Cartesian_d.h index 6d889e0116d..e0dda612003 100644 --- a/Kernel_d/include/CGAL/Cartesian_d.h +++ b/Kernel_d/include/CGAL/Cartesian_d.h @@ -251,6 +251,7 @@ public: typedef Compare_lexicographicallyCd Compare_lexicographically_d; typedef Lt_from_compare Less_lexicographically_d; typedef Le_from_compare Less_or_equal_lexicographically_d; + typedef Less_coordinateCd Less_coordinate_d; typedef Eq_from_method Equal_d; typedef Center_of_sphereCd Center_of_sphere_d; typedef Contained_in_linear_hullCd Contained_in_linear_hull_d; @@ -260,6 +261,8 @@ public: Compute_coordinate_d compute_coordinate_d_object() const { return Compute_coordinate_d(); } + Less_coordinate_d less_coordinate_d_object() const + { return Less_coordinate_d(); } Lift_to_paraboloid_d lift_to_paraboloid_d_object() const { return Lift_to_paraboloid_d(); } Project_along_d_axis_d project_along_d_axis_d_object() const diff --git a/Kernel_d/include/CGAL/Homogeneous_d.h b/Kernel_d/include/CGAL/Homogeneous_d.h index 994abdfbc5d..e9fd5fddefe 100644 --- a/Kernel_d/include/CGAL/Homogeneous_d.h +++ b/Kernel_d/include/CGAL/Homogeneous_d.h @@ -253,6 +253,7 @@ public: typedef Compare_lexicographicallyHd Compare_lexicographically_d; typedef Lt_from_compare Less_lexicographically_d; typedef Le_from_compare Less_or_equal_lexicographically_d; + typedef Less_coordinateHd Less_coordinate_d; typedef Eq_from_method Equal_d; typedef Center_of_sphereHd Center_of_sphere_d; typedef Contained_in_linear_hullHd Contained_in_linear_hull_d; @@ -262,6 +263,8 @@ public: Compute_coordinate_d compute_coordinate_d_object() const { return Compute_coordinate_d(); } + Less_coordinate_d less_coordinate_d_object() const + { return Less_coordinate_d(); } Lift_to_paraboloid_d lift_to_paraboloid_d_object() const { return Lift_to_paraboloid_d(); } Project_along_d_axis_d project_along_d_axis_d_object() const diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h b/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h index 69edd4b09e0..4884db18529 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h @@ -49,6 +49,19 @@ class Compute_coordinateCd { } }; +template +class Less_coordinateCd { + typedef typename K::FT FT; + typedef typename K::Point_d Point_d; + public: + typedef bool result_type; + const result_type + operator()(const Point_d& p, const Point_d& q, int i) const + { + return p.cartesian(i) struct Lift_to_paraboloidCd { typedef typename R::Point_d Point_d; diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h b/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h index eaedbc5ec1e..c34995abb12 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h @@ -48,6 +48,20 @@ class Compute_coordinateHd { } }; +template +class Less_coordinateHd { + typedef typename K::RT RT; + typedef typename K::Point_d Point_d; + public: + typedef bool result_type; + const result_type + operator()(const Point_d& p, const Point_d& q, int i) const + { + int d = p.dimension(); + return p.cartesian(i)*q.homogeneous(d) struct Lift_to_paraboloidHd { typedef typename R::Point_d Point_d; diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex index 92f718dbe74..21d9d7f9b66 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex @@ -22,7 +22,7 @@ functions and functors. } -\ccNestedType{Compute_coordinate_d(}% +\ccNestedType{Compute_coordinate_d}% {Functor object type returning the coordinates of a \ccc{Point_d}. Must provide \ccc{FT operator()(Point_d p, int i)} returning the $i$th @@ -31,6 +31,17 @@ functions and functors. argument of \ccc{CGAL::to_double}. } + +\ccNestedType{Less_coordinate_d}% + {Binary predicate object type comparing \ccc{Point_d}s + along some coordinate. + Must provide + \ccc{bool operator()(Point_d p, Point_d q, int i)} where \ccc{true} + is returned iff $p_i < q_i$, + where $p_i$ and $q_i$ denote $i$th coordinate of point $p$ and $q$, + respectively. + } + \ccCreation \ccCreationVariable{traits} %% choose variable name @@ -45,6 +56,7 @@ object types must exist. \setlength\parskip{0mm} \ccMemberFunction{Compute_coordinate_d compute_coordinate_d_object(); }{} +\ccMemberFunction{Less_coordinate_d less_coordinate_d_object(); }{} \ccParDims \ccHasModels diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index b49bbe6d9d2..37e6a648fb1 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -42,10 +42,8 @@ namespace internal { : axe(a), orient(o), k(_k) {} bool operator() (const Point &p, const Point &q) const { - return (orient ? (k.compute_coordinate_d_object() (p,axe) - > k.compute_coordinate_d_object() (q,axe)) - : (k.compute_coordinate_d_object() (p,axe) - < k.compute_coordinate_d_object() (q,axe)) ) ; + return (orient ? (k.less_coordinate_d_object() (q,p,axe) ) + : (k.less_coordinate_d_object() (p,q,axe) )); } }; From e4ef31590ca4d711b95ac49fee64c06caf3ed86d Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Fri, 29 Apr 2011 14:50:29 +0000 Subject: [PATCH 06/65] small corrections (doc) --- .../doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex index 21d9d7f9b66..06659646395 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex @@ -26,8 +26,7 @@ functions and functors. {Functor object type returning the coordinates of a \ccc{Point_d}. Must provide \ccc{FT operator()(Point_d p, int i)} returning the $i$th - coordinate of $p$. \ccc{FT} is a type that can be compared by - operator \ccc{<} and \ccc{<=} and can be used as + coordinate of $p$. \ccc{FT} is a type that can be used as argument of \ccc{CGAL::to_double}. } From 56b9e3f3ca4b5223b344e31cc0cf29ec2f04a8c5 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Mon, 2 May 2011 12:56:47 +0000 Subject: [PATCH 07/65] sort_indices no longer needs argument --- .gitattributes | 2 -- Spatial_sorting/examples/Spatial_sorting/data/input.cin | 8 -------- Spatial_sorting/examples/Spatial_sorting/sort_indices.cmd | 1 - 3 files changed, 11 deletions(-) delete mode 100644 Spatial_sorting/examples/Spatial_sorting/data/input.cin delete mode 100644 Spatial_sorting/examples/Spatial_sorting/sort_indices.cmd diff --git a/.gitattributes b/.gitattributes index e31bbb8f9d6..fd0819bc919 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3312,11 +3312,9 @@ Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex -text Spatial_sorting/dont_submit -text -Spatial_sorting/examples/Spatial_sorting/data/input.cin -text Spatial_sorting/examples/Spatial_sorting/hilbert.cpp -text Spatial_sorting/examples/Spatial_sorting/hilbert_policies.cpp -text Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp -text -Spatial_sorting/examples/Spatial_sorting/sort_indices.cmd -text Spatial_sorting/include/CGAL/Hilbert_policy_tags.h -text Spatial_sorting/include/CGAL/Hilbert_sort_d.h -text Spatial_sorting/include/CGAL/Hilbert_sort_median_2.h -text diff --git a/Spatial_sorting/examples/Spatial_sorting/data/input.cin b/Spatial_sorting/examples/Spatial_sorting/data/input.cin deleted file mode 100644 index 2299ded9baf..00000000000 --- a/Spatial_sorting/examples/Spatial_sorting/data/input.cin +++ /dev/null @@ -1,8 +0,0 @@ -1 0 -3 2 -4 5 -9 8 -7 4 -5 2 -6 3 -10 1 diff --git a/Spatial_sorting/examples/Spatial_sorting/sort_indices.cmd b/Spatial_sorting/examples/Spatial_sorting/sort_indices.cmd deleted file mode 100644 index d391bf0a1c3..00000000000 --- a/Spatial_sorting/examples/Spatial_sorting/sort_indices.cmd +++ /dev/null @@ -1 +0,0 @@ -< data/input.cin \ No newline at end of file From 646a19a28120c55ddbb1630b89ec6824b467534d Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Mon, 2 May 2011 12:56:54 +0000 Subject: [PATCH 08/65] sort_indices no longer needs argument --- .gitattributes | 1 - Spatial_sorting/dont_submit | 3 --- 2 files changed, 4 deletions(-) delete mode 100644 Spatial_sorting/dont_submit diff --git a/.gitattributes b/.gitattributes index fd0819bc919..93bdf4a77ed 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3311,7 +3311,6 @@ Spatial_sorting/doc_tex/Spatial_sorting/fig/hilbertLarge.jpg -text Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex -text -Spatial_sorting/dont_submit -text Spatial_sorting/examples/Spatial_sorting/hilbert.cpp -text Spatial_sorting/examples/Spatial_sorting/hilbert_policies.cpp -text Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp -text diff --git a/Spatial_sorting/dont_submit b/Spatial_sorting/dont_submit deleted file mode 100644 index 606782a434f..00000000000 --- a/Spatial_sorting/dont_submit +++ /dev/null @@ -1,3 +0,0 @@ -examples/Spatial_sorting/*.cmd -examples/Spatial_sorting/data/input.cin -examples/Spatial_sorting/data From ba2d4c67ad8806a8ff3a82f5a3ad845d0f91c8ba Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 5 May 2011 07:28:18 +0000 Subject: [PATCH 10/65] bug for very high dim --- .../Spatial_sorting/spatial_sorting.tex | 16 ++++++--- .../include/CGAL/Hilbert_sort_median_d.h | 12 +++---- .../test/Spatial_sorting/test_hilbert.cpp | 33 +++++++++++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index 807db95b739..d50fd33d795 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -23,7 +23,7 @@ to be able to combine the good randomized complexity and the good effects of locality \cite{acr-icb-03}. -The only predicates used by this package are comparisons between coordinates, +The predicates used by this package are comparisons between coordinates, thus there is no robustness issues involved here, for example to choose the arithmetic of the kernel. @@ -129,10 +129,16 @@ similar manner and we get also a suitable ordering of the points \cgal\ provides Hilbert sorting for points in 2D, 3D and higher dimensions, in the middle and the median policies. -The median policy seems interesting in practice and his invariant to -scaling, while the middle policy is easier to analyze. Most -theoretical results are using the middle policy -\cite{acr-icb-03,other-references}.. +The middle policy is easier to analyze, and is interesting in practice +for well distributed set of points in small dimension (if the number +of points is really smaller than $2^d$). +The median policy should be prefered for high dimension or if +the point set distribution is not regular (or unknown). +Since the median policy cannot be much worse than the middle +policy, while the converse can happen, the median policy is the +default behavior. +Most theoretical results are using the middle policy +\cite{acr-icb-03,other-references}. This other example illustrates the use of the two different policies diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index 37e6a648fb1..922562945b5 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -90,7 +90,6 @@ public: } } - std::vector places(nb_splits +1); std::vector dir (nb_splits +1); places[0]=begin; @@ -144,16 +143,15 @@ public: two_to_dim = 1; Starting_position start(_dimension); - + int N=end-begin;N*=2; + for (int i=0; i<_dimension; ++i) start[i]=false; // we start below in all coordinates for (int i=0; i<_dimension; ++i) { - start[i]=false; // we start below in all coordinates two_to_dim *= 2; // compute 2^_dimension - if (two_to_dim*2 <= 0) { - CGAL_assertion(end-begin < two_to_dim);//too many points in such dim - break; - } + N/=2; + if (N==0) break; // not many points, this number of dimension is enough } + // we start with direction 0; sort (begin, end, start, 0); } diff --git a/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp b/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp index 7364d547d77..a174c694faf 100644 --- a/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp +++ b/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp @@ -342,6 +342,39 @@ int main () std::cout << "no points lost." << std::endl; } + { + int dim = 10; + std::cout << "Testing "< v; + v.reserve (nb_points_d); + + CGAL::Random_points_in_cube_d gen (dim, 1.0, random); + + for (int i = 0; i < nb_points_d; ++i) + v.push_back (*gen++); + + std::cout << "done." << std::endl; + + std::vector v2 (v); + + std::cout << " Sorting points ... " << std::flush; + + cost.reset();cost.start(); + CGAL::hilbert_sort (v.begin(), v.end(), + CGAL::Hilbert_sort_middle_policy()); + cost.stop(); + + std::cout << "done in "< Date: Thu, 5 May 2011 08:45:59 +0000 Subject: [PATCH 11/65] add references --- Manual/doc_tex/Manual/geom.bib | 17 +++++++++++++++++ .../doc_tex/Spatial_sorting/spatial_sorting.tex | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Manual/doc_tex/Manual/geom.bib b/Manual/doc_tex/Manual/geom.bib index 1410057becd..f2f52a5f4ea 100644 --- a/Manual/doc_tex/Manual/geom.bib +++ b/Manual/doc_tex/Manual/geom.bib @@ -20469,6 +20469,15 @@ $O(n^2)$ in the plane." , update = "98.11 bibrelex" } +@article{bg-sfche-89 +, title = "On the space-filling curve heuristic for the euclidean traveling salesman problem" +, author = "D. Bertsimas and M. Grigni" +, journal = "Operations Research Letters" +, year = 1989 +, volume = 8 +, pages = "241-244" +} + @techreport{bcdtt-hdspd-92t , author = "P. Bertolazzi and R. F. Cohen and G. {Di Battista} and R. Tamassia and I. G. Tollis" , title = "How to Draw a Series-Parallel Digraph" @@ -29187,6 +29196,14 @@ determinants." , update = "96.09 kreveld" } +@article{b-aahsf-71 +, title = "Alternative Algorithm for {H}ilbert's Space-Filling curve" +, author = "Arthur Butz" +, journal = "IEEE Transactions on computers" +, year = 1971 +, pages = "424-425" +} + @article{b-agtg1-76 , author = "A. Bykat" , title = "Automatic generation of triangular grid: {I} --- subdivision of a general polygon into convex subregions; {II} --- triangulation of convex polygons" diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index d50fd33d795..daaa9b0b309 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -138,7 +138,7 @@ Since the median policy cannot be much worse than the middle policy, while the converse can happen, the median policy is the default behavior. Most theoretical results are using the middle policy -\cite{acr-icb-03,other-references}. +\cite{acr-icb-03,b-aahsf-71,bg-sfche-89,pb-scpts-89}. This other example illustrates the use of the two different policies From 7c3fdd91b486b9e523086bc47d9a658f0f69439f Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 5 May 2011 14:23:37 +0000 Subject: [PATCH 12/65] add missing file --- .gitattributes | 1 + .../Kernel_d_ref/Kernel_Less_coordinate_d.tex | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100755 Kernel_d/doc_tex/Kernel_d_ref/Kernel_Less_coordinate_d.tex diff --git a/.gitattributes b/.gitattributes index 56a47af6077..dcfa0cc4b7c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1716,6 +1716,7 @@ Kernel_23/include/CGAL/internal/Projection_traits_3.h -text Kernel_23/test/Kernel_23/CMakeLists.txt -text Kernel_d/doc_tex/Kernel_d/hypercube.png -text Kernel_d/doc_tex/Kernel_d_ref/Kernel_Compute_coordinate_d.tex -text +Kernel_d/doc_tex/Kernel_d_ref/Kernel_Less_coordinate_d.tex -text Kernel_d/include/CGAL/Kernel_d/Cartesian_const_iterator_d.h -text Kernel_d/test/Kernel_d/Linear_algebra-test.cmd eol=lf Kinetic_data_structures/demo/Kinetic_data_structures/data/after002 -text diff --git a/Kernel_d/doc_tex/Kernel_d_ref/Kernel_Less_coordinate_d.tex b/Kernel_d/doc_tex/Kernel_d_ref/Kernel_Less_coordinate_d.tex new file mode 100755 index 00000000000..b47f0e2b256 --- /dev/null +++ b/Kernel_d/doc_tex/Kernel_d_ref/Kernel_Less_coordinate_d.tex @@ -0,0 +1,13 @@ +\begin{ccRefFunctionObjectConcept}{Kernel::Less_coordinate_d} +A model for this must provide: + +\ccCreationVariable{fo} + +\ccMemberFunction{ bool operator()(const Kernel::Point_d& + p,const Kernel::Point_d& + q, int i);} {returns \ccc{true} iff the $i$th cartesian coordinate + of \ccc{p} is + smaller than the $i$th cartesian coordinate of \ccc{q}. \ccPrecond \ccc{p} and \ccc{q} have + the same dimension.} + +\end{ccRefFunctionObjectConcept} From 65a359580068c9d9be1bab707ee20cc4f8d77a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 5 May 2011 14:41:42 +0000 Subject: [PATCH 13/65] crop gif --- .../Spatial_sorting/fig/Hilbert-median.gif | Bin 11995 -> 11080 bytes .../Spatial_sorting/fig/Hilbert-middle.gif | Bin 28980 -> 26754 bytes .../doc_tex/Spatial_sorting/fig/Hilbert8.gif | Bin 10599 -> 8422 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.gif b/Spatial_sorting/doc_tex/Spatial_sorting/fig/Hilbert-median.gif index cadcba5cdd6808562ab2bb2bf13844f8f4391ca7..bcc1aa3052c8bd7962145f78037a372ad56d9338 100644 GIT binary patch delta 10524 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 L$2SKEz>)bs)zkUG delta 11446 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�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 delta 28415 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 O-FO{)whaLT^!^V;B8O4{ delta 10391 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 Date: Tue, 10 May 2011 07:36:24 +0000 Subject: [PATCH 14/65] warning test-suite --- Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index 922562945b5..c8b653eed54 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -39,7 +39,7 @@ namespace internal { int axe; bool orient; Hilbert_cmp_d (int a, bool o, const K &_k = K()) - : axe(a), orient(o), k(_k) {} + : axe(a), k(_k), orient(o) {} bool operator() (const Point &p, const Point &q) const { return (orient ? (k.less_coordinate_d_object() (q,p,axe) ) diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h index 97c4814d5ee..54768939de6 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h @@ -40,7 +40,7 @@ namespace internal { bool orient; double value; Fixed_hilbert_cmp_d (int a, bool o, double v, const K &_k = K()) - : axe(a), orient(o), k(_k), value(v) {} + : axe(a), k(_k), orient(o), value(v) {} bool operator() (const Point &p) const { return (orient From d465be6a7e046ba3a7570d1a3f3ef9d20d1c6d46 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 12 May 2011 07:43:26 +0000 Subject: [PATCH 15/65] warning test-suite --- Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index c8b653eed54..e879ddba8c5 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -39,7 +39,7 @@ namespace internal { int axe; bool orient; Hilbert_cmp_d (int a, bool o, const K &_k = K()) - : axe(a), k(_k), orient(o) {} + : k(_k), axe(a), orient(o) {} bool operator() (const Point &p, const Point &q) const { return (orient ? (k.less_coordinate_d_object() (q,p,axe) ) diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h index 54768939de6..1a6cb9f3e78 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h @@ -40,7 +40,7 @@ namespace internal { bool orient; double value; Fixed_hilbert_cmp_d (int a, bool o, double v, const K &_k = K()) - : axe(a), k(_k), orient(o), value(v) {} + : k(_k), axe(a), orient(o), value(v) {} bool operator() (const Point &p) const { return (orient From defa7adb5bfeeb88334e7dc6a8214b0c4345e0a7 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Mon, 16 May 2011 07:45:58 +0000 Subject: [PATCH 16/65] remove warning --- Spatial_sorting/examples/Spatial_sorting/hilbert.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_sorting/examples/Spatial_sorting/hilbert.cpp b/Spatial_sorting/examples/Spatial_sorting/hilbert.cpp index 7730cd35c47..aceafaaf245 100644 --- a/Spatial_sorting/examples/Spatial_sorting/hilbert.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/hilbert.cpp @@ -17,6 +17,6 @@ int main () CGAL::hilbert_sort (v.begin(), v.end()); // sort - for(int i=0; i Date: Thu, 19 May 2011 06:19:32 +0000 Subject: [PATCH 17/65] warning correction --- Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp b/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp index 3019d764a3c..f8fab758aed 100644 --- a/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/sort_indices.cpp @@ -40,7 +40,7 @@ int main () std::vector iterators; iterators.reserve(size); CGAL::Random_points_in_square_2 gen (10.0); - for (int i = 0; i < size; ++i) points.push_back (*gen++); + for (std::size_t i = 0; i < size; ++i) points.push_back (*gen++); for(Point_it it = points.begin(); it != points.end(); ++it) iterators.push_back(it); my_sort(iterators.begin(), iterators.end()); From 98ddbf9c7ec255854621860e7003d5d952cb4dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 24 May 2011 15:48:31 +0000 Subject: [PATCH 19/65] merge packages Spatial_sorting, Triangulation_2 and Triangulation_3 from branch spatial_sorting-add_info-sloriot --- .gitattributes | 9 +- .../Spatial_sorting/spatial_sorting.tex | 35 +++++ .../SpatialSortingTraits_2.tex | 4 +- .../SpatialSortingTraits_3.tex | 3 +- .../Spatial_sort_traits_adapter_2.tex | 36 +++++ .../Spatial_sort_traits_adapter_3.tex | 35 +++++ .../doc_tex/Spatial_sorting_ref/intro.tex | 4 + .../doc_tex/Spatial_sorting_ref/main.tex | 2 + .../examples/Spatial_sorting/myPoint.cpp | 72 +++++++++ .../sp_sort_using_property_map_2.cpp | 46 ++++++ .../sp_sort_using_property_map_3.cpp | 37 +++++ .../sp_sort_using_property_map_d.cpp | 57 +++++++ .../CGAL/Spatial_sort_traits_adapter_2.h | 71 +++++++++ .../CGAL/Spatial_sort_traits_adapter_3.h | 81 ++++++++++ .../include/CGAL/Delaunay_triangulation_2.h | 15 +- .../include/CGAL/Regular_triangulation_2.h | 15 +- .../include/CGAL/Delaunay_triangulation_3.h | 15 +- .../include/CGAL/Regular_triangulation_3.h | 15 +- .../include/CGAL/internal/info_check.h | 44 ++++++ .../spatial_sorting_traits_with_indices.h | 146 ------------------ 20 files changed, 565 insertions(+), 177 deletions(-) create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex create mode 100644 Spatial_sorting/examples/Spatial_sorting/myPoint.cpp create mode 100644 Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp create mode 100644 Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp create mode 100644 Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp create mode 100644 Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h create mode 100644 Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h create mode 100644 Triangulation_3/include/CGAL/internal/info_check.h delete mode 100644 Triangulation_3/include/CGAL/internal/spatial_sorting_traits_with_indices.h diff --git a/.gitattributes b/.gitattributes index 07e64ed84fb..52f4dff2c89 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3314,9 +3314,14 @@ Spatial_sorting/doc_tex/Spatial_sorting/fig/hilbertLarge.jpg -text Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_policy_tags.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex -text +Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex -text +Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex -text Spatial_sorting/examples/Spatial_sorting/hilbert.cpp -text Spatial_sorting/examples/Spatial_sorting/hilbert_policies.cpp -text Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp -text +Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp -text +Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp -text +Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp -text Spatial_sorting/include/CGAL/Hilbert_policy_tags.h -text Spatial_sorting/include/CGAL/Hilbert_sort_d.h -text Spatial_sorting/include/CGAL/Hilbert_sort_median_2.h -text @@ -3326,6 +3331,8 @@ Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h -text Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h -text Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h -text Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h -text +Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h -text +Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h -text Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_0.poly -text svneol=unset#application/octet-stream Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_1.poly -text svneol=unset#application/octet-stream Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_2.poly -text svneol=unset#application/octet-stream @@ -4112,7 +4119,7 @@ Triangulation_3/examples/Triangulation_3/info_insert_with_zip_iterator.cpp -text Triangulation_3/include/CGAL/internal/Static_filters/Compare_weighted_squared_radius_3.h -text Triangulation_3/include/CGAL/internal/Static_filters/Power_test_3.h -text Triangulation_3/include/CGAL/internal/Static_filters/Regular_triangulation_static_filters_traits_3.h -text -Triangulation_3/include/CGAL/internal/spatial_sorting_traits_with_indices.h -text +Triangulation_3/include/CGAL/internal/info_check.h -text Triangulation_3/test/Triangulation_3/include/CGAL/_test_remove_cluster.h -text Triangulation_3/test/Triangulation_3/test_regular_insert_range_with_info.cpp -text Triangulation_3/test/Triangulation_3/test_static_filters.cpp -text diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index daaa9b0b309..e002bcdc448 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -180,3 +180,38 @@ Next example describes how a traits class different than CGAL Kernel can be used to sort a container of handle on points instead of points directly. \ccIncludeExampleCode{Spatial_sorting/sort_indices.cpp} + + +\subsection{Sorting Arbitrary Types} +\label{sec:sort_any_type} +It is possible using a traits class adapter to sort a random-access +iterator range over objects of an arbitrary type, if this type is associated +to a point. The association to the point is done thanks to a +\ccAnchor{http://www.boost.org/doc/libs/release/libs/property_map/index.html}{property map}. +The following examples show several applications. + +\subsubsection{Sorting using pairs of point and integer} +\label{sec:sort_any_type_2} +In this example program, the sorted sequence of points is retrieved +using a vector of pairs of point and integer. +\ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_2.cpp} + +\subsubsection{Sorting using indices of points} +In this example program, the sorted sequence of points is retrieved +using the indices of the points in a vector of points. +\ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_3.cpp} + +\subsubsection{Sorting using indices of pairs of point and integer} +In this example program, the sorted sequence of points is retrieved +using the indices of the points in a vector of pairs of point and integer. +\ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_d.cpp} + +If you want to sort points of your own point type, +you only have to provide functors that compare +the \ccc{x} and \ccc{y} coordinates of your points. Note that in case you simply want +to associate an extra information to your point you might consider the example of this section +\ref{sec:sort_any_type_2} +as an alternative. + +\ccIncludeExampleCode{Spatial_sorting/myPoint.cpp} + diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex index df1d1f53ad0..2808c04f27c 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_2.tex @@ -80,7 +80,9 @@ object types must exist. \ccParDims \ccHasModels -Any \cgal{} kernel. +Any \cgal{} kernel.\\ +\ccc{CGAL::Spatial_sort_traits_adapter_2}. + \ccParDims \end{ccRefConcept} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex index 18f90121d0c..249a629e96e 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_3.tex @@ -102,7 +102,8 @@ object types must exist. \ccParDims \ccHasModels -Any \cgal{} kernel. +Any \cgal{} kernel.\\ +\ccc{CGAL::Spatial_sort_traits_adapter_3}. \ccParDims \end{ccRefConcept} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex new file mode 100644 index 00000000000..1ff3e212beb --- /dev/null +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex @@ -0,0 +1,36 @@ +\begin{ccRefClass}{Spatial_sort_traits_adapter_2} + +\ccDefinition + +Given a property map associating a key to a point, the class \ccRefName\ induces a spatial +reorder of the keys instead of the points, the comparisons being done on the associated points. +In other words, the traits provides to a spatial sort algorithm a point type which is a key, +while the actual point type is \ccc{Base_traits::Point_2}. + +\ccRequirements \ccc{Base_traits} is a model for \ccc{SpatialSortingTraits_2}. +\ccc{PointPropertyMap} is a model of \ccAnchor{http://www.boost.org/doc/libs/release/libs/property_map/doc/ReadablePropertyMap.html}{boost::ReadablePropertyMap} +with \ccc{Base_traits::Point_2} as \ccc{value_type}. + + +\ccInheritsFrom +\ccc{Base_traits} + +\ccIsModel +\ccc{SpatialSortingTraits_2} + +\ccTypes +\ccTypedef{boost::property_traits::key_type Point_2;}{} + +\ccTagFullDeclarations +\ccCreationVariable{o} +\ccCreation +\ccConstructor{Spatial_sort_traits_adapter_2(Base_traits base=Base_traits());}{} +\ccConstructor{Spatial_sort_traits_adapter_2(const PointPropertyMap& ppmap,Base_traits base=Base_traits());}{} + +\ccOperations +\ccThree{void;;}{A}{} + +\ccMethod{const PointPropertyMap& point_property_map() const;}{Returns a const reference to the point property map.} + + +\end{ccRefClass} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex new file mode 100644 index 00000000000..c90c6e167e4 --- /dev/null +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex @@ -0,0 +1,35 @@ +\begin{ccRefClass}{Spatial_sort_traits_adapter_3} + +\ccDefinition + +Given a property map associating a key to a point, the class \ccRefName\ induces a spatial +reorder of the keys instead of the points, the comparisons being done on the associated points. +In other words, the traits provides to a spatial sort algorithm a point type which is a key, +while the actual point type is \ccc{Base_traits::Point_3}. + +\ccRequirements \ccc{Base_traits} is a model for \ccc{SpatialSortingTraits_3}. +\ccc{PointPropertyMap} is a model of \ccAnchor{http://www.boost.org/doc/libs/release/libs/property_map/doc/ReadablePropertyMap.html}{boost::ReadablePropertyMap} +with \ccc{Base_traits::Point_3} as \ccc{value_type}. + +\ccInheritsFrom +\ccc{Base_traits} + +\ccIsModel +\ccc{SpatialSortingTraits_3} + +\ccTypes +\ccTypedef{boost::property_traits::key_type Point_3;}{} + +\ccTagFullDeclarations +\ccCreationVariable{o} +\ccCreation +\ccConstructor{Spatial_sort_traits_adapter_3(Base_traits base=Base_traits());}{} +\ccConstructor{Spatial_sort_traits_adapter_3(const PointPropertyMap& ppmap,Base_traits base=Base_traits());}{} + +\ccOperations +\ccThree{void;;}{A}{} + +\ccMethod{const PointPropertyMap& point_property_map() const;}{Returns a const reference to the point property map.} + + +\end{ccRefClass} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex index ad4c5be5b83..4ee265f1512 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex @@ -21,6 +21,10 @@ \ccRefIdfierPage{CGAL::Hilbert_sort_3} \\ \ccRefIdfierPage{CGAL::Hilbert_sort_d} \\ +\ccHeading{Traits classes} +\ccRefIdfierPage{CGAL::Spatial_sort_traits_adapter_2} \\ +\ccRefIdfierPage{CGAL::Spatial_sort_traits_adapter_3} \\ + \ccHeading{Concepts} \ccRefIdfierPage{SpatialSortingTraits_2} \\ diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex index 029a4dc5cf4..2412d151368 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex @@ -17,5 +17,7 @@ \input{Spatial_sorting_ref/Hilbert_sort_d.tex} \input{Spatial_sorting_ref/Multiscale_sort.tex} \input{Spatial_sorting_ref/Hilbert_policy_tags.tex} +\input{Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex} +\input{Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex} %% EOF diff --git a/Spatial_sorting/examples/Spatial_sorting/myPoint.cpp b/Spatial_sorting/examples/Spatial_sorting/myPoint.cpp new file mode 100644 index 00000000000..a8a0796843e --- /dev/null +++ b/Spatial_sorting/examples/Spatial_sorting/myPoint.cpp @@ -0,0 +1,72 @@ +#include + +struct MyPoint { + double x,y; + int color; + MyPoint() + : x(0), y(0),color(0) + {} + + MyPoint(double x, double y, int color=0) + : x(x), y(y), color(color) + {} +}; + + +struct MyLessX { + + bool operator()(const MyPoint& p, const MyPoint& q) const + { + return p.x < q.x; + } + +}; + +struct MyLessY { + + bool operator()(const MyPoint& p, const MyPoint& q) const + { + return p.y < q.y; + } + +}; + +struct MySpatialSortingTraits { + + typedef MyPoint Point_2; + + typedef MyLessX Less_x_2; + typedef MyLessY Less_y_2; + + Less_x_2 less_x_2_object() const + { + return Less_x_2(); + } + + Less_y_2 less_y_2_object() const + { + return Less_y_2(); + } +}; + +int main() +{ + std::vector< MyPoint > points; + + points.push_back(MyPoint(14,12, 3)); + points.push_back(MyPoint(1,2 , 0)); + points.push_back(MyPoint(414,2, 5)); + points.push_back(MyPoint(4,21 , 1)); + points.push_back(MyPoint(7,74 , 2)); + points.push_back(MyPoint(74,4 , 4)); + + MySpatialSortingTraits sst; + CGAL::spatial_sort(points.begin(), points.end(), sst); + + for (std::vector< MyPoint >::iterator it=points.begin();it!=points.end();++it) + std::cout << it->color << " "; + std::cout << "\n"; + + std::cerr << "done" << std::endl; + return 0; +} diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp new file mode 100644 index 00000000000..1076ddd3363 --- /dev/null +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_2 Point_2; +typedef std::pair Point_with_info; +typedef std::vector< Point_with_info > Data_vector; + +//property map +struct First_of_pair{ + //classical typedefs + typedef Point_with_info key_type; + typedef Point_2 value_type; + typedef const Point_2& reference; + typedef boost::readable_property_map_tag category; +}; +//get function for property map +First_of_pair::reference +get(const First_of_pair&, const First_of_pair::key_type& k) { + return k.first; +} + +typedef CGAL::Spatial_sort_traits_adapter_2 Search_traits_2; + +int main() +{ + Data_vector points; + points.push_back(std::make_pair(Point_2(14,12) , 3)); + points.push_back(std::make_pair(Point_2(1,2) , 0)); + points.push_back(std::make_pair(Point_2(414,2) , 5)); + points.push_back(std::make_pair(Point_2(4,21) , 1)); + points.push_back(std::make_pair(Point_2(7,74) , 2)); + points.push_back(std::make_pair(Point_2(74,4) , 4)); + + Search_traits_2 traits; + CGAL::spatial_sort(points.begin(), points.end(), traits); + for (Data_vector::iterator it=points.begin();it!=points.end();++it) + std::cout << it->second << " "; + std::cout << "\n"; + + std::cout << "done" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp new file mode 100644 index 00000000000..9c4c3032647 --- /dev/null +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +//using a pointer as a special property map type +typedef CGAL::Spatial_sort_traits_adapter_3 Search_traits_3; + +int main() +{ + std::vector points; + points.push_back(Point_3(1,3,11)); + points.push_back(Point_3(14,34,46)); + points.push_back(Point_3(414,34,4)); + points.push_back(Point_3(4,2,56)); + points.push_back(Point_3(744,4154,43)); + points.push_back(Point_3(74,44,1)); + + std::vector indices; + indices.reserve(points.size()); + + std::copy(boost::counting_iterator(0), + boost::counting_iterator(points.size()), + std::back_inserter(indices)); + + CGAL::spatial_sort( indices.begin(),indices.end(),Search_traits_3(&(points[0])) ); + + for (std::vector::iterator it=indices.begin();it!=indices.end();++it) + std::cout << points[*it] << "\n"; + + std::cout << "done" << std::endl; + + return 0; +} diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp new file mode 100644 index 00000000000..c2f8f8e239a --- /dev/null +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +typedef CGAL::Cartesian_d Kernel; +typedef Kernel::Point_d Point_d; +typedef std::pair Point_with_info; +typedef std::vector< Point_with_info > Data_vector; + +//property map and get as friend +// to be allowed to use private member +class Vect_ppmap{ + const Data_vector& points +public: + //classical typedefs + typedef Data_vector::size_t key_type; + typedef Point_d value_type; + typedef const Point_d& reference; + typedef boost::readable_property_map_tag category; + + Vect_ppmap(const Data_vector& points_):points(points_){} + + friend reference get(const Vect_ppmap& vmap,key_type i) const{ + return vmap.points[i]; + } +}; + +typedef CGAL::Spatial_sort_traits_adapter_d Search_traits_d; + +int main() +{ + double coords[] ={ 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0 }; + + Data_vector points; + points.push_back(std::make_pair(Point_d(4,coords ,coords+4) , 1)); + points.push_back(std::make_pair(Point_d(4,coords+4,coords+8) , 2)); + + std::vector indices; + indices.reserve(points.size()); + + std::copy(boost::counting_iterator(0), + boost::counting_iterator(points.size()), + std::back_inserter(indices)); + + CGAL::spatial_sort( indices.begin(),indices.end(),Search_traits_d(Vect_ppmap(points)) ); + + for (Data_vector::iterator it=points.begin();it!=points.end();++it) + std::cout << it->second << " "; + std::cout << "\n"; + + std::cout << "done" << std::endl; + + return 0; +} diff --git a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h new file mode 100644 index 00000000000..101b728a901 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h @@ -0,0 +1,71 @@ +// Copyright (c) 2011 GeometryFactory (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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Sebastien Loriot + + +#ifndef CGAL_SPATIAL_SORT_TRAITS_ADAPTER_2_H +#define CGAL_SPATIAL_SORT_TRAITS_ADAPTER_2_H + +#include +#include + +namespace CGAL{ + +using ::get; + +template +class Spatial_sort_traits_adapter_2:public Base_traits{ + PointPropertyMap ppmap_; +public: + Spatial_sort_traits_adapter_2(Base_traits base=Base_traits()):Base_traits(base){} + + Spatial_sort_traits_adapter_2(const PointPropertyMap& ppmap,Base_traits base=Base_traits()) + :Base_traits(base),ppmap_(ppmap){} + + typedef Base_traits Gt; + typedef typename boost::property_traits::key_type Point_2; + typedef typename boost::call_traits::param_type Arg_type; + + struct Less_x_2 : public Base_traits::Less_x_2{ + Less_x_2(const PointPropertyMap& ppmap,const typename Base_traits::Less_x_2& base): + Base_traits::Less_x_2(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + bool operator()(Arg_type p,Arg_type q) const { + return static_cast(this)->operator()(get(ppmap_,p),get(ppmap_,q)); + } + }; + + struct Less_y_2 : public Base_traits::Less_y_2{ + Less_y_2(const PointPropertyMap& ppmap,const typename Base_traits::Less_y_2& base): + Base_traits::Less_y_2(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + bool operator()(Arg_type p,Arg_type q) const { + return static_cast(this)->operator()(get(ppmap_,p),get(ppmap_,q)); + } + }; + + Less_x_2 less_x_2_object () const {return Less_x_2(ppmap_,static_cast(this)->less_x_2_object() );} + Less_y_2 less_y_2_object () const {return Less_y_2(ppmap_,static_cast(this)->less_y_2_object() );} + + const PointPropertyMap& point_property_map() const {return ppmap_;} + +}; + +} //namespace CGAL + +#endif //CGAL_SPATIAL_SORT_TRAITS_ADAPTER_2_H diff --git a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h new file mode 100644 index 00000000000..c49edadeb8a --- /dev/null +++ b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h @@ -0,0 +1,81 @@ +// Copyright (c) 2011 GeometryFactory (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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Sebastien Loriot + + +#ifndef CGAL_SPATIAL_SORT_TRAITS_ADAPTER_3_H +#define CGAL_SPATIAL_SORT_TRAITS_ADAPTER_3_H + +#include +#include + +namespace CGAL{ + +using ::get; + +template +class Spatial_sort_traits_adapter_3:public Base_traits{ + PointPropertyMap ppmap_; +public: + Spatial_sort_traits_adapter_3(Base_traits base=Base_traits()):Base_traits(base){} + + Spatial_sort_traits_adapter_3(const PointPropertyMap& ppmap,Base_traits base=Base_traits()) + :Base_traits(base),ppmap_(ppmap){} + + typedef Base_traits Gt; + typedef typename boost::property_traits::key_type Point_3; + typedef typename boost::call_traits::param_type Arg_type; + + struct Less_x_3 : public Base_traits::Less_x_3{ + Less_x_3(const PointPropertyMap& ppmap,const typename Base_traits::Less_x_3& base): + Base_traits::Less_x_3(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + bool operator()(Arg_type p,Arg_type q) const { + return static_cast(this)->operator()(get(ppmap_,p),get(ppmap_,q)); + } + }; + + struct Less_y_3 : public Base_traits::Less_y_3{ + Less_y_3(const PointPropertyMap& ppmap,const typename Base_traits::Less_y_3& base): + Base_traits::Less_y_3(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + bool operator()(Arg_type p,Arg_type q) const { + return static_cast(this)->operator()(get(ppmap_,p),get(ppmap_,q)); + } + }; + + struct Less_z_3 : public Base_traits::Less_z_3{ + Less_z_3(const PointPropertyMap& ppmap,const typename Base_traits::Less_z_3& base): + Base_traits::Less_z_3(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + bool operator()(Arg_type p,Arg_type q) const { + return static_cast(this)->operator()(get(ppmap_,p),get(ppmap_,q)); + } + }; + + Less_x_3 less_x_3_object () const {return Less_x_3(ppmap_,static_cast(this)->less_x_3_object() );} + Less_y_3 less_y_3_object () const {return Less_y_3(ppmap_,static_cast(this)->less_y_3_object() );} + Less_z_3 less_z_3_object () const {return Less_z_3(ppmap_,static_cast(this)->less_z_3_object() );} + + const PointPropertyMap& point_property_map() const {return ppmap_;} + +}; + +} //namespace CGAL + +#endif //CGAL_SPATIAL_SORT_TRAITS_ADAPTER_3_H diff --git a/Triangulation_2/include/CGAL/Delaunay_triangulation_2.h b/Triangulation_2/include/CGAL/Delaunay_triangulation_2.h index 20559f7a137..2b87d0c42fe 100644 --- a/Triangulation_2/include/CGAL/Delaunay_triangulation_2.h +++ b/Triangulation_2/include/CGAL/Delaunay_triangulation_2.h @@ -28,7 +28,8 @@ #include #ifndef CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO -#include +#include +#include #include #include @@ -307,6 +308,7 @@ public: #ifndef CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO private: + //top stands for tuple-or-pair template const Point& top_get_first(const std::pair& pair) const { return pair.first; } template @@ -320,10 +322,10 @@ private: std::ptrdiff_t insert_with_info(InputIterator first,InputIterator last) { size_type n = this->number_of_vertices(); - std::vector indices; + std::vector indices; std::vector points; std::vector infos; - std::size_t index=0; + std::ptrdiff_t index=0; for (InputIterator it=first;it!=last;++it){ Tuple_or_pair value=*it; points.push_back( top_get_first(value) ); @@ -331,14 +333,13 @@ private: indices.push_back(index++); } - typedef internal::Vector_property_map Point_pmap; - typedef internal::Spatial_sort_traits_with_property_map_2 Search_traits; + typedef Spatial_sort_traits_adapter_2 Search_traits; - spatial_sort(indices.begin(),indices.end(),Search_traits(Point_pmap(points),geom_traits())); + spatial_sort(indices.begin(),indices.end(),Search_traits(&(points[0]),geom_traits())); Vertex_handle v_hint; Face_handle hint; - for (typename std::vector::const_iterator + for (typename std::vector::const_iterator it = indices.begin(), end = indices.end(); it != end; ++it){ v_hint = insert(points[*it], hint); diff --git a/Triangulation_2/include/CGAL/Regular_triangulation_2.h b/Triangulation_2/include/CGAL/Regular_triangulation_2.h index 4280f6fcec3..a364dba8697 100644 --- a/Triangulation_2/include/CGAL/Regular_triangulation_2.h +++ b/Triangulation_2/include/CGAL/Regular_triangulation_2.h @@ -28,7 +28,8 @@ #include #ifndef CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO -#include +#include +#include #include #include @@ -383,6 +384,7 @@ public: #ifndef CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO private: + //top stands for tuple-or-pair template const Weighted_point& top_get_first(const std::pair& pair) const { return pair.first; } template @@ -396,10 +398,10 @@ private: std::ptrdiff_t insert_with_info(InputIterator first,InputIterator last) { int n = number_of_vertices(); - std::vector indices; + std::vector indices; std::vector points; std::vector infos; - std::size_t index=0; + std::ptrdiff_t index=0; for (InputIterator it=first;it!=last;++it){ Tuple_or_pair pair = *it; points.push_back( top_get_first(pair) ); @@ -407,14 +409,13 @@ private: indices.push_back(index++); } - typedef internal::Vector_property_map Point_pmap; - typedef internal::Spatial_sort_traits_with_property_map_2 Search_traits; + typedef Spatial_sort_traits_adapter_2 Search_traits; - spatial_sort(indices.begin(),indices.end(),Search_traits(Point_pmap(points),geom_traits())); + spatial_sort(indices.begin(),indices.end(),Search_traits(&(points[0]),geom_traits())); Face_handle hint; Vertex_handle v_hint; - for (typename std::vector::const_iterator + for (typename std::vector::const_iterator it = indices.begin(), end = indices.end(); it != end; ++it) { diff --git a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h index 0e52632eb40..62f59e96751 100644 --- a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h @@ -32,7 +32,8 @@ #include #ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO -#include +#include +#include #include #include @@ -243,6 +244,7 @@ public: #ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO private: + //top stands for tuple-or-pair template const Point& top_get_first(const std::pair& pair) const { return pair.first; } template @@ -256,10 +258,10 @@ private: std::ptrdiff_t insert_with_info(InputIterator first,InputIterator last) { size_type n = number_of_vertices(); - std::vector indices; + std::vector indices; std::vector points; std::vector infos; - std::size_t index=0; + std::ptrdiff_t index=0; for (InputIterator it=first;it!=last;++it){ Tuple_or_pair value=*it; points.push_back( top_get_first(value) ); @@ -267,13 +269,12 @@ private: indices.push_back(index++); } - typedef internal::Vector_property_map Point_pmap; - typedef internal::Spatial_sort_traits_with_property_map_3 Search_traits; + typedef Spatial_sort_traits_adapter_3 Search_traits; - spatial_sort(indices.begin(),indices.end(),Search_traits(Point_pmap(points),geom_traits())); + spatial_sort(indices.begin(),indices.end(),Search_traits(&(points[0]),geom_traits())); Vertex_handle hint; - for (typename std::vector::const_iterator + for (typename std::vector::const_iterator it = indices.begin(), end = indices.end(); it != end; ++it){ hint = insert(points[*it], hint); diff --git a/Triangulation_3/include/CGAL/Regular_triangulation_3.h b/Triangulation_3/include/CGAL/Regular_triangulation_3.h index 5583161da8c..203a905ea95 100644 --- a/Triangulation_3/include/CGAL/Regular_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Regular_triangulation_3.h @@ -31,7 +31,8 @@ #include #ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO -#include +#include +#include #include #include @@ -200,6 +201,7 @@ public: #ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO private: + //top stands for tuple-or-pair template const Weighted_point& top_get_first(const std::pair& pair) const { return pair.first; } template @@ -213,10 +215,10 @@ private: std::ptrdiff_t insert_with_info(InputIterator first,InputIterator last) { size_type n = number_of_vertices(); - std::vector indices; + std::vector indices; std::vector points; std::vector infos; - std::size_t index=0; + std::ptrdiff_t index=0; for (InputIterator it=first;it!=last;++it){ Tuple_or_pair pair = *it; points.push_back( top_get_first(pair) ); @@ -224,13 +226,12 @@ private: indices.push_back(index++); } - typedef internal::Vector_property_map Point_pmap; - typedef internal::Spatial_sort_traits_with_property_map_3 Search_traits; + typedef Spatial_sort_traits_adapter_3 Search_traits; - spatial_sort(indices.begin(),indices.end(),Search_traits(Point_pmap(points),geom_traits())); + spatial_sort( indices.begin(),indices.end(),Search_traits(&(points[0]),geom_traits()) ); Cell_handle hint; - for (typename std::vector::const_iterator + for (typename std::vector::const_iterator it = indices.begin(), end = indices.end(); it != end; ++it) { diff --git a/Triangulation_3/include/CGAL/internal/info_check.h b/Triangulation_3/include/CGAL/internal/info_check.h new file mode 100644 index 00000000000..31d86a738bf --- /dev/null +++ b/Triangulation_3/include/CGAL/internal/info_check.h @@ -0,0 +1,44 @@ +// Copyright (c) 2010 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you may redistribute it under +// the terms of the Q Public License version 1.0. +// See the file LICENSE.QPL distributed with CGAL. +// +// 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) : Sebastien Loriot +// + +#ifndef CGAL_INTERNAL_INFO_CHECK_H +#define CGAL_INTERNAL_INFO_CHECK_H + +#include + +namespace CGAL { + +namespace internal{ + +BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_typedef_Info,Info,false) + +template ::value> + struct Info_check{ + struct type{}; +}; + +template +struct Info_check{ + typedef typename T::Info type; +}; + +} } //namespace CGAL::internal + +#endif //CGAL_INTERNAL_INFO_CHECK_H diff --git a/Triangulation_3/include/CGAL/internal/spatial_sorting_traits_with_indices.h b/Triangulation_3/include/CGAL/internal/spatial_sorting_traits_with_indices.h deleted file mode 100644 index b2da4a9f508..00000000000 --- a/Triangulation_3/include/CGAL/internal/spatial_sorting_traits_with_indices.h +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2010 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org); you may redistribute it under -// the terms of the Q Public License version 1.0. -// See the file LICENSE.QPL distributed with CGAL. -// -// 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) : Sebastien Loriot -// - -#ifndef CGAL_INTERNAL_SPATIAL_SORTING_TRAITS_WITH_INDICES -#define CGAL_INTERNAL_SPATIAL_SORTING_TRAITS_WITH_INDICES - -#include -#include - -namespace CGAL { - -namespace internal{ - -BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_typedef_Info,Info,false) - -template ::value> - struct Info_check{ - struct type{}; -}; - -template -struct Info_check{ - typedef typename T::Info type; -}; - -template sizeof(int*))> -struct Arg_type_selection; - -template -struct Arg_type_selection{ - typedef T type; -}; - -template -struct Arg_type_selection{ - typedef const T& type; -}; - -template -class Vector_property_map{ - const std::vector& data; -public: - typedef std::size_t key_type; - Vector_property_map(const std::vector& input):data(input){} - - const T& operator[](key_type i) const{ - return data[i]; - } -}; - -template -class Spatial_sort_traits_with_property_map_3:public Base_traits{ - PointPropertyMap accessor_; -public: - Spatial_sort_traits_with_property_map_3(const PointPropertyMap& accessor,Base_traits base=Base_traits()) - :Base_traits(base),accessor_(accessor){} - - typedef Base_traits Gt; - typedef typename PointPropertyMap::key_type Point_3; - typedef typename Arg_type_selection::type Arg_type; - - struct Less_x_3 : public Base_traits::Less_x_3{ - Less_x_3(const PointPropertyMap& accessor,const typename Base_traits::Less_x_3& base): - Base_traits::Less_x_3(base),accessor_(accessor){} - const PointPropertyMap& accessor_; - bool operator()(Arg_type p,Arg_type q) const { - return static_cast(this)->operator()(accessor_[p],accessor_[q]); - } - }; - - struct Less_y_3 : public Base_traits::Less_y_3{ - Less_y_3(const PointPropertyMap& accessor,const typename Base_traits::Less_y_3& base): - Base_traits::Less_y_3(base),accessor_(accessor){} - const PointPropertyMap& accessor_; - bool operator()(Arg_type p,Arg_type q) const { - return static_cast(this)->operator()(accessor_[p],accessor_[q]); - } - }; - - struct Less_z_3 : public Base_traits::Less_z_3{ - Less_z_3(const PointPropertyMap& accessor,const typename Base_traits::Less_z_3& base): - Base_traits::Less_z_3(base),accessor_(accessor){} - const PointPropertyMap& accessor_; - bool operator()(Arg_type p,Arg_type q) const { - return static_cast(this)->operator()(accessor_[p],accessor_[q]); - } - }; - - Less_x_3 less_x_3_object () const {return Less_x_3(accessor_,static_cast(this)->less_x_3_object() );} - Less_y_3 less_y_3_object () const {return Less_y_3(accessor_,static_cast(this)->less_y_3_object() );} - Less_z_3 less_z_3_object () const {return Less_z_3(accessor_,static_cast(this)->less_z_3_object() );} -}; - -template -class Spatial_sort_traits_with_property_map_2:public Base_traits{ - PointPropertyMap accessor_; -public: - Spatial_sort_traits_with_property_map_2(const PointPropertyMap& accessor,Base_traits base=Base_traits()) - :Base_traits(base),accessor_(accessor){} - - typedef Base_traits Gt; - typedef typename PointPropertyMap::key_type Point_2; - typedef typename Arg_type_selection::type Arg_type; - - struct Less_x_2 : public Base_traits::Less_x_2{ - Less_x_2(const PointPropertyMap& accessor,const typename Base_traits::Less_x_2& base): - Base_traits::Less_x_2(base),accessor_(accessor){} - const PointPropertyMap& accessor_; - bool operator()(Arg_type p,Arg_type q) const { - return static_cast(this)->operator()(accessor_[p],accessor_[q]); - } - }; - - struct Less_y_2 : public Base_traits::Less_y_2{ - Less_y_2(const PointPropertyMap& accessor,const typename Base_traits::Less_y_2& base): - Base_traits::Less_y_2(base),accessor_(accessor){} - const PointPropertyMap& accessor_; - bool operator()(Arg_type p,Arg_type q) const { - return static_cast(this)->operator()(accessor_[p],accessor_[q]); - } - }; - - Less_x_2 less_x_2_object () const {return Less_x_2(accessor_,static_cast(this)->less_x_2_object() );} - Less_y_2 less_y_2_object () const {return Less_y_2(accessor_,static_cast(this)->less_y_2_object() );} - -}; -} } //namespace CGAL::internal - -#endif //CGAL_INTERNAL_SPATIAL_SORTING_TRAITS_WITH_INDICES From 397d3c079a848c833d1cf11f6d070db0869d481c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 24 May 2011 16:36:48 +0000 Subject: [PATCH 20/65] *add Spatial_sort_traits_adapter_d and its documentation *update reference manual(comments sort_indice which is outdated) and reintroduced myPoint.cpp example *remove unused variable warning *remove const bool warning --- .gitattributes | 2 + .../Spatial_sorting/spatial_sorting.tex | 23 +++--- .../SpatialSortingTraits_d.tex | 3 +- .../Spatial_sort_traits_adapter_d.tex | 36 +++++++++ .../doc_tex/Spatial_sorting_ref/intro.tex | 1 + .../doc_tex/Spatial_sorting_ref/main.tex | 1 + .../sp_sort_using_property_map_d.cpp | 22 +++--- .../CGAL/Spatial_sort_traits_adapter_d.h | 76 +++++++++++++++++++ Spatial_sorting/include/CGAL/hilbert_sort.h | 2 +- Spatial_sorting/include/CGAL/spatial_sort.h | 6 +- 10 files changed, 145 insertions(+), 27 deletions(-) create mode 100644 Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_d.tex create mode 100644 Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h diff --git a/.gitattributes b/.gitattributes index 52f4dff2c89..ae00e7df0f4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3316,6 +3316,7 @@ Spatial_sorting/doc_tex/Spatial_sorting_ref/Hilbert_sort_d.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex -text Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex -text +Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_d.tex -text Spatial_sorting/examples/Spatial_sorting/hilbert.cpp -text Spatial_sorting/examples/Spatial_sorting/hilbert_policies.cpp -text Spatial_sorting/examples/Spatial_sorting/small_example_delaunay_2.cpp -text @@ -3333,6 +3334,7 @@ Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h -text Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h -text Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h -text Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h -text +Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h -text Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_0.poly -text svneol=unset#application/octet-stream Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_1.poly -text svneol=unset#application/octet-stream Straight_skeleton_2/demo/Straight_skeleton_2/data/complex_2.poly -text svneol=unset#application/octet-stream diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index e002bcdc448..9470465bb6d 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -161,7 +161,7 @@ such an order provides enough randomness to combine the advantages of a random \cgal\ provides spatial sorting for points in 2D, 3D and higher dimensions, with the middle and the median policies for Hilbert sort in the buckets. -\subsection{Examples} +\subsection{Basic Example} The following example shows that, on particular input, spatial sort runs much faster than a bad order or than Hilbert sort (below results @@ -176,11 +176,19 @@ $ ./small_example_delaunay_2 \ccIncludeExampleCode{Spatial_sorting/small_example_delaunay_2.cpp} -Next example describes how a traits class different than CGAL Kernel can be -used to sort a container of handle on points instead of points directly. +%Next example describes how a traits class different than CGAL Kernel can be +%used to sort a container of handle on points instead of points directly. +%\ccIncludeExampleCode{Spatial_sorting/sort_indices.cpp} -\ccIncludeExampleCode{Spatial_sorting/sort_indices.cpp} +\subsection{Using your own Point Type} +If you want to sort points of your own point type, +you only have to provide functors that compare +the \ccc{x} and \ccc{y} coordinates of your points. Note that in case you simply want +to associate an extra information to your point you might consider the example of this section +\ref{sec:sort_any_type_2} +as an alternative. +\ccIncludeExampleCode{Spatial_sorting/myPoint.cpp} \subsection{Sorting Arbitrary Types} \label{sec:sort_any_type} @@ -206,12 +214,5 @@ In this example program, the sorted sequence of points is retrieved using the indices of the points in a vector of pairs of point and integer. \ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_d.cpp} -If you want to sort points of your own point type, -you only have to provide functors that compare -the \ccc{x} and \ccc{y} coordinates of your points. Note that in case you simply want -to associate an extra information to your point you might consider the example of this section -\ref{sec:sort_any_type_2} -as an alternative. -\ccIncludeExampleCode{Spatial_sorting/myPoint.cpp} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex index 06659646395..94b3863882e 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex @@ -60,7 +60,8 @@ object types must exist. \ccParDims \ccHasModels -Any \cgal{} $d$ dimensional kernel. +Any \cgal{} $d$ dimensional kernel.\\ +\ccc{CGAL::Spatial_sort_traits_adapter_d}. \ccParDims \end{ccRefConcept} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_d.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_d.tex new file mode 100644 index 00000000000..f69cff26075 --- /dev/null +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/Spatial_sort_traits_adapter_d.tex @@ -0,0 +1,36 @@ +\begin{ccRefClass}{Spatial_sort_traits_adapter_d} + +\ccDefinition + +Given a property map associating a key to a point, the class \ccRefName\ induces a spatial +reorder of the keys instead of the points, the comparisons being done on the associated points. +In other words, the traits provides to a spatial sort algorithm a point type which is a key, +while the actual point type is \ccc{Base_traits::Point_d}. + +\ccRequirements \ccc{Base_traits} is a model for \ccc{SpatialSortingTraits_d}. +\ccc{PointPropertyMap} is a model of \ccAnchor{http://www.boost.org/doc/libs/release/libs/property_map/doc/ReadablePropertyMap.html}{boost::ReadablePropertyMap} +with \ccc{Base_traits::Point_d} as \ccc{value_type}. + + +\ccInheritsFrom +\ccc{Base_traits} + +\ccIsModel +\ccc{SpatialSortingTraits_d} + +\ccTypes +\ccTypedef{boost::property_traits::key_type Point_d;}{} + +\ccTagFullDeclarations +\ccCreationVariable{o} +\ccCreation +\ccConstructor{Spatial_sort_traits_adapter_d(Base_traits base=Base_traits());}{} +\ccConstructor{Spatial_sort_traits_adapter_d(const PointPropertyMap& ppmap,Base_traits base=Base_traits());}{} + +\ccOperations +\ccThree{void;;}{A}{} + +\ccMethod{const PointPropertyMap& point_property_map() const;}{Returns a const reference to the point property map.} + + +\end{ccRefClass} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex index 4ee265f1512..f06bd424fa3 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/intro.tex @@ -24,6 +24,7 @@ \ccHeading{Traits classes} \ccRefIdfierPage{CGAL::Spatial_sort_traits_adapter_2} \\ \ccRefIdfierPage{CGAL::Spatial_sort_traits_adapter_3} \\ +\ccRefIdfierPage{CGAL::Spatial_sort_traits_adapter_d} \\ \ccHeading{Concepts} diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex index 2412d151368..dc005400549 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/main.tex @@ -19,5 +19,6 @@ \input{Spatial_sorting_ref/Hilbert_policy_tags.tex} \input{Spatial_sorting_ref/Spatial_sort_traits_adapter_2.tex} \input{Spatial_sorting_ref/Spatial_sort_traits_adapter_3.tex} +\input{Spatial_sorting_ref/Spatial_sort_traits_adapter_d.tex} %% EOF diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp index c2f8f8e239a..c13b829b713 100644 --- a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp @@ -12,18 +12,18 @@ typedef std::vector< Point_with_info > Data_vector; //property map and get as friend // to be allowed to use private member class Vect_ppmap{ - const Data_vector& points + const Data_vector& points; public: //classical typedefs - typedef Data_vector::size_t key_type; + typedef Data_vector::size_type key_type; typedef Point_d value_type; - typedef const Point_d& reference; + typedef const value_type& reference; typedef boost::readable_property_map_tag category; Vect_ppmap(const Data_vector& points_):points(points_){} - friend reference get(const Vect_ppmap& vmap,key_type i) const{ - return vmap.points[i]; + friend reference get(const Vect_ppmap& vmap, key_type i) { + return vmap.points[i].first; } }; @@ -38,17 +38,17 @@ int main() points.push_back(std::make_pair(Point_d(4,coords ,coords+4) , 1)); points.push_back(std::make_pair(Point_d(4,coords+4,coords+8) , 2)); - std::vector indices; + std::vector indices; indices.reserve(points.size()); - std::copy(boost::counting_iterator(0), - boost::counting_iterator(points.size()), + std::copy(boost::counting_iterator(0), + boost::counting_iterator(points.size()), std::back_inserter(indices)); CGAL::spatial_sort( indices.begin(),indices.end(),Search_traits_d(Vect_ppmap(points)) ); - - for (Data_vector::iterator it=points.begin();it!=points.end();++it) - std::cout << it->second << " "; + std::vector::iterator it=indices.begin(); + for (;it!=indices.end();++it) + std::cout << points[*it].second << " "; std::cout << "\n"; std::cout << "done" << std::endl; diff --git a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h new file mode 100644 index 00000000000..5115f58f3d5 --- /dev/null +++ b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h @@ -0,0 +1,76 @@ +// Copyright (c) 2011 GeometryFactory (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 Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// 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) : Sebastien Loriot + + +#ifndef CGAL_SPATIAL_SORT_TRAITS_ADAPTER_D_H +#define CGAL_SPATIAL_SORT_TRAITS_ADAPTER_D_H + +#include +#include + +namespace CGAL{ + +using ::get; + +template +class Spatial_sort_traits_adapter_d:public Base_traits{ + PointPropertyMap ppmap_; +public: + Spatial_sort_traits_adapter_d(Base_traits base=Base_traits()):Base_traits(base){} + + Spatial_sort_traits_adapter_d(const PointPropertyMap& ppmap,Base_traits base=Base_traits()) + :Base_traits(base),ppmap_(ppmap){} + + typedef Base_traits Gt; + typedef typename boost::property_traits::key_type Point_d; + typedef typename boost::call_traits::param_type Arg_type; + + + + struct Less_coordinate_d: public Base_traits::Less_coordinate_d{ + Less_coordinate_d(const PointPropertyMap& ppmap,const typename Base_traits::Less_coordinate_d& base): + Base_traits::Less_coordinate_d(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + bool operator()(Arg_type p,Arg_type q,int i) const { + return static_cast(this)->operator()(get(ppmap_,p),get(ppmap_,q),i); + } + }; + + + struct Compute_coordinate_d: public Base_traits::Compute_coordinate_d{ + Compute_coordinate_d(const PointPropertyMap& ppmap,const typename Base_traits::Compute_coordinate_d& base): + Base_traits::Compute_coordinate_d(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + bool operator()(Arg_type p,int i) const { + return static_cast(this)->operator()(get(ppmap_,p),i); + } + }; + + + + Less_coordinate_d less_coordinate_d_object () const {return Less_coordinate_d(ppmap_,static_cast(this)->less_coordinate_d_object() );} + Compute_coordinate_d compute_coordinate_d_object () const {return Compute_coordinate_d(ppmap_,static_cast(this)->compute_coordinate_d_object() );} + + const PointPropertyMap& point_property_map() const {return ppmap_;} + +}; + +} //namespace CGAL + +#endif //CGAL_SPATIAL_SORT_TRAITS_ADAPTER_D_H diff --git a/Spatial_sorting/include/CGAL/hilbert_sort.h b/Spatial_sorting/include/CGAL/hilbert_sort.h index 2529325ca03..b79431b28d2 100644 --- a/Spatial_sorting/include/CGAL/hilbert_sort.h +++ b/Spatial_sorting/include/CGAL/hilbert_sort.h @@ -41,7 +41,7 @@ namespace internal { template void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, - Policy policy, + Policy /*policy*/, const Kernel &k, typename Kernel::Point_2 *) { boost::rand48 random; diff --git a/Spatial_sorting/include/CGAL/spatial_sort.h b/Spatial_sorting/include/CGAL/spatial_sort.h index 1d561149fba..ec93d9e1eb8 100644 --- a/Spatial_sorting/include/CGAL/spatial_sort.h +++ b/Spatial_sorting/include/CGAL/spatial_sort.h @@ -40,7 +40,7 @@ namespace internal { void spatial_sort ( RandomAccessIterator begin, RandomAccessIterator end, const Kernel &k, - Policy policy, + Policy /*policy*/, typename Kernel::Point_2 *, std::ptrdiff_t threshold_hilbert, std::ptrdiff_t threshold_multiscale, @@ -63,7 +63,7 @@ namespace internal { void spatial_sort ( RandomAccessIterator begin, RandomAccessIterator end, const Kernel &k, - Policy policy, + Policy /*policy*/, typename Kernel::Point_3 *, std::ptrdiff_t threshold_hilbert, std::ptrdiff_t threshold_multiscale, @@ -86,7 +86,7 @@ namespace internal { void spatial_sort ( RandomAccessIterator begin, RandomAccessIterator end, const Kernel &k, - Policy policy, + Policy /*policy*/, typename Kernel::Point_d *, std::ptrdiff_t threshold_hilbert, std::ptrdiff_t threshold_multiscale, From 4934cff531dce56bf88b3ca8fc08264f9b0317b4 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Wed, 25 May 2011 08:39:09 +0000 Subject: [PATCH 21/65] add Point_dimension_d functor in kerneld and spatial_sorting_d traits class --- Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex | 2 ++ Kernel_d/doc_tex/Kernel_d_ref/main.tex | 1 + Kernel_d/include/CGAL/Cartesian_d.h | 3 +++ Kernel_d/include/CGAL/Homogeneous_d.h | 3 +++ .../include/CGAL/Kernel_d/function_objectsCd.h | 13 +++++++++++++ .../include/CGAL/Kernel_d/function_objectsHd.h | 14 ++++++++++++++ .../Spatial_sorting_ref/SpatialSortingTraits_d.tex | 7 +++++++ .../include/CGAL/Hilbert_sort_median_d.h | 2 +- .../include/CGAL/Hilbert_sort_middle_d.h | 7 +++---- .../test/Spatial_sorting/test_hilbert.cpp | 2 +- 10 files changed, 48 insertions(+), 6 deletions(-) diff --git a/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex b/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex index 76d051ce30a..00116ee1002 100644 --- a/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex +++ b/Kernel_d/doc_tex/Kernel_d_ref/Kernel.tex @@ -126,6 +126,8 @@ replacing operators, especially for equality testing. \ccGlue \ccNestedType{Orthogonal_vector_d}{} \ccGlue +\ccNestedType{Point_dimension_d}{} +\ccGlue \ccNestedType{Point_of_sphere_d}{} \ccGlue \ccNestedType{Point_to_vector_d}{} diff --git a/Kernel_d/doc_tex/Kernel_d_ref/main.tex b/Kernel_d/doc_tex/Kernel_d_ref/main.tex index 7e481266a81..9ad0cc9a3d7 100644 --- a/Kernel_d/doc_tex/Kernel_d_ref/main.tex +++ b/Kernel_d/doc_tex/Kernel_d_ref/main.tex @@ -97,6 +97,7 @@ \input{Kernel_d_ref/Kernel_Orientation_d.tex} \input{Kernel_d_ref/Kernel_Oriented_side_d.tex} \input{Kernel_d_ref/Kernel_Orthogonal_vector_d.tex} +\input{Kernel_d_ref/Kernel_Point_dimension_d.tex} \input{Kernel_d_ref/Kernel_Point_of_sphere_d.tex} \input{Kernel_d_ref/Kernel_Point_to_vector_d.tex} \input{Kernel_d_ref/Kernel_Project_along_d_axis_d.tex} diff --git a/Kernel_d/include/CGAL/Cartesian_d.h b/Kernel_d/include/CGAL/Cartesian_d.h index e0dda612003..52097613d40 100644 --- a/Kernel_d/include/CGAL/Cartesian_d.h +++ b/Kernel_d/include/CGAL/Cartesian_d.h @@ -252,6 +252,7 @@ public: typedef Lt_from_compare Less_lexicographically_d; typedef Le_from_compare Less_or_equal_lexicographically_d; typedef Less_coordinateCd Less_coordinate_d; + typedef Point_dimensionCd Point_dimension_d; typedef Eq_from_method Equal_d; typedef Center_of_sphereCd Center_of_sphere_d; typedef Contained_in_linear_hullCd Contained_in_linear_hull_d; @@ -261,6 +262,8 @@ public: Compute_coordinate_d compute_coordinate_d_object() const { return Compute_coordinate_d(); } + Point_dimension_d point_dimension_d_object() const + { return Point_dimension_d(); } Less_coordinate_d less_coordinate_d_object() const { return Less_coordinate_d(); } Lift_to_paraboloid_d lift_to_paraboloid_d_object() const diff --git a/Kernel_d/include/CGAL/Homogeneous_d.h b/Kernel_d/include/CGAL/Homogeneous_d.h index e9fd5fddefe..d968a94c4f5 100644 --- a/Kernel_d/include/CGAL/Homogeneous_d.h +++ b/Kernel_d/include/CGAL/Homogeneous_d.h @@ -254,6 +254,7 @@ public: typedef Lt_from_compare Less_lexicographically_d; typedef Le_from_compare Less_or_equal_lexicographically_d; typedef Less_coordinateHd Less_coordinate_d; + typedef Point_dimensionHd Point_dimension_d; typedef Eq_from_method Equal_d; typedef Center_of_sphereHd Center_of_sphere_d; typedef Contained_in_linear_hullHd Contained_in_linear_hull_d; @@ -263,6 +264,8 @@ public: Compute_coordinate_d compute_coordinate_d_object() const { return Compute_coordinate_d(); } + Point_dimension_d point_dimension_d_object() const + { return Point_dimension_d(); } Less_coordinate_d less_coordinate_d_object() const { return Less_coordinate_d(); } Lift_to_paraboloid_d lift_to_paraboloid_d_object() const diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h b/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h index 4884db18529..9eb7f1224b7 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h @@ -49,6 +49,19 @@ class Compute_coordinateCd { } }; +template +class Point_dimensionCd { + typedef typename K::FT FT; + typedef typename K::Point_d Point_d; + public: + typedef int result_type; + const result_type + operator()(const Point_d& p) const + { + return p.dimension(); + } +}; + template class Less_coordinateCd { typedef typename K::FT FT; diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h b/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h index c34995abb12..0d692f48997 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h @@ -48,6 +48,19 @@ class Compute_coordinateHd { } }; +template +class Point_dimensionHd { + typedef typename K::RT RT; + typedef typename K::Point_d Point_d; + public: + typedef int result_type; + const result_type + operator()(const Point_d& p) const + { + return p.dimension(); + } +}; + template class Less_coordinateHd { typedef typename K::RT RT; @@ -62,6 +75,7 @@ class Less_coordinateHd { } }; + template struct Lift_to_paraboloidHd { typedef typename R::Point_d Point_d; diff --git a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex index 06659646395..7b8039ba26f 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting_ref/SpatialSortingTraits_d.tex @@ -22,6 +22,12 @@ functions and functors. } +\ccNestedType{Point_dimension_d}% + {Functor object type returning the dimension of a \ccc{Point_d}. + Must provide + \ccc{int operator()(Point_d p)} returning the dimension of $p$. + } + \ccNestedType{Compute_coordinate_d}% {Functor object type returning the coordinates of a \ccc{Point_d}. Must provide @@ -54,6 +60,7 @@ The following member functions to create instances of the above predicate object types must exist. \setlength\parskip{0mm} +\ccMemberFunction{Point_dimension_d point_dimension_d_object(); }{} \ccMemberFunction{Compute_coordinate_d compute_coordinate_d_object(); }{} \ccMemberFunction{Less_coordinate_d less_coordinate_d_object(); }{} diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index e879ddba8c5..80a2bcb3c3d 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -139,7 +139,7 @@ public: template void operator() (RandomAccessIterator begin, RandomAccessIterator end) const { - _dimension = begin->dimension(); + _dimension = _k.point_dimension_d_object()(*begin); two_to_dim = 1; Starting_position start(_dimension); diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h index 1a6cb9f3e78..76c7dc3a0f2 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h @@ -146,17 +146,16 @@ public: template void operator() (RandomAccessIterator begin, RandomAccessIterator end) const { - K k; - _dimension = begin->dimension(); + _dimension = _k.point_dimension_d_object()(*begin); two_to_dim = 1; Starting_position start(_dimension); Corner min(_dimension),max(_dimension); for (int i=0; i<_dimension; ++i) - min[i]=max[i]=to_double( k.compute_coordinate_d_object() (*begin,i) ); + min[i]=max[i]=to_double( _k.compute_coordinate_d_object() (*begin,i) ); for(RandomAccessIterator it=begin+1; it max[i]) max[i] = d; } diff --git a/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp b/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp index a174c694faf..23ab7cbfb5d 100644 --- a/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp +++ b/Spatial_sorting/test/Spatial_sorting/test_hilbert.cpp @@ -297,7 +297,7 @@ int main () std::cout << " Sorting points... " << std::flush; cost.reset();cost.start(); - CGAL::hilbert_sort (v.begin(), v.end()); + CGAL::hilbert_sort (v.begin(), v.end(),CGAL::Hilbert_sort_median_policy()); cost.stop(); std::cout << "done in "< Date: Wed, 25 May 2011 08:43:59 +0000 Subject: [PATCH 22/65] add Point_dimension_d functor in kerneld and spatial_sorting_d traits class --- .gitattributes | 1 + .../doc_tex/Kernel_d_ref/Kernel_Point_dimension_d.tex | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 Kernel_d/doc_tex/Kernel_d_ref/Kernel_Point_dimension_d.tex diff --git a/.gitattributes b/.gitattributes index 07e64ed84fb..365a622e607 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1717,6 +1717,7 @@ Kernel_23/test/Kernel_23/CMakeLists.txt -text Kernel_d/doc_tex/Kernel_d/hypercube.png -text Kernel_d/doc_tex/Kernel_d_ref/Kernel_Compute_coordinate_d.tex -text Kernel_d/doc_tex/Kernel_d_ref/Kernel_Less_coordinate_d.tex -text +Kernel_d/doc_tex/Kernel_d_ref/Kernel_Point_dimension_d.tex -text Kernel_d/include/CGAL/Kernel_d/Cartesian_const_iterator_d.h -text Kernel_d/test/Kernel_d/Linear_algebra-test.cmd eol=lf Kinetic_data_structures/demo/Kinetic_data_structures/data/after002 -text diff --git a/Kernel_d/doc_tex/Kernel_d_ref/Kernel_Point_dimension_d.tex b/Kernel_d/doc_tex/Kernel_d_ref/Kernel_Point_dimension_d.tex new file mode 100644 index 00000000000..29b8b175a19 --- /dev/null +++ b/Kernel_d/doc_tex/Kernel_d_ref/Kernel_Point_dimension_d.tex @@ -0,0 +1,9 @@ +\begin{ccRefFunctionObjectConcept}{Kernel::Point_dimension_d} +A model for this must provide: + +\ccCreationVariable{fo} + +\ccMemberFunction{ int operator()(const Kernel::Point_d& + p);} {returns the dimension of $p$} + +\end{ccRefFunctionObjectConcept} From ca1d3536d9af5c99a98f31a165f145acf6793ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 25 May 2011 09:23:01 +0000 Subject: [PATCH 23/65] *use Point_dimension_d in adapter_d *remove const in Kernel_d result_type functors --- .../include/CGAL/Kernel_d/function_objectsCd.h | 4 ++-- .../include/CGAL/Kernel_d/function_objectsHd.h | 6 +++--- .../sp_sort_using_property_map_2.cpp | 2 +- .../sp_sort_using_property_map_3.cpp | 7 ++++--- .../sp_sort_using_property_map_d.cpp | 15 ++++++++++----- .../include/CGAL/Spatial_sort_traits_adapter_d.h | 10 ++++++++++ 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h b/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h index 1f742684f0d..ae5887d33f1 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objectsCd.h @@ -42,7 +42,7 @@ class Compute_coordinateCd { typedef typename K::Point_d Point_d; public: typedef FT result_type; - const result_type + result_type operator()(const Point_d& p, int i) const { return p.cartesian(i); @@ -55,7 +55,7 @@ class Point_dimensionCd { typedef typename K::Point_d Point_d; public: typedef int result_type; - const result_type + result_type operator()(const Point_d& p) const { return p.dimension(); diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h b/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h index 0d692f48997..2e719d9b6b8 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objectsHd.h @@ -41,7 +41,7 @@ class Compute_coordinateHd { typedef typename K::Point_d Point_d; public: typedef FT result_type; - const result_type + result_type operator()(const Point_d& p, int i) const { return p.cartesian(i); @@ -54,7 +54,7 @@ class Point_dimensionHd { typedef typename K::Point_d Point_d; public: typedef int result_type; - const result_type + result_type operator()(const Point_d& p) const { return p.dimension(); @@ -67,7 +67,7 @@ class Less_coordinateHd { typedef typename K::Point_d Point_d; public: typedef bool result_type; - const result_type + result_type operator()(const Point_d& p, const Point_d& q, int i) const { int d = p.dimension(); diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp index 1076ddd3363..091da4ae35c 100644 --- a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp @@ -22,7 +22,7 @@ get(const First_of_pair&, const First_of_pair::key_type& k) { return k.first; } -typedef CGAL::Spatial_sort_traits_adapter_2 Search_traits_2; +typedef CGAL::Spatial_sort_traits_adapter_2 Search_traits_2; int main() { diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp index 9c4c3032647..ab48feafc9f 100644 --- a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_3.cpp @@ -4,10 +4,11 @@ #include #include -typedef CGAL::Simple_cartesian Kernel; -typedef Kernel::Point_3 Point_3; +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; //using a pointer as a special property map type -typedef CGAL::Spatial_sort_traits_adapter_3 Search_traits_3; +typedef + CGAL::Spatial_sort_traits_adapter_3 Search_traits_3; int main() { diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp index c13b829b713..64aa5fdf48f 100644 --- a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_d.cpp @@ -41,15 +41,20 @@ int main() std::vector indices; indices.reserve(points.size()); - std::copy(boost::counting_iterator(0), - boost::counting_iterator(points.size()), - std::back_inserter(indices)); + std::copy( + boost::counting_iterator(0), + boost::counting_iterator(points.size()), + std::back_inserter(indices) ); - CGAL::spatial_sort( indices.begin(),indices.end(),Search_traits_d(Vect_ppmap(points)) ); + CGAL::spatial_sort( + indices.begin(), + indices.end(), + Search_traits_d(Vect_ppmap(points)) ); + std::vector::iterator it=indices.begin(); for (;it!=indices.end();++it) std::cout << points[*it].second << " "; - std::cout << "\n"; + std::cout << std::endl; std::cout << "done" << std::endl; diff --git a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h index 5115f58f3d5..b569046bb42 100644 --- a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h +++ b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h @@ -43,6 +43,15 @@ public: + struct Point_dimension_d: public Base_traits::Point_dimension_d{ + Point_dimension_d(const PointPropertyMap& ppmap,const typename Base_traits::Point_dimension_d& base): + Base_traits::Point_dimension_d(base),ppmap_(ppmap){} + const PointPropertyMap& ppmap_; + int operator()(Arg_type p) const { + return static_cast(this)->operator()(get(ppmap_,p)); + } + }; + struct Less_coordinate_d: public Base_traits::Less_coordinate_d{ Less_coordinate_d(const PointPropertyMap& ppmap,const typename Base_traits::Less_coordinate_d& base): Base_traits::Less_coordinate_d(base),ppmap_(ppmap){} @@ -64,6 +73,7 @@ public: + Point_dimension_d point_dimension_d_object () const {return Point_dimension_d(ppmap_,static_cast(this)->point_dimension_d_object() );} Less_coordinate_d less_coordinate_d_object () const {return Less_coordinate_d(ppmap_,static_cast(this)->less_coordinate_d_object() );} Compute_coordinate_d compute_coordinate_d_object () const {return Compute_coordinate_d(ppmap_,static_cast(this)->compute_coordinate_d_object() );} From 1177c88b9c897c88eafba4eda9b21842a1336045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 25 May 2011 09:26:38 +0000 Subject: [PATCH 24/65] remove warnings --- Spatial_sorting/include/CGAL/hilbert_sort.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Spatial_sorting/include/CGAL/hilbert_sort.h b/Spatial_sorting/include/CGAL/hilbert_sort.h index b79431b28d2..3d58550d99f 100644 --- a/Spatial_sorting/include/CGAL/hilbert_sort.h +++ b/Spatial_sorting/include/CGAL/hilbert_sort.h @@ -53,7 +53,7 @@ namespace internal { template void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, - Policy policy, + Policy /*policy*/, const Kernel &k, typename Kernel::Point_3 *) { boost::rand48 random; @@ -65,7 +65,7 @@ namespace internal { template void hilbert_sort (RandomAccessIterator begin, RandomAccessIterator end, - Policy policy, + Policy /*policy*/, const Kernel &k, typename Kernel::Point_d *) { boost::rand48 random; From b35ab8afb65379a2a901b747359e43f9b682d084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 May 2011 06:41:06 +0000 Subject: [PATCH 25/65] conditionnal include path for property_map.hpp --- .../include/CGAL/Spatial_sort_traits_adapter_2.h | 8 +++++++- .../include/CGAL/Spatial_sort_traits_adapter_3.h | 8 +++++++- .../include/CGAL/Spatial_sort_traits_adapter_d.h | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h index 101b728a901..1bc0d0d642a 100644 --- a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h +++ b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_2.h @@ -22,7 +22,13 @@ #define CGAL_SPATIAL_SORT_TRAITS_ADAPTER_2_H #include -#include +#include +#if BOOST_VERSION >= 104000 + #include +#else + #include +#endif + namespace CGAL{ diff --git a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h index c49edadeb8a..2a3f07d0af5 100644 --- a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h +++ b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_3.h @@ -22,7 +22,13 @@ #define CGAL_SPATIAL_SORT_TRAITS_ADAPTER_3_H #include -#include +#include +#if BOOST_VERSION >= 104000 + #include +#else + #include +#endif + namespace CGAL{ diff --git a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h index b569046bb42..3c0c11934d0 100644 --- a/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h +++ b/Spatial_sorting/include/CGAL/Spatial_sort_traits_adapter_d.h @@ -22,7 +22,13 @@ #define CGAL_SPATIAL_SORT_TRAITS_ADAPTER_D_H #include -#include +#include +#if BOOST_VERSION >= 104000 + #include +#else + #include +#endif + namespace CGAL{ From bd09762c70c53a1715c74efaf00c8e2730f49fe4 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 26 May 2011 08:18:48 +0000 Subject: [PATCH 26/65] capitalize --- Manual/doc_tex/Manual/geom.bib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Manual/doc_tex/Manual/geom.bib b/Manual/doc_tex/Manual/geom.bib index f2f52a5f4ea..aa71e56cfe3 100644 --- a/Manual/doc_tex/Manual/geom.bib +++ b/Manual/doc_tex/Manual/geom.bib @@ -1755,7 +1755,7 @@ cell neighborhood in $O(m)$ time." @inproceedings{acr-icb-03 , author = "Nina Amenta and Sunghee Choi and G{\"u}nter Rote" -, title = "Incremental constructions con BRIO" +, title = "Incremental constructions con {BRIO}" , booktitle = "Proc. 19th Annu. Sympos. Comput. Geom." , year = 2003 , pages = "211-219" From 5c4013d8080ba93e8950196f01805015912db4e2 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Thu, 26 May 2011 12:03:56 +0000 Subject: [PATCH 27/65] edit on coyright years --- Spatial_sorting/include/CGAL/Hilbert_policy_tags.h | 6 +++--- Spatial_sorting/include/CGAL/Hilbert_sort_2.h | 6 +++--- Spatial_sorting/include/CGAL/Hilbert_sort_3.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_d.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h | 2 +- Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h | 2 +- Spatial_sorting/include/CGAL/hilbert_sort.h | 2 +- Spatial_sorting/include/CGAL/spatial_sort.h | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h b/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h index b8aeb45c765..c0f17180eb9 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h +++ b/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or @@ -12,8 +12,8 @@ // 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: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.6-branch/Spatial_sorting/include/CGAL/hilbert_sort.h $ -// $Id: hilbert_sort.h 53867 2010-01-28 12:18:19Z lrineau $ +// $URL: +// $Id: // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h index 58dc3c4bade..85f242a3ac3 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2007 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or @@ -12,8 +12,8 @@ // 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$ +// $URL: +// $Id: // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_3.h b/Spatial_sorting/include/CGAL/Hilbert_sort_3.h index 876c5adbeb0..76f100f1931 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_3.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_3.h @@ -1,4 +1,4 @@ -// Copyright (c) 2007 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_d.h index 2ecc9184859..aacfcdf8cf1 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_d.h @@ -1,4 +1,4 @@ -// Copyright (c) 2007 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index 80a2bcb3c3d..85bb92b44e0 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h index c0b0f34c6c4..853e64bc114 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h index d09fc96f665..d2e590e7421 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h index 0f19a50b825..3144082a371 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h index 76c7dc3a0f2..e08e853e51c 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// Copyright (c) 2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/hilbert_sort.h b/Spatial_sorting/include/CGAL/hilbert_sort.h index 2529325ca03..9eb6673ab00 100644 --- a/Spatial_sorting/include/CGAL/hilbert_sort.h +++ b/Spatial_sorting/include/CGAL/hilbert_sort.h @@ -1,4 +1,4 @@ -// Copyright (c) 2007 INRIA Sophia-Antipolis (France). +// Copyright (c) 2007-2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or diff --git a/Spatial_sorting/include/CGAL/spatial_sort.h b/Spatial_sorting/include/CGAL/spatial_sort.h index 1d561149fba..3ca3c3f85db 100644 --- a/Spatial_sorting/include/CGAL/spatial_sort.h +++ b/Spatial_sorting/include/CGAL/spatial_sort.h @@ -1,4 +1,4 @@ -// Copyright (c) 2007 INRIA Sophia-Antipolis (France). +// Copyright (c) 2007-2011 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or From 36a988ac26f23e8cfa20305d46598907e2a35e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 May 2011 12:31:19 +0000 Subject: [PATCH 28/65] correct svn tags --- Spatial_sorting/include/CGAL/Hilbert_policy_tags.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_2.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h | 4 ++-- Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h | 4 ++-- Spatial_sorting/include/CGAL/spatial_sort.h | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h b/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h index c0f17180eb9..3297a507966 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h +++ b/Spatial_sorting/include/CGAL/Hilbert_policy_tags.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h index 85f242a3ac3..021b105c7fd 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_2.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_2.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index 85bb92b44e0..1a9dbca4492 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h index 853e64bc114..303b224432d 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_2.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h index d2e590e7421..5b5d6d2fd63 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_3.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h index 3144082a371..fcda1b94b37 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_base.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h index e08e853e51c..cf1ae7f9085 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_middle_d.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Olivier Devillers diff --git a/Spatial_sorting/include/CGAL/spatial_sort.h b/Spatial_sorting/include/CGAL/spatial_sort.h index 3ca3c3f85db..3f4e3007927 100644 --- a/Spatial_sorting/include/CGAL/spatial_sort.h +++ b/Spatial_sorting/include/CGAL/spatial_sort.h @@ -12,8 +12,8 @@ // 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: +// $URL$ +// $Id$ // // Author(s) : Christophe Delage // : Olivier Devillers From fc3ab31981c143e11a103d9f64f7942f3884e6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 May 2011 16:34:59 +0000 Subject: [PATCH 29/65] fix typo and move figures after the corresponding text --- .../Spatial_sorting/spatial_sorting.tex | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index daaa9b0b309..88c4cb9b303 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -24,31 +24,10 @@ good effects of locality \cite{acr-icb-03}. The predicates used by this package are comparisons between coordinates, -thus there is no robustness issues involved here, for example to choose the +thus there is no robustness issue involved here, for example to choose the arithmetic of the kernel. - -\begin{ccTexOnly} -\newpage -\end{ccTexOnly} - - -\begin{figure} -\begin{ccHtmlOnly} -
- -
-\end{ccHtmlOnly} -\begin{ccTexOnly} -\begin{center} -\includegraphics[width=11.5cm]{Spatial_sorting/fig/Hilbert8} -\end{center} -\end{ccTexOnly} -\caption{Hilbert mapping -\label{Spatial_sorting_fig_Hilbert8}} -\end{figure} - \section{Hilbert Sorting\label{sec:hilbert_sorting}} @@ -70,8 +49,23 @@ $f(\frac{3}{4})=(1,\frac{1}{2})$. Then each square is subdivided in the same way recursively. Figure~\ref{Spatial_sorting_fig_Hilbert8} illustrates this process. +\begin{figure} +\begin{ccHtmlOnly} +
+ +
+\end{ccHtmlOnly} +\begin{ccTexOnly} +\begin{center} +\includegraphics[width=11.5cm]{Spatial_sorting/fig/Hilbert8} +\end{center} +\end{ccTexOnly} +\caption{Hilbert mapping +\label{Spatial_sorting_fig_Hilbert8}} +\end{figure} + Now given a set of 2D points, they can be sorted in the order they have on such -a space filling curve as illustrated on Figure~\ref{Spatial_sorting_fig_Hilbert_middle} : +a space filling curve as illustrated in Figure~\ref{Spatial_sorting_fig_Hilbert_middle} : \begin{figure}[h] \begin{ccHtmlOnly} @@ -99,6 +93,14 @@ The code to use Hilbert sort is as simple as the following example: \ccIncludeExampleCode{Spatial_sorting/hilbert.cpp} +If instead of subdividing the square in a fixed way at its middle point, + as above, we subdivide it +by splitting at the median point (in $x$ or $y$ directions alternating), +we construct a 2-d tree adapted to the point set. This tree can be visited in a +similar manner and we get also a suitable ordering of the points +(see Figure~\ref{Spatial_sorting_fig_Hilbert_median}). + + \begin{figure}[t] \begin{ccHtmlOnly}
@@ -114,17 +116,6 @@ The code to use Hilbert sort is as simple as the following example: \label{Spatial_sorting_fig_Hilbert_median}} \end{figure} -If instead of subdividing the square in a fixed way at its middle point, - as above, we subdivide it -by splitting at the median point (in $x$ or $y$ directions alternating), -we construct a 2-d tree adapted to the point set. This tree can be visited in a -similar manner and we get also a suitable ordering of the points -(see Figure~\ref{Spatial_sorting_fig_Hilbert_median}). - - - - - \cgal\ provides Hilbert sorting for points in 2D, 3D and higher dimensions, in the middle and the median policies. From e125678a088eca6edd206ab61e8e0f5dbba268d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 May 2011 16:36:44 +0000 Subject: [PATCH 30/65] merge from Spatial_sorting-increase_dimension-odevil --- .../Spatial_sorting/spatial_sorting.tex | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index 9470465bb6d..4a72e1caa3d 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -24,31 +24,10 @@ good effects of locality \cite{acr-icb-03}. The predicates used by this package are comparisons between coordinates, -thus there is no robustness issues involved here, for example to choose the +thus there is no robustness issue involved here, for example to choose the arithmetic of the kernel. - -\begin{ccTexOnly} -\newpage -\end{ccTexOnly} - - -\begin{figure} -\begin{ccHtmlOnly} -
- -
-\end{ccHtmlOnly} -\begin{ccTexOnly} -\begin{center} -\includegraphics[width=11.5cm]{Spatial_sorting/fig/Hilbert8} -\end{center} -\end{ccTexOnly} -\caption{Hilbert mapping -\label{Spatial_sorting_fig_Hilbert8}} -\end{figure} - \section{Hilbert Sorting\label{sec:hilbert_sorting}} @@ -70,8 +49,23 @@ $f(\frac{3}{4})=(1,\frac{1}{2})$. Then each square is subdivided in the same way recursively. Figure~\ref{Spatial_sorting_fig_Hilbert8} illustrates this process. +\begin{figure} +\begin{ccHtmlOnly} +
+ +
+\end{ccHtmlOnly} +\begin{ccTexOnly} +\begin{center} +\includegraphics[width=11.5cm]{Spatial_sorting/fig/Hilbert8} +\end{center} +\end{ccTexOnly} +\caption{Hilbert mapping +\label{Spatial_sorting_fig_Hilbert8}} +\end{figure} + Now given a set of 2D points, they can be sorted in the order they have on such -a space filling curve as illustrated on Figure~\ref{Spatial_sorting_fig_Hilbert_middle} : +a space filling curve as illustrated in Figure~\ref{Spatial_sorting_fig_Hilbert_middle} : \begin{figure}[h] \begin{ccHtmlOnly} @@ -99,6 +93,14 @@ The code to use Hilbert sort is as simple as the following example: \ccIncludeExampleCode{Spatial_sorting/hilbert.cpp} +If instead of subdividing the square in a fixed way at its middle point, + as above, we subdivide it +by splitting at the median point (in $x$ or $y$ directions alternating), +we construct a 2-d tree adapted to the point set. This tree can be visited in a +similar manner and we get also a suitable ordering of the points +(see Figure~\ref{Spatial_sorting_fig_Hilbert_median}). + + \begin{figure}[t] \begin{ccHtmlOnly}
@@ -114,17 +116,6 @@ The code to use Hilbert sort is as simple as the following example: \label{Spatial_sorting_fig_Hilbert_median}} \end{figure} -If instead of subdividing the square in a fixed way at its middle point, - as above, we subdivide it -by splitting at the median point (in $x$ or $y$ directions alternating), -we construct a 2-d tree adapted to the point set. This tree can be visited in a -similar manner and we get also a suitable ordering of the points -(see Figure~\ref{Spatial_sorting_fig_Hilbert_median}). - - - - - \cgal\ provides Hilbert sorting for points in 2D, 3D and higher dimensions, in the middle and the median policies. From 6a2f4a4238a2233df5020b06853c7f7e1d76a2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 May 2011 16:37:48 +0000 Subject: [PATCH 31/65] typos --- .../doc_tex/Spatial_sorting/spatial_sorting.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index 4a72e1caa3d..3d7468137c9 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -175,7 +175,7 @@ $ ./small_example_delaunay_2 If you want to sort points of your own point type, you only have to provide functors that compare the \ccc{x} and \ccc{y} coordinates of your points. Note that in case you simply want -to associate an extra information to your point you might consider the example of this section +to associate an extra information to your point you might consider the example of Section \ref{sec:sort_any_type_2} as an alternative. @@ -189,10 +189,10 @@ to a point. The association to the point is done thanks to a \ccAnchor{http://www.boost.org/doc/libs/release/libs/property_map/index.html}{property map}. The following examples show several applications. -\subsubsection{Sorting using pairs of point and integer} +\subsubsection{Sorting using pairs of points and integers} \label{sec:sort_any_type_2} In this example program, the sorted sequence of points is retrieved -using a vector of pairs of point and integer. +using a vector of pairs of points and integers. \ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_2.cpp} \subsubsection{Sorting using indices of points} @@ -200,9 +200,9 @@ In this example program, the sorted sequence of points is retrieved using the indices of the points in a vector of points. \ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_3.cpp} -\subsubsection{Sorting using indices of pairs of point and integer} +\subsubsection{Sorting using indices of pairs of points and integers} In this example program, the sorted sequence of points is retrieved -using the indices of the points in a vector of pairs of point and integer. +using the indices of the points in a vector of pairs of points and integers. \ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_d.cpp} From 3c498005f540dd9416a21c25ed48058cda038b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 May 2011 17:14:41 +0000 Subject: [PATCH 32/65] improve text --- .../doc_tex/Spatial_sorting/spatial_sorting.tex | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index 3d7468137c9..bc994359df9 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -183,11 +183,20 @@ as an alternative. \subsection{Sorting Arbitrary Types} \label{sec:sort_any_type} -It is possible using a traits class adapter to sort a random-access -iterator range over objects of an arbitrary type, if this type is associated -to a point. The association to the point is done thanks to a +The spatial sorting traits class provides a point type and +functors for comparing, for example, the \ccc{x}-coordinates +of two points. +% +If you want to sort something else than just points, for example +a sequence of tuples containing a point, or a sequence of indices +in a vector of points, you need another level of indirection. +% +We provide the spatial sorting traits class adapters which are templated by +another spatial sorting traits class, and a \ccAnchor{http://www.boost.org/doc/libs/release/libs/property_map/index.html}{property map}. -The following examples show several applications. +which allows to obtain a point from whatever you want to sort. + +The following examples illustrate the usage of these traits class adapters. \subsubsection{Sorting using pairs of points and integers} \label{sec:sort_any_type_2} From 582ef667c628dca8f8e56d0bb0f11448588586c9 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Tue, 31 May 2011 13:10:39 +0000 Subject: [PATCH 33/65] remove warmning --- .../examples/Spatial_sorting/sp_sort_using_property_map_2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp index 091da4ae35c..cffcfd2f980 100644 --- a/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp +++ b/Spatial_sorting/examples/Spatial_sorting/sp_sort_using_property_map_2.cpp @@ -43,4 +43,4 @@ int main() std::cout << "done" << std::endl; return 0; -} \ No newline at end of file +} From 2005afd37b5488f5bb6088c4a8cbf3008de53d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 1 Jun 2011 13:07:26 +0000 Subject: [PATCH 34/65] remove warning --- Nef_S2/test/Nef_S2/include/CGAL/test_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h b/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h index ed43a0684b0..90ca085a900 100644 --- a/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h +++ b/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h @@ -10,7 +10,7 @@ #define CGAL_TEST(b) if (!(b)) { ++cgal_test_res; \ std::cerr<<"ERROR: ("<<__LINE__ <<") test "<<#b<<" failed."< Date: Wed, 1 Jun 2011 13:13:20 +0000 Subject: [PATCH 35/65] undo r63820 --- Nef_S2/test/Nef_S2/include/CGAL/test_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h b/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h index 90ca085a900..ed43a0684b0 100644 --- a/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h +++ b/Nef_S2/test/Nef_S2/include/CGAL/test_macros.h @@ -10,7 +10,7 @@ #define CGAL_TEST(b) if (!(b)) { ++cgal_test_res; \ std::cerr<<"ERROR: ("<<__LINE__ <<") test "<<#b<<" failed."< Date: Wed, 1 Jun 2011 13:47:17 +0000 Subject: [PATCH 36/65] BUGFIX: revert parts of modifications done in r58343, r58233, r58232 The constness problem fixed by the aforementioned modifications was induced by a non-used function that I commented. --- Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h b/Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h index 69f54b2ebe1..494cd701075 100644 --- a/Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h +++ b/Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h @@ -92,9 +92,8 @@ public: typedef typename Decorator_traits::SVertex_handle SVertex_handle; typedef typename Decorator_traits::SHalfedge_handle SHalfedge_handle; typedef typename Decorator_traits::SHalfloop_handle SHalfloop_handle; - typedef typename Decorator_traits::SHalfloop_const_handle SHalfloop_const_handle; typedef typename Decorator_traits::SFace_handle SFace_handle; - typedef typename Decorator_traits::SFace_const_handle SFace_const_handle; + typedef typename Decorator_traits::SVertex_iterator SVertex_iterator; typedef typename Decorator_traits::SHalfedge_iterator SHalfedge_iterator; @@ -182,7 +181,7 @@ public: enum SOLUTION { is_vertex_, is_edge_, is_loop_ }; // enumeration for internal use - Object_handle locate(const Sphere_point& p, bool skipVEL = false) const + Object_handle locate(const Sphere_point& p, bool skipVEL = false) /*{\Mop returns a generic handle |h| to an object (vertex, halfedge, face) of the underlying plane map |P| which contains the point |p = s.source()| in its relative interior. |s.target()| must be a point @@ -209,7 +208,7 @@ public: if ( this->has_shalfloop() && this->shalfloop()->circle().has_on(p)) { CGAL_NEF_TRACEN( " on loop"); - return make_object(SHalfloop_const_handle(this->shalfloop())); + return make_object(SHalfloop_handle(this->shalfloop())); } } @@ -224,7 +223,7 @@ public: SVertex_handle v_res; SHalfedge_handle e_res; - SHalfloop_const_handle l_res(this->shalfloop()); + SHalfloop_handle l_res(this->shalfloop()); SOLUTION solution; CGAL_NEF_TRACEN(" on face..."); @@ -312,7 +311,7 @@ public: case is_edge_: return make_object(SFace_handle(e_res->incident_sface())); case is_loop_: - return make_object(SFace_const_handle(l_res->incident_sface())); + return make_object(SFace_handle(l_res->incident_sface())); case is_vertex_: return make_object(SFace_handle(v_res->incident_sface())); default: CGAL_error_msg("missing solution."); @@ -320,6 +319,7 @@ public: return Object_handle(); // never reached! } +#if 0 //THIS CODE DOES NOT SEEM TO BE USED template Object_handle ray_shoot(const Sphere_point& p, const Sphere_direction& d, @@ -336,7 +336,7 @@ public: { Sphere_circle c(d.circle()); Sphere_segment s; - Object_handle h = this->locate(p); + Object_handle h = locate(p); SVertex_handle v; SHalfedge_handle e; SHalfloop_handle l; @@ -404,7 +404,8 @@ public: CGAL_error_msg("not yet correct"); return h; } - +#endif + Object_handle ray_shoot(const Sphere_point& p, const Sphere_circle& c, Sphere_point& ip, From f15c8870be2a6396dfaca256baec76b8c4577ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 3 Jun 2011 06:49:51 +0000 Subject: [PATCH 37/65] remove warning on windows x64 --- Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h index 1a9dbca4492..ea597cc5049 100644 --- a/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h +++ b/Spatial_sorting/include/CGAL/Hilbert_sort_median_d.h @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace CGAL { @@ -143,7 +144,8 @@ public: two_to_dim = 1; Starting_position start(_dimension); - int N=end-begin;N*=2; + typename std::iterator_traits::difference_type N=end-begin; + N*=2; for (int i=0; i<_dimension; ++i) start[i]=false; // we start below in all coordinates for (int i=0; i<_dimension; ++i) { two_to_dim *= 2; // compute 2^_dimension From 985612cf886e20ca9525445fb309f675d5a12051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 3 Jun 2011 10:17:34 +0000 Subject: [PATCH 38/65] BUGFIX: Info must be default constructible and assignable (as the model are) --- .../Triangulation_2_ref/TriangulationVertexBaseWithInfo_2.tex | 3 +-- .../Triangulation_3_ref/TriangulationVertexBaseWithInfo_3.tex | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Triangulation_2/doc_tex/Triangulation_2_ref/TriangulationVertexBaseWithInfo_2.tex b/Triangulation_2/doc_tex/Triangulation_2_ref/TriangulationVertexBaseWithInfo_2.tex index de8810a3a2a..0899f90898a 100644 --- a/Triangulation_2/doc_tex/Triangulation_2_ref/TriangulationVertexBaseWithInfo_2.tex +++ b/Triangulation_2/doc_tex/Triangulation_2_ref/TriangulationVertexBaseWithInfo_2.tex @@ -22,8 +22,7 @@ and provides an additional information storage. \ccRefines{\ccc{TriangulationVertexBase_2}} \ccTypes -\ccNestedType{Info} -{.} +\ccNestedType{Info}{A type which is \ccc{DefaultConstructible} and \ccc{Assignable}.} \ccCreationVariable{v} %% choose variable name diff --git a/Triangulation_3/doc_tex/Triangulation_3_ref/TriangulationVertexBaseWithInfo_3.tex b/Triangulation_3/doc_tex/Triangulation_3_ref/TriangulationVertexBaseWithInfo_3.tex index 54d8ad10635..88b429d5247 100644 --- a/Triangulation_3/doc_tex/Triangulation_3_ref/TriangulationVertexBaseWithInfo_3.tex +++ b/Triangulation_3/doc_tex/Triangulation_3_ref/TriangulationVertexBaseWithInfo_3.tex @@ -22,8 +22,8 @@ and provides an additional information storage. \ccRefines{\ccc{TriangulationVertexBase_3}} \ccTypes -\ccNestedType{Info} -{.} +\ccNestedType{Info}{A type which is \ccc{DefaultConstructible} and \ccc{Assignable}.} + \ccCreationVariable{v} %% choose variable name From e5d8b79a9f07e99bda1080068b5300019de95a78 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 13:06:15 +0000 Subject: [PATCH 39/65] Begin to update Polyhedron demo from work done in the Mesh_3 dev'branch Step 1: - Polyhedron_type.h no longer defines Kernel and geometric types. Kernel_type.h defines the EPIC kernel. - Each plugin typedefs the geometric types it needs. - Polyhedron defined in Polyhedron_type.h uses special "demo items": - edges can be marked as "feature edge", - facets have a "patch id" (an integer), - and vertices have a set of patch ids. --- Polyhedron/demo/Polyhedron/Kernel_type.h | 13 ++ .../Polyhedron_demo_kernel_plugin.cpp | 7 + .../Polyhedron/Polyhedron_demo_pca_plugin.cpp | 10 ++ ...hedron_demo_remeshing_plugin_cgal_code.cpp | 2 + ...lyhedron_demo_self_intersection_plugin.cpp | 3 + Polyhedron/demo/Polyhedron/Polyhedron_type.h | 129 ++++++++++++++++-- .../demo/Polyhedron/Polyhedron_type_fwd.h | 28 +++- Polyhedron/demo/Polyhedron/Scene_plane_item.h | 4 +- .../demo/Polyhedron/include/CGAL/Dualizer.h | 1 + .../include/CGAL/Polyhedron_kernel.h | 3 + 10 files changed, 179 insertions(+), 21 deletions(-) create mode 100644 Polyhedron/demo/Polyhedron/Kernel_type.h diff --git a/Polyhedron/demo/Polyhedron/Kernel_type.h b/Polyhedron/demo/Polyhedron/Kernel_type.h new file mode 100644 index 00000000000..6da8cc541a5 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Kernel_type.h @@ -0,0 +1,13 @@ +#ifndef KERNEL_TYPE_H +#define KERNEL_TYPE_H + +#include +#include + +namespace kernel_type_h { + typedef CGAL::Exact_predicates_inexact_constructions_kernel K1; +} + +typedef CGAL::Mesh_3::Robust_intersection_traits_3 Kernel; + +#endif // KERNEL_TYPE_H diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_kernel_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_kernel_plugin.cpp index 3e3d15629f7..d4403303f8b 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_kernel_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_kernel_plugin.cpp @@ -17,6 +17,13 @@ #include #include +#include "Kernel_type.h" +typedef Kernel::Triangle_3 Triangle; +typedef Kernel::Point_3 Point; +typedef Kernel::Vector_3 Vector; +typedef Kernel::Plane_3 Plane; +typedef Kernel::FT FT; + class Polyhedron_demo_kernel_plugin : public QObject, public Polyhedron_demo_plugin_helper diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_pca_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_pca_plugin.cpp index ae758e747d6..3560a5ea981 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_pca_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_pca_plugin.cpp @@ -14,6 +14,16 @@ #include // output for plane fitting #include // output for line fitting +#include "Kernel_type.h" +typedef Kernel::Plane_3 Plane; +typedef Kernel::Iso_cuboid_3 Iso_cuboid; +typedef Kernel::Triangle_3 Triangle; +typedef Kernel::Line_3 Line; +typedef Kernel::Vector_3 Vector; +typedef Kernel::Point_3 Point; +typedef Kernel::FT FT; + + class Polyhedron_demo_pca_plugin : public QObject, public Polyhedron_demo_plugin_helper diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_remeshing_plugin_cgal_code.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_remeshing_plugin_cgal_code.cpp index 3985513e9ea..a5aaa911898 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_remeshing_plugin_cgal_code.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_remeshing_plugin_cgal_code.cpp @@ -296,6 +296,8 @@ Scene_item* cgal_code_remesh(QWidget* parent, { // new scope for the initialization, so that the vector // polyhedron_points is destroyed as soon as the initialization is // finished + typedef Kernel::Point_3 Point; + std::vector polyhedron_points; polyhedron_points.reserve(pMesh->size_of_vertices()); std::copy(pMesh->points_begin(), pMesh->points_end(), diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_self_intersection_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_self_intersection_plugin.cpp index cd35942c854..5df1f10acd2 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_self_intersection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_self_intersection_plugin.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "Kernel_type.h" #include "Polyhedron_type.h" #include "Scene_polyhedron_item.h" @@ -14,6 +15,8 @@ #include #include +typedef Kernel::Triangle_3 Triangle; + class Polyhedron_demo_self_intersection_plugin : public QObject, public Polyhedron_demo_plugin_helper diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_type.h b/Polyhedron/demo/Polyhedron/Polyhedron_type.h index a1785386f9a..feaf36eda34 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_type.h +++ b/Polyhedron/demo/Polyhedron/Polyhedron_type.h @@ -3,27 +3,126 @@ // CGAL // kernel -#include - -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +#include "Kernel_type.h" // surface mesh #include +#include + +#include + +template +class Polyhedron_demo_vertex : + public CGAL::HalfedgeDS_vertex_base +{ +public: + typedef std::set Set_of_indices; + +private: + typedef CGAL::HalfedgeDS_vertex_base Pdv_base; + + Set_of_indices indices; +public: + int nb_of_feature_edges; + + bool is_corner() const { + return nb_of_feature_edges > 2; + } + + bool is_feature_vertex() const { + return nb_of_feature_edges != 0; + } + + void add_incident_patch(const Patch_id i) { + indices.insert(i); + } + + const Set_of_indices& + incident_patches_ids_set() const { + return indices; + } + + Polyhedron_demo_vertex() : Pdv_base(), nb_of_feature_edges(0) {} + Polyhedron_demo_vertex(const Point& p) : Pdv_base(p), nb_of_feature_edges(0) {} +}; + +template +class Polyhedron_demo_halfedge : + public CGAL::HalfedgeDS_halfedge_base +{ +private: + bool feature_edge; +public: + + Polyhedron_demo_halfedge() + : feature_edge(false) {}; + + bool is_feature_edge() const { + return feature_edge; + } + + void set_feature_edge(const bool b) { + feature_edge = b; + this->opposite()->feature_edge = b; + } +}; + +template +class Polyhedron_demo_face : + public CGAL::HalfedgeDS_face_base +{ +private: + Patch_id_ patch_id_; +public: + typedef Patch_id_ Patch_id; + + Polyhedron_demo_face() + : patch_id_(1) {} + + int patch_id() const { + return patch_id_; + } + + void set_patch_id(const int i) { + patch_id_ = i; + } +}; + +template +class Polyhedron_demo_items : public CGAL::Polyhedron_items_3 { +public: + // wrap vertex + template struct Vertex_wrapper + { + typedef typename Traits::Point_3 Point; + typedef Polyhedron_demo_vertex Vertex; + }; + + // wrap face + template struct Face_wrapper + { + typedef Polyhedron_demo_face Face; + }; + + // wrap halfedge + template struct Halfedge_wrapper + { + typedef Polyhedron_demo_halfedge Halfedge; + }; +}; #include "Polyhedron_type_fwd.h" -// simple geometric types -typedef Kernel::FT FT; -typedef Kernel::Line_3 Line; -typedef Kernel::Point_3 Point; -typedef Kernel::Plane_3 Plane; -typedef Kernel::Sphere_3 Sphere; -typedef Kernel::Vector_3 Vector; -typedef Kernel::Triangle_3 Triangle; -typedef Kernel::Iso_cuboid_3 Iso_cuboid; -typedef Kernel::Plane_3 Plane_3; - // surface mesh -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Polyhedron_3 > Polyhedron; #endif // POLYHEDRON_TYPE_H diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_type_fwd.h b/Polyhedron/demo/Polyhedron/Polyhedron_type_fwd.h index b950b1ed784..294e96bdf5b 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_type_fwd.h +++ b/Polyhedron/demo/Polyhedron/Polyhedron_type_fwd.h @@ -8,8 +8,16 @@ #include +template +class Polyhedron_demo_items; + namespace CGAL { + namespace Mesh_3 { + template + struct Robust_intersection_traits_3; + } + template < typename FT_ > struct Simple_cartesian; @@ -32,15 +40,27 @@ namespace CGAL { > class Polyhedron_3; +// changed since CGAL-3.8-Ic-8 +#if CGAL_VERSION_NR > 1030800008 + class Epick; +#endif } // end namespace CGAL // kernel - -typedef CGAL::Epick Kernel; +namespace polyhedron_type_fwd_h { +// changed since CGAL-3.8-Ic-8 +#if CGAL_VERSION_NR > 1030800008 + typedef CGAL::Epick K1; +#else + typedef CGAL::Filtered_kernel< CGAL::Simple_cartesian, true > K1; +#endif + typedef CGAL::Mesh_3::Robust_intersection_traits_3 Kernel; +} // surface mesh -typedef CGAL::Polyhedron_3, + // CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator > Polyhedron; diff --git a/Polyhedron/demo/Polyhedron/Scene_plane_item.h b/Polyhedron/demo/Polyhedron/Scene_plane_item.h index 3f94f9db5ac..7d80c1c7ad3 100644 --- a/Polyhedron/demo/Polyhedron/Scene_plane_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_plane_item.h @@ -12,8 +12,8 @@ #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef Kernel::Plane_3 Plane_3; +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel_epic; +typedef Kernel_epic::Plane_3 Plane_3; class SCENE_BASIC_OBJECTS_EXPORT Scene_plane_item : public Scene_item diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/Dualizer.h b/Polyhedron/demo/Polyhedron/include/CGAL/Dualizer.h index 5f9f1f96c8e..5b1eb889b01 100644 --- a/Polyhedron/demo/Polyhedron/include/CGAL/Dualizer.h +++ b/Polyhedron/demo/Polyhedron/include/CGAL/Dualizer.h @@ -19,6 +19,7 @@ private: typedef typename Kernel::Point_3 Point; typedef typename Kernel::Plane_3 Plane; typedef typename Kernel::Vector_3 Vector; + typedef typename Kernel::FT FT; typedef typename HDS::Vertex Vertex; typedef typename HDS::Face_handle Face_handle; diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/Polyhedron_kernel.h b/Polyhedron/demo/Polyhedron/include/CGAL/Polyhedron_kernel.h index 7fe966c7906..c0f023fcb3c 100644 --- a/Polyhedron/demo/Polyhedron/include/CGAL/Polyhedron_kernel.h +++ b/Polyhedron/demo/Polyhedron/include/CGAL/Polyhedron_kernel.h @@ -37,6 +37,7 @@ private: typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point; typedef typename Kernel::Plane_3 Plane; + typedef typename Kernel::Vector_3 Vector; typedef typename Kernel::Triangle_3 Triangle; // program and solution types @@ -162,6 +163,8 @@ void get_triangles(Polyhedron& polyhedron, { typedef typename Polyhedron::Facet_iterator Facet_iterator; typedef typename Polyhedron::Halfedge_handle Halfedge_handle; + typedef typename Polyhedron::Point_3 Point; + typedef typename Polyhedron::Traits::Triangle_3 Triangle; for(Facet_iterator f = polyhedron.facets_begin(); f != polyhedron.facets_end(); From d6f8ae61d1ae18e82df42b426a5d3343e6c22af1 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 13:46:14 +0000 Subject: [PATCH 40/65] Begin to update Polyhedron demo from work done in the Mesh_3 dev'branch Step 2: - Update the Scene_item class (a class from the framework): - add the popup menu (not used at the moment), - add the selection (not used). - Update the Scene_polyhedron_item class. - menu, - picking. --- Polyhedron/demo/Polyhedron/Color_map.h | 26 ++ Polyhedron/demo/Polyhedron/Scene_item.cpp | 104 +++++-- Polyhedron/demo/Polyhedron/Scene_item.h | 54 +++- .../demo/Polyhedron/Scene_polyhedron_item.cpp | 278 +++++++++++++++++- .../demo/Polyhedron/Scene_polyhedron_item.h | 38 ++- .../demo/Polyhedron/include/CGAL/gl_render.h | 20 +- 6 files changed, 491 insertions(+), 29 deletions(-) create mode 100644 Polyhedron/demo/Polyhedron/Color_map.h diff --git a/Polyhedron/demo/Polyhedron/Color_map.h b/Polyhedron/demo/Polyhedron/Color_map.h new file mode 100644 index 00000000000..fb89f4d2c3f --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Color_map.h @@ -0,0 +1,26 @@ +#ifndef _COLOR_MAP_H +#define _COLOR_MAP_H + +#include + +template +Output_color_iterator +compute_color_map(QColor base_color, + unsigned nb_of_colors, + Output_color_iterator out) +{ + qreal hue = base_color.hueF(); + const qreal step = ((qreal)1) / nb_of_colors; + + qreal h = hue; + for(unsigned i = 0; i < nb_of_colors; ++i) { + h += step; + if ( h > 1 ) { h -= 1; } + *out++ = QColor::fromHsvF(h, + base_color.saturationF(), + base_color.valueF()); + } + return out; +} + +#endif diff --git a/Polyhedron/demo/Polyhedron/Scene_item.cpp b/Polyhedron/demo/Polyhedron/Scene_item.cpp index 8e8e7b2a9ad..7a4aedde781 100644 --- a/Polyhedron/demo/Polyhedron/Scene_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_item.cpp @@ -1,34 +1,104 @@ #include "Scene_item.h" +#include "Scene_interface.h" +#include const QColor Scene_item::defaultColor = QColor(100, 100, 255); -Scene_item::~Scene_item() {} +Scene_item::~Scene_item() { + delete defaultContextMenu; +} void Scene_item::itemAboutToBeDestroyed(Scene_item* item) { if(this == item) emit aboutToBeDestroyed(); } + +QString modeName(RenderingMode mode) { + switch(mode) + { + case Points: + return QObject::tr("points"); + case Wireframe: + return QObject::tr("wire"); + case Flat: + return QObject::tr("flat"); + case FlatPlusEdges: + return QObject::tr("flat+edges"); + case Gouraud: + return QObject::tr("Gouraud"); + default: + Q_ASSERT(false); + return QObject::tr("unknown"); + } +} + +const char* slotName(RenderingMode mode) { + switch(mode) + { + case Points: + return SLOT(setPointsMode()); + case Wireframe: + return SLOT(setWireframeMode()); + case Flat: + return SLOT(setFlatMode()); + case FlatPlusEdges: + return SLOT(setFlatPlusEdgesMode()); + case Gouraud: + return SLOT(setGouraudMode()); + default: + Q_ASSERT(false); + return ""; + } +} + // Rendering mode as a human readable string QString Scene_item::renderingModeName() const { - switch(renderingMode()) - { - case Points: - return tr("points"); - case Wireframe: - return tr("wire"); - case Flat: - return tr("flat"); - case FlatPlusEdges: - return tr("flat+edges"); - case Gouraud: - return tr("Gouraud"); - default: - Q_ASSERT(false); - return tr("unknown"); - } + return modeName(renderingMode()); } +QMenu* Scene_item::contextMenu() +{ + if(defaultContextMenu) { + defaultContextMenu->setTitle(name()); + return defaultContextMenu; + } + + defaultContextMenu = new QMenu(name()); + // defaultContextMenu->addAction(name()); + // defaultContextMenu->addSeparator(); + // QMenu* modeMenu = new QMenu(QObject::tr("Rendering mode"), + // defaultContextMenu); + for(unsigned int mode = 0; mode < NumberOfRenderingMode; + ++mode) + { + if(!supportsRenderingMode(RenderingMode(mode))) continue; + QString mName = modeName(RenderingMode(mode)); + QAction* action = + defaultContextMenu->addAction(tr("Set %1 mode") + .arg(mName), + this, + slotName(RenderingMode(mode))); + QObject::connect(action, SIGNAL(triggered()), + this, SIGNAL(itemChanged())); + } + // defaultContextMenu->addAction(modeMenu->menuAction()); + return defaultContextMenu; +} + +void Scene_item::changed() { + // emit itemChanged(); +} + +void Scene_item::select(double /*orig_x*/, + double /*orig_y*/, + double /*orig_z*/, + double /*dir_x*/, + double /*dir_y*/, + double /*dir_z*/) +{ +} + #include "Scene_item.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene_item.h b/Polyhedron/demo/Polyhedron/Scene_item.h index 63c9ded36d9..0463b4e3978 100644 --- a/Polyhedron/demo/Polyhedron/Scene_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_item.h @@ -4,12 +4,15 @@ #include "Scene_item_config.h" #include "Scene_interface.h" #include +#include #include namespace qglviewer { class ManipulatedFrame; } +class QMenu; + // This class represents an object in the OpenGL scene class SCENE_ITEM_EXPORT Scene_item : public QObject { Q_OBJECT @@ -28,7 +31,8 @@ public: : name_("unamed"), color_(defaultColor), visible_(true), - rendering_mode(FlatPlusEdges) + rendering_mode(FlatPlusEdges), + defaultContextMenu(0) {}; virtual ~Scene_item(); virtual Scene_item* clone() const = 0; @@ -44,6 +48,7 @@ public: // Functions for displaying meta-data of the item virtual QString toolTip() const = 0; + virtual QPixmap graphicalToolTip() const { return QPixmap(); } virtual QFont font() const { return QFont(); } // Functions that help the Scene to compute its bbox @@ -60,25 +65,63 @@ public: virtual QString name() const { return name_; } virtual bool visible() const { return visible_; } virtual RenderingMode renderingMode() const { return rendering_mode; } - virtual QString renderingModeName() const; // Rendering mode as a human readable string + virtual QString renderingModeName() const; // Rendering mode as a human + // readable string + + // Context menu + virtual QMenu* contextMenu(); public slots: // Call that once you have finished changing something in the item // (either the properties or internal data) - virtual void changed() {} + virtual void changed(); // Setters for the four basic properties virtual void setColor(QColor c) { color_ = c; } + void setRbgColor(int r, int g, int b) { setColor(QColor(r, g, b)); } virtual void setName(QString n) { name_ = n; } virtual void setVisible(bool b) { visible_ = b; } virtual void setRenderingMode(RenderingMode m) { if (supportsRenderingMode(m)) rendering_mode = m; } + void setPointsMode() { + setRenderingMode(Points); + } + + void setWireframeMode() { + setRenderingMode(Wireframe); + } + void setWireframe() { + setRenderingMode(Wireframe); + } + + void setFlat() { + setRenderingMode(Flat); + } + void setFlatMode() { + setRenderingMode(Flat); + } + + void setFlatPlusEdgesMode() { + setRenderingMode(FlatPlusEdges); + } + + void setGouraudMode() { + setRenderingMode(Gouraud); + } virtual void itemAboutToBeDestroyed(Scene_item*); + virtual void select(double orig_x, + double orig_y, + double orig_z, + double dir_x, + double dir_y, + double dir_z); + signals: + void itemChanged(); void aboutToBeDestroyed(); protected: @@ -87,7 +130,12 @@ protected: QColor color_; bool visible_; RenderingMode rendering_mode; + QMenu* defaultContextMenu; }; // end class Scene_item + +#include +Q_DECLARE_METATYPE(Scene_item*) + #endif // SCENE_ITEM_H diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp index 795e0ea5ca7..52a051f87bc 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp @@ -1,39 +1,127 @@ +#include #include "Scene_polyhedron_item.h" +#include "Kernel_type.h" #include "Polyhedron_type.h" #include +#include +#include +#include + +#include +#include + +typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; +typedef CGAL::AABB_traits AABB_traits; +typedef CGAL::AABB_tree Input_facets_AABB_tree; + +const char* aabb_property_name = "Scene_polyhedron_item aabb tree"; + +Input_facets_AABB_tree* get_aabb_tree(Scene_polyhedron_item* item) +{ + QVariant aabb_tree_property = item->property(aabb_property_name); + if(aabb_tree_property.isValid()) { + void* ptr = aabb_tree_property.value(); + return static_cast(ptr); + } + else { + Polyhedron* poly = item->polyhedron(); + if(poly) { + Input_facets_AABB_tree* tree = + new Input_facets_AABB_tree(poly->facets_begin(), + poly->facets_end()); + item->setProperty(aabb_property_name, + QVariant::fromValue(tree)); + return tree; + } + else return 0; + } +} + +void delete_aabb_tree(Scene_polyhedron_item* item) +{ + QVariant aabb_tree_property = item->property(aabb_property_name); + if(aabb_tree_property.isValid()) { + void* ptr = aabb_tree_property.value(); + Input_facets_AABB_tree* tree = static_cast(ptr); + if(tree) { + delete tree; + tree = 0; + } + item->setProperty(aabb_property_name, QVariant()); + } +} + #include +#include +#include #include Scene_polyhedron_item::Scene_polyhedron_item() : Scene_item_with_display_list(), - poly(new Polyhedron) + poly(new Polyhedron), + show_only_feature_edges_m(false), + facet_picking_m(false), + erase_next_picked_facet_m(false) { + //init(); } Scene_polyhedron_item::Scene_polyhedron_item(Polyhedron* const p) : Scene_item_with_display_list(), - poly(p) + poly(p), + show_only_feature_edges_m(false), + facet_picking_m(false), + erase_next_picked_facet_m(false) { + init(); } Scene_polyhedron_item::Scene_polyhedron_item(const Polyhedron& p) : Scene_item_with_display_list(), - poly(new Polyhedron(p)) + poly(new Polyhedron(p)), + show_only_feature_edges_m(false), + facet_picking_m(false), + erase_next_picked_facet_m(false) { + init(); } // Scene_polyhedron_item::Scene_polyhedron_item(const Scene_polyhedron_item& item) // : Scene_item_with_display_list(item), -// poly(new Polyhedron(*item.poly)) +// poly(new Polyhedron(*item.poly)), +// show_only_feature_edges_m(false) // { // } Scene_polyhedron_item::~Scene_polyhedron_item() { + delete_aabb_tree(this); delete poly; } +#include "Color_map.h" + +void +Scene_polyhedron_item:: +init() +{ + typedef Polyhedron::Facet_iterator Facet_iterator; + + // Fill indices map and get max subdomain value + int max = 0; + for(Facet_iterator fit = poly->facets_begin(), end = poly->facets_end() ; + fit != end; ++fit) + { + max = (std::max)(max, fit->patch_id()); + } + + colors_.clear(); + compute_color_map(this->color(), max + 1, + std::back_inserter(colors_)); +} + + Scene_polyhedron_item* Scene_polyhedron_item::clone() const { return new Scene_polyhedron_item(*poly); @@ -44,13 +132,20 @@ bool Scene_polyhedron_item::load(std::istream& in) { in >> *poly; - return in && !isEmpty(); + + if ( in && !isEmpty() ) + { + changed(); + return true; + } + return false; } // Write polyhedron to .OFF file bool Scene_polyhedron_item::save(std::ostream& out) const { + out.precision(13); out << *poly; return out; } @@ -73,9 +168,100 @@ Scene_polyhedron_item::toolTip() const .arg(this->color().name()); } +QMenu* Scene_polyhedron_item::contextMenu() +{ + const char* prop_name = "Menu modified by Scene_polyhedron_item."; + + QMenu* menu = Scene_item::contextMenu(); + + // Use dynamic properties: + // http://doc.trolltech.com/lastest/qobject.html#property + bool menuChanged = menu->property(prop_name).toBool(); + + if(!menuChanged) { + + QAction* actionShowOnlyFeatureEdges = + menu->addAction(tr("Show only &feature edges")); + actionShowOnlyFeatureEdges->setCheckable(true); + actionShowOnlyFeatureEdges->setObjectName("actionShowOnlyFeatureEdges"); + connect(actionShowOnlyFeatureEdges, SIGNAL(toggled(bool)), + this, SLOT(show_only_feature_edges(bool))); + + QAction* actionPickFacets = + menu->addAction(tr("Facets picking")); + actionPickFacets->setCheckable(true); + actionPickFacets->setObjectName("actionPickFacets"); + connect(actionPickFacets, SIGNAL(toggled(bool)), + this, SLOT(enable_facets_picking(bool))); + + QAction* actionEraseNextFacet = + menu->addAction(tr("Erase next picked facet")); + actionEraseNextFacet->setCheckable(true); + actionEraseNextFacet->setObjectName("actionEraseNextFacet"); + connect(actionEraseNextFacet, SIGNAL(toggled(bool)), + this, SLOT(set_erase_next_picked_facet(bool))); + + menu->setProperty(prop_name, true); + } + QAction* action = menu->findChild("actionPickFacets"); + if(action) action->setChecked(facet_picking_m); + action = menu->findChild("actionEraseNextFacet"); + if(action) action->setChecked(erase_next_picked_facet_m); + return menu; +} + +void Scene_polyhedron_item::show_only_feature_edges(bool b) +{ + show_only_feature_edges_m = b; + emit itemChanged(); +} + +void Scene_polyhedron_item::enable_facets_picking(bool b) +{ + facet_picking_m = b; +} + +void Scene_polyhedron_item::set_erase_next_picked_facet(bool b) +{ + erase_next_picked_facet_m = b; +} + // Points/Wireframe/Flat/Gouraud OpenGL drawing in a display list void Scene_polyhedron_item::direct_draw() const { - gl_render_facets(*poly); + gl_render_facets(*poly,colors_); +} + +// Points/Wireframe/Flat/Gouraud OpenGL drawing in a display list +void Scene_polyhedron_item::direct_draw_edges() const { + typedef Kernel::Point_3 Point; + typedef Polyhedron::Edge_iterator Edge_iterator; + + ::glBegin(GL_LINES); + Edge_iterator he; + if(!show_only_feature_edges_m) { + for(he = poly->edges_begin(); + he != poly->edges_end(); + he++) + { + if(he->is_feature_edge()) continue; + const Point& a = he->vertex()->point(); + const Point& b = he->opposite()->vertex()->point(); + ::glVertex3d(a.x(),a.y(),a.z()); + ::glVertex3d(b.x(),b.y(),b.z()); + } + } + ::glColor3d(1.0, 0.0, 0.0); + for(he = poly->edges_begin(); + he != poly->edges_end(); + he++) + { + if(!he->is_feature_edge()) continue; + const Point& a = he->vertex()->point(); + const Point& b = he->opposite()->vertex()->point(); + ::glVertex3d(a.x(),a.y(),a.z()); + ::glVertex3d(b.x(),b.y(),b.z()); + } + ::glEnd(); } Polyhedron* @@ -90,7 +276,7 @@ Scene_polyhedron_item::isEmpty() const { Scene_polyhedron_item::Bbox Scene_polyhedron_item::bbox() const { - const Point& p = *(poly->points_begin()); + const Kernel::Point_3& p = *(poly->points_begin()); CGAL::Bbox_3 bbox(p.x(), p.y(), p.z(), p.x(), p.y(), p.z()); for(Polyhedron::Point_iterator it = poly->points_begin(); it != poly->points_end(); @@ -101,4 +287,82 @@ Scene_polyhedron_item::bbox() const { bbox.xmax(),bbox.ymax(),bbox.zmax()); } + +void +Scene_polyhedron_item:: +changed() +{ + delete_aabb_tree(this); + init(); + Base::changed(); +} + +void +Scene_polyhedron_item::select(double orig_x, + double orig_y, + double orig_z, + double dir_x, + double dir_y, + double dir_z) +{ + if(facet_picking_m) { + typedef Input_facets_AABB_tree Tree; + typedef Tree::Object_and_primitive_id Object_and_primitive_id; + typedef Tree::Primitive_id Primitive_id; + + Tree* aabb_tree = get_aabb_tree(this); + if(aabb_tree) { + const Kernel::Point_3 ray_origin(orig_x, orig_y, orig_z); + const Kernel::Vector_3 ray_dir(dir_x, dir_y, dir_z); + const Kernel::Ray_3 ray(ray_origin, ray_dir); + + typedef std::list Intersections; + Intersections intersections; + + aabb_tree->all_intersections(ray, std::back_inserter(intersections)); + + Intersections::iterator closest = intersections.begin(); + if(closest != intersections.end()) { + const Kernel::Point_3* closest_point = + CGAL::object_cast(&closest->first); + Kernel::Compare_squared_distance_3 comp_sq_dist = + Kernel().compare_squared_distance_3_object(); + + for(Intersections::iterator + it = boost::next(intersections.begin()), + end = intersections.end(); + it != end; ++it) + { + if(! closest_point) { + closest = it; + } + else { + const Kernel::Point_3* it_point = + CGAL::object_cast(&it->first); + if(it_point && + (ray_dir * (*it_point - *closest_point)) < 0) + { + closest = it; + closest_point = it_point; + } + } + } + if(closest_point) { + Polyhedron::Facet_handle selected_facet = closest->second; + if(erase_next_picked_facet_m) { + polyhedron()->erase_facet(selected_facet->halfedge()); + polyhedron()->normalize_border(); + set_erase_next_picked_facet(false); + changed(); + emit itemChanged(); + } + std::cerr << "Facet selected. patch_id=" + << selected_facet->patch_id() << std::endl; + } + } + } + } + Base::select(orig_x, orig_y, orig_z, dir_x, dir_y, dir_z); +} + #include "Scene_polyhedron_item.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h index 2b8981b25bd..0342d290977 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h @@ -6,6 +6,13 @@ #include "Polyhedron_type_fwd.h" #include +#include +#include + +#include + +class QMenu; + // This class represents a polyhedron in the OpenGL scene class SCENE_POLYHEDRON_ITEM_EXPORT Scene_polyhedron_item : public Scene_item_with_display_list { @@ -26,10 +33,14 @@ public: // Function for displaying meta-data of the item virtual QString toolTip() const; + // Function to override the context menu + QMenu* contextMenu(); + // Indicate if rendering mode is supported - virtual bool supportsRenderingMode(RenderingMode m) const { return true; } + virtual bool supportsRenderingMode(RenderingMode) const { return true; } // Points/Wireframe/Flat/Gouraud OpenGL drawing in a display list virtual void direct_draw() const; + virtual void direct_draw_edges() const; // Get wrapped polyhedron Polyhedron* polyhedron(); @@ -40,9 +51,34 @@ public: bool isEmpty() const; Bbox bbox() const; +public slots: + virtual void changed(); + void show_only_feature_edges(bool); + void enable_facets_picking(bool); + void set_erase_next_picked_facet(bool); + + void select(double orig_x, + double orig_y, + double orig_z, + double dir_x, + double dir_y, + double dir_z); +private: + // Initialization + void init(); + private: Polyhedron* poly; +private: + typedef Scene_item_with_display_list Base; + typedef std::vector Color_vector; + + Color_vector colors_; + + bool show_only_feature_edges_m; + bool facet_picking_m; + bool erase_next_picked_facet_m; }; // end class Scene_polyhedron_item #endif // SCENE_POLYHEDRON_ITEM_H diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/gl_render.h b/Polyhedron/demo/Polyhedron/include/CGAL/gl_render.h index fe76152afab..28613bc2a8c 100644 --- a/Polyhedron/demo/Polyhedron/include/CGAL/gl_render.h +++ b/Polyhedron/demo/Polyhedron/include/CGAL/gl_render.h @@ -4,8 +4,25 @@ #include #include + +namespace { + void CGALglcolor(QColor c, int dv = 0) + { + if ( 0 != dv ) + { +// workaround for Qt-4.2. +#if QT_VERSION < 0x040300 +# define darker dark +#endif + c = c.darker(dv); +#undef darker + } + ::glColor4f(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0); + } +} + template -void gl_render_facets(Polyhedron& polyhedron) +void gl_render_facets(Polyhedron& polyhedron, const std::vector& colors) { typedef typename Polyhedron::Traits Kernel; typedef typename Kernel::Point_3 Point; @@ -23,6 +40,7 @@ void gl_render_facets(Polyhedron& polyhedron) f != polyhedron.facets_end(); f++) { + CGALglcolor(colors[f->patch_id()]); ::glBegin(GL_POLYGON); // If Flat shading: 1 normal per polygon From 9670c424030f9e0a617042a983cc7b3364848c15 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 14:40:06 +0000 Subject: [PATCH 41/65] Begin to update Polyhedron demo from work done in the Mesh_3 dev'branch Step 3: - Update the API of the Scene and Viewer class (some methods are not yet used). - Update the CMakeLists.txt, to compile all major classes of the framework (Scene, Viewer, Scene_item) into a demo_framework library. --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 88 ++++--- Polyhedron/demo/Polyhedron/Scene.cpp | 245 ++++++++++++++---- Polyhedron/demo/Polyhedron/Scene.h | 44 +++- Polyhedron/demo/Polyhedron/Scene_config.h | 16 ++ Polyhedron/demo/Polyhedron/Scene_find_items.h | 121 +++++++++ Polyhedron/demo/Polyhedron/Viewer.cpp | 207 +++++++++++++-- Polyhedron/demo/Polyhedron/Viewer.h | 34 ++- Polyhedron/demo/Polyhedron/Viewer_config.h | 16 ++ 8 files changed, 647 insertions(+), 124 deletions(-) create mode 100644 Polyhedron/demo/Polyhedron/Scene_config.h create mode 100644 Polyhedron/demo/Polyhedron/Scene_find_items.h create mode 100644 Polyhedron/demo/Polyhedron/Viewer_config.h diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 076e343bed6..2bc24a24ab8 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -80,9 +80,9 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) message(STATUS "NOTICE: LAPACK is not found. curvatures estimation will not be available.") endif(LAPACK_FOUND) - qt4_wrap_ui( UI_FILES MainWindow.ui ) - + qt4_wrap_ui( MainWindowUI_files MainWindow.ui ) qt4_wrap_ui( remeshingUI_FILES Remeshing_dialog.ui) + qt4_wrap_ui( meshingUI_FILES Meshing_dialog.ui Meshing_pause_widget.ui ) include(AddFileDependencies) @@ -92,15 +92,12 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) qt4_generate_moc( "Viewer.h" "${CMAKE_CURRENT_BINARY_DIR}/Viewer_moc.cpp" ) add_file_dependencies( Viewer_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/Viewer.h" ) - qt4_generate_moc( "Scene.h" "${CMAKE_CURRENT_BINARY_DIR}/Scene_moc.cpp" ) - add_file_dependencies( Scene_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/Scene.h" ) - - qt4_generate_moc( "Polyhedron_demo_remeshing_plugin_cgal_code.cpp" "${CMAKE_CURRENT_BINARY_DIR}/Polyhedron_demo_remeshing_plugin_cgal_code.moc" ) qt4_add_resources ( RESOURCE_FILES Polyhedron_3.qrc ) - qt4_automoc(Scene_item.cpp + qt4_automoc(Scene.cpp + Scene_item.cpp Scene_plane_item.cpp Scene_polygon_soup.cpp Scene_polyhedron_item.cpp @@ -112,42 +109,53 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) # put plugins (which are shared libraries) at the same location as # executable files - set(LIBRARY_OUTPUT_PATH ${RUNTIME_OUTPUT_PATH}) - add_library(scene_item SHARED + add_library(demo_framework SHARED + Scene.cpp + Viewer.cpp Viewer_moc.cpp Scene_item.cpp Scene_item.moc Scene_item_with_display_list.cpp Polyhedron_demo_plugin_helper.cpp) add_library(scene_basic_objects SHARED Scene_plane_item.cpp Scene_plane_item.moc) - target_link_libraries(scene_basic_objects scene_item ${QGLVIEWER_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}) + target_link_libraries(scene_basic_objects + demo_framework + ${QGLVIEWER_LIBRARIES} + ${OPENGL_gl_LIBRARY} + ${OPENGL_glu_LIBRARY} + ) add_library(scene_c2t3_item SHARED Scene_c2t3_item.cpp Scene_c2t3_item.moc) - target_link_libraries(scene_c2t3_item scene_item) + target_link_libraries(scene_c2t3_item demo_framework) add_library(scene_polyhedron_item SHARED Scene_polyhedron_item.cpp Scene_polyhedron_item.moc) - target_link_libraries(scene_polyhedron_item scene_item) + target_link_libraries(scene_polyhedron_item demo_framework) if(TAUCS_FOUND) add_library(scene_textured_polyhedron_item SHARED Scene_textured_polyhedron_item.cpp texture.cpp Scene_textured_polyhedron_item.moc) - target_link_libraries(scene_textured_polyhedron_item scene_item) + target_link_libraries(scene_textured_polyhedron_item demo_framework) endif(TAUCS_FOUND) - add_library(polygon_soup SHARED + add_library(scene_polygon_soup_item SHARED Scene_polygon_soup.cpp Scene_polygon_soup.moc) - target_link_libraries(polygon_soup scene_item) + target_link_libraries(scene_polygon_soup_item demo_framework scene_polyhedron_item) add_library(scene_nef_polyhedron_item SHARED Scene_nef_polyhedron_item.cpp Scene_nef_polyhedron_item.moc Scene_nef_rendering.cpp) - target_link_libraries(scene_nef_polyhedron_item scene_polyhedron_item) + target_link_libraries(scene_nef_polyhedron_item demo_framework scene_polyhedron_item) - foreach( lib scene_item scene_basic_objects scene_polyhedron_item polygon_soup scene_nef_polyhedron_item ) + foreach( lib + demo_framework + scene_basic_objects + scene_polyhedron_item + scene_polygon_soup_item + scene_nef_polyhedron_item ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS ${lib} ) endforeach() @@ -156,13 +164,12 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) add_definitions(-DUSE_FORWARD_DECL) add_executable ( Polyhedron_3 MainWindow.cpp Polyhedron_3.cpp - Viewer.cpp - Scene.cpp +# Viewer.cpp +# Scene.cpp # MainWindow_curvature_estimation.cpp MainWindow_moc.cpp - Scene_moc.cpp - Viewer_moc.cpp - ${UI_FILES} ${RESOURCE_FILES} ) +# Viewer_moc.cpp + ${MainWindowUI_files} ${RESOURCE_FILES} ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polyhedron_3 ) if(TAUCS_FOUND) # add_executable( Polyhedron_3 Scene_tex_rendering.cpp Scene_tex_polyhedron_operations.cpp ) @@ -177,6 +184,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) # Link with Qt libraries target_link_libraries( Polyhedron_3 ${QT_LIBRARIES} ) + target_link_libraries( Polyhedron_3 demo_framework ) # Link with CGAL target_link_libraries( Polyhedron_3 ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ) @@ -184,9 +192,6 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) # Link with libQGLViewer, OpenGL target_link_libraries( Polyhedron_3 ${QGLVIEWER_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) - # Link with the scene_item library. -# target_link_libraries( Polyhedron_3 scene_item ) - add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polyhedron_3 ) @@ -198,26 +203,37 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) macro(polyhedron_demo_plugin plugin_name plugin_implementation_base_name) list_split(option ARGN_TAIL ${ARGN} ) if(NOT ${option} STREQUAL "EXCLUDE_FROM_ALL") - set(other_sources ${ARGN}) - set(option "") + if(NOT ${option} STREQUAL "NO_MOC") + set(other_sources ${ARGN}) + set(option "") + else() + set(other_sources ${ARGN_TAIL}) + endif() else() set(other_sources ${ARGN_TAIL}) endif() - qt4_generate_moc( ${plugin_implementation_base_name}.cpp "${CMAKE_CURRENT_BINARY_DIR}/${plugin_implementation_base_name}.moc" ) - add_file_dependencies( ${plugin_implementation_base_name}.moc "${CMAKE_CURRENT_SOURCE_DIR}/${plugin_implementation_base_name}.cpp" ) + if("${option}" STREQUAL "NO_MOC") + set(option "") + set(moc_file_name "") + else() + set(moc_file_name ${plugin_implementation_base_name}.moc ) + qt4_generate_moc( ${plugin_implementation_base_name}.cpp "${CMAKE_CURRENT_BINARY_DIR}/${moc_file_name}" ) + add_file_dependencies( ${moc_file_name} "${CMAKE_CURRENT_SOURCE_DIR}/${plugin_implementation_base_name}.cpp" ) + endif() - add_library(${plugin_name} MODULE ${option} ${plugin_implementation_base_name}.moc ${plugin_implementation_base_name}.cpp ${other_sources}) + add_library(${plugin_name} MODULE ${option} ${moc_file_name} ${plugin_implementation_base_name}.cpp ${other_sources}) add_to_cached_list( CGAL_EXECUTABLE_TARGETS ${plugin_name} ) # Link with Qt target_link_libraries( ${plugin_name} ${QT_LIBRARIES} ) - # Link with scene_item - target_link_libraries( ${plugin_name} scene_item) + # Link with the demo_framework + target_link_libraries( ${plugin_name} demo_framework) # Link with CGAL target_link_libraries( ${plugin_name} ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ) + add_dependencies( ${plugin_name} Polyhedron_3 ) endmacro(polyhedron_demo_plugin) polyhedron_demo_plugin(remeshing_plugin Polyhedron_demo_remeshing_plugin Polyhedron_demo_remeshing_plugin_cgal_code.cpp Polyhedron_demo_remeshing_plugin_cgal_code.moc ${remeshingUI_FILES}) - target_link_libraries(remeshing_plugin scene_polyhedron_item polygon_soup scene_c2t3_item) + target_link_libraries(remeshing_plugin scene_polyhedron_item scene_polygon_soup_item scene_c2t3_item) if ( Boost_VERSION GREATER 103400 ) qt4_generate_moc( "Polyhedron_demo_mesh_3_plugin_cgal_code.cpp" "${CMAKE_CURRENT_BINARY_DIR}/Scene_c3t3_item.moc" ) @@ -230,13 +246,13 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) endif( Boost_VERSION GREATER 103400 ) polyhedron_demo_plugin(inside_out_plugin Polyhedron_demo_inside_out_plugin) - target_link_libraries(inside_out_plugin scene_polyhedron_item polygon_soup) + target_link_libraries(inside_out_plugin scene_polyhedron_item scene_polygon_soup_item) polyhedron_demo_plugin(off_plugin Polyhedron_demo_off_plugin) - target_link_libraries(off_plugin scene_polyhedron_item polygon_soup) + target_link_libraries(off_plugin scene_polyhedron_item scene_polygon_soup_item) polyhedron_demo_plugin(orient_soup_plugin Polyhedron_demo_orient_soup_plugin) - target_link_libraries(orient_soup_plugin polygon_soup) + target_link_libraries(orient_soup_plugin scene_polygon_soup_item scene_polyhedron_item) polyhedron_demo_plugin(triangulate_facets_plugin Polyhedron_demo_triangulate_facets_plugin) target_link_libraries(triangulate_facets_plugin scene_polyhedron_item) diff --git a/Polyhedron/demo/Polyhedron/Scene.cpp b/Polyhedron/demo/Polyhedron/Scene.cpp index a53badda303..70db1e37cc7 100644 --- a/Polyhedron/demo/Polyhedron/Scene.cpp +++ b/Polyhedron/demo/Polyhedron/Scene.cpp @@ -2,6 +2,8 @@ #include "Scene.h" #include "Scene_item.h" +#include +#include #include #include #include @@ -10,11 +12,12 @@ #include #include #include +#include namespace { void CGALglcolor(QColor c) { - ::glColor4f(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0); + ::glColor4d(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0); } } @@ -24,29 +27,54 @@ Scene::Scene(QObject* parent) item_A(-1), item_B(-1) { + connect(this, SIGNAL(selectionRay(double, double, double, + double, double, double)), + this, SLOT(setSelectionRay(double, double, double, + double, double, double))); } Scene::Item_id Scene::addItem(Scene_item* item) { - entries.push_back(item); + m_entries.push_back(item); + connect(item, SIGNAL(itemChanged()), + this, SLOT(itemChanged())); emit updated_bbox(); emit updated(); QAbstractListModel::reset(); - return entries.size() - 1; + Item_id id = m_entries.size() - 1; + emit newItem(id); + return id; +} + +Scene_item* +Scene::replaceItem(Scene::Item_id index, Scene_item* item) +{ + if(index < 0 || index >= m_entries.size()) + return 0; + + connect(item, SIGNAL(itemChanged()), + this, SLOT(itemChanged())); + std::swap(m_entries[index], item); + + emit updated_bbox(); + emit updated(); + itemChanged(index); + QAbstractListModel::reset(); + return item; } int Scene::erase(int index) { - if(index < 0 || index >= entries.size()) + if(index < 0 || index >= m_entries.size()) return -1; - Scene_item* item = entries[index]; + Scene_item* item = m_entries[index]; emit itemAboutToBeDestroyed(item); delete item; - entries.removeAt(index); + m_entries.removeAt(index); selected_item = -1; emit updated(); @@ -54,30 +82,62 @@ Scene::erase(int index) if(--index >= 0) return index; - if(!entries.isEmpty()) + if(!m_entries.isEmpty()) + return 0; + return -1; +} + +int +Scene::erase(QList indices) +{ + QList to_be_removed; + + int max_index = -1; + Q_FOREACH(int index, indices) { + if(index < 0 || index >= m_entries.size()) + continue; + max_index = (std::max)(max_index, index); + Scene_item* item = m_entries[index]; + to_be_removed.push_back(item); + emit itemAboutToBeDestroyed(item); + delete item; + } + + Q_FOREACH(Scene_item* item, to_be_removed) { + m_entries.removeAll(item); + } + + selected_item = -1; + emit updated(); + QAbstractListModel::reset(); + + int index = max_index + 1 - indices.size(); + if(index >= 0) + return index; + if(!m_entries.isEmpty()) return 0; return -1; } Scene::~Scene() { - Q_FOREACH(Scene_item* item_ptr, entries) + Q_FOREACH(Scene_item* item_ptr, m_entries) { delete item_ptr; } - entries.clear(); + m_entries.clear(); } Scene_item* Scene::item(Item_id index) const { - return entries.value(index); // QList::value checks bounds + return m_entries.value(index); // QList::value checks bounds } size_t Scene::numberOfEntries() const { - return entries.size(); + return m_entries.size(); } // Duplicate a scene item. @@ -85,17 +145,17 @@ Scene::numberOfEntries() const Scene::Item_id Scene::duplicate(Item_id index) { - if(index < 0 || index >= entries.size()) + if(index < 0 || index >= m_entries.size()) return -1; - const Scene_item* item = entries[index]; + const Scene_item* item = m_entries[index]; Scene_item* new_item = item->clone(); if(new_item) { new_item->setName(tr("%1 (copy)").arg(item->name())); new_item->setColor(item->color()); new_item->setVisible(item->visible()); addItem(new_item); - return entries.size() - 1; + return m_entries.size() - 1; } else return -1; @@ -125,12 +185,12 @@ void Scene::draw_aux(bool with_names) { // Flat/Gouraud OpenGL drawing - for(int index = 0; index < entries.size(); ++index) + for(int index = 0; index < m_entries.size(); ++index) { if(with_names) { ::glPushName(index); } - Scene_item& item = *entries[index]; + Scene_item& item = *m_entries[index]; if(item.visible()) { if(item.renderingMode() == Flat || item.renderingMode() == FlatPlusEdges || item.renderingMode() == Gouraud) @@ -157,12 +217,12 @@ Scene::draw_aux(bool with_names) } // Wireframe OpenGL drawing - for(int index = 0; index < entries.size(); ++index) + for(int index = 0; index < m_entries.size(); ++index) { if(with_names) { ::glPushName(index); } - Scene_item& item = *entries[index]; + Scene_item& item = *m_entries[index]; if(item.visible()) { if(item.renderingMode() == FlatPlusEdges || item.renderingMode() == Wireframe) @@ -185,12 +245,12 @@ Scene::draw_aux(bool with_names) } // Points OpenGL drawing - for(int index = 0; index < entries.size(); ++index) + for(int index = 0; index < m_entries.size(); ++index) { if(with_names) { ::glPushName(index); } - Scene_item& item = *entries[index]; + Scene_item& item = *m_entries[index]; if(item.visible()) { if(item.renderingMode() == Points) @@ -222,7 +282,7 @@ Scene::rowCount(const QModelIndex & parent) const if (parent.isValid()) return 0; else - return entries.size(); + return m_entries.size(); } int @@ -240,33 +300,33 @@ Scene::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - if(index.row() < 0 || index.row() >= entries.size()) + if(index.row() < 0 || index.row() >= m_entries.size()) return QVariant(); if(role == ::Qt::ToolTipRole) { - return entries[index.row()]->toolTip(); + return m_entries[index.row()]->toolTip(); } switch(index.column()) { case ColorColumn: if(role == ::Qt::DisplayRole || role == ::Qt::EditRole) - return entries.value(index.row())->color(); + return m_entries.value(index.row())->color(); else if(role == ::Qt::DecorationRole) - return entries.value(index.row())->color(); + return m_entries.value(index.row())->color(); break; case NameColumn: if(role == ::Qt::DisplayRole || role == ::Qt::EditRole) - return entries.value(index.row())->name(); + return m_entries.value(index.row())->name(); if(role == ::Qt::FontRole) - return entries.value(index.row())->font(); + return m_entries.value(index.row())->font(); break; case RenderingModeColumn: if(role == ::Qt::DisplayRole) { - return entries.value(index.row())->renderingModeName(); + return m_entries.value(index.row())->renderingModeName(); } else if(role == ::Qt::EditRole) { - return static_cast(entries.value(index.row())->renderingMode()); + return static_cast(m_entries.value(index.row())->renderingMode()); } else if(role == ::Qt::TextAlignmentRole) { return ::Qt::AlignCenter; @@ -285,7 +345,7 @@ Scene::data(const QModelIndex &index, int role) const break; case VisibleColumn: if(role == ::Qt::DisplayRole || role == ::Qt::EditRole) - return entries.value(index.row())->visible(); + return m_entries.value(index.row())->visible(); break; default: return QVariant(); @@ -350,10 +410,10 @@ Scene::setData(const QModelIndex &index, if( role != ::Qt::EditRole || !index.isValid() ) return false; - if(index.row() < 0 || index.row() >= entries.size()) + if(index.row() < 0 || index.row() >= m_entries.size()) return false; - Scene_item* item = entries[index.row()]; + Scene_item* item = m_entries[index.row()]; if(!item) return false; switch(index.column()) { @@ -397,6 +457,10 @@ Scene::Item_id Scene::mainSelectionIndex() const { return selected_item; } +QList Scene::selectionIndices() const { + return selected_items_list; +} + int Scene::selectionAindex() const { return item_A; } @@ -411,12 +475,25 @@ QItemSelection Scene::createSelection(int i) QAbstractItemModel::createIndex(i, LastColumn)); } +QItemSelection Scene::createSelectionAll() +{ + return QItemSelection(QAbstractItemModel::createIndex(0, 0), + QAbstractItemModel::createIndex(m_entries.size() - 1 , LastColumn)); +} + +void Scene::itemChanged() +{ + Scene_item* item = qobject_cast(sender()); + if(item) + itemChanged(item); +} + void Scene::itemChanged(Item_id i) { - if(i < 0 || i >= entries.size()) + if(i < 0 || i >= m_entries.size()) return; - entries[i]->changed(); + m_entries[i]->changed(); emit dataChanged(QAbstractItemModel::createIndex(i, 0), QAbstractItemModel::createIndex(i, LastColumn)); } @@ -425,7 +502,7 @@ void Scene::itemChanged(Scene_item* item) { item->changed(); emit dataChanged(QAbstractItemModel::createIndex(0, 0), - QAbstractItemModel::createIndex(entries.size() - 1, LastColumn)); + QAbstractItemModel::createIndex(m_entries.size() - 1, LastColumn)); } bool SceneDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, @@ -451,13 +528,16 @@ bool SceneDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, break; case Scene::ColorColumn: if (event->type() == QEvent::MouseButtonPress) { - QColor color = - QColorDialog::getColor(model->data(index).value(), - 0/*, - tr("Select color"), - QColorDialog::ShowAlphaChannel*/); - if (color.isValid()) { - model->setData(index, color ); + QMouseEvent *mouseEvent = static_cast(event); + if(mouseEvent->button() == ::Qt::LeftButton) { + QColor color = + QColorDialog::getColor(model->data(index).value(), + 0/*, + tr("Select color"), + QColorDialog::ShowAlphaChannel*/); + if (color.isValid()) { + model->setData(index, color ); + } } } else if(event->type() == QEvent::MouseButtonDblClick) { @@ -467,10 +547,13 @@ bool SceneDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, break; case Scene::RenderingModeColumn: if (event->type() == QEvent::MouseButtonPress) { - // Switch rendering mode - /*RenderingMode*/int rendering_mode = model->data(index, ::Qt::EditRole).toInt(); - rendering_mode = (rendering_mode+1) % NumberOfRenderingMode; - model->setData(index, rendering_mode); + QMouseEvent *mouseEvent = static_cast(event); + if(mouseEvent->button() == ::Qt::LeftButton) { + // Switch rendering mode + /*RenderingMode*/int rendering_mode = model->data(index, ::Qt::EditRole).toInt(); + rendering_mode = (rendering_mode+1) % NumberOfRenderingMode; + model->setData(index, rendering_mode); + } } else if(event->type() == QEvent::MouseButtonDblClick) { return true; // block double-click @@ -538,13 +621,29 @@ void SceneDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, void Scene::setItemVisible(int index, bool b) { - if( index < 0 || index >= entries.size() ) + if( index < 0 || index >= m_entries.size() ) return; - entries[index]->setVisible(b); + m_entries[index]->setVisible(b); emit dataChanged(QAbstractItemModel::createIndex(index, VisibleColumn), QAbstractItemModel::createIndex(index, VisibleColumn)); } +void Scene::setSelectionRay(double orig_x, + double orig_y, + double orig_z, + double dir_x, + double dir_y, + double dir_z) +{ + Scene_item* item = this->item(selected_item); + if(item) item->select(orig_x, + orig_y, + orig_z, + dir_x, + dir_y, + dir_z); +} + void Scene::setItemA(int i) { item_A = i; @@ -553,7 +652,7 @@ void Scene::setItemA(int i) item_B = -1; } emit dataChanged(QAbstractItemModel::createIndex(0, ABColumn), - QAbstractItemModel::createIndex(entries.size()-1, ABColumn)); + QAbstractItemModel::createIndex(m_entries.size()-1, ABColumn)); } void Scene::setItemB(int i) @@ -565,17 +664,17 @@ void Scene::setItemB(int i) } emit updated(); emit dataChanged(QAbstractItemModel::createIndex(0, ABColumn), - QAbstractItemModel::createIndex(entries.size()-1, ABColumn)); + QAbstractItemModel::createIndex(m_entries.size()-1, ABColumn)); } Scene::Bbox Scene::bbox() const { - if(entries.empty()) + if(m_entries.empty()) return Bbox(); bool bbox_initialized = false; Bbox bbox; - Q_FOREACH(Scene_item* item, entries) + Q_FOREACH(Scene_item* item, m_entries) { if(item->isFinite() && !item->isEmpty()) { if(bbox_initialized) { @@ -589,3 +688,45 @@ Scene::Bbox Scene::bbox() const } return bbox; } + +#include "Scene_find_items.h" + +namespace scene { namespace details { + +Q_DECL_EXPORT +Scene_item* +findItem(const Scene_interface* scene_interface, + const QMetaObject& metaobj, + QString name, Scene_item_name_fn_ptr fn) { + const Scene* scene = dynamic_cast(scene_interface); + if(!scene) return 0; + Q_FOREACH(Scene_item* item, scene->entries()) { + Scene_item* ptr = qobject_cast(metaobj.cast(item)); + if(ptr && ((ptr->*fn)() == name)) return ptr; + } + return 0; +} + +Q_DECL_EXPORT +QList +findItems(const Scene_interface* scene_interface, + const QMetaObject&, + QString name, Scene_item_name_fn_ptr fn) +{ + const Scene* scene = dynamic_cast(scene_interface); + QList list; + if(!scene) return list; + + Q_FOREACH(Scene_item* item, scene->entries()) { + Scene_item* ptr = qobject_cast(item); + if(ptr && ((ptr->*fn)() == name)) { + list << ptr; + } + } + return list; +} + +} // end namespace details +} // end namespace scene + +#include "Scene.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene.h b/Polyhedron/demo/Polyhedron/Scene.h index 3c08c03ccb5..a39ea37400f 100644 --- a/Polyhedron/demo/Polyhedron/Scene.h +++ b/Polyhedron/demo/Polyhedron/Scene.h @@ -1,6 +1,7 @@ #ifndef SCENE_H #define SCENE_H #include "config.h" +#include "Scene_config.h" #include "Scene_interface.h" #include "Scene_draw_interface.h" @@ -21,10 +22,11 @@ class QEvent; class QMouseEvent; -class Scene : +class SCENE_EXPORT Scene : public QAbstractListModel, public Scene_interface, public Scene_draw_interface { Q_OBJECT + Q_PROPERTY(int numberOfEntries READ numberOfEntries) friend class SceneDelegate; @@ -40,19 +42,24 @@ public: Scene(QObject* parent); ~Scene(); - Item_id addItem(Scene_item* item); + int addItem(Scene_item* item); + Scene_item* replaceItem(int index, Scene_item* item); - int erase(int); // Returns the index of the polyhedra just before the - // one that is erased, or just after. Returns -1 if - // the list is empty. + Q_INVOKABLE int erase(int); + int erase(QList); + // Returns the index of the polyhedra just before the + // one that is erased, or just after. Returns -1 if + // the list is empty. // Duplicate a scene item. Return the ID of the new item (-1 on error). - Item_id duplicate(Item_id index); + int duplicate(int index); // Accessors (getters) size_t numberOfEntries() const; - Scene_item* item(Item_id) const ; - Item_id mainSelectionIndex() const; + const QList& entries() const { return m_entries; } + Q_INVOKABLE Scene_item* item(int) const ; + int mainSelectionIndex() const; + QList selectionIndices() const; int selectionAindex() const; int selectionBindex() const; @@ -83,38 +90,51 @@ public: // auxiliary public function for QMainWindow QItemSelection createSelection(int i); + QItemSelection createSelectionAll(); public slots: // Notify the scene that an item was modified - void itemChanged(Item_id i); + void itemChanged(); // slots called by items themself + void itemChanged(int i); void itemChanged(Scene_item*); - void setSelectedItem(Item_id i ) + void setSelectedItem(int i ) { selected_item = i; }; + void setSelectedItemsList(QList l ) + { + selected_items_list = l; + }; + // Accessors (setters) void setItemVisible(int, bool b); void setItemA(int i); void setItemB(int i); signals: + void newItem(int); void updated_bbox(); void updated(); void itemAboutToBeDestroyed(Scene_item*); + void selectionRay(double, double, double, double, double, double); + +private slots: + void setSelectionRay(double, double, double, double, double, double); private: void draw_aux(bool with_names); typedef QList Entries; - Entries entries; + Entries m_entries; int selected_item; + QList selected_items_list; int item_A; int item_B; }; // end class Scene -class SceneDelegate : public QItemDelegate +class SCENE_EXPORT SceneDelegate : public QItemDelegate { public: SceneDelegate(QObject * parent = 0) diff --git a/Polyhedron/demo/Polyhedron/Scene_config.h b/Polyhedron/demo/Polyhedron/Scene_config.h new file mode 100644 index 00000000000..6c532250add --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Scene_config.h @@ -0,0 +1,16 @@ +#ifndef SCENE_CONFIG_H +#define SCENE_CONFIG_H + +#include + +#ifdef demo_framework_EXPORTS +# define scene_EXPORTS +#endif + +#ifdef scene_EXPORTS +# define SCENE_EXPORT Q_DECL_EXPORT +#else +# define SCENE_EXPORT Q_DECL_IMPORT +#endif + +#endif // SCENE_CONFIG_H diff --git a/Polyhedron/demo/Polyhedron/Scene_find_items.h b/Polyhedron/demo/Polyhedron/Scene_find_items.h new file mode 100644 index 00000000000..00372aca9fb --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Scene_find_items.h @@ -0,0 +1,121 @@ +#ifndef SCENE_FIND_ITEMS +#define SCENE_FIND_ITEMS + +#include +#include +#include "Scene_item.h" // required, to have &Scene_item::name +#include "Scene_config.h" + +class Scene_interface; + +namespace scene { +namespace details { + +typedef QString (Scene_item ::*Scene_item_name_fn_ptr)() const; + +// Declaration only (defined in Scene.cpp) +SCENE_EXPORT +Scene_item* +findItem(const Scene_interface* scene_interface, + const QMetaObject& metaobj, + QString name, Scene_item_name_fn_ptr fn); + +// Declaration only (defined in Scene.cpp) +SCENE_EXPORT +QList +findItems(const Scene_interface* scene_interface, + const QMetaObject& metaobj, + QString name, Scene_item_name_fn_ptr fn); // fwd declaration + +template +T findItem(const Scene_interface* scene, QString name, + Scene_item_name_fn_ptr fn) +{ + return + static_cast(findItem(scene, + reinterpret_cast(0)->staticMetaObject, + name, fn)); +} + +template +QList findItems(const Scene_interface* scene, QString name, + Scene_item_name_fn_ptr fn) +{ + QList void_list = + findItems(scene, reinterpret_cast(0)->staticMetaObject, + name, fn); + QList list; + Q_FOREACH(Scene_item* ptr, void_list) { + list << qobject_cast(ptr); + } + return list; +} + +} // end namespace details + +// Searches + +/** Search the first item that can be cast to T (T must be a pointer + type), and called "name". If "name" is omitted, all names are + accepted. +*/ +template +T findItem(const Scene_interface* scene, + QString item_name = QString()) +{ return details::findItem(scene, item_name, &Scene_item::name); } + +/** Returns all items that can be cast to T (T must be a pointer + type), and called "name". If "name" is omitted, all names are + accepted. +*/ +template +QList findItems(const Scene_interface* scene, + QString item_name = QString()) +{ return details::findItems(scene, item_name, &Scene_item::name); } + +/** Search the first item that can be cast to T (T must be a pointer + type), and that has objectName() equal to "name". If "name" is + omitted, all names are accepted. +*/ +template +T findItemByObjectName(const Scene_interface* scene, + QString obj_name = QString()) +{ return details::findItem(scene, obj_name, &QObject::objectName); } + +/** Returns all items that can be cast to T (T must be a pointer type), + and have objectName() equal to "name". If "name" is omitted, all + names are accepted. +*/ +template +QList findItemsByObjectName(const Scene_interface* scene, + QString obj_name = QString()) +{ return details::findItems(scene, obj_name, &QObject::objectName); } + + +// template +// T scene_findItem(const Scene* scene, QString name, Scene_item_name_fn_ptr fn) { +// return +// static_cast(scene_findItem(scene, name, fn, +// reinterpret_cast(0)->staticMetaObject())); +// } + +// template +// QList +// scene_findItems(const Scene* scene, QString name, Scene_item_name_fn_ptr fn) { +// QList void_list = +// scene_findItems(scene, name, fn, +// reinterpret_cast(0)->staticMetaObject()); +// QList list; +// Q_FOREACH(void* ptr, void_list) { +// list << static_cast(ptr); +// } +// return list; +// } + +// } // end scene namespace + +} // end namespace scene + + + +#endif diff --git a/Polyhedron/demo/Polyhedron/Viewer.cpp b/Polyhedron/demo/Polyhedron/Viewer.cpp index ffe0fc930ba..bd69a082f2c 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.cpp +++ b/Polyhedron/demo/Polyhedron/Viewer.cpp @@ -1,46 +1,144 @@ #include "Viewer.h" #include "Scene_draw_interface.h" +#include +#include + +class Viewer_impl { +public: + Scene_draw_interface* scene; + bool antialiasing; + bool twosides; + bool macro_mode; + + void draw_aux(bool with_names); +}; Viewer::Viewer(QWidget* parent, bool antialiasing) - : QGLViewer(parent), - scene(0), - antialiasing(antialiasing), - twosides(false) + : QGLViewer(parent) { - setBackgroundColor(::Qt::white); + d = new Viewer_impl; + d->scene = 0; + d->antialiasing = antialiasing; + d->twosides = false; + d->macro_mode = false; + setShortcut(EXIT_VIEWER, 0); + setMouseBinding(Qt::SHIFT + Qt::LeftButton, SELECT); + setMouseBindingDescription(Qt::SHIFT + Qt::RightButton, + tr("Selects and display context " + "menu of the selected item")); + setKeyDescription(Qt::Key_T, + tr("Turn the camera by 180 degrees")); + setKeyDescription(Qt::Key_M, + tr("Toggle macro mode: useful to view details very near from the camera, " + "but decrease the z-buffer precision")); +} + +Viewer::~Viewer() +{ + delete d; } void Viewer::setScene(Scene_draw_interface* scene) { - this->scene = scene; + d->scene = scene; +} + +bool Viewer::antiAliasing() const +{ + return d->antialiasing; } void Viewer::setAntiAliasing(bool b) { - antialiasing = b; + d->antialiasing = b; updateGL(); } void Viewer::setTwoSides(bool b) { - twosides = b; + d->twosides = b; updateGL(); } void Viewer::draw() { - draw_aux(false); + // ::glFogf(GL_FOG_END, 2*sceneRadius()); + // ::glEnable(GL_FOG); + QGLViewer::draw(); + d->draw_aux(false); + // drawLight(GL_LIGHT0); } void Viewer::initializeGL() { QGLViewer::initializeGL(); - scene->initializeGL(); + setBackgroundColor(::Qt::white); + d->scene->initializeGL(); + + const GLfloat ambient_light[4] = { 0.6f, 0.6f, 0.6f, 1.0f }; + const GLfloat diffuse_light[4] = { 0.6f, 0.6f, 0.6f, 1.0f }; + + ::glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light); + ::glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light); + // ::glFogf(GL_FOG_DENSITY, 0.05f); + // ::glHint(GL_FOG_HINT, GL_NICEST); + // ::glFogi(GL_FOG_MODE, GL_LINEAR); + // static const GLfloat fogColor[] = {0.5f, 0.5f, 0.5f, 1}; + // ::glFogfv(GL_FOG_COLOR, fogColor); } -void Viewer::draw_aux(bool with_names) +#include + +void Viewer::mousePressEvent(QMouseEvent* event) +{ + if(event->button() == Qt::RightButton && + event->modifiers().testFlag(Qt::ShiftModifier)) + { + select(event->pos()); + requestContextMenu(event->globalPos()); + event->accept(); + } + else { + QGLViewer::mousePressEvent(event); + } +} + +void Viewer::keyPressEvent(QKeyEvent* e) +{ + if(!e->modifiers()) { + if(e->key() == Qt::Key_T) { + turnCameraBy180Degres(); + return; + } + else if(e->key() == Qt::Key_M) { + d->macro_mode = ! d->macro_mode; + if(d->macro_mode) { + camera()->setZNearCoefficient(0.0005f); + } else { + camera()->setZNearCoefficient(0.005f); + } + this->displayMessage(tr("Macro mode: %1"). + arg(d->macro_mode ? tr("on") : tr("off"))); + return; + } + } + QGLViewer::keyPressEvent(e); +} + +void Viewer::turnCameraBy180Degres() { + qglviewer::Camera* camera = this->camera(); + using qglviewer::ManipulatedCameraFrame; + + ManipulatedCameraFrame frame_from(*camera->frame()); + camera->setViewDirection(-camera->viewDirection()); + ManipulatedCameraFrame frame_to(*camera->frame()); + + camera->setOrientation(frame_from.orientation()); + camera->interpolateTo(frame_to, 0.5f); +} + +void Viewer_impl::draw_aux(bool with_names) { - QGLViewer::draw(); if(scene == 0) return; @@ -48,15 +146,16 @@ void Viewer::draw_aux(bool with_names) ::glPointSize(2.f); ::glEnable(GL_POLYGON_OFFSET_FILL); ::glPolygonOffset(1.0f,1.0f); - ::glClearColor(1.0f,1.0f,1.0f,0.0f); ::glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + ::glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); + if(twosides) ::glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); else ::glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - if(antiAliasing()) + if(antialiasing) { ::glEnable(GL_BLEND); ::glEnable(GL_LINE_SMOOTH); @@ -79,10 +178,84 @@ void Viewer::draw_aux(bool with_names) void Viewer::drawWithNames() { - draw_aux(true); + QGLViewer::draw(); + d->draw_aux(true); } -void Viewer::postSelection(const QPoint&) +void Viewer::postSelection(const QPoint& pixel) { - emit selected(this->selectedName()); + bool found = false; + qglviewer::Vec point = camera()->pointUnderPixel(pixel, found); + if(found) { + emit selectedPoint(point.x, + point.y, + point.z); + emit selected(this->selectedName()); + const qglviewer::Vec orig = camera()->position(); + const qglviewer::Vec dir = point - orig; + emit selectionRay(orig.x, orig.y, orig.z, + dir.x, dir.y, dir.z); + } +} + +bool Viewer::readFrame(QString s, qglviewer::Frame& frame) +{ + QStringList list = s.split(" ", QString::SkipEmptyParts); + if(list.size() != 7) + return false; + float vec[3]; + for(int i = 0; i < 3; ++i) + { + bool ok; + vec[i] = list[i].toFloat(&ok); + if(!ok) return false; + } + double orient[4]; + for(int i = 0; i < 4; ++i) + { + bool ok; + orient[i] = list[i + 3].toDouble(&ok); + if(!ok) return false; + } + frame.setPosition(qglviewer::Vec(vec[0], + vec[1], + vec[2])); + frame.setOrientation(orient[0], + orient[1], + orient[2], + orient[3]); + return true; +} + +QString Viewer::dumpFrame(const qglviewer::Frame& frame) { + const qglviewer::Vec pos = frame.position(); + const qglviewer::Quaternion q = frame.orientation(); + + return QString("%1 %2 %3 %4 %5 %6 %7") + .arg(pos[0]) + .arg(pos[1]) + .arg(pos[2]) + .arg(q[0]) + .arg(q[1]) + .arg(q[2]) + .arg(q[3]); +} + +bool Viewer::moveCameraToCoordinates(QString s, float animation_duration) { + qglviewer::Frame new_frame; + if(readFrame(s, new_frame)) { + camera()->interpolateTo(new_frame, animation_duration); + return true; + } + else + return false; +} + +QString Viewer::dumpCameraCoordinates() +{ + if(camera()->frame()) { + return dumpFrame(*camera()->frame()); + } else { + return QString(); + } } diff --git a/Polyhedron/demo/Polyhedron/Viewer.h b/Polyhedron/demo/Polyhedron/Viewer.h index f2396af5ceb..c2ffa7c946e 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.h +++ b/Polyhedron/demo/Polyhedron/Viewer.h @@ -1,18 +1,26 @@ #ifndef VIEWER_H #define VIEWER_H +#include "Viewer_config.h" + #include +#include // forward declarations class QWidget; class Scene_draw_interface; +class QMouseEvent; +class QKeyEvent; -class Viewer : public QGLViewer { +class Viewer_impl; + +class VIEWER_EXPORT Viewer : public QGLViewer { Q_OBJECT public: Viewer(QWidget * parent, bool antialiasing = false); + ~Viewer(); // overload several QGLViewer virtual functions void draw(); @@ -21,21 +29,33 @@ public: void postSelection(const QPoint&); void setScene(Scene_draw_interface* scene); - bool antiAliasing() const { return antialiasing; } + bool antiAliasing() const; + + static bool readFrame(QString, qglviewer::Frame&); + static QString dumpFrame(const qglviewer::Frame&); signals: void selected(int); + void requestContextMenu(QPoint global_pos); + void selectedPoint(double, double, double); + void selectionRay(double, double, double, double, double, double); public slots: void setAntiAliasing(bool b); void setTwoSides(bool b); -private: - void draw_aux(bool with_names); + void turnCameraBy180Degres(); - Scene_draw_interface* scene; - bool antialiasing; - bool twosides; + QString dumpCameraCoordinates(); + bool moveCameraToCoordinates(QString, + float animation_duration = 0.5f); + +protected: + void mousePressEvent(QMouseEvent*); + void keyPressEvent(QKeyEvent*); + +protected: + Viewer_impl* d; }; // end class Viewer #endif // VIEWER_H diff --git a/Polyhedron/demo/Polyhedron/Viewer_config.h b/Polyhedron/demo/Polyhedron/Viewer_config.h new file mode 100644 index 00000000000..2a79ddf681d --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Viewer_config.h @@ -0,0 +1,16 @@ +#ifndef VIEWER_CONFIG_H +#define VIEWER_CONFIG_H + +#include + +#ifdef demo_framework_EXPORTS +# define viewer_EXPORTS +#endif + +#ifdef viewer_EXPORTS +# define VIEWER_EXPORT Q_DECL_EXPORT +#else +# define VIEWER_EXPORT Q_DECL_IMPORT +#endif + +#endif // VIEWER_CONFIG_H From fd4d050b394aa3363650589a3252ff6ab6617659 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 15:18:56 +0000 Subject: [PATCH 42/65] Begin to update Polyhedron demo from work done in the Mesh_3 dev'branch Step 4: - Update the MainWindow class, to use all the new possibilities of the framework: - multi-selection of items in the scene, - activate the use of the items popup-menus. - Add Qt Script possibilities. - New actions in the "View" menu: "Look at", copy-paste of camera positions, select background color. - New action "Reload item", to reload an item if it was loaded from a file. --- .gitattributes | 1 + Polyhedron/demo/Polyhedron/CMakeLists.txt | 19 +- Polyhedron/demo/Polyhedron/MainWindow.cpp | 577 +++++++++++++++++- Polyhedron/demo/Polyhedron/MainWindow.h | 52 +- Polyhedron/demo/Polyhedron/MainWindow.ui | 114 +++- .../demo/Polyhedron/Point_dialog_config.h | 12 + Polyhedron/demo/Polyhedron/Polyhedron_3.cpp | 19 +- .../demo/Polyhedron/Show_point_dialog.cpp | 73 +++ .../demo/Polyhedron/Show_point_dialog.h | 35 ++ .../demo/Polyhedron/Show_point_dialog.ui | 161 +++++ 10 files changed, 1012 insertions(+), 51 deletions(-) create mode 100644 Polyhedron/demo/Polyhedron/Point_dialog_config.h create mode 100644 Polyhedron/demo/Polyhedron/Show_point_dialog.cpp create mode 100644 Polyhedron/demo/Polyhedron/Show_point_dialog.h create mode 100644 Polyhedron/demo/Polyhedron/Show_point_dialog.ui diff --git a/.gitattributes b/.gitattributes index e49130b59db..a84851b5107 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2854,6 +2854,7 @@ Polygon/doc_tex/Polygon/polygon.png -text Polyhedron/demo/Polyhedron/MainWindow.ui -text Polyhedron/demo/Polyhedron/Polyhedron_3.qrc -text Polyhedron/demo/Polyhedron/Remeshing_dialog.ui -text +Polyhedron/demo/Polyhedron/Show_point_dialog.ui -text Polyhedron/demo/Polyhedron/cgal_test_with_cmake eol=lf Polyhedron/demo/Polyhedron/data/anchor.off -text svneol=unset#application/octet-stream Polyhedron/demo/Polyhedron/data/bones.off -text svneol=unset#application/octet-stream diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 2bc24a24ab8..de17fd0dc8f 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -36,11 +36,17 @@ include_directories( BEFORE ./ ./include ../../include ) find_package(CGAL COMPONENTS Qt4) include( ${CGAL_USE_FILE} ) +option( POLYHEDRON_QTSCRIPT_DEBUGGER + "Activate the use of Qt Script Debugger in Polyhedron_3 demo" OFF) + # Find Qt4 itself set( QT_USE_QTXML TRUE ) set( QT_USE_QTMAIN TRUE ) set( QT_USE_QTSCRIPT TRUE ) set( QT_USE_QTOPENGL TRUE ) +if( POLYHEDRON_QTSCRIPT_DEBUGGER) + set( QT_USE_QTSCRIPTTOOLS TRUE ) +endif() find_package(Qt4) # Find OpenGL @@ -49,6 +55,7 @@ find_package(OpenGL) # Find QGLViewer if(QT4_FOUND) include(${QT_USE_FILE}) + include_directories( ${QT_INCLUDE_DIR}/QtScriptTools ) find_package(QGLViewer ) endif(QT4_FOUND) @@ -81,6 +88,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) endif(LAPACK_FOUND) qt4_wrap_ui( MainWindowUI_files MainWindow.ui ) + qt4_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) qt4_wrap_ui( remeshingUI_FILES Remeshing_dialog.ui) qt4_wrap_ui( meshingUI_FILES Meshing_dialog.ui Meshing_pause_widget.ui ) @@ -103,7 +111,9 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) Scene_polyhedron_item.cpp Scene_textured_polyhedron_item.cpp Scene_c2t3_item.cpp - Scene_nef_polyhedron_item.cpp) + Scene_nef_polyhedron_item.cpp + Show_point_dialog.cpp + ) # AUXILIARY LIBRARIES @@ -127,6 +137,8 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) ${OPENGL_glu_LIBRARY} ) + add_library(point_dialog Show_point_dialog.cpp Show_point_dialog.ui ${Show_point_dialogUI_FILES} ) + add_library(scene_c2t3_item SHARED Scene_c2t3_item.cpp Scene_c2t3_item.moc) target_link_libraries(scene_c2t3_item demo_framework) @@ -183,8 +195,13 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) # Link with Qt libraries + if( POLYHEDRON_QTSCRIPT_DEBUGGER ) + add_definitions( -DQT_SCRIPTTOOLS_LIB ) + target_link_libraries( Polyhedron_3 QtScriptTools ) + endif() target_link_libraries( Polyhedron_3 ${QT_LIBRARIES} ) target_link_libraries( Polyhedron_3 demo_framework ) + target_link_libraries( Polyhedron_3 point_dialog ) # Link with CGAL target_link_libraries( Polyhedron_3 ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 6dee0b44be5..e6f25314f68 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -10,17 +10,94 @@ #include #include #include +#include +#include #include #include #include #include #include +#include +#include +#include +#include + +#ifdef QT_SCRIPT_LIB +# include +# ifdef QT_SCRIPTTOOLS_LIB +# include +# endif +#endif #include "Polyhedron_demo_plugin_interface.h" #include "Polyhedron_demo_io_plugin_interface.h" #include "ui_MainWindow.h" +#include "Show_point_dialog.h" + +#ifdef QT_SCRIPT_LIB +# include +# include + +QScriptValue +myScene_itemToScriptValue(QScriptEngine *engine, + Scene_item* const &in) +{ + return engine->newQObject(in); +} + +void myScene_itemFromScriptValue(const QScriptValue &object, + Scene_item* &out) +{ + out = qobject_cast(object.toQObject()); +} +#endif // QT_SCRIPT_LIB + +#ifdef QT_SCRIPT_LIB +# ifdef QT_SCRIPTTOOLS_LIB + +const QScriptEngineDebugger::DebuggerWidget debug_widgets[9] = { + QScriptEngineDebugger::ConsoleWidget, + QScriptEngineDebugger::StackWidget, + QScriptEngineDebugger::ScriptsWidget, + QScriptEngineDebugger::LocalsWidget, + QScriptEngineDebugger::CodeWidget, + QScriptEngineDebugger::CodeFinderWidget, + QScriptEngineDebugger::BreakpointsWidget, + QScriptEngineDebugger::DebugOutputWidget, + QScriptEngineDebugger::ErrorLogWidget +}; +const QString debug_widgets_names[9] = { + "Script console", + "Stack", + "Scripts", + "Locals", + "Code", + "CodeFinder", + "Breakpoints", + "DebugOutput", + "ErrorLog" +}; + +# endif +#endif + +QScriptValue myPrintFunction(QScriptContext *context, QScriptEngine *engine) +{ + MainWindow* mw = qobject_cast(engine->parent()); + QString result; + for (int i = 0; i < context->argumentCount(); ++i) { + if (i > 0) + result.append(" "); + result.append(context->argument(i).toString()); + } + + if(mw) mw->message(QString("QtScript: ") + result, ""); + + return engine->undefinedValue(); +} + MainWindow::~MainWindow() { delete ui; @@ -70,6 +147,10 @@ MainWindow::MainWindow(QWidget* parent) connect(scene, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex & )), this, SLOT(updateInfo())); + + connect(scene, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex & )), + this, SLOT(updateDisplayInfo())); + connect(scene, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex & )), viewer, SLOT(updateGL())); @@ -86,12 +167,37 @@ MainWindow::MainWindow(QWidget* parent) SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & ) ), this, SLOT(updateInfo())); + connect(treeView->selectionModel(), + SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & ) ), + this, SLOT(updateDisplayInfo())); + connect(treeView->selectionModel(), SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & ) ), this, SLOT(selectionChanged())); + treeView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(treeView, SIGNAL(customContextMenuRequested(const QPoint & )), + this, SLOT(showSceneContextMenu(const QPoint &))); + connect(viewer, SIGNAL(selected(int)), this, SLOT(selectSceneItem(int))); + connect(viewer, SIGNAL(selectedPoint(double, double, double)), + this, SLOT(showSelectedPoint(double, double, double))); + + connect(viewer, SIGNAL(selectionRay(double, double, double, + double, double, double)), + scene, SIGNAL(selectionRay(double, double, double, + double, double, double))); + + connect(viewer, SIGNAL(requestContextMenu(QPoint)), + this, SLOT(contextMenuRequested(QPoint))); + connect(ui->infoLabel, SIGNAL(customContextMenuRequested(const QPoint & )), + this, SLOT(showSceneContextMenu(const QPoint &))); + + connect(ui->actionRecenterScene, SIGNAL(triggered()), + viewer->camera(), SLOT(interpolateToFitScene())); + connect(ui->actionRecenterScene, SIGNAL(triggered()), + viewer, SLOT(update())); connect(ui->actionAntiAliasing, SIGNAL(toggled(bool)), viewer, SLOT(setAntiAliasing(bool))); @@ -100,7 +206,7 @@ MainWindow::MainWindow(QWidget* parent) viewer, SLOT(setTwoSides(bool))); // enable anti-aliasing by default - ui->actionAntiAliasing->setChecked(true); + // ui->actionAntiAliasing->setChecked(true); // add the "About CGAL..." and "About demo..." entries this->addAboutCGAL(); @@ -116,6 +222,10 @@ MainWindow::MainWindow(QWidget* parent) connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(quit())); + // Connect "Select all items" + connect(ui->actionSelect_all_items, SIGNAL(triggered()), + this, SLOT(selectAll())); + // Recent files menu this->addRecentFiles(ui->menuFile, ui->actionQuit); connect(this, SIGNAL(openRecentFile(QString)), @@ -124,10 +234,118 @@ MainWindow::MainWindow(QWidget* parent) // Reset the "Operation menu" clearMenu(ui->menuOperations); +#ifdef QT_SCRIPT_LIB + std::cerr << "Enable scripts.\n"; + script_engine = new QScriptEngine(this); + qScriptRegisterMetaType(script_engine, + myScene_itemToScriptValue, + myScene_itemFromScriptValue); +# ifdef QT_SCRIPTTOOLS_LIB + QScriptEngineDebugger* debugger = new QScriptEngineDebugger(this); + debugger->setObjectName("qt script debugger"); + QAction* debuggerMenuAction = + menuBar()->addMenu(debugger->createStandardMenu()); + debuggerMenuAction->setText(tr("Qt Script &debug")); + for(unsigned int i = 0; i < 9; ++i) + { + QDockWidget* dock = new QDockWidget(debug_widgets_names[i], this); + dock->setObjectName(debug_widgets_names[i]); + dock->setWidget(debugger->widget(debug_widgets[i])); + this->addDockWidget(Qt::BottomDockWidgetArea, dock); + dock->hide(); + } + debugger->setAutoShowStandardWindow(false); + debugger->attachTo(script_engine); +# endif // QT_SCRIPTTOOLS_LIB + QScriptValue fun = script_engine->newFunction(myPrintFunction); + script_engine->globalObject().setProperty("print", fun); + + evaluate_script("print('hello', 'world', 'from QtScript!')"); + QScriptValue mainWindowObjectValue = script_engine->newQObject(this); + script_engine->globalObject().setProperty("main_window", mainWindowObjectValue); + + QScriptValue sceneObjectValue = script_engine->newQObject(scene); + mainWindowObjectValue.setProperty("scene", sceneObjectValue); + script_engine->globalObject().setProperty("scene", sceneObjectValue); + + QScriptValue viewerObjectValue = script_engine->newQObject(viewer); + mainWindowObjectValue.setProperty("viewer", viewerObjectValue); + script_engine->globalObject().setProperty("viewer", viewerObjectValue); + + QScriptValue cameraObjectValue = script_engine->newQObject(viewer->camera()); + viewerObjectValue.setProperty("camera", cameraObjectValue); + script_engine->globalObject().setProperty("camera", cameraObjectValue); + + evaluate_script("var plugins = new Array();"); +# ifdef QT_SCRIPTTOOLS_LIB + QScriptValue debuggerObjectValue = script_engine->newQObject(debugger); + script_engine->globalObject().setProperty("debugger", debuggerObjectValue); +# endif +#endif + // Load plugins, and re-enable actions that need it. loadPlugins(); readSettings(); // Among other things, the column widths are stored. + +#ifdef QT_SCRIPT_LIB + // evaluate_script("print(plugins);"); + Q_FOREACH(QAction* action, findChildren()) { + if(action->objectName() != "") { + QScriptValue objectValue = script_engine->newQObject(action); + script_engine->globalObject().setProperty(action->objectName(), + objectValue); + } + } + // debugger->action(QScriptEngineDebugger::InterruptAction)->trigger(); +#endif +} + +#ifdef QT_SCRIPT_LIB +void MainWindow::evaluate_script(QString script, + const QString& filename, + const bool quiet) { + QScriptValue value = script_engine->evaluate(script); + if(script_engine->hasUncaughtException()) { + QTextStream err(stderr); + err << "Qt Script exception:\n" + << script_engine->uncaughtException().toString() + << "\nBacktrace:\n"; + Q_FOREACH(QString line, script_engine->uncaughtExceptionBacktrace()) { + err << " " << line << "\n"; + } + } + else if(!quiet && !value.isNull() && !value.isUndefined()) { + QTextStream(stderr) << "Qt Script evaluated to \"" + << value.toString() << "\"\n"; + } +} + +void MainWindow::evaluate_script_quiet(QString script, + const QString& filename) +{ + evaluate_script(script, filename, true); +} +#endif + +void MainWindow::enableScriptDebugger(bool b /* = true */) +{ + Q_UNUSED(b); +#ifdef QT_SCRIPT_LIB +# ifdef QT_SCRIPTTOOLS_LIB + QScriptEngineDebugger* debugger = + findChild("qt script debugger"); + if(debugger) { + if(b) { + debugger->action(QScriptEngineDebugger::InterruptAction)->trigger(); + } + } + return; +# endif +#endif + // If we are here, then the debugger is not available + this->error(tr("Your version of Qt is too old, and for that reason" + "the Qt Script Debugger is not available.")); } void MainWindow::loadPlugins() @@ -140,7 +358,7 @@ void MainWindow::loadPlugins() QList plugins_directories; plugins_directories << qApp->applicationDirPath(); - QString env_path = ::getenv("POLYHEDRON_DEMO_PLUGINS_PATH"); + QString env_path = qgetenv("POLYHEDRON_DEMO_PLUGINS_PATH"); if(!env_path.isEmpty()) { Q_FOREACH (QString pluginsDir, env_path.split(":", QString::SkipEmptyParts)) { @@ -154,11 +372,15 @@ void MainWindow::loadPlugins() qPrintable(pluginsDir.absolutePath())); Q_FOREACH (QString fileName, pluginsDir.entryList(QDir::Files)) { if(fileName.contains("plugin") && QLibrary::isLibrary(fileName)) { - qDebug("### Loading \"%s\"...", fileName.toUtf8().data()); + qDebug("### Loading \"%s\"...", qPrintable(fileName)); QPluginLoader loader; loader.setFileName(pluginsDir.absoluteFilePath(fileName)); QObject *obj = loader.instance(); if(obj) { + QString name = fileName; + name.remove(QRegExp("^lib")); + name.remove(QRegExp("\\..*")); + obj->setObjectName(name); initPlugin(obj); initIOPlugin(obj); } @@ -172,6 +394,11 @@ void MainWindow::loadPlugins() } } +bool MainWindow::hasPlugin(QString pluginName) +{ + return plugins.contains(pluginName); +} + bool MainWindow::initPlugin(QObject* obj) { QObjectList childs = this->children(); @@ -180,6 +407,13 @@ bool MainWindow::initPlugin(QObject* obj) if(plugin) { // Call plugin's init() method plugin->init(this, this->scene, this); + plugins << obj->objectName(); +#ifdef QT_SCRIPT_LIB + QScriptValue objectValue = + script_engine->newQObject(obj); + script_engine->globalObject().setProperty(obj->objectName(), objectValue); + evaluate_script_quiet(QString("plugins.push(%1);").arg(obj->objectName())); +#endif Q_FOREACH(QAction* action, plugin->actions()) { // If action does not belong to the menus, add it to "Operations" menu @@ -201,6 +435,7 @@ bool MainWindow::initIOPlugin(QObject* obj) qobject_cast(obj); if(plugin) { // std::cerr << "I/O plugin\n"; + plugins << obj->objectName(); io_plugins << plugin; return true; } @@ -240,12 +475,51 @@ void MainWindow::addAction(QAction* action) } } +void MainWindow::addAction(QString actionName, + QString actionText, + QString menuName) { + QMenu* menu = 0; + Q_FOREACH(QAction* action, findChildren()) { + if(!action->menu()) continue; + QString menuText = action->menu()->title(); + if(menuText != menuName) continue; + menu = action->menu(); + } + if(menu == 0) { + menu = new QMenu(menuName, this); + menuBar()->insertMenu(ui->menuView->menuAction(), menu); + } + QAction* action = new QAction(actionText, this); + action->setObjectName(actionName); + menu->addAction(action); +#ifdef QT_SCRIPT_LIB + QScriptValue objectValue = script_engine->newQObject(action); + script_engine->globalObject().setProperty(action->objectName(), + objectValue); +#endif +} + +void MainWindow::viewerShow(float x, float y, float z) { + viewer->camera()->setRevolveAroundPoint(qglviewer::Vec(x, y, z)); + // viewer->camera()->lookAt(qglviewer::Vec(x, y, z)); + + qglviewer::ManipulatedCameraFrame backup_frame(*viewer->camera()->frame()); + viewer->camera()->fitSphere(qglviewer::Vec(x, y, z), + viewer->camera()->sceneRadius()/100); + qglviewer::ManipulatedCameraFrame new_frame(*viewer->camera()->frame()); + *viewer->camera()->frame() = backup_frame; + viewer->camera()->interpolateTo(new_frame, 1.f); + viewer->setVisualHintsMask(1); +} + void MainWindow::message(QString message, QString colorName, QString font) { if (message.endsWith('\n')) { message.remove(message.length()-1, 1); } + std::cerr << qPrintable(message) << std::endl; statusBar()->showMessage(message, 5000); - message = "" + message + "
"; + message = "" + + message + "
"; message = "[" + QTime::currentTime().toString() + "] " + message; ui->consoleTextEdit->insertHtml(message); ui->consoleTextEdit->verticalScrollBar()->setValue(ui->consoleTextEdit->verticalScrollBar()->maximum()); @@ -282,21 +556,101 @@ void MainWindow::updateViewerBBox() viewer->camera()->showEntireScene(); } -void MainWindow::open(QString filename) +void MainWindow::reload_item() { + QAction* sender_action = qobject_cast(sender()); + if(!sender_action) return; + + bool ok; + int item_index = sender_action->data().toInt(&ok); + QObject* item_object = scene->item(item_index); + if(!ok || !item_object || sender_action->data().type() != QVariant::Int) { + std::cerr << "Cannot reload item: " + << "the reload action has not item attached\n"; + return; + } + Scene_item* item = qobject_cast(item_object); + if(!item) { + std::cerr << "Cannot reload item: " + << "the reload action has a QObject* pointer attached\n" + << "that is not a Scene_item*\n"; + return; + } + QString filename = item->property("source filename").toString(); + if(filename.isEmpty()) { + std::cerr << "Cannot reload item: " + << "the item has not filename attached\n"; + return; + } + QFileInfo fileinfo(filename); + if(! (fileinfo.isFile() && fileinfo.isReadable()) ) { + std::cerr << "Cannot reload item: " + << "cannot read file " << qPrintable(filename) << " \n"; + return; + } + Scene_item* new_item = load_item(fileinfo); + if(!new_item) { + std::cerr << "Cannot reload item: " + << "file " << qPrintable(filename) << " is not an item\n"; + return; + } + new_item->setName(item->name()); + new_item->setColor(item->color()); + new_item->setRenderingMode(item->renderingMode()); + new_item->setVisible(item->visible()); + new_item->setProperty("source filename", item->property("source filename")); + new_item->changed(); + scene->replaceItem(item_index, new_item); + delete item; +} + +Scene_item* MainWindow::load_item(QFileInfo fileinfo) const { + Scene_item* item = 0; + Q_FOREACH(Polyhedron_demo_io_plugin_interface* plugin, + io_plugins) + { + if(plugin->canLoad()) { + item = plugin->load(fileinfo); + if(item) break; // go out of the loop + } + } + return item; +} + +void MainWindow::open(QString filename, bool no_popup) { +#ifdef QT_SCRIPT_LIB + QString program; + if(filename.startsWith("javascript:")) { + program=filename.right(filename.size() - 11); + } + if(filename.startsWith("qtscript:")) { + program=filename.right(filename.size() - 9); + } + if(filename.endsWith(".js")) { + QFile script_file(filename); + script_file.open(QIODevice::ReadOnly); + program = script_file.readAll(); + } + if(!program.isEmpty()) + { + { + QTextStream(stderr) << "Execution of script \"" + << filename << "\"\n"; + // << filename << "\", with following content:\n" + // << program; + } + evaluate_script(program, filename); + return; + } +#endif + QFileInfo fileinfo(filename); Scene_item* item = 0; if(fileinfo.isFile() && fileinfo.isReadable()) { - Q_FOREACH(Polyhedron_demo_io_plugin_interface* plugin, - io_plugins) - { - if(plugin->canLoad()) { - item = plugin->load(fileinfo); - if(item) break; // go out of the loop - } - } + item = load_item(fileinfo); if(item) { Scene::Item_id index = scene->addItem(item); + item->setProperty("source filename", fileinfo.absoluteFilePath()); QSettings settings; settings.setValue("OFF open directory", fileinfo.absoluteDir().absolutePath()); @@ -304,6 +658,7 @@ void MainWindow::open(QString filename) selectSceneItem(index); } else { + if(no_popup) return; QMessageBox::critical(this, tr("Cannot open file"), tr("File %1 has not a known file format.") @@ -311,6 +666,7 @@ void MainWindow::open(QString filename) } } else { + if(no_popup) return; QMessageBox::critical(this, tr("Cannot open file"), tr("File %1 is not a readable file.") @@ -327,18 +683,62 @@ void MainWindow::selectSceneItem(int i) QItemSelectionModel::ClearAndSelect); } +void MainWindow::showSelectedPoint(double x, double y, double z) +{ + information(QString("Selected point: (%1, %2, %3)"). + arg(x, 0, 'g', 10). + arg(y, 0, 'g', 10). + arg(z, 0, 'g', 10)); +} + +void MainWindow::unSelectSceneItem(int i) +{ + removeSceneItemFromSelection(i); +} + +void MainWindow::addSceneItemInSelection(int i) +{ + treeView->selectionModel()->select(scene->createSelection(i), + QItemSelectionModel::Select); + scene->itemChanged(i); +} + +void MainWindow::removeSceneItemFromSelection(int i) +{ + treeView->selectionModel()->select(scene->createSelection(i), + QItemSelectionModel::Deselect); + scene->itemChanged(i); +} + +void MainWindow::selectAll() +{ + treeView->selectionModel()->select(scene->createSelectionAll(), + QItemSelectionModel::ClearAndSelect); +} + int MainWindow::getSelectedSceneItemIndex() const { QModelIndexList selectedRows = treeView->selectionModel()->selectedRows(); - if(selectedRows.empty()) + if(selectedRows.size() != 1) return -1; else return selectedRows.first().row(); } +QList MainWindow::getSelectedSceneItemIndices() const +{ + QModelIndexList selectedRows = treeView->selectionModel()->selectedRows(); + QList result; + Q_FOREACH(QModelIndex index, selectedRows) { + result << index.row(); + } + return result; +} + void MainWindow::selectionChanged() { scene->setSelectedItem(getSelectedSceneItemIndex()); + scene->setSelectedItemsList(getSelectedSceneItemIndices()); Scene_item* item = scene->item(getSelectedSceneItemIndex()); if(item != NULL && item->manipulatable()) { viewer->setManipulatedFrame(item->manipulatedFrame()); @@ -349,6 +749,53 @@ void MainWindow::selectionChanged() viewer->updateGL(); } +void MainWindow::contextMenuRequested(const QPoint& global_pos) { + int index = scene->mainSelectionIndex(); + showSceneContextMenu(index, global_pos); +} + +void MainWindow::showSceneContextMenu(int selectedItemIndex, + const QPoint& global_pos) +{ + Scene_item* item = scene->item(selectedItemIndex); + if(!item) return; + + const char* prop_name = "Menu modified by MainWindow."; + + QMenu* menu = item->contextMenu(); + if(menu && !item->property("source filename").toString().isEmpty()) { + bool menuChanged = menu->property(prop_name).toBool(); + if(!menuChanged) { + menu->addSeparator(); + QAction* reload = menu->addAction(tr("Reload item from file")); + reload->setData(qVariantFromValue(selectedItemIndex)); + connect(reload, SIGNAL(triggered()), + this, SLOT(reload_item())); + menu->setProperty(prop_name, true); + } + } + if(menu) + menu->exec(global_pos); +} + +void MainWindow::showSceneContextMenu(const QPoint& p) { + QWidget* sender = qobject_cast(this->sender()); + if(!sender) return; + + int index = -1; + if(sender == treeView) { + QModelIndex modelIndex = treeView->indexAt(p); + if(!modelIndex.isValid()) return; + + index = modelIndex.row(); + } + else { + index = scene->mainSelectionIndex(); + } + + showSceneContextMenu(index, sender->mapToGlobal(p)); +} + void MainWindow::removeManipulatedFrame(Scene_item* item) { if(item->manipulatable() && @@ -359,12 +806,26 @@ void MainWindow::removeManipulatedFrame(Scene_item* item) void MainWindow::updateInfo() { Scene_item* item = scene->item(getSelectedSceneItemIndex()); - if(item) - ui->infoLabel->setText(item->toolTip()); + if(item) { + QString item_text = item->toolTip(); + QString item_filename = item->property("source filename").toString(); + if(!item_filename.isEmpty()) { + item_text += QString("
File: %1").arg(item_filename); + } + ui->infoLabel->setText(item_text); + } else ui->infoLabel->clear(); } +void MainWindow::updateDisplayInfo() { + Scene_item* item = scene->item(getSelectedSceneItemIndex()); + if(item) + ui->displayLabel->setPixmap(item->graphicalToolTip()); + else + ui->displayLabel->clear(); +} + void MainWindow::readSettings() { this->readState("MainWindow", Size|State); @@ -390,12 +851,25 @@ void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::on_actionLoad_triggered() { QStringList filters; + QStringList extensions; Q_FOREACH(Polyhedron_demo_io_plugin_interface* plugin, io_plugins) { if(plugin->canLoad()) { - filters += plugin->nameFilters(); + Q_FOREACH(QString filter, plugin->nameFilters()) { + if(!filter.isEmpty()) { + QRegExp re1("\\((.+)\\)"); + if(re1.indexIn(filter) != -1) { + QString filter_extensions = re1.cap(1); + extensions += filter_extensions.simplified().split(" "); + } + filters << filter; + } + } } } + QStringList sorted_extensions = extensions.toSet().toList(); filters << tr("All files (*)"); + filters.push_front(QString("All know files (%1)") + .arg(sorted_extensions.join(" "))); QSettings settings; QString directory = settings.value("OFF open directory", @@ -444,19 +918,15 @@ void MainWindow::on_actionSaveAs_triggered() QFileDialog::getSaveFileName(this, tr("Save to File..."), QString(), - tr("OFF files (*.off)\n" - "All files (*)")); - QFileInfo fileinfo(filename); - if(!fileinfo.isFile() || - QMessageBox::warning(this, - tr("File exists"), - tr("The file %1 already exists! Continue?") - .arg(filename), - QMessageBox::Yes|QMessageBox::No) == - QMessageBox::Yes) - { + filters.join(";;")); + save(filename, item); +} - Q_FOREACH(Polyhedron_demo_io_plugin_interface* plugin, canSavePlugins) { +void MainWindow::save(QString filename, Scene_item* item) { + QFileInfo fileinfo(filename); + + Q_FOREACH(Polyhedron_demo_io_plugin_interface* plugin, io_plugins) { + if(plugin->canSave(item)) { if(plugin->save(item, fileinfo)) break; } @@ -465,9 +935,9 @@ void MainWindow::on_actionSaveAs_triggered() bool MainWindow::on_actionErase_triggered() { - int index = scene->erase(getSelectedSceneItemIndex()); - selectSceneItem(index); - return index >= 0; + int next_index = scene->erase(scene->selectionIndices()); + selectSceneItem(next_index); + return next_index >= 0; } void MainWindow::on_actionEraseAll_triggered() @@ -505,6 +975,49 @@ void MainWindow::on_actionSetPolyhedronB_triggered() scene->setItemB(i); } +void MainWindow::on_actionSetBackgroundColor_triggered() +{ + QColor c = QColorDialog::getColor(); + if(c.isValid()) { + viewer->setBackgroundColor(c); + } +} + +void MainWindow::on_action_Look_at_triggered() +{ + Show_point_dialog dialog(this); + int i = dialog.exec(); + if( i == QDialog::Accepted && + dialog.has_correct_coordinates() ) + { + viewerShow((float)dialog.get_x(), + (float)dialog.get_y(), + (float)dialog.get_z()); + } +} + +QString MainWindow::camera_string() const +{ + return viewer->dumpCameraCoordinates(); +} + +void MainWindow::on_actionDumpCamera_triggered() +{ + information(QString("Camera: %1") + .arg(camera_string())); +} + +void MainWindow::on_action_Copy_camera_triggered() +{ + qApp->clipboard()->setText(this->camera_string()); +} + +void MainWindow::on_action_Paste_camera_triggered() +{ + QString s = qApp->clipboard()->text(); + viewer->moveCameraToCoordinates(s, 0.5f); +} + void MainWindow::setAddKeyFrameKeyboardModifiers(::Qt::KeyboardModifiers m) { viewer->setAddKeyFrameKeyboardModifiers(m); diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index d6d13bfe50e..e030162fa8f 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -4,8 +4,14 @@ #include #include +#ifdef QT_SCRIPT_LIB +# include +#endif #include +#include +#include +#include class Scene; class Viewer; @@ -35,22 +41,44 @@ public: public slots: void updateViewerBBox(); - void open(QString filename); + void open(QString filename, bool no_popup = false); + Scene_item* load_item(QFileInfo) const; + void reload_item(); void selectSceneItem(int i); + void showSelectedPoint(double, double, double); + void unSelectSceneItem(int i); + void selectAll(); + void addSceneItemInSelection(int i); + void removeSceneItemFromSelection(int i); // same as unSelectSceneItem void setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers); void clearMenu(QMenu*); void addAction(QAction*); + void addAction(QString actionName, + QString actionText, + QString menuName); + void viewerShow(float, float, float); void information(QString); void warning(QString); void error(QString); + void message(QString, QString, QString = QString("normal")); + + bool hasPlugin(QString); + void enableScriptDebugger(bool = true); protected slots: void selectionChanged(); + + void contextMenuRequested(const QPoint& global_pos); + void showSceneContextMenu(int selectedItemIndex, + const QPoint& global_pos); + void showSceneContextMenu(const QPoint& local_pos_of_treeview); + void updateInfo(); + void updateDisplayInfo(); void removeManipulatedFrame(Scene_item*); // settings @@ -73,9 +101,18 @@ protected slots: // save as... void on_actionSaveAs_triggered(); + void save(QString filename, Scene_item* item); + + void on_actionSetBackgroundColor_triggered(); + + void on_action_Look_at_triggered(); + + QString camera_string() const; + void on_actionDumpCamera_triggered(); + void on_action_Copy_camera_triggered(); + void on_action_Paste_camera_triggered(); protected: - void message(QString, QString, QString = QString("normal")); void loadPlugins(); bool initPlugin(QObject*); bool initIOPlugin(QObject*); @@ -84,6 +121,7 @@ protected: bool onePolygonIsSelected() const; int getSelectedSceneItemIndex() const; + QList getSelectedSceneItemIndices() const; private: QString strippedName(const QString &fullFileName); @@ -93,6 +131,16 @@ private: QTreeView* treeView; Ui::MainWindow* ui; QVector io_plugins; + QStringList plugins; +#ifdef QT_SCRIPT_LIB + QScriptEngine* script_engine; +public: + void evaluate_script(QString script, + const QString & fileName = QString(), + const bool quiet = false); + void evaluate_script_quiet(QString script, + const QString & fileName = QString()); +#endif }; #endif // ifndef MAINWINDOW_H diff --git a/Polyhedron/demo/Polyhedron/MainWindow.ui b/Polyhedron/demo/Polyhedron/MainWindow.ui index f48127f67a7..85fe822068d 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.ui +++ b/Polyhedron/demo/Polyhedron/MainWindow.ui @@ -1,4 +1,3 @@ - MainWindow @@ -29,9 +28,6 @@ - - - @@ -40,7 +36,7 @@ 0 0 978 - 26 + 23 @@ -62,6 +58,7 @@ + @@ -124,9 +121,21 @@ + + + Ca&mera + + + + + + + + + @@ -139,7 +148,7 @@ - Polyhedra + Geometric Objects 1 @@ -206,6 +215,9 @@ true + + QAbstractItemView::ExtendedSelection + 0 @@ -238,6 +250,45 @@ + + + Infos + + + 1 + + + + + + + 0 + + + + + Qt::CustomContextMenu + + + 0 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + + + + + + &Quit @@ -431,17 +482,11 @@ Set polyhedron A - - Ctrl+A - Set polyhedron B - - Ctrl+B - @@ -453,6 +498,11 @@ &Remeshing + + + Convex Decomposition + + Mean &value coordinates @@ -489,6 +539,19 @@ Ctrl+T + + + Re&center scene + + + Ctrl+C + + + + + Change &background color... + + &Minkowski sum @@ -497,9 +560,32 @@ Ctrl+O, M - + - Convex Decomposition + &Look at... + + + + + &Dump camera coordinates + + + + + &Copy camera + + + + + &Paste camera + + + + + Select all items + + + Ctrl+A diff --git a/Polyhedron/demo/Polyhedron/Point_dialog_config.h b/Polyhedron/demo/Polyhedron/Point_dialog_config.h new file mode 100644 index 00000000000..4133f9776b6 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Point_dialog_config.h @@ -0,0 +1,12 @@ +#ifndef POINT_DIALOG_CONFIG_H +#define POINT_DIALOG_CONFIG_H + +#include + +#ifdef point_dialog_EXPORTS +# define POINT_DIALOG_EXPORT Q_DECL_EXPORT +#else +# define POINT_DIALOG_EXPORT Q_DECL_IMPORT +#endif + +#endif // POINT_DIALOG_CONFIG_H diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_3.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_3.cpp index c03c4b22ffc..ba0eb98f23e 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_3.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_3.cpp @@ -25,11 +25,26 @@ int main(int argc, char **argv) mainWindow.setAddKeyFrameKeyboardModifiers(::Qt::MetaModifier); args.removeAt(0); } - +#ifdef QT_SCRIPT_LIB + if(!args.empty() && args[0] == "--debug-scripts") + { + mainWindow.enableScriptDebugger(); + args.removeAt(0); + } + mainWindow.open("autostart.js", true); +#endif Q_FOREACH(QString filename, args) { mainWindow.open(filename); } - return app.exec(); + + // A Qt Script may have closed the main window + // The following loop launch app.exec() only if there is a visible + // window. + Q_FOREACH (QWidget *widget, QApplication::topLevelWidgets()) { + if(widget->isVisible()) + return app.exec(); + } + return 0; } #ifndef USE_FORWARD_DECL diff --git a/Polyhedron/demo/Polyhedron/Show_point_dialog.cpp b/Polyhedron/demo/Polyhedron/Show_point_dialog.cpp new file mode 100644 index 00000000000..c0802a85457 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Show_point_dialog.cpp @@ -0,0 +1,73 @@ +#include "Show_point_dialog.h" +#include "ui_Show_point_dialog.h" + +Show_point_dialog::Show_point_dialog(QWidget* parent) + : QDialog(parent) + , ui(new Ui::Show_point_dialog) + , m_has_correct_coordinates(false) +{ + ui->setupUi(this); + + connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), + this, SLOT(interprete_string(const QString&))); +} + +Show_point_dialog::~Show_point_dialog() +{ + delete ui; +} + +void Show_point_dialog::interprete_string(const QString& string) +{ + QString double_re("([-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?)"); + QString not_double_char_re("[^0-9-+.eE]"); + QString full_re = QString("^") + + not_double_char_re + "*" + + double_re + + not_double_char_re + "+" + + double_re + + not_double_char_re + "+" + + double_re + + "(" + not_double_char_re + "*" + + "|" + not_double_char_re + "+" + double_re + + ")" + + "$"; + QRegExp re(full_re); + if(re.exactMatch(string)) { + // const double x = re.cap(1).toDouble(); + // const double y = re.cap(2).toDouble(); + // const double z = re.cap(3).toDouble(); + ui->coord_x->setText(QString(re.cap(1))); + ui->coord_y->setText(QString(re.cap(2))); + ui->coord_z->setText(QString(re.cap(3))); + m_has_correct_coordinates = true; + } + else { + ui->coord_x->setText(QString()); + ui->coord_y->setText(QString()); + ui->coord_z->setText(QString()); + m_has_correct_coordinates = false; + } +} + +double Show_point_dialog::get_x() const +{ + return ui->coord_x->text().toDouble(); +} + +double Show_point_dialog::get_y() const +{ + return ui->coord_y->text().toDouble(); +} + +double Show_point_dialog::get_z() const +{ + return ui->coord_z->text().toDouble(); +} + +bool Show_point_dialog::has_correct_coordinates() const +{ + return m_has_correct_coordinates; +} + +#include "Show_point_dialog.moc" diff --git a/Polyhedron/demo/Polyhedron/Show_point_dialog.h b/Polyhedron/demo/Polyhedron/Show_point_dialog.h new file mode 100644 index 00000000000..5a00b0485de --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Show_point_dialog.h @@ -0,0 +1,35 @@ +#ifndef SHOW_POINT_DIALOG_H +#define SHOW_POINT_DIALOG_H +#include "config.h" + +#include "Point_dialog_config.h" + +#include + +namespace Ui { + class Show_point_dialog; +} + +class POINT_DIALOG_EXPORT Show_point_dialog : + public QDialog +{ + Q_OBJECT +public: + Show_point_dialog(QWidget* parent = 0); + ~Show_point_dialog(); + + bool has_correct_coordinates() const; + + double get_x() const; + double get_y() const; + double get_z() const; + +protected slots: + void interprete_string(const QString&); + +protected: + Ui::Show_point_dialog* ui; + bool m_has_correct_coordinates; +}; + +#endif diff --git a/Polyhedron/demo/Polyhedron/Show_point_dialog.ui b/Polyhedron/demo/Polyhedron/Show_point_dialog.ui new file mode 100644 index 00000000000..5543f27c91f --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Show_point_dialog.ui @@ -0,0 +1,161 @@ + + + Show_point_dialog + + + + 0 + 0 + 575 + 151 + + + + Dialog + + + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + Point &coordinates + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lineEdit + + + + + + + + 1 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu LGC Sans'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paste here the coordinates of a point. It can be for example:</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&quot;(10., -2e-2, .4)&quot;</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or:</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&quot;-2 3 5&quot;</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or even something with garbage around:</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&quot;point (-2, 5, 0) and...&quot;</p></body></html> + + + + + + + x + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + y + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + z + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + lineEdit + + + + + buttonBox + accepted() + Show_point_dialog + accept() + + + 423 + 120 + + + 387 + 139 + + + + + buttonBox + rejected() + Show_point_dialog + reject() + + + 520 + 120 + + + 512 + 138 + + + + + From cef624afb796416525ac5261bd4200644e3536c2 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 15:36:38 +0000 Subject: [PATCH 43/65] Begin to update Polyhedron demo from work done in the Mesh_3 dev'branch Step 3 (bis): I forgot those small but important patches. The compilation was OK. The run on Linux too, but there could have been runtime linking errors on Windows, and subtle runtime issues (such as a missing draw refresh). --- Polyhedron/demo/Polyhedron/Scene_interface.h | 6 ++++++ Polyhedron/demo/Polyhedron/Scene_item_config.h | 4 ++++ Polyhedron/demo/Polyhedron/Scene_item_with_display_list.cpp | 1 + 3 files changed, 11 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Scene_interface.h b/Polyhedron/demo/Polyhedron/Scene_interface.h index 6c3b85c26d2..f94ee24bd3a 100644 --- a/Polyhedron/demo/Polyhedron/Scene_interface.h +++ b/Polyhedron/demo/Polyhedron/Scene_interface.h @@ -3,6 +3,7 @@ #include #include +#include #include class Scene_item; @@ -50,6 +51,7 @@ public: virtual ~Scene_interface() {}; virtual Item_id addItem(Scene_item* item) = 0; + virtual Scene_item* replaceItem(Item_id, Scene_item*) = 0; virtual Item_id erase(Item_id) = 0; // Returns the index of the item just before the one that is erased, @@ -64,6 +66,7 @@ public: virtual size_t numberOfEntries() const = 0; virtual Scene_item* item(Item_id) const = 0; virtual Item_id mainSelectionIndex() const = 0; + virtual QList selectionIndices() const = 0; virtual Item_id selectionAindex() const = 0; virtual Item_id selectionBindex() const = 0; @@ -75,6 +78,9 @@ public: // Notify the scene that an item was modified virtual void itemChanged(Item_id i) = 0; virtual void itemChanged(Scene_item*) = 0; + + // Select an item + virtual void setSelectedItem(Item_id) = 0; }; // end interface Scene_interface diff --git a/Polyhedron/demo/Polyhedron/Scene_item_config.h b/Polyhedron/demo/Polyhedron/Scene_item_config.h index ac71781315e..08c864bdce5 100644 --- a/Polyhedron/demo/Polyhedron/Scene_item_config.h +++ b/Polyhedron/demo/Polyhedron/Scene_item_config.h @@ -3,6 +3,10 @@ #include +#ifdef demo_framework_EXPORTS +# define scene_item_EXPORTS +#endif + #ifdef scene_item_EXPORTS # define SCENE_ITEM_EXPORT Q_DECL_EXPORT #else diff --git a/Polyhedron/demo/Polyhedron/Scene_item_with_display_list.cpp b/Polyhedron/demo/Polyhedron/Scene_item_with_display_list.cpp index 07be9511902..f77c1574962 100644 --- a/Polyhedron/demo/Polyhedron/Scene_item_with_display_list.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_item_with_display_list.cpp @@ -69,4 +69,5 @@ void Scene_item_with_display_list::changed() for(int i = 0; i < NB_OF_DISPLAY_LISTS; ++i) { display_list_built[i] = false; } + Scene_item::changed(); } From 2f039d1b57b6d3880726652927285d5ae8b60cd1 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 15:42:04 +0000 Subject: [PATCH 44/65] Remove warnings. --- Polyhedron/demo/Polyhedron/texture.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/texture.cpp b/Polyhedron/demo/Polyhedron/texture.cpp index ff574ca5eb6..ae99232bbe7 100644 --- a/Polyhedron/demo/Polyhedron/texture.cpp +++ b/Polyhedron/demo/Polyhedron/texture.cpp @@ -972,7 +972,7 @@ void Texture::GenerateHStripes(unsigned int width, //*************************************** void Texture::GenerateGrid(unsigned int width, unsigned int height, - int size, + int /*size*/, unsigned int thickness, unsigned char r, unsigned char g, @@ -1016,7 +1016,7 @@ void Texture::GenerateGrid(unsigned int width, void Texture::GenerateGradientH(unsigned int width, unsigned int height, - int size) + int /*size*/) { Alloc(width,height,24); @@ -1034,7 +1034,7 @@ void Texture::GenerateGradientH(unsigned int width, } void Texture::GenerateGradientV(unsigned int width, unsigned int height, - int size) + int /*size*/) { Alloc(width,height,24); From 2111f2b39529a4d239e8bb3fc679962450c94229 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 15:48:04 +0000 Subject: [PATCH 45/65] Fix OFF I/O for polyhedra and Nef polyhedra --- .../Polyhedron/Polyhedron_demo_off_plugin.cpp | 2 +- .../Polyhedron_demo_off_to_nef_plugin.cpp | 2 +- .../Polyhedron/Scene_nef_polyhedron_item.cpp | 17 ++++++++++++++++- .../demo/Polyhedron/Scene_nef_polyhedron_item.h | 2 ++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_plugin.cpp index 5dc9fba218b..d21a51808e1 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_plugin.cpp @@ -32,7 +32,7 @@ bool Polyhedron_demo_off_plugin::canLoad() const { Scene_item* Polyhedron_demo_off_plugin::load(QFileInfo fileinfo) { - + if(fileinfo.suffix().toLower() != "off") return 0; // Open file std::ifstream in(fileinfo.filePath().toUtf8()); if(!in) { diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_to_nef_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_to_nef_plugin.cpp index 77874a6951e..4016bfffddd 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_to_nef_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_off_to_nef_plugin.cpp @@ -36,7 +36,7 @@ Polyhedron_demo_off_to_nef_plugin::load(QFileInfo fileinfo) { std::cerr << "Error!\n"; Scene_nef_polyhedron_item* item = new Scene_nef_polyhedron_item(); - if(!item->load(in)) + if(!item->load_from_off(in)) { delete item; return 0; diff --git a/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp index 83fc94f3d77..16473326d78 100644 --- a/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp @@ -5,6 +5,7 @@ #include // #include #include +#include #include #include @@ -49,7 +50,7 @@ Scene_nef_polyhedron_item::clone() const { } bool -Scene_nef_polyhedron_item::load(std::istream& in) +Scene_nef_polyhedron_item::load_from_off(std::istream& in) { // const std::size_t discarded = CGAL::OFF_to_nef_3(in, *nef_poly); // return discarded != 0; @@ -71,6 +72,20 @@ Scene_nef_polyhedron_item::font() const { return font; } +bool +Scene_nef_polyhedron_item::load(std::istream& in) +{ + in >> *nef_poly; + return in; +} + +bool +Scene_nef_polyhedron_item::save(std::ostream& in) const +{ + in << *nef_poly; + return in; +} + QString Scene_nef_polyhedron_item::toolTip() const { diff --git a/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.h index 974edfcf202..4e837aa9f8b 100644 --- a/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.h @@ -20,7 +20,9 @@ public: ~Scene_nef_polyhedron_item(); Scene_nef_polyhedron_item* clone() const; + bool load_from_off(std::istream& in); bool load(std::istream& in); + bool save(std::ostream& in) const; QFont font() const; QString toolTip() const; From 3adc79986da549fa6039f716e07709c910cce121 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 15:48:56 +0000 Subject: [PATCH 46/65] Update the triangulate_facets plugin, that was buggy in the trunk/next branch --- ...yhedron_demo_triangulate_facets_plugin.cpp | 213 ++---------------- 1 file changed, 14 insertions(+), 199 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_triangulate_facets_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_triangulate_facets_plugin.cpp index f1198a7013b..ddf73011158 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_triangulate_facets_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_triangulate_facets_plugin.cpp @@ -6,125 +6,9 @@ #include "Polyhedron_demo_plugin_helper.h" #include "Scene_polyhedron_item.h" #include "Polyhedron_type.h" -#include - -#include -#include - -#include -#include -#include -#include -#include #include "CGAL/compute_normal.h" - -#include - -typedef Polyhedron::Halfedge_handle Halfedge_handle; - -typedef CGAL::Triangulation_2_filtered_projection_traits_3 Traits; - -typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; - -struct Face_info { - Halfedge_handle e[3]; - bool is_external; -}; - -typedef CGAL::Triangulation_face_base_with_info_2 Fb1; - -typedef CGAL::Constrained_triangulation_face_base_2 Fb; -typedef CGAL::Triangulation_data_structure_2 TDS; -typedef CGAL::No_intersection_tag Itag; -typedef CGAL::Constrained_Delaunay_triangulation_2 CDTbase; -typedef CGAL::Constrained_triangulation_plus_2 CDT; - -typedef Polyhedron::HalfedgeDS HDS; - -class Triangulate_modifier : public CGAL::Modifier_base { - CDT* cdt; - Polyhedron::Facet_handle fh; - -public: - Triangulate_modifier(CDT* cdt, - Polyhedron::Facet_handle fh) - : cdt(cdt), fh(fh) - { - } - - bool is_external(CDT::Face_handle fh) const { - return fh->info().is_external; - } - - void operator()(HDS& hds) { - CGAL::HalfedgeDS_decorator decorator(hds); - typedef Polyhedron::Halfedge Halfedge; - - decorator.make_hole(fh->halfedge()); - for(CDT::Finite_edges_iterator - eit = cdt->finite_edges_begin(), - end = cdt->finite_edges_end(); - eit != end; ++eit) - { - CDT::Face_handle fh = eit->first; - const int index = eit->second; - CDT::Face_handle opposite_fh = fh->neighbor(eit->second); - const int opposite_index = opposite_fh->index(fh); - const CDT::Vertex_handle va = fh->vertex(cdt-> cw(index)); - const CDT::Vertex_handle vb = fh->vertex(cdt->ccw(index)); - - if( ! (is_external(fh) && is_external(opposite_fh)) && - ! cdt->is_constrained(*eit) ) - { - // strictly internal edge - Halfedge_handle h = hds.edges_push_back(Halfedge(), - Halfedge()); - fh->info().e[index] = h; - opposite_fh->info().e[opposite_index] = h->opposite(); - - decorator.set_vertex(h, va->info()->vertex()); - decorator.set_vertex(h->opposite(), vb->info()->vertex()); - } - if( cdt->is_constrained(*eit) ) - { - if(!is_external(fh)) { - fh->info().e[index] = va->info(); - } - if(!is_external(opposite_fh)) { - opposite_fh->info().e[opposite_index] = vb->info(); - } - } - } - for(CDT::Finite_faces_iterator - fit = cdt->finite_faces_begin(), - end = cdt->finite_faces_end(); - fit != end; ++fit) - { - if(!is_external(fit)) - { - Halfedge_handle h0 = fit->info().e[0]; - Halfedge_handle h1 = fit->info().e[1]; - Halfedge_handle h2 = fit->info().e[2]; - CGAL_assertion( h0 != Halfedge_handle() ); - CGAL_assertion( h1 != Halfedge_handle() ); - CGAL_assertion( h2 != Halfedge_handle() ); - - typedef Halfedge::Base HBase; - h0->HBase::set_next(h1); - decorator.set_prev(h1, h0); - h1->HBase::set_next(h2); - decorator.set_prev(h2, h1); - h2->HBase::set_next(h0); - decorator.set_prev(h0, h2); - - decorator.fill_hole(h0); - } - } - } -}; +#include "CGAL/triangulate_polyhedron.h" class Polyhedron_demo_triangulate_facets_plugin : public QObject, @@ -159,7 +43,6 @@ public: public slots: void untriangulate() { - CGAL::set_error_behaviour(CGAL::ABORT); const Scene_interface::Item_id index = scene->mainSelectionIndex(); Scene_polyhedron_item* item = @@ -187,7 +70,7 @@ public slots: !eit_copy->vertex()->is_bivalent() && !eit_copy->opposite()->vertex()->is_bivalent()) { - Kernel::Vector_3 v1 = compute_facet_normal(*fh1); + Kernel::Vector_3 v1 = compute_facet_normal(*fh1); Kernel::Vector_3 v2 = compute_facet_normal(*fh2); if(v1 * v2 > 0.99) { std::cerr << "join\n"; @@ -206,103 +89,35 @@ public slots: } void triangulate() { - CGAL::set_error_behaviour(CGAL::ABORT); - const Scene_interface::Item_id index = scene->mainSelectionIndex(); - + Q_FOREACH(Scene_interface::Item_id index, scene->selectionIndices()) { + Scene_polyhedron_item* item = qobject_cast(scene->item(index)); if(item) { Polyhedron* pMesh = item->polyhedron(); - if(!pMesh) return; + if(!pMesh) continue; if(pMesh->is_pure_triangle()) { messages->warning(tr("The polyhedron \"%1\" is already triangulated.") .arg(item->name())); - return; + continue; } QApplication::setOverrideCursor(Qt::WaitCursor); - typedef Polyhedron::Facet Facet; - typedef Polyhedron::Facet_iterator Facet_iterator; - typedef Polyhedron::Facet_handle Facet_handle; + CGAL::triangulate_polyhedron(*pMesh); - // One need to store facet handles into a vector, because the list of - // facets of the polyhedron will be modified during the loop, and - // that invalidates the range [facets_begin(), facets_end()[. - std::vector facets; - facets.reserve(pMesh->size_of_facets()); - for(Facet_iterator - fit = pMesh->facets_begin(), - end = pMesh->facets_end(); - fit != end; ++fit) { - facets.push_back(fit); - } - - // Iterates on the vector of facet handles - for(std::vector::iterator - fit_it = facets.begin(), - end = facets.end(); - fit_it != end; ++fit_it) - { - Facet_handle fit = *fit_it; - Kernel::Vector_3 normal = compute_facet_normal(*fit); - - Traits cdt_traits(normal); - CDT cdt(cdt_traits); - - Facet::Halfedge_around_facet_circulator - he_circ = fit->facet_begin(), - he_circ_end(he_circ); - CDT::Vertex_handle previous, first; - do { - CDT::Vertex_handle vh = cdt.insert(he_circ->vertex()->point()); - if(first == 0) { - first = vh; - } - vh->info() = he_circ; - if(previous != 0 && previous != vh) { - cdt.insert_constraint(previous, vh); - } - previous = vh; - } while( ++he_circ != he_circ_end ); - cdt.insert_constraint(previous, first); - - // sets mark is_external - for(CDT::Finite_faces_iterator - fit = cdt.finite_faces_begin(), - end = cdt.finite_faces_end(); - fit != end; ++fit) - { - fit->info().is_external = false; - } - std::queue face_queue; - face_queue.push(cdt.infinite_vertex()->face()); - while(! face_queue.empty() ) { - CDT::Face_handle fh = face_queue.front(); - face_queue.pop(); - CGAL_assertion(cdt.is_infinite(fh)); - if(fh->info().is_external) continue; - std::cerr << (void*)(&*fh) << std::endl; - fh->info().is_external = true; - for(int i = 0; i <3; ++i) { - if(!cdt.is_constrained(std::make_pair(fh, i))) - { - face_queue.push(fh->neighbor(i)); - } - } - } - // then modify the polyhedron - Triangulate_modifier modifier(&cdt, fit); - pMesh->delegate(modifier); - } CGAL_assertion_code(pMesh->normalize_border()); CGAL_assertion(pMesh->is_valid(false, 3)); + scene->itemChanged(item); - // default cursor - QApplication::restoreOverrideCursor(); - } + + } // end of if(item) + + } // end of the loop on the selected items + // default cursor + QApplication::restoreOverrideCursor(); } private: From c0df6c5134e23d733befcc7cc84a7f40155344b9 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 15:49:53 +0000 Subject: [PATCH 47/65] Sync with the branch: missing (?) #include --- .../demo/Polyhedron/Polyhedron_demo_parameterization_plugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_parameterization_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_parameterization_plugin.cpp index d1b0c5880b6..3291389b87f 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_parameterization_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_parameterization_plugin.cpp @@ -5,6 +5,7 @@ #include "Scene_polyhedron_item.h" #include "Scene_textured_polyhedron_item.h" #include "Textured_polyhedron_type.h" +#include "Polyhedron_type.h" #include From c5c6b5f9a85c68fdca738c220b177b91cd81d371 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 15:50:19 +0000 Subject: [PATCH 48/65] Add the Scene_polygon_soup, and the orient_soup plugin. --- .../Polyhedron_demo_orient_soup_plugin.cpp | 72 +++++--- .../demo/Polyhedron/Scene_polygon_soup.cpp | 161 +++++++++++++++++- .../demo/Polyhedron/Scene_polygon_soup.h | 11 ++ .../Polyhedron/Scene_polygon_soup_config.h | 2 +- 4 files changed, 219 insertions(+), 27 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp index eab5c9d82d7..555917c4ddc 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp @@ -6,6 +6,7 @@ #include #include "Scene_polygon_soup.h" +#include "Scene_polyhedron_item.h" #include "Polyhedron_demo_plugin_interface.h" #include "Messages_interface.h" @@ -46,6 +47,7 @@ void Polyhedron_demo_orient_soup_plugin::init(QMainWindow* mainWindow, mw = mainWindow; messages = m; actionOrient = new QAction(tr("Orient polygon soup"), mainWindow); + actionOrient->setObjectName("actionOrient"); connect(actionOrient, SIGNAL(triggered()), this, SLOT(orient())); @@ -67,26 +69,41 @@ QList Polyhedron_demo_orient_soup_plugin::actions() const { void Polyhedron_demo_orient_soup_plugin::orient() { - const Scene_interface::Item_id index = scene->mainSelectionIndex(); - - Scene_polygon_soup* item = - qobject_cast(scene->item(index)); - - if(item) + Q_FOREACH(Scene_interface::Item_id index, scene->selectionIndices()) { -// qDebug() << tr("I have the item %1\n").arg(item->name()); - QApplication::setOverrideCursor(Qt::WaitCursor); - if(!item->orient()) - messages->warning(tr("The polygon soup \"%1\" is not orientable.") - .arg(item->name())); - // QMessageBox::information(mw, tr("Not orientable"), -// tr("The polygon soup \"%1\" is not orientable.") -// .arg(item->name())); + Scene_polygon_soup* item = + qobject_cast(scene->item(index)); - scene->itemChanged(item); - - QApplication::restoreOverrideCursor(); + if(item) + { + // qDebug() << tr("I have the item %1\n").arg(item->name()); + QApplication::setOverrideCursor(Qt::WaitCursor); + if(!item->orient()) { + messages->warning(tr("The polygon soup \"%1\" is not orientable.") + .arg(item->name())); + // QMessageBox::information(mw, tr("Not orientable"), + // tr("The polygon soup \"%1\" is not orientable.") + // .arg(item->name())); + scene->itemChanged(item); + } else { + + Scene_polyhedron_item* poly_item = new Scene_polyhedron_item(); + if(item->exportAsPolyhedron(poly_item->polyhedron())) { + poly_item->setName(item->name()); + poly_item->setColor(item->color()); + poly_item->setRenderingMode(item->renderingMode()); + poly_item->setVisible(item->visible()); + poly_item->changed(); + poly_item->setProperty("source filename", item->property("source filename")); + scene->replaceItem(index, poly_item); + delete item; + } else { + scene->itemChanged(item); + } + } + } } + QApplication::restoreOverrideCursor(); } void Polyhedron_demo_orient_soup_plugin::shuffle() @@ -96,9 +113,26 @@ void Polyhedron_demo_orient_soup_plugin::shuffle() Scene_polygon_soup* item = qobject_cast(scene->item(index)); - if(item) + if(item) { item->shuffle_orientations(); - scene->itemChanged(item); + scene->itemChanged(item); + } + else { + Scene_polyhedron_item* poly_item = + qobject_cast(scene->item(index)); + if(poly_item) { + item = new Scene_polygon_soup(); + item->setName(poly_item->name()); + item->setColor(poly_item->color()); + item->setRenderingMode(poly_item->renderingMode()); + item->setVisible(poly_item->visible()); + item->setProperty("source filename", poly_item->property("source filename")); + item->load(poly_item); + item->shuffle_orientations(); + scene->replaceItem(index, item); + delete poly_item; + } + } } void Polyhedron_demo_orient_soup_plugin::displayNonManifoldEdges() diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup.cpp b/Polyhedron/demo/Polyhedron/Scene_polygon_soup.cpp index 6f18f295557..f33e6dece1e 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup.cpp @@ -1,5 +1,8 @@ #include "Scene_polygon_soup.h" +#include "Scene_polyhedron_item.h" #include +#include "Polyhedron_type.h" +#include #include #include @@ -12,11 +15,13 @@ #include #include +#include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point_3; -struct Polygon_soup { +struct Polygon_soup : + public CGAL::Modifier_base +{ typedef std::vector Points; typedef std::vector Polygon_3; typedef std::map, std::set > Edges_map; @@ -86,8 +91,51 @@ struct Polygon_soup { void inverse_orientation(const std::size_t index) { std::reverse(polygons[index].begin(), polygons[index].end()); } + + void operator()(Polyhedron::HalfedgeDS& out_hds); }; +struct Polyhedron_to_polygon_soup_writer { + Polygon_soup* soup; + Polygon_soup::Polygon_3 polygon; + + Polyhedron_to_polygon_soup_writer(Polygon_soup* soup) : soup(soup), polygon() { + } + + void write_header( std::ostream&, + std::size_t vertices, + std::size_t halfedges, + std::size_t facets, + bool normals = false ) { + soup->clear(); + } + + void write_footer() { + } + + void write_vertex( const double& x, const double& y, const double& z) { + soup->points.push_back(Point_3(x, y, z)); + } + + void write_normal( const double& x, const double& y, const double& z) { + } + + void write_facet_header() { + } + + void write_facet_begin( std::size_t no) { + polygon.clear(); + polygon.reserve(no); + } + void write_facet_vertex_index( std::size_t index) { + polygon.push_back(index); + } + void write_facet_end() { + soup->polygons.push_back(polygon); + polygon.clear(); + } +}; // end struct Polyhedron_to_soup_writer + Scene_polygon_soup::Scene_polygon_soup() : Scene_item_with_display_list(), soup(0), @@ -111,13 +159,18 @@ Scene_polygon_soup::clone() const { bool Scene_polygon_soup::load(std::istream& in) { +#if CGAL_VERSION_NR >= 1030700091 + typedef std::size_t indices_t; +#else + typedef CGAL::Integer32 indices_t; +#endif if(!soup) soup = new Polygon_soup; CGAL::File_scanner_OFF scanner(in); soup->clear(); soup->points.resize(scanner.size_of_vertices()); soup->polygons.resize(scanner.size_of_facets()); - for (std::size_t i = 0; i < scanner.size_of_vertices(); ++i) { + for (indices_t i = 0; i < scanner.size_of_vertices(); ++i) { double x, y, z, w; scanner.scan_vertex( x, y, z, w); soup->points[i] = Point_3(x, y, z, w); @@ -126,12 +179,13 @@ Scene_polygon_soup::load(std::istream& in) if(!in) return false; - for (std::size_t i = 0; i < scanner.size_of_facets(); ++i) { - std::size_t no; + for (indices_t i = 0; i < scanner.size_of_facets(); ++i) { + indices_t no; + scanner.scan_facet( no, i); soup->polygons[i].resize(no); - for(std::size_t j = 0; j < no; ++j) { - std::size_t id; + for(indices_t j = 0; j < no; ++j) { + indices_t id; scanner.scan_facet_vertex_index(id, i); if(id < scanner.size_of_vertices()) { @@ -146,6 +200,24 @@ Scene_polygon_soup::load(std::istream& in) return in; } + +#include +#include + +void Scene_polygon_soup::load(Scene_polyhedron_item* poly_item) { + if(!poly_item) return; + if(!poly_item->polyhedron()) return; + + if(!soup) + soup = new Polygon_soup; + + Polyhedron_to_polygon_soup_writer writer(soup); + CGAL::generic_print_polyhedron(std::cerr, + *poly_item->polyhedron(), + writer); + emit changed(); +} + void Scene_polygon_soup::setDisplayNonManifoldEdges(const bool b) { @@ -321,6 +393,44 @@ Scene_polygon_soup::save(std::ostream& out) const return out; } +void +Polygon_soup::operator()(Polyhedron::HalfedgeDS& out_hds) +{ + typedef Polyhedron::HalfedgeDS Output_HDS; + + CGAL::Polyhedron_incremental_builder_3 builder(out_hds); + + typedef Polygon_soup::size_type size_type; + builder.begin_surface(points.size(), + polygons.size(), + edges.size() * 2); + for(size_type i = 0, end = points.size(); + i < end; ++i) + { + builder.add_vertex(points[i]); + } + for(size_type i = 0, end = polygons.size(); + i < end; ++i) + { + const Polygon_soup::Polygon_3& polygon = polygons[i]; + const size_type size = polygon.size(); + builder.begin_facet(); + for(size_type j = 0; j < size; ++j) { + builder.add_vertex_to_facet(polygon[j]); + } + builder.end_facet(); + } + builder.end_surface(); +} + +bool +Scene_polygon_soup::exportAsPolyhedron(Polyhedron* out_polyhedron) +{ + orient(); + out_polyhedron->delegate(*soup); + return out_polyhedron->size_of_vertices() > 0; +} + QString Scene_polygon_soup::toolTip() const { @@ -363,8 +473,11 @@ Scene_polygon_soup::direct_draw() const { } if(soup->display_non_manifold_edges) { double current_color[4]; + GLboolean lightning; ::glGetDoublev(GL_CURRENT_COLOR, current_color); ::glColor3d(1., 0., 0.); // red + ::glGetBooleanv(GL_LIGHTING, &lightning); + ::glDisable(GL_LIGHTING); for(Polygon_soup::size_type i = 0, @@ -379,10 +492,24 @@ Scene_polygon_soup::direct_draw() const { ::glVertex3d(b.x(), b.y(), b.z()); ::glEnd(); } + if(lightning) glEnable(GL_LIGHTING); ::glColor4dv(current_color); } } +void +Scene_polygon_soup::draw_points() const { + if(soup == 0) return; + ::glBegin(GL_POINTS); + for(Polygon_soup::Points::const_iterator pit = soup->points.begin(), + end = soup->points.end(); + pit != end; ++pit) + { + ::glVertex3d(pit->x(), pit->y(), pit->z()); + } + ::glEnd(); +} + bool Scene_polygon_soup::isEmpty() const { return (soup == 0 || soup->points.empty()); @@ -401,4 +528,24 @@ Scene_polygon_soup::bbox() const { bbox.xmax(),bbox.ymax(),bbox.zmax()); } +void +Scene_polygon_soup::new_vertex(const double& x, + const double& y, + const double& z) +{ + soup->points.push_back(Point_3(x, y, z)); +} + +void +Scene_polygon_soup::new_triangle(const std::size_t i, + const std::size_t j, + const std::size_t k) +{ + Polygon_soup::Polygon_3 new_polygon(3); + new_polygon[0] = i; + new_polygon[1] = j; + new_polygon[2] = k; + soup->polygons.push_back(new_polygon); +} + #include "Scene_polygon_soup.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup.h b/Polyhedron/demo/Polyhedron/Scene_polygon_soup.h index 154b09bc71f..016b327cfc5 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup.h +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup.h @@ -5,7 +5,10 @@ #include "Scene_item_with_display_list.h" #include +#include "Polyhedron_type_fwd.h" + struct Polygon_soup; +class Scene_polyhedron_item; class SCENE_POLYGON_SOUP_EXPORT Scene_polygon_soup : public Scene_item_with_display_list @@ -17,6 +20,7 @@ public: Scene_polygon_soup* clone() const; bool load(std::istream& in); + void load(Scene_polyhedron_item*); bool save(std::ostream& out) const; QString toolTip() const; @@ -25,17 +29,24 @@ public: virtual bool supportsRenderingMode(RenderingMode m) const { return m != Gouraud; } // CHECK THIS! // OpenGL drawing in a display list void direct_draw() const; + void draw_points() const; bool isFinite() const { return true; } bool isEmpty() const; Bbox bbox() const; + void new_vertex(const double&, const double&, const double&); + void new_triangle(const std::size_t, const std::size_t, const std::size_t); + +public slots: void shuffle_orientations(); bool orient(); + bool exportAsPolyhedron(Polyhedron*); void inside_out(); void setDisplayNonManifoldEdges(const bool); bool displayNonManifoldEdges() const; + private: Polygon_soup* soup; bool oriented; diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_config.h b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_config.h index 5a568ac4da0..47898403aaa 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_config.h +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_config.h @@ -1,7 +1,7 @@ #ifndef SCENE_POLYGON_SOUP_CONFIG_H #define SCENE_POLYGON_SOUP_CONFIG_H -#ifdef polygon_soup_EXPORTS +#ifdef scene_polygon_soup_item_EXPORTS # define SCENE_POLYGON_SOUP_EXPORT Q_DECL_EXPORT #else # define SCENE_POLYGON_SOUP_EXPORT Q_DECL_IMPORT From abd3051dbfc34fbb51b7bbd4815eee18ca7e4247 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 16:02:09 +0000 Subject: [PATCH 49/65] Forgot this file! --- .../include/CGAL/triangulate_polyhedron.h | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 Polyhedron/demo/Polyhedron/include/CGAL/triangulate_polyhedron.h diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/triangulate_polyhedron.h b/Polyhedron/demo/Polyhedron/include/CGAL/triangulate_polyhedron.h new file mode 100644 index 00000000000..4012c9fd57c --- /dev/null +++ b/Polyhedron/demo/Polyhedron/include/CGAL/triangulate_polyhedron.h @@ -0,0 +1,225 @@ +// Copyright (c) 2010-2011 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you may redistribute it under +// the terms of the Q Public License version 1.0. +// See the file LICENSE.QPL distributed with CGAL. +// +// 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) : Laurent Rineau + +#ifndef CGAL_TRIANGULATE_POLYHEDRON_H + +#include +#include + +#include +#include +#include +#include +#include + +// TODO: submit this file to CGAL too +#include "CGAL/compute_normal.h" + +#include +#include +#include + +namespace CGAL { + +template +class Triangulate_modifier + : public CGAL::Modifier_base +{ + typedef typename Polyhedron::HalfedgeDS HDS; + typedef typename Polyhedron::Traits Traits; + + typedef typename Polyhedron::Halfedge_handle Halfedge_handle; + typedef typename Polyhedron::Facet Facet; + typedef typename Polyhedron::Facet_iterator Facet_iterator; + typedef typename Polyhedron::Facet_handle Facet_handle; + + typedef CGAL::Triangulation_2_filtered_projection_traits_3 P_traits; + + typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; + + struct Face_info { + typename Polyhedron::Halfedge_handle e[3]; + bool is_external; + }; + + typedef CGAL::Triangulation_face_base_with_info_2 Fb1; + + typedef CGAL::Constrained_triangulation_face_base_2 Fb; + typedef CGAL::Triangulation_data_structure_2 TDS; + typedef CGAL::No_intersection_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDTbase; + typedef CGAL::Constrained_triangulation_plus_2 CDT; + +public: + Triangulate_modifier() + { + } + + bool is_external(typename CDT::Face_handle fh) const { + return fh->info().is_external; + } + + void operator()(HDS& hds) { + CGAL::HalfedgeDS_decorator decorator(hds); + typedef typename HDS::Halfedge Halfedge; + + // One need to store facet handles into a vector, because the list of + // facets of the polyhedron will be modified during the loop, and + // that invalidates the range [facets_begin(), facets_end()[. + std::vector facets; + facets.reserve(hds.size_of_faces()); + for(Facet_iterator + fit = hds.faces_begin(), + end = hds.faces_end(); + fit != end; ++fit) { + facets.push_back(fit); + } + + // Iterates on the vector of facet handles + for(typename std::vector::iterator + fit_it = facets.begin(), + end = facets.end(); + fit_it != end; ++fit_it) + { + Facet_handle fit = *fit_it; + typename Traits::Vector_3 normal = + compute_facet_normal(*fit); + + P_traits cdt_traits(normal); + CDT cdt(cdt_traits); + + typename Facet::Halfedge_around_facet_circulator + he_circ = fit->facet_begin(), + he_circ_end(he_circ); + typename CDT::Vertex_handle previous, first; + do { + typename CDT::Vertex_handle vh = cdt.insert(he_circ->vertex()->point()); + if(first == 0) { + first = vh; + } + vh->info() = he_circ; + if(previous != 0 && previous != vh) { + cdt.insert_constraint(previous, vh); + } + previous = vh; + } while( ++he_circ != he_circ_end ); + cdt.insert_constraint(previous, first); + + // sets mark is_external + for(typename CDT::All_faces_iterator + fit = cdt.all_faces_begin(), + end = cdt.all_faces_end(); + fit != end; ++fit) + { + fit->info().is_external = false; + } + std::queue face_queue; + face_queue.push(cdt.infinite_vertex()->face()); + while(! face_queue.empty() ) { + typename CDT::Face_handle fh = face_queue.front(); + face_queue.pop(); + if(fh->info().is_external) continue; + fh->info().is_external = true; + for(int i = 0; i <3; ++i) { + if(!cdt.is_constrained(std::make_pair(fh, i))) + { + face_queue.push(fh->neighbor(i)); + } + } + } + + // then modify the polyhedron + decorator.make_hole(fit->halfedge()); + for(typename CDT::Finite_edges_iterator + eit = cdt.finite_edges_begin(), + end = cdt.finite_edges_end(); + eit != end; ++eit) + { + typename CDT::Face_handle fh = eit->first; + const int index = eit->second; + typename CDT::Face_handle opposite_fh = fh->neighbor(eit->second); + const int opposite_index = opposite_fh->index(fh); + const typename CDT::Vertex_handle va = fh->vertex(cdt. cw(index)); + const typename CDT::Vertex_handle vb = fh->vertex(cdt.ccw(index)); + + if( ! (is_external(fh) && is_external(opposite_fh)) && + ! cdt.is_constrained(*eit) ) + { + // strictly internal edge + Halfedge_handle h = hds.edges_push_back(Halfedge(), + Halfedge()); + fh->info().e[index] = h; + opposite_fh->info().e[opposite_index] = h->opposite(); + + decorator.set_vertex(h, va->info()->vertex()); + decorator.set_vertex(h->opposite(), vb->info()->vertex()); + } + if( cdt.is_constrained(*eit) ) + { + if(!is_external(fh)) { + fh->info().e[index] = va->info(); + } + if(!is_external(opposite_fh)) { + opposite_fh->info().e[opposite_index] = vb->info(); + } + } + } + for(typename CDT::Finite_faces_iterator + fit = cdt.finite_faces_begin(), + end = cdt.finite_faces_end(); + fit != end; ++fit) + { + if(!is_external(fit)) + { + Halfedge_handle h0 = fit->info().e[0]; + Halfedge_handle h1 = fit->info().e[1]; + Halfedge_handle h2 = fit->info().e[2]; + CGAL_assertion( h0 != Halfedge_handle() ); + CGAL_assertion( h1 != Halfedge_handle() ); + CGAL_assertion( h2 != Halfedge_handle() ); + + typedef typename Halfedge::Base HBase; + h0->HBase::set_next(h1); + decorator.set_prev(h1, h0); + h1->HBase::set_next(h2); + decorator.set_prev(h2, h1); + h2->HBase::set_next(h0); + decorator.set_prev(h0, h2); + + decorator.fill_hole(h0); + } + } + } // end loop on facets of the input polyhedron + } +}; // end class Triangulate_modifier + +template +void triangulate_polyhedron(Polyhedron& p) +{ + CGAL::Triangulate_modifier modifier; + p.delegate(modifier); +} + +} // end namespace CGAL + +#endif // CGAL_TRIANGULATE_POLYHEDRON_H From 167dd190c74865c15e5be8eb3ffbc589ef7d4173 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 16:42:30 +0000 Subject: [PATCH 50/65] Fix compilation error about boost::bind Fix an ambiguity between boost::bind and std::bind (C++0x): prefix bind with boost:: explicitly. --- .../include/CGAL/Convex_hull_2/ch_akl_toussaint_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Convex_hull_2/include/CGAL/Convex_hull_2/ch_akl_toussaint_impl.h b/Convex_hull_2/include/CGAL/Convex_hull_2/ch_akl_toussaint_impl.h index 7e75eee7c84..76f7556f02e 100644 --- a/Convex_hull_2/include/CGAL/Convex_hull_2/ch_akl_toussaint_impl.h +++ b/Convex_hull_2/include/CGAL/Convex_hull_2/ch_akl_toussaint_impl.h @@ -98,9 +98,9 @@ ch_akl_toussaint(ForwardIterator first, ForwardIterator last, std::sort( successor(region2.begin() ), region2.end(), ch_traits.less_xy_2_object() ); std::sort( successor(region3.begin() ), region3.end(), - bind(ch_traits.less_xy_2_object(), _2, _1) ); + boost::bind(ch_traits.less_xy_2_object(), _2, _1) ); std::sort( successor(region4.begin() ), region4.end(), - bind(ch_traits.less_xy_2_object(), _2, _1) ); + boost::bind(ch_traits.less_xy_2_object(), _2, _1) ); if (! equal_points(*w,*s) ) { From 3e100e387d1c4c7eeff2c9339c6d1acd5e4241eb Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 16:44:36 +0000 Subject: [PATCH 51/65] Fix linking errors on Windows. --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index de17fd0dc8f..c482d9904bb 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -128,6 +128,12 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) Scene_item_with_display_list.cpp Polyhedron_demo_plugin_helper.cpp) + target_link_libraries(demo_framework + ${QGLVIEWER_LIBRARIES} + ${OPENGL_gl_LIBRARY} + ${OPENGL_glu_LIBRARY} + ) + add_library(scene_basic_objects SHARED Scene_plane_item.cpp Scene_plane_item.moc) target_link_libraries(scene_basic_objects @@ -137,7 +143,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) ${OPENGL_glu_LIBRARY} ) - add_library(point_dialog Show_point_dialog.cpp Show_point_dialog.ui ${Show_point_dialogUI_FILES} ) + add_library(point_dialog SHARED Show_point_dialog.cpp Show_point_dialog.ui ${Show_point_dialogUI_FILES} ) add_library(scene_c2t3_item SHARED Scene_c2t3_item.cpp Scene_c2t3_item.moc) From 409c28464fe5e2e3455ba5ad0b92d4fba68626c0 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 16:51:48 +0000 Subject: [PATCH 52/65] numberOfEntries() must return an int, because it is a Qt property. --- Polyhedron/demo/Polyhedron/Scene.cpp | 2 +- Polyhedron/demo/Polyhedron/Scene.h | 2 +- Polyhedron/demo/Polyhedron/Scene_interface.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene.cpp b/Polyhedron/demo/Polyhedron/Scene.cpp index 70db1e37cc7..04a501d3f7d 100644 --- a/Polyhedron/demo/Polyhedron/Scene.cpp +++ b/Polyhedron/demo/Polyhedron/Scene.cpp @@ -134,7 +134,7 @@ Scene::item(Item_id index) const return m_entries.value(index); // QList::value checks bounds } -size_t +int Scene::numberOfEntries() const { return m_entries.size(); diff --git a/Polyhedron/demo/Polyhedron/Scene.h b/Polyhedron/demo/Polyhedron/Scene.h index a39ea37400f..a00a012eea1 100644 --- a/Polyhedron/demo/Polyhedron/Scene.h +++ b/Polyhedron/demo/Polyhedron/Scene.h @@ -55,7 +55,7 @@ public: int duplicate(int index); // Accessors (getters) - size_t numberOfEntries() const; + int numberOfEntries() const; const QList& entries() const { return m_entries; } Q_INVOKABLE Scene_item* item(int) const ; int mainSelectionIndex() const; diff --git a/Polyhedron/demo/Polyhedron/Scene_interface.h b/Polyhedron/demo/Polyhedron/Scene_interface.h index f94ee24bd3a..52e8be1bb50 100644 --- a/Polyhedron/demo/Polyhedron/Scene_interface.h +++ b/Polyhedron/demo/Polyhedron/Scene_interface.h @@ -63,7 +63,7 @@ public: // clonable), returns -1. // Accessors (getters) - virtual size_t numberOfEntries() const = 0; + virtual int numberOfEntries() const = 0; virtual Scene_item* item(Item_id) const = 0; virtual Item_id mainSelectionIndex() const = 0; virtual QList selectionIndices() const = 0; From 28bc66c69d3088abfd7e8066ba0cb00cb0da7a74 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 16:54:25 +0000 Subject: [PATCH 53/65] Remove this cast, now that scene->numberOfEntries() is an int. --- Polyhedron/demo/Polyhedron/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index e6f25314f68..a63d0e00fc4 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -677,7 +677,7 @@ void MainWindow::open(QString filename, bool no_popup) void MainWindow::selectSceneItem(int i) { if(i < 0) return; - if((unsigned int)i >= scene->numberOfEntries()) return; + if(i >= scene->numberOfEntries()) return; treeView->selectionModel()->select(scene->createSelection(i), QItemSelectionModel::ClearAndSelect); From 538ad27a5a4003ef9990252971a7e0ae685d601e Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 3 Jun 2011 17:03:15 +0000 Subject: [PATCH 54/65] Fix a warning --- Polyhedron/demo/Polyhedron/Polyhedron_demo_trivial_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_trivial_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_trivial_plugin.cpp index 3f1912c073f..c81ca089e55 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_trivial_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_trivial_plugin.cpp @@ -125,7 +125,7 @@ QList Polyhedron_demo_trivial_plugin::actions() const { void Polyhedron_demo_trivial_plugin::bbox() { - for(size_t i = 0, end = scene->numberOfEntries(); + for(int i = 0, end = scene->numberOfEntries(); i < end; ++i) { if(qobject_cast(scene->item(i))) From 0c8b4d894ed6610e053c2fcb878ab18ae2b766a5 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Sat, 4 Jun 2011 16:57:32 +0000 Subject: [PATCH 55/65] Fix CMakeLists.txt: Qt3 is used. --- CGALimageIO/demo/CGALimageIO/CMakeLists.txt | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/CGALimageIO/demo/CGALimageIO/CMakeLists.txt b/CGALimageIO/demo/CGALimageIO/CMakeLists.txt index bae0cdad183..0dbff9bf359 100644 --- a/CGALimageIO/demo/CGALimageIO/CMakeLists.txt +++ b/CGALimageIO/demo/CGALimageIO/CMakeLists.txt @@ -30,13 +30,17 @@ endforeach() find_package(CGAL REQUIRED ImageIO) include( ${CGAL_USE_FILE} ) find_package(VTK QUIET) +find_package(Qt3-patched QUIET) -if(VTK_FOUND) +if(QT3_FOUND AND VTK_FOUND) add_definitions(-DCGAL_USE_VTK) include(${VTK_USE_FILE}) + add_definitions(${QT3_DEFINITIONS}) + if(VTK_USE_QVTK) include_directories( ${VTK_QT_INCLUDE_DIR} ) + include_directories( ${QT3_INCLUDE_DIR} ) add_executable( image_to_vtk_viewer image_to_vtk_viewer.cpp ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS image_to_vtk_viewer ) @@ -48,12 +52,16 @@ if(VTK_FOUND) vtkCommon ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ${VTK_QT_QT_LIBRARY} + ${QT3_LIBRARIES} ) else(VTK_USE_QVTK) message(STATUS "NOTICE: This demo needs QVTK, and will not be compiled.") endif(VTK_USE_QVTK) -else(VTK_FOUND) - - message(STATUS "NOTICE: This demo needs VTK, and will not be compiled.") - -endif(VTK_FOUND) +else() + if(NOT VTK_FOUND) + message(STATUS "NOTICE: This demo needs VTK, and will not be compiled.") + endif() + if(NOT QT3_FOUND) + message(STATUS "NOTICE: This demo needs Qt3, and will not be compiled.") + endif() +endif() From 0a363c52b5131bb35711edc109e34471bc952c2a Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Sat, 4 Jun 2011 17:00:31 +0000 Subject: [PATCH 56/65] Fix a bug introduced in trunk: criteria for Mesh_2 needs a geom traits --- .../CGAL/Lipschitz_sizing_field_criteria_2.h | 19 +++++++++++++------ .../CGAL/Delaunay_mesh_area_criteria_2.h | 16 +++++++++++----- .../include/CGAL/Delaunay_mesh_criteria_2.h | 2 +- .../Delaunay_mesh_local_size_criteria_2.h | 14 +++++++++----- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/GraphicsView/demo/Triangulation_2/include/CGAL/Lipschitz_sizing_field_criteria_2.h b/GraphicsView/demo/Triangulation_2/include/CGAL/Lipschitz_sizing_field_criteria_2.h index 8085c29c27b..ad4da9f21bf 100644 --- a/GraphicsView/demo/Triangulation_2/include/CGAL/Lipschitz_sizing_field_criteria_2.h +++ b/GraphicsView/demo/Triangulation_2/include/CGAL/Lipschitz_sizing_field_criteria_2.h @@ -24,21 +24,27 @@ public: protected: Sizing_field* sizing_field; + + typedef typename CDT::Geom_traits Geom_traits; + Geom_traits traits; public: typedef Delaunay_mesh_criteria_2 Base; Lipschitz_sizing_field_criteria_2(const double aspect_bound = 0.125, - Sizing_field* sf = 0) - : Base(aspect_bound), sizing_field(sf) + Sizing_field* sf = 0, + const Geom_traits& traits = Geom_traits()) + : Base(aspect_bound), sizing_field(sf), traits(traits) {} Lipschitz_sizing_field_criteria_2& operator =(const Lipschitz_sizing_field_criteria_2& c) { + if(&c == this) return *this; this->sizing_field = c.sizing_field; + this->traits = c.traits; return *this; - } + } inline const Sizing_field* sizing_field_object() { @@ -81,8 +87,9 @@ public: typedef typename Base::Is_bad::Point_2 Point_2; - Is_bad(const double aspect_bound, Sizing_field* sf) - : Base::Is_bad(aspect_bound), sizing_field(sf) + Is_bad(const double aspect_bound, Sizing_field* sf, + const Geom_traits& traits) + : Base::Is_bad(aspect_bound, traits), sizing_field(sf) { } @@ -189,7 +196,7 @@ public: Is_bad is_bad_object() const { - return Is_bad(this->bound(), sizing_field); + return Is_bad(this->bound(), sizing_field, traits); } }; diff --git a/Mesh_2/include/CGAL/Delaunay_mesh_area_criteria_2.h b/Mesh_2/include/CGAL/Delaunay_mesh_area_criteria_2.h index 4dadb89309f..1d99ea90c93 100644 --- a/Mesh_2/include/CGAL/Delaunay_mesh_area_criteria_2.h +++ b/Mesh_2/include/CGAL/Delaunay_mesh_area_criteria_2.h @@ -32,6 +32,10 @@ class Delaunay_mesh_area_criteria_2 Delaunay_mesh_size_criteria_2. Delaunay_mesh_criteria_2 is a virtual base class of Delaunay_mesh_size_criteria_2. */ { + typedef typename Tr::Geom_traits Geom_traits; + +protected: + Geom_traits traits; public: typedef Delaunay_mesh_criteria_2 Base; typedef Delaunay_mesh_size_criteria_2 Private_base; @@ -39,8 +43,9 @@ public: typedef typename Delaunay_mesh_size_criteria_2::Quality Quality; Delaunay_mesh_area_criteria_2(const double aspect_bound = 0.125, - const double area_bound = 0) - : Private_base(aspect_bound, area_bound) {} + const double area_bound = 0, + const Geom_traits& traits = Geom_traits()) + : Private_base(aspect_bound, area_bound, traits), traits(traits) {} inline double area_bound() const { return this->sizebound; } @@ -58,8 +63,9 @@ public: typedef typename Tr::Face_handle Face_handle; Is_bad(const double aspect_bound, - const double area_bound) - : Is_bad_base(aspect_bound, area_bound) {} + const double area_bound, + const Geom_traits& traits) + : Is_bad_base(aspect_bound, area_bound, traits) {} Mesh_2::Face_badness operator()(Quality q) { @@ -126,7 +132,7 @@ public: }; // end class Is_bad Is_bad is_bad_object() const - { return Is_bad(this->bound(), area_bound()); } + { return Is_bad(this->bound(), area_bound(), traits); } }; } //end namespace diff --git a/Mesh_2/include/CGAL/Delaunay_mesh_criteria_2.h b/Mesh_2/include/CGAL/Delaunay_mesh_criteria_2.h index 7a29d19c50c..c67a13fed72 100644 --- a/Mesh_2/include/CGAL/Delaunay_mesh_criteria_2.h +++ b/Mesh_2/include/CGAL/Delaunay_mesh_criteria_2.h @@ -31,7 +31,7 @@ class Delaunay_mesh_criteria_2 protected: typedef typename Tr::Geom_traits Geom_traits; - const Geom_traits& traits; + Geom_traits traits; public: typedef typename Tr::Face_handle Face_handle; diff --git a/Mesh_2/include/CGAL/Delaunay_mesh_local_size_criteria_2.h b/Mesh_2/include/CGAL/Delaunay_mesh_local_size_criteria_2.h index 1fde2bbbf27..a8ae1d36fc7 100644 --- a/Mesh_2/include/CGAL/Delaunay_mesh_local_size_criteria_2.h +++ b/Mesh_2/include/CGAL/Delaunay_mesh_local_size_criteria_2.h @@ -41,13 +41,16 @@ public: private: bool local; Segment _s; + Geom_traits traits; public: Delaunay_mesh_local_size_criteria_2(const double aspect_bound = 0.125, const double size_bound = 0, const bool is_local_size = false, - const Segment s = Segment()) - : Base(aspect_bound, size_bound), local(is_local_size), _s(s) {} + const Segment s = Segment(), + const Geom_traits& traits = Geom_traits()) + : Base(aspect_bound, size_bound), local(is_local_size), _s(s) + , traits(traits) {} inline Segment segment() const { return _s; } @@ -82,8 +85,9 @@ public: Is_bad(const double aspect_bound, const double size_bound, const bool l, - const Segment_2 _s) - : Base::Is_bad(aspect_bound, size_bound), local(l), s(_s) {} + const Segment_2 _s, + const Geom_traits& traits) + : Base::Is_bad(aspect_bound, size_bound, traits), local(l), s(_s) {} Mesh_2::Face_badness operator()(Quality q) const { @@ -119,7 +123,7 @@ public: }; Is_bad is_bad_object() const - { return Is_bad(this->bound(), this->size_bound(), local, segment()); } + { return Is_bad(this->bound(), this->size_bound(), local, segment(), traits); } }; } //end namespace From 776dbf5d0d1fd8d2366ad3c19dea6f2fbec6032d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 6 Jun 2011 07:25:33 +0000 Subject: [PATCH 57/65] typo --- Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3_Halfedge.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3_Halfedge.tex b/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3_Halfedge.tex index d79b00da4a9..b4ecd69a550 100644 --- a/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3_Halfedge.tex +++ b/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3_Halfedge.tex @@ -91,7 +91,7 @@ class \ccc{Nef_polyhedron_3} manages the needed halfedges internally. \ccMethod{Halfedge_const_handle twin() const;}{the twin of \ccVar\ .} \ccMethod{SHalfedge_const_handle out_sedge() const;} -{the first out sedege of \ccVar\ .} +{the first out sedge of \ccVar\ .} \ccMethod{SFace_const_handle incident_sface() const;} {the incident sface of \ccVar\ .} From 5194b7f8a417967bcaeddb370fa4c34780da1e58 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Mon, 6 Jun 2011 13:03:55 +0000 Subject: [PATCH 58/65] Let the plugins be compiled and created in the same directory as executables --- Mesh_3/demo/Mesh_3/CMakeLists.txt | 3 +++ Mesh_3/demo/Mesh_3/implicit_functions/CMakeLists.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Mesh_3/demo/Mesh_3/CMakeLists.txt b/Mesh_3/demo/Mesh_3/CMakeLists.txt index 13e544eab66..545ad51d313 100644 --- a/Mesh_3/demo/Mesh_3/CMakeLists.txt +++ b/Mesh_3/demo/Mesh_3/CMakeLists.txt @@ -11,6 +11,9 @@ if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6) endif() endif() +# Let plugins be compiled in the same directory as the executable. +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + #option(MESH_3_DEMO_ENABLE_FORWARD_DECL "In the Mesh_3 demo, enable " OFF) #mark_as_advanced(MESH_3_DEMO_ENABLE_FORWARD_DECL) diff --git a/Mesh_3/demo/Mesh_3/implicit_functions/CMakeLists.txt b/Mesh_3/demo/Mesh_3/implicit_functions/CMakeLists.txt index 4f9b7ebcfb1..3a08b852110 100644 --- a/Mesh_3/demo/Mesh_3/implicit_functions/CMakeLists.txt +++ b/Mesh_3/demo/Mesh_3/implicit_functions/CMakeLists.txt @@ -11,6 +11,9 @@ if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6) endif() endif() +# Let plugins be compiled in the same directory as the executable. +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + # Include directory of demo includes include_directories( BEFORE ${Mesh_3_implicit_functions_BINARY_DIR} ../include ) From a9c8f70c004ce039420fc1a3029efbe1fc08a24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 6 Jun 2011 14:25:18 +0000 Subject: [PATCH 59/65] typo --- Nef_S2/doc_tex/Nef_S2_ref/Nef_polyhedron_S2_SVertex.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nef_S2/doc_tex/Nef_S2_ref/Nef_polyhedron_S2_SVertex.tex b/Nef_S2/doc_tex/Nef_S2_ref/Nef_polyhedron_S2_SVertex.tex index e93bec58c52..075a5376472 100644 --- a/Nef_S2/doc_tex/Nef_S2_ref/Nef_polyhedron_S2_SVertex.tex +++ b/Nef_S2/doc_tex/Nef_S2_ref/Nef_polyhedron_S2_SVertex.tex @@ -60,7 +60,7 @@ class \ccc{Nef_polyhedron_S2} manages the needed svertices internally. \ccMethod{SVertex_const_handle twin() const;}{the twin of \ccVar\ .} \ccMethod{SHalfedge_const_handle out_sedge() const;} -{the first out sedege of \ccVar\ .} +{the first out sedge of \ccVar\ .} \ccMethod{SFace_const_handle incident_sface() const;} {the incident sface of \ccVar\ .} From 6a29626a8f5ab6136408a46170c5fbf6718c57d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 6 Jun 2011 14:31:17 +0000 Subject: [PATCH 60/65] typo --- Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3.tex b/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3.tex index 662a3a2a9d3..9e2822b0909 100644 --- a/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3.tex +++ b/Nef_3/doc_tex/Nef_3_ref/Nef_polyhedron_3.tex @@ -105,7 +105,7 @@ template parameters. \ccGlue \ccNestedType{SHalfedge_around_sface_const_circulator}{non-mutable circulator of shalfedges around a sface (ccw).} \ccGlue -\ccNestedType{SHalfedge_aroud_facet_const_circulator}{non-mutable circulator of shalfedges around a halffacet (ccw).} +\ccNestedType{SHalfedge_around_facet_const_circulator}{non-mutable circulator of shalfedges around a halffacet (ccw).} \ccGlue \ccNestedType{SFace_cycle_const_iterator}{non-mutable iterator over the cylces of a sface.} \ccGlue From 93a4063a3b3240cc4044cec1dee98327b9d27f39 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Mon, 6 Jun 2011 15:01:31 +0000 Subject: [PATCH 61/65] Update the cgal_test: polygon_soup has been renamed scene_polygon_soup --- Polyhedron/demo/Polyhedron/cgal_test_with_cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/cgal_test_with_cmake b/Polyhedron/demo/Polyhedron/cgal_test_with_cmake index bd8bf57d219..855f39543e4 100755 --- a/Polyhedron/demo/Polyhedron/cgal_test_with_cmake +++ b/Polyhedron/demo/Polyhedron/cgal_test_with_cmake @@ -144,8 +144,8 @@ if ${MAKE_CMD} -f Makefile help | grep "pca_plugin" > /dev/null; then compile_and_run pca_plugin NEED_CLEAN=y fi -if ${MAKE_CMD} -f Makefile help | grep "polygon_soup" > /dev/null; then - compile_and_run polygon_soup +if ${MAKE_CMD} -f Makefile help | grep "scene_polygon_soup" > /dev/null; then + compile_and_run scene_polygon_soup NEED_CLEAN=y fi if ${MAKE_CMD} -f Makefile help | grep "remeshing_plugin" > /dev/null; then From fba23bf717539336272984a7a025c513a28e2830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 7 Jun 2011 07:39:21 +0000 Subject: [PATCH 62/65] capitalize heading --- .../doc_tex/Spatial_sorting/spatial_sorting.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex index bc994359df9..58bc26026b0 100644 --- a/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex +++ b/Spatial_sorting/doc_tex/Spatial_sorting/spatial_sorting.tex @@ -171,7 +171,7 @@ $ ./small_example_delaunay_2 %used to sort a container of handle on points instead of points directly. %\ccIncludeExampleCode{Spatial_sorting/sort_indices.cpp} -\subsection{Using your own Point Type} +\subsection{Using Your Own Point Type} If you want to sort points of your own point type, you only have to provide functors that compare the \ccc{x} and \ccc{y} coordinates of your points. Note that in case you simply want @@ -198,18 +198,18 @@ which allows to obtain a point from whatever you want to sort. The following examples illustrate the usage of these traits class adapters. -\subsubsection{Sorting using pairs of points and integers} +\subsubsection{Sorting Using Pairs of Points and Integers} \label{sec:sort_any_type_2} In this example program, the sorted sequence of points is retrieved using a vector of pairs of points and integers. \ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_2.cpp} -\subsubsection{Sorting using indices of points} +\subsubsection{Sorting Using Indices of Points} In this example program, the sorted sequence of points is retrieved using the indices of the points in a vector of points. \ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_3.cpp} -\subsubsection{Sorting using indices of pairs of points and integers} +\subsubsection{Sorting Using Indices of Pairs of Points and Integers} In this example program, the sorted sequence of points is retrieved using the indices of the points in a vector of pairs of points and integers. \ccIncludeExampleCode{Spatial_sorting/sp_sort_using_property_map_d.cpp} From 96d79852f98611be4ba32b6c7fa16d548b3a0ee3 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Tue, 7 Jun 2011 08:25:42 +0000 Subject: [PATCH 63/65] remove spatial sort branch from features to be tested --- Maintenance/test_handling/candidate_branches | 1 - 1 file changed, 1 deletion(-) diff --git a/Maintenance/test_handling/candidate_branches b/Maintenance/test_handling/candidate_branches index 207a38270ad..6ad05bd1130 100644 --- a/Maintenance/test_handling/candidate_branches +++ b/Maintenance/test_handling/candidate_branches @@ -1,3 +1,2 @@ Combinatorial_map-gdamiand unique_sqrt_extension-sloriot -spatial_sorting-increase_dim_and_add_info-sloriot From c3585756e7c84beae13f3121326d004915492775 Mon Sep 17 00:00:00 2001 From: Olivier Devillers Date: Tue, 7 Jun 2011 09:02:00 +0000 Subject: [PATCH 64/65] changes file (spatial sorting) --- Installation/changes.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Installation/changes.html b/Installation/changes.html index 3663499cb3d..4f96e706cc9 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -114,6 +114,14 @@ CGAL 3.9 offers the following improvements and new functionality :

  • Various fixes in the manual.
  • +

    Spatial_sorting (major new feature added)

    +
      +
    • General dimension is now supported.
    • +
    • Hilbert supporting admits now two policies: splitting at + median or at middle (see user manual).
    • +
    • sorting on indices isntead of points is easier using + property maps
    • +

    Release 3.8

    From 88ae0503ece315716293bde364212c5eab5fd852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 7 Jun 2011 12:34:49 +0000 Subject: [PATCH 65/65] typos + add kernel_d small feature to list of changes --- Installation/changes.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Installation/changes.html b/Installation/changes.html index 4f96e706cc9..7a43e3ef474 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -114,13 +114,15 @@ CGAL 3.9 offers the following improvements and new functionality :

  • Various fixes in the manual.
  • +

    dD Kernel

    +
  • The d-dimensional kernel concept and models have been modified + to additionally provide two new functors Less_coordinate_d and Point_dimension_d.
  • Spatial_sorting (major new feature added)

    • General dimension is now supported.
    • -
    • Hilbert supporting admits now two policies: splitting at +
    • Hilbert sorting admits now two policies: splitting at median or at middle (see user manual).
    • -
    • sorting on indices isntead of points is easier using - property maps
    • +
    • Using a property map, sorting on keys instead of points is now easier

    Release 3.8