From 6b407609818f855307f9e2a70c4ea7dc6ea5b9fc Mon Sep 17 00:00:00 2001
From: Brad Barber <bradb@shore.net>
Date: Sun, 14 Mar 2010 19:10:11 -0400
Subject: [PATCH] Add Qhull::defineVertexFacetNeighbors() to define the
 facetNeighbors of all vertices.   Automatically called for facet merging and
 Voronoi diagrams

<<QhullVertex does not print facetNeighbors() if !facetNeighborsDefined()
      Was not caught by QhullVertex_test due to facet merging

Fixed type of vertex->neighbors in qh_printvoronoi [no effect on results]

Removed unnecessary if statement in qh_printvoronoi

index.htm: Add Google Scholar references
---
 cpp/Qhull.cpp                      | 18 ++++++++++++++++++
 cpp/Qhull.h                        |  1 +
 cpp/QhullVertex.cpp                | 29 +++++++++++++++++------------
 cpp/QhullVertex.h                  |  2 ++
 cpp/qhulltest/QhullVertex_test.cpp | 26 ++++++++++++++++++++++++++
 cpp/qhulltest/Qhull_test.cpp       |  2 ++
 cpp/qhulltest/qhulltest.cpp        |  2 +-
 index.htm                          |  3 ++-
 src/Changes.txt                    | 12 ++++++++++--
 src/io.c                           | 10 ++++------
 10 files changed, 83 insertions(+), 22 deletions(-)

diff --git a/cpp/Qhull.cpp b/cpp/Qhull.cpp
index 3931829..de43d7e 100644
--- a/cpp/Qhull.cpp
+++ b/cpp/Qhull.cpp
@@ -292,6 +292,23 @@ volume(){
 }//volume
 
 #//ForEach
+
+//! Define QhullVertex::neighborFacets().
+//! Automatically called if merging facets or computing the Voronoi diagram.
+//! Noop if called multiple times.
+void Qhull::
+defineVertexNeighborFacets(){
+    checkIfQhullInitialized();
+    UsingLibQhull q(this);
+    if(!qh hasAreaVolume){
+        int exitCode = setjmp(qh errexit);
+        if(!exitCode){ // no object creation -- destructors skipped on longjmp()
+            qh_vertexneighbors();
+        }
+        maybeThrowQhullMessage(exitCode);
+    }
+}//defineVertexNeighborFacets
+
 QhullFacetList Qhull::
 facetList() const{
     return QhullFacetList(beginFacet(), endFacet());
@@ -309,6 +326,7 @@ otherPoints() const
     return QhullPointSet(hullDimension(), qhull_qh->other_points);
 }//otherPoints
 
