1 /****************************************************************************
2 **
3 ** Copyright (c) 2009-2019 C.B. Barber. All rights reserved.
4 ** $Id: //main/2019/qhull/src/libqhullcpp/PointCoordinates.cpp#1 $$Change: 2661 $
5 ** $DateTime: 2019/05/24 20:09:58 $$Author: bbarber $
6 **
7 ****************************************************************************/
8 
9 #include "libqhullcpp/PointCoordinates.h"
10 
11 #include "libqhullcpp/QhullError.h"
12 #include "libqhullcpp/QhullPoint.h"
13 
14 #include <iterator>
15 #include <iostream>
16 
17 using std::istream;
18 using std::string;
19 using std::ws;
20 
21 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
22 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
23 #endif
24 
25 namespace orgQhull {
26 
27 #//! PointCoordinates -- vector of PointCoordinates
28 
29 #//!\name Constructors
30 
31 PointCoordinates::
PointCoordinates()32 PointCoordinates()
33 : QhullPoints()
34 , point_coordinates()
35 , describe_points()
36 {
37 }
38 
39 PointCoordinates::
PointCoordinates(const std::string & aComment)40 PointCoordinates(const std::string &aComment)
41 : QhullPoints()
42 , point_coordinates()
43 , describe_points(aComment)
44 {
45 }
46 
47 PointCoordinates::
PointCoordinates(int pointDimension,const std::string & aComment)48 PointCoordinates(int pointDimension, const std::string &aComment)
49 : QhullPoints()
50 , point_coordinates()
51 , describe_points(aComment)
52 {
53     setDimension(pointDimension);
54 }
55 
56 //! Qhull and QhullQh constructors are the same
57 PointCoordinates::
PointCoordinates(const Qhull & q)58 PointCoordinates(const Qhull &q)
59 : QhullPoints(q)
60 , point_coordinates()
61 , describe_points()
62 {
63 }
64 
65 PointCoordinates::
PointCoordinates(const Qhull & q,const std::string & aComment)66 PointCoordinates(const Qhull &q, const std::string &aComment)
67 : QhullPoints(q)
68 , point_coordinates()
69 , describe_points(aComment)
70 {
71 }
72 
73 PointCoordinates::
PointCoordinates(const Qhull & q,int pointDimension,const std::string & aComment)74 PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment)
75 : QhullPoints(q)
76 , point_coordinates()
77 , describe_points(aComment)
78 {
79     setDimension(pointDimension);
80 }
81 
82 PointCoordinates::
PointCoordinates(const Qhull & q,int pointDimension,const std::string & aComment,countT coordinatesCount,const coordT * c)83 PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c)
84 : QhullPoints(q)
85 , point_coordinates()
86 , describe_points(aComment)
87 {
88     setDimension(pointDimension);
89     append(coordinatesCount, c);
90 }
91 
92 PointCoordinates::
PointCoordinates(QhullQh * qqh)93 PointCoordinates(QhullQh *qqh)
94 : QhullPoints(qqh)
95 , point_coordinates()
96 , describe_points()
97 {
98 }
99 
100 PointCoordinates::
PointCoordinates(QhullQh * qqh,const std::string & aComment)101 PointCoordinates(QhullQh *qqh, const std::string &aComment)
102 : QhullPoints(qqh)
103 , point_coordinates()
104 , describe_points(aComment)
105 {
106 }
107 
108 PointCoordinates::
PointCoordinates(QhullQh * qqh,int pointDimension,const std::string & aComment)109 PointCoordinates(QhullQh *qqh, int pointDimension, const std::string &aComment)
110 : QhullPoints(qqh)
111 , point_coordinates()
112 , describe_points(aComment)
113 {
114     setDimension(pointDimension);
115 }
116 
117 PointCoordinates::
PointCoordinates(QhullQh * qqh,int pointDimension,const std::string & aComment,countT coordinatesCount,const coordT * c)118 PointCoordinates(QhullQh *qqh, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c)
119 : QhullPoints(qqh)
120 , point_coordinates()
121 , describe_points(aComment)
122 {
123     setDimension(pointDimension);
124     append(coordinatesCount, c);
125 }
126 
127 PointCoordinates::
PointCoordinates(const PointCoordinates & other)128 PointCoordinates(const PointCoordinates &other)
129 : QhullPoints(other)
130 , point_coordinates(other.point_coordinates)
131 , describe_points(other.describe_points)
132 {
133     makeValid();  // Update point_first and point_end
134 }
135 
136 PointCoordinates & PointCoordinates::
operator =(const PointCoordinates & other)137 operator=(const PointCoordinates &other)
138 {
139     QhullPoints::operator=(other);
140     point_coordinates= other.point_coordinates;
141     describe_points= other.describe_points;
142     makeValid(); // Update point_first and point_end
143     return *this;
144 }//operator=
145 
146 PointCoordinates::
~PointCoordinates()147 ~PointCoordinates()
148 { }
149 
150 #//!\name GetSet
151 
152 void PointCoordinates::
checkValid() const153 checkValid() const
154 {
155     if(getCoordinates().data()!=data()
156     || getCoordinates().count()!=coordinateCount()){
157         throw QhullError(10060, "Qhull error: first point (%x) is not PointCoordinates.data() or count (%d) is not PointCoordinates.count (%d)", coordinateCount(), getCoordinates().count(), 0.0, data());
158     }
159 }//checkValid
160 
161 void PointCoordinates::
setDimension(int i)162 setDimension(int i)
163 {
164     if(i<0){
165         throw QhullError(10062, "Qhull error: can not set PointCoordinates dimension to %d", i);
166     }
167     int currentDimension=QhullPoints::dimension();
168     if(currentDimension!=0 && i!=currentDimension){
169         throw QhullError(10063, "Qhull error: can not change PointCoordinates dimension (from %d to %d)", currentDimension, i);
170     }
171     QhullPoints::setDimension(i);
172 }//setDimension
173 
174 #//!\name Foreach
175 
176 Coordinates::ConstIterator PointCoordinates::
beginCoordinates(countT pointIndex) const177 beginCoordinates(countT pointIndex) const
178 {
179     return point_coordinates.begin()+indexOffset(pointIndex);
180 }
181 
182 Coordinates::Iterator PointCoordinates::
beginCoordinates(countT pointIndex)183 beginCoordinates(countT pointIndex)
184 {
185     return point_coordinates.begin()+indexOffset(pointIndex);
186 }
187 
188 #//!\name Methods
189 
190 void PointCoordinates::
append(countT coordinatesCount,const coordT * c)191 append(countT coordinatesCount, const coordT *c)
192 {
193     if(coordinatesCount<=0){
194         return;
195     }
196     if(includesCoordinates(c)){
197         throw QhullError(10065, "Qhull error: can not append a subset of PointCoordinates to itself.  The coordinates for point %d may move.", indexOf(c, QhullError::NOthrow));
198     }
199     reserveCoordinates(coordinatesCount);
200     std::copy(c, c+coordinatesCount, std::back_inserter(point_coordinates));
201     makeValid();
202 }//append coordT
203 
204 void PointCoordinates::
append(const PointCoordinates & other)205 append(const PointCoordinates &other)
206 {
207     setDimension(other.dimension());
208     append(other.coordinateCount(), other.data());
209 }//append PointCoordinates
210 
211 void PointCoordinates::
append(const QhullPoint & p)212 append(const QhullPoint &p)
213 {
214     setDimension(p.dimension());
215     append(p.dimension(), p.coordinates());
216 }//append QhullPoint
217 
218 void PointCoordinates::
appendComment(const std::string & s)219 appendComment(const std::string &s){
220     if(char c= s[0] && describe_points.empty()){
221         if(c=='-' || isdigit(c)){
222             throw QhullError(10028, "Qhull argument error: comments can not start with a number or minus, %s", 0, 0, 0.0, s.c_str());
223         }
224     }
225     describe_points += s;
226 }//appendComment
227 
228 //! Read PointCoordinates from istream.  First two numbers are dimension and count.  A non-digit starts a rboxCommand.
229 //! Overwrites describe_points.  See qh_readpoints [io.c]
230 void PointCoordinates::
appendPoints(istream & in)231 appendPoints(istream &in)
232 {
233     int inDimension;
234     countT inCount;
235     in >> ws >> inDimension >> ws;
236     if(!in.good()){
237         in.clear();
238         string remainder;
239         getline(in, remainder);
240         throw QhullError(10005, "Qhull error: input did not start with dimension or count -- %s", 0, 0, 0, remainder.c_str());
241     }
242     char c= static_cast<char>(in.peek());
243     if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
244         getline(in, describe_points);
245         in >> ws;
246     }
247     in >> inCount >> ws;
248     if(!in.good()){
249         in.clear();
250         string remainder;
251         getline(in, remainder);
252         throw QhullError(10009, "Qhull error: input did not start with dimension and count -- %d %s", inDimension, 0, 0, remainder.c_str());
253     }
254     c= static_cast<char>(in.peek());
255     if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
256         getline(in, describe_points);
257         in >> ws;
258     }
259     if(inCount<inDimension){           // Count may precede dimension
260         std::swap(inCount, inDimension);
261     }
262     setDimension(inDimension);
263     reserveCoordinates(inCount*inDimension);
264     countT coordinatesCount= 0;
265     while(!in.eof()){
266         realT p;
267         in >> p;
268         if(in.fail()){
269             in.clear();
270             string remainder;
271             getline(in, remainder);
272             throw QhullError(10008, "Qhull error: failed to read coordinate %d  of point %d\n   '%s'", coordinatesCount % inDimension, coordinatesCount/inDimension, 0, remainder.c_str());
273         }else{
274             point_coordinates.push_back(p);
275             coordinatesCount++;
276         }
277         in >> ws;
278     }
279     if(coordinatesCount != inCount*inDimension){
280         if(coordinatesCount%inDimension==0){
281             throw QhullError(10006, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates", int(inCount), inDimension, 0.0, int(coordinatesCount/inDimension));
282         }else{
283             throw QhullError(10012, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates plus %f extra coordinates", inCount, inDimension, float(coordinatesCount%inDimension), coordinatesCount/inDimension);
284         }
285     }
286     makeValid();
287 }//appendPoints istream
288 
289 PointCoordinates PointCoordinates::
operator +(const PointCoordinates & other) const290 operator+(const PointCoordinates &other) const
291 {
292     PointCoordinates pc= *this;
293     pc << other;
294     return pc;
295 }//operator+
296 
297 void PointCoordinates::
reserveCoordinates(countT newCoordinates)298 reserveCoordinates(countT newCoordinates)
299 {
300     // vector::reserve is not const
301     point_coordinates.reserve(static_cast<countT>(point_coordinates.size()+newCoordinates)); // WARN64
302     makeValid();
303 }//reserveCoordinates
304 
305 #//!\name Helpers
306 
307 countT PointCoordinates::
indexOffset(countT i) const308 indexOffset(countT i) const {
309     countT n= i*dimension();
310     countT coordinatesCount= point_coordinates.count();
311     if(i<0 || n>coordinatesCount){
312         throw QhullError(10061, "Qhull error: point_coordinates is too short (%d) for point %d", coordinatesCount, i);
313     }
314     return n;
315 }
316 
317 }//namespace orgQhull
318 
319 #//!\name Global functions
320 
321 using std::endl;
322 using std::ostream;
323 
324 using orgQhull::Coordinates;
325 using orgQhull::PointCoordinates;
326 
327 ostream&
operator <<(ostream & os,const PointCoordinates & p)328 operator<<(ostream &os, const PointCoordinates &p)
329 {
330     p.checkValid();
331     countT count= p.count();
332     int dimension= p.dimension();
333     string comment= p.comment();
334     if(comment.empty()){
335         os << dimension << endl;
336     }else{
337         os << dimension << " " << comment << endl;
338     }
339     os << count << endl;
340     Coordinates::ConstIterator c= p.beginCoordinates();
341     for(countT i=0; i<count; i++){
342         for(int j=0; j<dimension; j++){
343             os << *c++ << " ";
344         }
345         os << endl;
346     }
347     return os;
348 }//operator<<
349 
350