+//! Return vertices of the convex hull.
 QhullVertexList Qhull::
 vertexList() const{
     return QhullVertexList(beginVertex(), endVertex());
diff --git a/cpp/Qhull.h b/cpp/Qhull.h
index b3b9768..aa63f27 100644
--- a/cpp/Qhull.h
+++ b/cpp/Qhull.h
@@ -116,6 +116,7 @@ public:
 #//ForEach
     QhullFacet          beginFacet() const { return QhullFacet(qhull_qh->facet_list); }
     QhullVertex         beginVertex() const { return QhullVertex(qhull_qh->vertex_list); }
+    void                defineVertexNeighborFacets(); //!< Automatically called if merging facets or Voronoi diagram
     QhullFacet          endFacet() const { return QhullFacet(qhull_qh->facet_tail); }
     QhullVertex         endVertex() const { return QhullVertex(qhull_qh->vertex_tail); }
     QhullFacetList      facetList() const;
diff --git a/cpp/QhullVertex.cpp b/cpp/QhullVertex.cpp
index dd483b6..1fe869c 100644
--- a/cpp/QhullVertex.cpp
+++ b/cpp/QhullVertex.cpp
@@ -29,11 +29,14 @@ s_empty_vertex= {0,0,0,0,0,
                  0,0};
 
 #//ForEach
+
+//! Return neighboring facets for a vertex
+//! If neither merging nor Voronoi diagram, requires Qhull::defineVertexNeighborFacets() beforehand.
 QhullFacetSet QhullVertex::
 neighborFacets() const
 {
-    if(!qh_vertex->neighbors){
-        throw QhullError(10034, "Qhull error: neighbors of vertex %d not defined.  Need to call defineVertexNeighbors().", id());
+    if(!neighborFacetsDefined()){
+        throw QhullError(10034, "Qhull error: neighboring facets of vertex %d not defined.  Please call Qhull::defineVertexNeighborFacets() beforehand.", id());
     }
     return QhullFacetSet(qh_vertex->neighbors);
 }//neighborFacets
@@ -71,18 +74,20 @@ operator<<(ostream &os, const QhullVertex::PrintVertex &pr)
         os << " ridgedeleted";
     }
     os << endl;
-    QhullFacetSetIterator i= v.neighborFacets();
-    if(i.hasNext()){
-        os << " neighborFacets:";
-        int count= 0;
-        while(i.hasNext()){
-            if(++count % 100 == 0){
-                os << endl << "     ";
+    if(v.neighborFacetsDefined()){
+        QhullFacetSetIterator i= v.neighborFacets();
+        if(i.hasNext()){
+            os << " neighborFacets:";
+            int count= 0;
+            while(i.hasNext()){
+                if(++count % 100 == 0){
+                    os << endl << "     ";
+                }
+                QhullFacet f= i.next();
+                os << " f" << f.id();
             }
-            QhullFacet f= i.next();
-            os << " f" << f.id();
+            os << endl;
         }
-        os << endl;
     }
     return os;
 }//<< PrintVertex
diff --git a/cpp/QhullVertex.h b/cpp/QhullVertex.h
index 1b50bf2..3b0902a 100644
--- a/cpp/QhullVertex.h
+++ b/cpp/QhullVertex.h
@@ -72,6 +72,8 @@ public:
     int                 dimension() const { return (qh_vertex->dim || !isDefined()) ? qh_vertex->dim : UsingLibQhull::globalVertexDimension(); }
     int                 id() const { return qh_vertex->id; }
     bool                isDefined() const { return qh_vertex != &s_empty_vertex; }
+                        //! True if defineVertexNeighborFacets() already called.  Auotomatically set for facet merging, Voronoi diagrams
+    bool                neighborFacetsDefined() const { return qh_vertex->neighbors != 0; }
     QhullVertex         next() const { return qh_vertex->next; }
     bool                operator==(const QhullVertex &o) const { return qh_vertex==o.qh_vertex; }
     bool                operator!=(const QhullVertex &o) const { return !operator==(o); }
diff --git a/cpp/qhulltest/QhullVertex_test.cpp b/cpp/qhulltest/QhullVertex_test.cpp
index eb7f18c..150dbcf 100644
--- a/cpp/qhulltest/QhullVertex_test.cpp
+++ b/cpp/qhulltest/QhullVertex_test.cpp
@@ -150,6 +150,32 @@ t_io()
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count("(v"), 10);
+        QCOMPARE(s.count(": f"), 2);
+    }
+    RboxPoints r10("10 D3");  // Without QhullVertex::facetNeighbors
+    {
+        Qhull q(r10, "");
+        QhullVertex v= q.beginVertex();
+        ostringstream os;
+        os << "\nTry again with simplicial facets.  No neighboring facets listed for vertices.\n";
+        os << "Vertex and vertices w/o runId:\n";
+        os << v;
+        q.defineVertexNeighborFacets();
+        os << "This time with neighborFacets() defined for all vertices:\n";
+        os << v;
+        cout << os.str();
+        QString s= QString::fromStdString(os.str());
+        QCOMPARE(s.count(": f"), 1);
+
+        Qhull q2(r10, "v"); // Voronoi diagram
+        QhullVertex v2= q2.beginVertex();
+        ostringstream os2;
+        os2 << "\nTry again with Voronoi diagram of simplicial facets.  Neighboring facets automatically defined for vertices.\n";
+        os2 << "Vertex and vertices w/o runId:\n";
+        os2 << v2;
+        cout << os2.str();
+        QString s2= QString::fromStdString(os2.str());
+        QCOMPARE(s2.count(": f"), 1);
     }
 }//t_io
 
diff --git a/cpp/qhulltest/Qhull_test.cpp b/cpp/qhulltest/Qhull_test.cpp
index 77cba85..e198f95 100644
--- a/cpp/qhulltest/Qhull_test.cpp
+++ b/cpp/qhulltest/Qhull_test.cpp
@@ -316,6 +316,8 @@ t_foreach()
         q.runQhull(rcube, "");
         QCOMPARE(q.facetList().count(), 6);
 
+        // defineVertexNeighborFacets() tested in QhullVertex_test::t_io()
+
         QhullFacetList facets(q.beginFacet(), q.endFacet());
         QCOMPARE(facets.count(), 6);
         QCOMPARE(q.firstFacet(), q.beginFacet());
diff --git a/cpp/qhulltest/qhulltest.cpp b/cpp/qhulltest/qhulltest.cpp
index 753643c..b85f563 100644
--- a/cpp/qhulltest/qhulltest.cpp
+++ b/cpp/qhulltest/qhulltest.cpp
@@ -22,7 +22,7 @@ namespace orgQhull {
 
 void addQhullTests(QStringList &args)
 {
-    TESTadd_(add_QhullSet_test); //copy
+    TESTadd_(add_QhullVertex_test); //copy
 
     if(args.contains("--all")){
         args.removeAll("--all");
diff --git a/index.htm b/index.htm
index 2219a3f..6bdb611 100644
--- a/index.htm
+++ b/index.htm
@@ -65,7 +65,8 @@ and higher. </p>
                 www.qhull.org
         <p>
     <li><a href="http://www.qhull.org/news/qhull-news.html#users">How</a> is Qhull used?</li>
-        <li><a href="http://citeseerx.ist.psu.edu/showciting?doi=10.1.1.117.405&sort=cite">CiteSeer</a> references to Qhull
+        <li><a href="http://citeseerx.ist.psu.edu/showciting?doi=10.1.1.117.405&sort=cite">CiteSeer</a>
+        and <a href="http://scholar.google.com/scholar?cites=6731193060570243661&hl=en&as_sdt=40000000">Google Scholar</a> references to Qhull
 </p>
         <li>
         <a href=http://www.google.com/search?as_q=qhull+-debian+-cvs+-gentoo+-pool+-mirrors&num=100>Google</a> Qhull,
diff --git a/src/Changes.txt b/src/Changes.txt
index 52039bb..98fa5ef 100644
--- a/src/Changes.txt
+++ b/src/Changes.txt
@@ -5,6 +5,7 @@
 Need help
  - The C++ interface needs work.  Give it a try and make it better.
    http://gitorious.org/qhull/
+ - Document with Qt conventions using Doxygen (//! and //!<)
  - Produce conformant triangulations for merged facets using option 'Qt' 
  - Add CMakeLists.txt for qhullcpp, user_eg3, cpp/, and cpp/road
    If practical, please move CMakeLists.txt to project/
@@ -20,12 +21,19 @@ To do
  - Create signed tags for Qhull versions
  - Add FIXUP for known problems and update wiki
  - Notes to compgeom on conformant triangulation and Voronoi volume
- 
+
+------------
+gitorious.org/qhull 2010/03/14
+- Add Qhull::defineVertexFacetNeighbors() for facetNeighbors of vertices.
+  Automatically called for facet merging and Voronoi diagrams
+  Do not print QhullVertex::facetNeighbors is !facetNeighborsDefined()
+- Fixed type of vertex->neighbors in qh_printvoronoi [no effect on results]
+- Removed unnecessary if statement in qh_printvoronoi
 
 ------------
 gitorious.org/qhull 2010/01/25
-- qh-optf.htm: Add note about order of 'Fn' matching 'Fv' order [Q. Pan]
 - Fixed src/CMakeLists.txt [M. Moll]
+- qh-optf.htm: Add note about order of 'Fn' matching 'Fv' order [Q. Pan]
 - Add .gitignore with ignored files and directories.  
 -   Use .git/info/exclude for locally excluded files.
 
diff --git a/src/io.c b/src/io.c
index 1ebea06..f912df4 100644
--- a/src/io.c
+++ b/src/io.c
@@ -3443,7 +3443,7 @@ void qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets,
       if (qh hull_dim == 3)
         qh_order_vertexneighbors(vertex);
       else if (qh hull_dim >= 4)
-        qsort(SETaddr_(vertex->neighbors, vertexT),
+        qsort(SETaddr_(vertex->neighbors, facetT),
              (size_t)qh_setsize(vertex->neighbors),
              sizeof(facetT *), qh_compare_facetvisit);
       FOREACHneighbor_(vertex) {
@@ -3456,11 +3456,9 @@ void qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets,
     if (format == qh_PRINTgeom) {
       if (vertex) {
         qh_fprintf(fp, 9262, "%d", numneighbors);
-        if (vertex) {
-          FOREACHneighbor_(vertex) {
-            if (neighbor->visitid && neighbor->visitid < numfacets)
-              qh_fprintf(fp, 9263, " %d", neighbor->visitid);
-          }
+        FOREACHneighbor_(vertex) {
+          if (neighbor->visitid && neighbor->visitid < numfacets)
+            qh_fprintf(fp, 9263, " %d", neighbor->visitid);
         }
         qh_fprintf(fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);
       }else
-- 
GitLab