1 /*
2  * Stellarium
3  * Copyright (C) 2009 Fabien Chereau
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18  */
19 
20 #ifndef STELSPHEREGEOMETRY_HPP
21 #define STELSPHEREGEOMETRY_HPP
22 
23 #include "OctahedronPolygon.hpp"
24 #include "StelVertexArray.hpp"
25 #include "VecMath.hpp"
26 
27 #include <QVector>
28 #include <QVariant>
29 #include <QDebug>
30 #include <QSharedPointer>
31 #include <QVarLengthArray>
32 #include <QDataStream>
33 
34 #include <cstdio>
35 
36 class SphericalRegion;
37 class SphericalPolygon;
38 class SphericalConvexPolygon;
39 class SphericalCap;
40 class SphericalPoint;
41 class AllSkySphericalRegion;
42 class EmptySphericalRegion;
43 
44 //! @file StelSphereGeometry.hpp
45 //! Define all SphericalGeometry primitives as well as the SphericalRegionP type.
46 
47 //! @class SphericalRegionP
48 //! A shared pointer on a SphericalRegion.
49 class SphericalRegionP : public QSharedPointer<SphericalRegion>
50 {
51 public:
52 	// Override the constructors of QSharedPointer
SphericalRegionP()53 	SphericalRegionP() {;}
SphericalRegionP(SphericalRegion * ptr)54 	SphericalRegionP(SphericalRegion* ptr) : QSharedPointer<SphericalRegion>(ptr) {;}
SphericalRegionP(SphericalRegion * ptr,Deleter deleter)55 	template <class Deleter> SphericalRegionP(SphericalRegion* ptr, Deleter deleter) : QSharedPointer<SphericalRegion>(ptr, deleter) {;}
SphericalRegionP(const SphericalRegionP & other)56 	SphericalRegionP(const SphericalRegionP& other) : QSharedPointer<SphericalRegion>(other) {;}
SphericalRegionP(const QWeakPointer<SphericalRegion> & other)57 	SphericalRegionP(const QWeakPointer<SphericalRegion>& other) : QSharedPointer<SphericalRegion>(other) {;}
operator =(const SphericalRegionP & other)58 	inline SphericalRegionP& operator=(const SphericalRegionP &other){QSharedPointer<SphericalRegion>::operator=(other); return *this;}
59 
60 	//! Create a SphericalRegion from the given input JSON stream.
61 	//! The type of the region is automatically recognized from the input format.
62 	//! The currently recognized format are:
63 	//! <ul>
64 	//! <li>Contour list:
65 	//! @code[[contour1], [contour2],[...]]@endcode
66 	//! This format consists of a list of contours. Contours defined in counterclockwise direction (CW) are
67 	//! added to the final region while CCW contours are subtracted (they can be used to form complex polygons even with holes).
68 	//! Each contour can have different format:
69 	//! <ul>
70 	//! <li>
71 	//! @code[[ra,dec], [ra,dec], [ra,dec], [ra,dec]]@endcode
72 	//! A list of points connected by great circles with the last point connected to the first one.
73 	//! Each point is defined by its ra,dec coordinates in degrees.</li>
74 	//! <li>
75 	//! @code["CAP", [raCenter,decCenter], ap]@endcode
76 	//! A spherical cap centered on raCenter/decCenter with aperture radius ap in degrees. For example:
77 	//! @code["CAP", [0.,-90.], 90]@endcode
78 	//! define the region covering the entire southern hemisphere.</li>
79 	//! <li>
80 	//! @code["PATH", [startRa,startDec], [[prim1],[prim2],[prim3],...]]@endcode
81 	//! A path is a contour starting a startRa/startDec and defined by a list of primitives. Each primitive can be either
82 	//! a great circle or a small circle. Great circles are defined by the point to link to: ["greatCircleTo", [ra,dec]]. Small
83 	//! circles are defined by a rotation axis and a rotation angle: ["smallCircle",[0,90],-88]. A full example is:
84 	//! @code["PATH",[330,-25],[["smallCircle",[0,90],82.5],["greatCircleTo",[52.5,-35]],["smallCircle",[0,90],-82.5]]]@endcode
85 	//! This defines a box of 82.5x10 degrees following latitude and longitude lines.</li>
86 	//! </ul>
87 	//! <li>Polygon vertex list with associated texture coordinates:
88 	//! @code{
89 	//!     "worldCoords": [[[ra,dec],[ra,dec],[ra,dec],[ra,dec]], [[ra,dec],[ra,dec],[ra,dec]],[...]],
90 	//!     "textureCoords": [[[u,v],[u,v],[u,v],[u,v]], [[u,v],[u,v],[u,v]], [...]]
91 	//! }@endcode
92 	//! The format is used to describe textured polygons. The worldCoords part is similar to the one described above.
93 	//! The textureCoords part is the addition of a list of texture coordinates in the u,v texture space (between 0 and 1).
94 	//! There must be one texture coordinate for each vertex.</li>
95 	//! </ul>
96 	//! @param in an open QIODevice ready for read.
97 	//! @throws std::runtime_error when there was an error while parsing the file.
98 	static SphericalRegionP loadFromJson(QIODevice* in);
99 
100 	//! Create a SphericalRegion from the given QByteArray containing the JSON data.
101 	//! @see loadFromJson(QIODevice* in) for format info.
102 	static SphericalRegionP loadFromJson(const QByteArray& a);
103 
104 	//! Create a SphericalRegion from the given QVariantMap with a format matching the JSON file parsed in loadFromJson().
105 	//! @param map a valid QVariantMap which can be created e.g. from parsing a JSON file with the StelJsonParser class.
106 	static SphericalRegionP loadFromQVariant(const QVariantMap& map);
107 	// It can only be a pure shape definition, without texture coords
108 	static SphericalRegionP loadFromQVariant(const QVariantList& list);
109 
110 	//! Method registered to JSON serializer.
111 	static void serializeToJson(const QVariant& jsonObject, QIODevice* output, int indentLevel=0);
112 
113 	//! The meta type ID associated to a SphericalRegionP.
114 	static int metaTypeId;
115 
116 private:
117 	//! Initialize stuff to allow SphericalRegionP to be used with Qt meta type system.
118 	static int initialize();
119 };
120 
121 // Allow to use SphericalRegionP with the Qt MetaType system.
122 Q_DECLARE_METATYPE(SphericalRegionP)
123 
124 //! Serialize the passed SphericalRegionP into a binary blob.
125 QDataStream& operator<<(QDataStream& out, const SphericalRegionP& region);
126 //! Load the SphericalRegionP from a binary blob.
127 QDataStream& operator>>(QDataStream& in, SphericalRegionP& region);
128 
129 //! @class SphericalRegion
130 //! Abstract class defining a region of the sphere. It provides default implementation for the general non-convex polygon
131 //! which can extend on more than 180 deg based on the OctahedronPolygon class.
132 //! Subclasses provides special faster implementations of many methods.
133 class SphericalRegion
134 {
135 public:
136 	//! @enum SphericalRegionType define types for all supported regions.
137 	enum SphericalRegionType
138 	{
139 		Point         = 0,
140 		Cap           = 1,
141 		AllSky        = 2,
142 		Polygon       = 3,
143 		ConvexPolygon = 4,
144 		Empty         = 5,
145 		Invalid       = 6
146 	};
147 
~SphericalRegion()148 	virtual ~SphericalRegion() {;}
149 
150 	virtual SphericalRegionType getType() const = 0;
151 
152 	//! Return the octahedron contour representation of the polygon.
153 	//! It can be used for safe computation of intersection/union in the general case.
154 	virtual OctahedronPolygon getOctahedronPolygon() const =0;
155 
156 	//! Return the area of the region in steradians.
getArea() const157 	virtual double getArea() const {return getOctahedronPolygon().getArea();}
158 
159 	//! Return true if the region is empty.
isEmpty() const160 	virtual bool isEmpty() const {return getOctahedronPolygon().isEmpty();}
161 
162 	//! Return a point located inside the region.
getPointInside() const163 	virtual Vec3d getPointInside() const {return getOctahedronPolygon().getPointInside();}
164 
165 	//! Return the list of SphericalCap bounding the ConvexPolygon.
166 	virtual QVector<SphericalCap> getBoundingSphericalCaps() const;
167 
168 	//! Return a bounding SphericalCap. This method is heavily used and therefore needs to be very fast.
169 	//! The returned SphericalCap doesn't have to be the smallest one, but smaller is better.
170 	virtual SphericalCap getBoundingCap() const;
171 
172 	//! Return an enlarged version of this SphericalRegion so that any point distant of more
173 	//! than the given margin now lays within the region.
174 	//! The returned region can be larger than the smallest enlarging region, therefore returning
175 	//! false positive on subsequent intersection tests.
176 	//! The default implementation always return an enlarged bounding SphericalCap.
177 	//! @param margin the minimum enlargement margin in radian.
178 	virtual SphericalRegionP getEnlarged(double margin) const;
179 
180 	//! Return an OpenGL compatible array to be displayed using vertex arrays.
getFillVertexArray() const181 	virtual StelVertexArray getFillVertexArray() const {return getOctahedronPolygon().getFillVertexArray();}
182 	//! Return an OpenGL compatible array to be displayed using vertex arrays.
183 	//! @note Presumably these general polygons of the base class don't describe geometry that may undergo aberration, so the observerVelocity must be zero.
184 	//! Implementation in derived classes should show aberration correction.
getFillVertexArray(const Vec3d & observerVelocityForAberration)185 	virtual StelVertexArray getFillVertexArray(const Vec3d &observerVelocityForAberration) {
186 		Q_ASSERT(observerVelocityForAberration==Vec3d(0.));
187 		return getOctahedronPolygon().getFillVertexArray();}
188 
189 	//! Get the outline of the contours defining the SphericalPolygon.
190 	//! @return a list of vertex which taken 2 by 2 define the contours of the polygon.
getOutlineVertexArray() const191 	virtual StelVertexArray getOutlineVertexArray() const {return getOctahedronPolygon().getOutlineVertexArray();}
192 	//! Get the outline of the contours defining the SphericalPolygon.
193 	//! @note Presumably these general polygons of the base class don't describe geometry that may undergo aberration, so the observerVelocity must be zero.
194 	//! Implementation in derived classes should show aberration correction.
getOutlineVertexArray(Vec3d observerVelocityForAberration)195 	virtual StelVertexArray getOutlineVertexArray(Vec3d observerVelocityForAberration) {
196 		Q_ASSERT(observerVelocityForAberration==Vec3d(0.));
197 		return getOctahedronPolygon().getOutlineVertexArray();}
198 
199 	//! Get the contours defining the SphericalPolygon when combined using a positive winding rule.
200 	//! The default implementation returns a list of tessellated triangles derived from the OctahedronPolygon.
201 	virtual QVector<QVector<Vec3d > > getSimplifiedContours() const;
202 
203 	//! Serialize the region into a QVariant list matching the JSON format.
204 	virtual QVariantList toQVariant() const = 0;
205 
206 	//! Serialize the region. This method must allow as fast as possible serialization and work with deserialize().
207 	virtual void serialize(QDataStream& out) const = 0;
208 
209 	//! Output a JSON string representing the polygon.
210 	//! This method is convenient for debugging.
211 	QByteArray toJSON() const;
212 
213 	//! Returns whether a SphericalRegion is contained into this region.
214 	//! A default potentially very slow implementation is provided for each cases.
215 	bool contains(const SphericalRegion* r) const;
contains(const SphericalRegionP r) const216 	bool contains(const SphericalRegionP r) const {return contains(r.data());}
contains(const Vec3d & p) const217 	virtual bool contains(const Vec3d& p) const {return getOctahedronPolygon().contains(p);}
218 	virtual bool contains(const SphericalPolygon& r) const;
219 	virtual bool contains(const SphericalConvexPolygon& r) const;
220 	virtual bool contains(const SphericalCap& r) const;
221 	virtual bool contains(const SphericalPoint& r) const;
222 	virtual bool contains(const AllSkySphericalRegion& r) const;
contains(const EmptySphericalRegion &) const223 	bool contains(const EmptySphericalRegion&) const {return false;}
224 
225 	//! Returns whether a SphericalRegion intersects with this region.
226 	//! A default potentially very slow implementation is provided for each cases.
227 	bool intersects(const SphericalRegion* r) const;
intersects(const SphericalRegionP r) const228 	bool intersects(const SphericalRegionP r) const {return intersects(r.data());}
intersects(const Vec3d & p) const229 	bool intersects(const Vec3d& p) const {return contains(p);}
230 	virtual bool intersects(const SphericalPolygon& r) const;
231 	virtual bool intersects(const SphericalConvexPolygon& r) const;
232 	virtual bool intersects(const SphericalCap& r) const;
233 	virtual bool intersects(const SphericalPoint& r) const;
234 	virtual bool intersects(const AllSkySphericalRegion& r) const;
intersects(const EmptySphericalRegion &) const235 	bool intersects(const EmptySphericalRegion&) const {return false;}
236 
237 	//! Return a new SphericalRegion consisting of the intersection of this and the given region.
238 	//! A default potentially very slow implementation is provided for each cases.
239 	SphericalRegionP getIntersection(const SphericalRegion* r) const;
getIntersection(const SphericalRegionP r) const240 	SphericalRegionP getIntersection(const SphericalRegionP r) const {return getIntersection(r.data());}
241 	virtual SphericalRegionP getIntersection(const SphericalPolygon& r) const;
242 	virtual SphericalRegionP getIntersection(const SphericalConvexPolygon& r) const;
243 	virtual SphericalRegionP getIntersection(const SphericalCap& r) const;
244 	virtual SphericalRegionP getIntersection(const SphericalPoint& r) const;
245 	virtual SphericalRegionP getIntersection(const AllSkySphericalRegion& r) const;
246 	SphericalRegionP getIntersection(const EmptySphericalRegion& r) const;
247 
248 	//! Return a new SphericalRegion consisting of the union of this and the given region.
249 	//! A default potentially very slow implementation is provided for each cases.
250 	SphericalRegionP getUnion(const SphericalRegion* r) const;
getUnion(const SphericalRegionP r) const251 	SphericalRegionP getUnion(const SphericalRegionP r) const {return getUnion(r.data());}
252 	virtual SphericalRegionP getUnion(const SphericalPolygon& r) const;
253 	virtual SphericalRegionP getUnion(const SphericalConvexPolygon& r) const;
254 	virtual SphericalRegionP getUnion(const SphericalCap& r) const;
255 	virtual SphericalRegionP getUnion(const SphericalPoint& r) const;
256 	SphericalRegionP getUnion(const AllSkySphericalRegion& r) const;
257 	virtual SphericalRegionP getUnion(const EmptySphericalRegion& r) const;
258 
259 	//! Return a new SphericalRegion consisting of the subtraction of the given region from this.
260 	//! A default potentially very slow implementation is provided for each cases.
261 	SphericalRegionP getSubtraction(const SphericalRegion* r) const;
getSubtraction(const SphericalRegionP r) const262 	SphericalRegionP getSubtraction(const SphericalRegionP r) const {return getSubtraction(r.data());}
263 	virtual SphericalRegionP getSubtraction(const SphericalPolygon& r) const;
264 	virtual SphericalRegionP getSubtraction(const SphericalConvexPolygon& r) const;
265 	virtual SphericalRegionP getSubtraction(const SphericalCap& r) const;
266 	virtual SphericalRegionP getSubtraction(const SphericalPoint& r) const;
267 	SphericalRegionP getSubtraction(const AllSkySphericalRegion& r) const;
268 	virtual SphericalRegionP getSubtraction(const EmptySphericalRegion& r) const;
269 
270 private:
271 	bool containsDefault(const SphericalRegion* r) const;
272 	bool intersectsDefault(const SphericalRegion* r) const;
273 	SphericalRegionP getIntersectionDefault(const SphericalRegion* r) const;
274 	SphericalRegionP getUnionDefault(const SphericalRegion* r) const;
275 	SphericalRegionP getSubtractionDefault(const SphericalRegion* r) const;
276 };
277 
278 
279 //! @class SphericalCap
280 //! A SphericalCap is defined by a direction and an aperture.
281 //! It forms a cone from the center of the Coordinate frame with a radius d.
282 //! It is a disc on the sphere, a region above a circle on the unit sphere.
283 class SphericalCap : public SphericalRegion
284 {
285 	using SphericalRegion::contains;
286 public:
287 	//! Construct a SphericalCap with a 90 deg aperture and an undefined direction.
SphericalCap()288 	SphericalCap() : d(0) {;}
289 
290 	//! Construct a SphericalCap from its direction and assumes a 90 deg aperture.
SphericalCap(double x,double y,double z)291 	SphericalCap(double x, double y, double z) : n(x,y,z), d(0) {;}
292 
293 	//! Construct a SphericalCap from its direction and aperture.
294 	//! @param an a unit vector indicating the direction.
295 	//! @param ar cosinus of the aperture.
SphericalCap(const Vec3d & an,double ar)296 	SphericalCap(const Vec3d& an, double ar) : n(an), d(ar) {//n.normalize();
297 		Q_ASSERT(d==0 || qFuzzyCompare(n.lengthSquared(),1.));}
298 	// FIXME: GZ reports 2013-03-02: apparently the Q_ASSERT is here because n should be normalized at this point, but
299 	// for efficiency n.normalize() should not be called at this point.
300 	// However, when zooming in a bit in Hammer-Aitoff and Mercator projections, this Assertion fires.
301 	// Atmosphere must be active
302 	// It may have to do with DSO texture rendering.
303 	// found at r5863.
304 	// n.normalize() prevents this for now, but may cost performance.
305 	// AARGH - activating n.normalize() inhibits mouse-identification/selection of stars!
306 	// May be compiler dependent (seen on Win/MinGW), AW cannot confirm it on Linux.
307 
308 	//! Copy constructor.
SphericalCap(const SphericalCap & other)309 	SphericalCap(const SphericalCap& other) : SphericalRegion(), n(other.n), d(other.d) {;}
operator =(const SphericalCap & other)310 	inline SphericalCap& operator=(const SphericalCap &other){n=other.n; d=other.d; return *this;}
311 
getType() const312 	virtual SphericalRegionType getType() const Q_DECL_OVERRIDE {return SphericalRegion::Cap;}
313 	virtual OctahedronPolygon getOctahedronPolygon() const Q_DECL_OVERRIDE;
314 
315 	//! Get the area of the intersection of the halfspace on the sphere in steradian.
getArea() const316 	virtual double getArea() const Q_DECL_OVERRIDE {return 2.*M_PI*(1.-d);}
317 
318 	//! Return true if the region is empty.
isEmpty() const319 	virtual bool isEmpty() const Q_DECL_OVERRIDE {return d>=1.;}
320 
321 	//! Return a point located inside the SphericalCap.
getPointInside() const322 	virtual Vec3d getPointInside() const Q_DECL_OVERRIDE {return n;}
323 
324 	//! Return itself.
getBoundingCap() const325 	virtual SphericalCap getBoundingCap() const Q_DECL_OVERRIDE {return *this;}
326 
327 	// Contain and intersect
contains(const Vec3d & v) const328 	virtual bool contains(const Vec3d &v) const Q_DECL_OVERRIDE {Q_ASSERT(d==0 || std::fabs(v.lengthSquared()-1.)<0.0000002);return (v*n>=d);}
contains(const Vec3f & v) const329 	virtual bool contains(const Vec3f &v) const {Q_ASSERT(d==0 || std::fabs(v.lengthSquared()-1.f)<0.000002f);return (v.toVec3d()*n>=d);}
330 	virtual bool contains(const SphericalConvexPolygon& r) const Q_DECL_OVERRIDE;
contains(const SphericalCap & h) const331 	virtual bool contains(const SphericalCap& h) const Q_DECL_OVERRIDE
332 	{
333 		const double a = n*h.n-d*h.d;
334 		return d<=h.d && ( a>=1. || (a>=0. && a*a >= (1.-d*d)*(1.-h.d*h.d)));
335 	}
contains(const AllSkySphericalRegion &) const336 	virtual bool contains(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return d<=-1;}
337 	virtual bool intersects(const SphericalPolygon& r) const Q_DECL_OVERRIDE;
338 	virtual bool intersects(const SphericalConvexPolygon& r) const Q_DECL_OVERRIDE;
339 	//! Returns whether a SphericalCap intersects with this one.
340 	//! I managed to make it without sqrt or acos, so it is very fast!
341 	//! @see http://f4bien.blogspot.com/2009/05/spherical-geometry-optimisations.html for detailed explanations.
intersects(const SphericalCap & h) const342 	virtual bool intersects(const SphericalCap& h) const Q_DECL_OVERRIDE
343 	{
344 		const double a = d*h.d - n*h.n;
345 		return d+h.d<=0. || a<=0. || (a<=1. && a*a <= (1.-d*d)*(1.-h.d*h.d));
346 	}
intersects(const AllSkySphericalRegion &) const347 	virtual bool intersects(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return d<=1.;}
348 
349 	//! Serialize the region into a QVariant map matching the JSON format.
350 	//! The format is ["CAP", [ra, dec], radius], with ra dec in degree in ICRS frame
351 	//! and radius in degree (between 0 and 180 deg)
352 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
353 
serialize(QDataStream & out) const354 	virtual void serialize(QDataStream& out) const Q_DECL_OVERRIDE {out << n << d;}
355 
356 	////////////////////////////////////////////////////////////////////
357 	// Methods specific to SphericalCap
358 
359 	//! Return the radiusof the cap  in radian
getRadius() const360 	double getRadius() const {return std::acos(d);}
361 
362 	//! Returns whether a HalfSpace (like a SphericalCap with d=0) intersects with this SphericalCap.
363 	//! @param hn0 the x direction of the halfspace.
364 	//! @param hn1 the y direction of the halfspace.
365 	//! @param hn2 the z direction of the halfspace.
intersectsHalfSpace(double hn0,double hn1,double hn2) const366 	inline bool intersectsHalfSpace(double hn0, double hn1, double hn2) const
367 	{
368 		const double a = n[0]*hn0+n[1]*hn1+n[2]*hn2;
369 		return d<=0. || a<=0. || (a<=1. && a*a <= (1.-d*d));
370 	}
371 
372 	//! Clip the passed great circle connecting points v1 and v2.
373 	//! @return true if the great circle intersects with the cap, false otherwise.
374 	bool clipGreatCircle(Vec3d& v1, Vec3d& v2) const;
375 
376 	//! Comparison operator.
operator ==(const SphericalCap & other) const377 	bool operator==(const SphericalCap& other) const {return (n==other.n && d==other.d);}
378 
379 	//! Return the list of closed contours defining the polygon boundaries.
380 	QVector<Vec3d> getClosedOutlineContour() const;
381 
382 	//! Return whether the cap intersect with a convex contour defined by nbVertice.
383 	bool intersectsConvexContour(const Vec3d* vertice, int nbVertice) const;
384 
385 	//! Return whether the cap contains the passed triangle.
386 	bool containsTriangle(const Vec3d* vertice) const;
387 
388 	//! Return whether the cap intersect with the passed triangle.
389 	bool intersectsTriangle(const Vec3d* vertice) const;
390 
391 	//! Deserialize the region. This method must allow as fast as possible deserialization.
392 	static SphericalRegionP deserialize(QDataStream& in);
393 
394 	//! Return the relative overlap between the areas of the 2 caps, i.e:
395 	//! min(intersectionArea/c1.area, intersectionArea/c2.area)
396 	static double relativeAreaOverlap(const SphericalCap& c1, const SphericalCap& c2);
397 
398 	//! Return the relative overlap between the diameter of the 2 caps, i.e:
399 	//! min(intersectionDistance/c1.diameter, intersectionDistance/c2.diameter)
400 	static double relativeDiameterOverlap(const SphericalCap& c1, const SphericalCap& c2);
401 
402 	//! Compute the intersection of 2 halfspaces on the sphere (usually on 2 points) and return it in p1 and p2.
403 	//! If the 2 SphericalCap don't intersect or intersect only at 1 point, false is returned and p1 and p2 are undefined.
404 	static bool intersectionPoints(const SphericalCap& h1, const SphericalCap& h2, Vec3d& p1, Vec3d& p2);
405 
406 	//! The direction unit vector. Only if d==0, this vector doesn't need to be unit.
407 	Vec3d n;
408 	//! The cos of cone radius
409 	double d;
410 };
411 
412 //! Return whether the halfspace defined by the vectors v1^v2 and with aperture 90 deg contains the point p.
413 //! The comparison is made with a double number slightly smaller than zero to avoid floating point precision
414 //! errors problems (one test fails if it is set to zero).
sideHalfSpaceContains(const Vec3d & v1,const Vec3d & v2,const Vec3d & p)415 inline bool sideHalfSpaceContains(const Vec3d& v1, const Vec3d& v2, const Vec3d& p)
416 {
417 	return (v1[1] * v2[2] - v1[2] * v2[1])*p[0] +
418 			(v1[2] * v2[0] - v1[0] * v2[2])*p[1] +
419 			(v1[0] * v2[1] - v1[1] * v2[0])*p[2]>=-1e-17;
420 }
421 
422 //! Return whether the halfspace defined by the vectors v1 and v2 contains the SphericalCap h.
sideHalfSpaceContains(const Vec3d & v1,const Vec3d & v2,const SphericalCap & h)423 inline bool sideHalfSpaceContains(const Vec3d& v1, const Vec3d& v2, const SphericalCap& h)
424 {
425 	Vec3d n(v1[1]*v2[2]-v1[2]*v2[1], v2[0]*v1[2]-v2[2]*v1[0], v2[1]*v1[0]-v2[0]*v1[1]);
426 	n.normalize();
427 	const double a = n*h.n;
428 	return 0<=h.d && ( a>=1. || (a>=0. && a*a >= 1.-h.d*h.d));
429 }
430 
431 //! Return whether the halfspace defined by the vectors v1 and v2 intersects the SphericalCap h.
sideHalfSpaceIntersects(const Vec3d & v1,const Vec3d & v2,const SphericalCap & h)432 inline bool sideHalfSpaceIntersects(const Vec3d& v1, const Vec3d& v2, const SphericalCap& h)
433 {
434 	Vec3d n(v1[1]*v2[2]-v1[2]*v2[1], v2[0]*v1[2]-v2[2]*v1[0], v2[1]*v1[0]-v2[0]*v1[1]);
435 	n.normalize();
436 	return  h.intersectsHalfSpace(n[0], n[1], n[2]);
437 }
438 
439 //! @class SphericalPoint
440 //! Special SphericalRegion for a point on the sphere.
441 class SphericalPoint : public SphericalRegion
442 {
443 public:
SphericalPoint(const Vec3d & an)444 	SphericalPoint(const Vec3d& an) : n(an) {Q_ASSERT(std::fabs(1.-n.length())<0.0000001);}
SphericalPoint(const SphericalPoint & other)445 	SphericalPoint(const SphericalPoint &other): n(other.n){}
operator =(const SphericalPoint & other)446 	inline SphericalPoint& operator=(const SphericalPoint &other){n=other.n; return *this;}
~SphericalPoint()447 	virtual ~SphericalPoint() Q_DECL_OVERRIDE {;}
448 
getType() const449 	virtual SphericalRegionType getType() const Q_DECL_OVERRIDE {return SphericalRegion::Point;}
450 	virtual OctahedronPolygon getOctahedronPolygon() const Q_DECL_OVERRIDE;
getArea() const451 	virtual double getArea() const Q_DECL_OVERRIDE {return 0.;}
isEmpty() const452 	virtual bool isEmpty() const Q_DECL_OVERRIDE {return false;}
getPointInside() const453 	virtual Vec3d getPointInside() const Q_DECL_OVERRIDE {return n;}
getBoundingCap() const454 	virtual SphericalCap getBoundingCap() const Q_DECL_OVERRIDE {return SphericalCap(n, 1);}
455 	//! Serialize the region into a QVariant map matching the JSON format.
456 	//! The format is ["POINT", [ra, dec]], with ra dec in degree in ICRS frame.
457 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
serialize(QDataStream & out) const458 	virtual void serialize(QDataStream& out) const Q_DECL_OVERRIDE {out << n;}
459 
460 	// Contain and intersect
contains(const Vec3d & p) const461 	virtual bool contains(const Vec3d& p) const Q_DECL_OVERRIDE {return n==p;}
contains(const SphericalPolygon &) const462 	virtual bool contains(const SphericalPolygon&) const Q_DECL_OVERRIDE {return false;}
contains(const SphericalConvexPolygon &) const463 	virtual bool contains(const SphericalConvexPolygon&) const Q_DECL_OVERRIDE {return false;}
contains(const SphericalCap &) const464 	virtual bool contains(const SphericalCap&) const Q_DECL_OVERRIDE {return false;}
contains(const SphericalPoint & r) const465 	virtual bool contains(const SphericalPoint& r) const Q_DECL_OVERRIDE {return n==r.n;}
contains(const AllSkySphericalRegion &) const466 	virtual bool contains(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return false;}
467 	virtual bool intersects(const SphericalPolygon&) const Q_DECL_OVERRIDE;
468 	virtual bool intersects(const SphericalConvexPolygon&) const Q_DECL_OVERRIDE;
intersects(const SphericalCap & r) const469 	virtual bool intersects(const SphericalCap& r) const Q_DECL_OVERRIDE {return r.contains(n);}
intersects(const SphericalPoint & r) const470 	virtual bool intersects(const SphericalPoint& r) const Q_DECL_OVERRIDE {return n==r.n;}
intersects(const AllSkySphericalRegion &) const471 	virtual bool intersects(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return true;}
472 
473 	//! Deserialize the region. This method must allow as fast as possible deserialization.
474 	static SphericalRegionP deserialize(QDataStream& in);
475 
476 	//! The unit vector of the point direction.
477 	Vec3d n;
478 };
479 
480 //! @class AllSkySphericalRegion
481 //! Special SphericalRegion for the whole sphere.
482 class AllSkySphericalRegion : public SphericalRegion
483 {
484 public:
~AllSkySphericalRegion()485 	virtual ~AllSkySphericalRegion() Q_DECL_OVERRIDE {;}
486 
getType() const487 	virtual SphericalRegionType getType() const Q_DECL_OVERRIDE {return SphericalRegion::AllSky;}
getOctahedronPolygon() const488 	virtual OctahedronPolygon getOctahedronPolygon() const Q_DECL_OVERRIDE {return OctahedronPolygon::getAllSkyOctahedronPolygon();}
getArea() const489 	virtual double getArea() const Q_DECL_OVERRIDE {return 4.*M_PI;}
isEmpty() const490 	virtual bool isEmpty() const Q_DECL_OVERRIDE {return false;}
getPointInside() const491 	virtual Vec3d getPointInside() const Q_DECL_OVERRIDE {return Vec3d(1,0,0);}
getBoundingCap() const492 	virtual SphericalCap getBoundingCap() const Q_DECL_OVERRIDE {return SphericalCap(Vec3d(1,0,0), -2);}
493 	//! Serialize the region into a QVariant map matching the JSON format.
494 	//! The format is ["ALLSKY"]
495 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
serialize(QDataStream &) const496 	virtual void serialize(QDataStream&) const Q_DECL_OVERRIDE {;}
497 
498 	// Contain and intersect
contains(const Vec3d &) const499 	virtual bool contains(const Vec3d&) const Q_DECL_OVERRIDE {return true;}
contains(const SphericalPolygon &) const500 	virtual bool contains(const SphericalPolygon&) const Q_DECL_OVERRIDE {return true;}
contains(const SphericalConvexPolygon &) const501 	virtual bool contains(const SphericalConvexPolygon&) const Q_DECL_OVERRIDE {return true;}
contains(const SphericalCap &) const502 	virtual bool contains(const SphericalCap&) const Q_DECL_OVERRIDE {return true;}
contains(const SphericalPoint &) const503 	virtual bool contains(const SphericalPoint&) const Q_DECL_OVERRIDE {return true;}
contains(const AllSkySphericalRegion &) const504 	virtual bool contains(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return true;}
intersects(const SphericalPolygon &) const505 	virtual bool intersects(const SphericalPolygon&) const Q_DECL_OVERRIDE {return true;}
intersects(const SphericalConvexPolygon &) const506 	virtual bool intersects(const SphericalConvexPolygon&) const Q_DECL_OVERRIDE {return true;}
intersects(const SphericalCap &) const507 	virtual bool intersects(const SphericalCap&) const Q_DECL_OVERRIDE {return true;}
intersects(const SphericalPoint &) const508 	virtual bool intersects(const SphericalPoint&) const Q_DECL_OVERRIDE {return true;}
intersects(const AllSkySphericalRegion &) const509 	virtual bool intersects(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return true;}
510 
511 	static const SphericalRegionP staticInstance;
512 };
513 
514 //! @class EmptySphericalRegion
515 //! Special SphericalRegion for --- UMM, WHAT EXACTLY?
516 class EmptySphericalRegion : public SphericalRegion
517 {
518 public:
519 	// Avoid name hiding when overloading the virtual methods.
520 	using SphericalRegion::intersects;
521 	using SphericalRegion::contains;
522 	using SphericalRegion::getIntersection;
523 	using SphericalRegion::getUnion;
524 	using SphericalRegion::getSubtraction;
525 
EmptySphericalRegion()526 	EmptySphericalRegion() {;}
~EmptySphericalRegion()527 	virtual ~EmptySphericalRegion() Q_DECL_OVERRIDE {;}
528 
getType() const529 	virtual SphericalRegionType getType() const Q_DECL_OVERRIDE {return SphericalRegion::Empty;}
getOctahedronPolygon() const530 	virtual OctahedronPolygon getOctahedronPolygon() const Q_DECL_OVERRIDE {return OctahedronPolygon::getEmptyOctahedronPolygon();}
getArea() const531 	virtual double getArea() const Q_DECL_OVERRIDE {return 0.;}
isEmpty() const532 	virtual bool isEmpty() const Q_DECL_OVERRIDE {return true;}
getPointInside() const533 	virtual Vec3d getPointInside() const Q_DECL_OVERRIDE {return Vec3d(1,0,0);}
getBoundingCap() const534 	virtual SphericalCap getBoundingCap() const Q_DECL_OVERRIDE {return SphericalCap(Vec3d(1,0,0), 2);}
535 	//! Serialize the region into a QVariant map matching the JSON format.
536 	//! The format is ["EMPTY"]
537 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
serialize(QDataStream &) const538 	virtual void serialize(QDataStream&) const Q_DECL_OVERRIDE {;}
539 
540 	// Contain and intersect
contains(const Vec3d &) const541 	virtual bool contains(const Vec3d&) const Q_DECL_OVERRIDE {return false;}
contains(const SphericalPolygon &) const542 	virtual bool contains(const SphericalPolygon&) const Q_DECL_OVERRIDE {return false;}
contains(const SphericalConvexPolygon &) const543 	virtual bool contains(const SphericalConvexPolygon&) const Q_DECL_OVERRIDE {return false;}
contains(const SphericalCap &) const544 	virtual bool contains(const SphericalCap&) const Q_DECL_OVERRIDE {return false;}
contains(const SphericalPoint &) const545 	virtual bool contains(const SphericalPoint&) const Q_DECL_OVERRIDE {return false;}
contains(const AllSkySphericalRegion &) const546 	virtual bool contains(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return false;}
intersects(const SphericalPolygon &) const547 	virtual bool intersects(const SphericalPolygon&) const Q_DECL_OVERRIDE {return false;}
intersects(const SphericalConvexPolygon &) const548 	virtual bool intersects(const SphericalConvexPolygon&) const Q_DECL_OVERRIDE {return false;}
intersects(const SphericalCap &) const549 	virtual bool intersects(const SphericalCap&) const Q_DECL_OVERRIDE {return false;}
intersects(const SphericalPoint &) const550 	virtual bool intersects(const SphericalPoint&) const Q_DECL_OVERRIDE {return false;}
intersects(const AllSkySphericalRegion &) const551 	virtual bool intersects(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return false;}
552 
553 	static const SphericalRegionP staticInstance;
554 };
555 
556 
557 //! @class SphericalPolygon
558 //! Class defining default implementations for some spherical geometry methods.
559 //! All methods are reentrant.
560 class SphericalPolygon : public SphericalRegion
561 {
562 public:
563 	// Avoid name hiding when overloading the virtual methods.
564 	using SphericalRegion::intersects;
565 	using SphericalRegion::contains;
566 	using SphericalRegion::getIntersection;
567 	using SphericalRegion::getUnion;
568 	using SphericalRegion::getSubtraction;
569 
SphericalPolygon()570 	SphericalPolygon() {;}
571 	//! Constructor from a list of contours.
SphericalPolygon(const QVector<QVector<Vec3d>> & contours)572 	SphericalPolygon(const QVector<QVector<Vec3d> >& contours) : octahedronPolygon(contours) {;}
573 	//! Constructor from one contour.
SphericalPolygon(const QVector<Vec3d> & contour)574 	SphericalPolygon(const QVector<Vec3d>& contour) : octahedronPolygon(contour) {;}
SphericalPolygon(const OctahedronPolygon & octContour)575 	SphericalPolygon(const OctahedronPolygon& octContour) : octahedronPolygon(octContour) {;}
SphericalPolygon(const QList<OctahedronPolygon> & octContours)576 	SphericalPolygon(const QList<OctahedronPolygon>& octContours) : octahedronPolygon(octContours) {;}
577 
getType() const578 	virtual SphericalRegionType getType() const Q_DECL_OVERRIDE {return SphericalRegion::Polygon;}
getOctahedronPolygon() const579 	virtual OctahedronPolygon getOctahedronPolygon() const Q_DECL_OVERRIDE {return octahedronPolygon;}
580 
581 	//! Serialize the region into a QVariant map matching the JSON format.
582 	//! The format is:
583 	//! @code[[[ra,dec], [ra,dec], [ra,dec], [ra,dec]], [[ra,dec], [ra,dec], [ra,dec]],[...]]@endcode
584 	//! it is a list of closed contours, with each points defined by ra dec in degree in the ICRS frame.
585 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
586 	virtual void serialize(QDataStream& out) const Q_DECL_OVERRIDE;
587 
588 	virtual SphericalCap getBoundingCap() const Q_DECL_OVERRIDE;
589 
contains(const Vec3d & p) const590 	virtual bool contains(const Vec3d& p) const Q_DECL_OVERRIDE {return octahedronPolygon.contains(p);}
contains(const SphericalPolygon & r) const591 	virtual bool contains(const SphericalPolygon& r) const Q_DECL_OVERRIDE {return octahedronPolygon.contains(r.octahedronPolygon);}
592 	virtual bool contains(const SphericalConvexPolygon& r) const Q_DECL_OVERRIDE;
contains(const SphericalCap & r) const593 	virtual bool contains(const SphericalCap& r) const Q_DECL_OVERRIDE {return octahedronPolygon.contains(r.getOctahedronPolygon());}
contains(const SphericalPoint & r) const594 	virtual bool contains(const SphericalPoint& r) const Q_DECL_OVERRIDE {return octahedronPolygon.contains(r.n);}
contains(const AllSkySphericalRegion & r) const595 	virtual bool contains(const AllSkySphericalRegion& r) const Q_DECL_OVERRIDE {return octahedronPolygon.contains(r.getOctahedronPolygon());}
596 
intersects(const SphericalPolygon & r) const597 	virtual bool intersects(const SphericalPolygon& r) const Q_DECL_OVERRIDE {return octahedronPolygon.intersects(r.octahedronPolygon);}
598 	virtual bool intersects(const SphericalConvexPolygon& r) const Q_DECL_OVERRIDE;
intersects(const SphericalCap & r) const599 	virtual bool intersects(const SphericalCap& r) const Q_DECL_OVERRIDE {return r.intersects(*this);}
intersects(const SphericalPoint & r) const600 	virtual bool intersects(const SphericalPoint& r) const Q_DECL_OVERRIDE {return octahedronPolygon.contains(r.n);}
intersects(const AllSkySphericalRegion &) const601 	virtual bool intersects(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return !isEmpty();}
602 
getIntersection(const SphericalPoint & r) const603 	virtual SphericalRegionP getIntersection(const SphericalPoint& r) const Q_DECL_OVERRIDE {return contains(r.n) ? SphericalRegionP(new SphericalPoint(r)) : EmptySphericalRegion::staticInstance;}
getIntersection(const AllSkySphericalRegion &) const604 	virtual SphericalRegionP getIntersection(const AllSkySphericalRegion& ) const Q_DECL_OVERRIDE {return SphericalRegionP(new SphericalPolygon(octahedronPolygon));}
605 
getUnion(const SphericalPoint &) const606 	virtual SphericalRegionP getUnion(const SphericalPoint&) const Q_DECL_OVERRIDE {return SphericalRegionP(new SphericalPolygon(octahedronPolygon));}
getUnion(const EmptySphericalRegion &) const607 	virtual SphericalRegionP getUnion(const EmptySphericalRegion&) const Q_DECL_OVERRIDE {return SphericalRegionP(new SphericalPolygon(octahedronPolygon));}
608 
getSubtraction(const SphericalPoint &) const609 	virtual SphericalRegionP getSubtraction(const SphericalPoint&) const Q_DECL_OVERRIDE {return SphericalRegionP(new SphericalPolygon(octahedronPolygon));}
getSubtraction(const EmptySphericalRegion &) const610 	virtual SphericalRegionP getSubtraction(const EmptySphericalRegion&) const Q_DECL_OVERRIDE {return SphericalRegionP(new SphericalPolygon(octahedronPolygon));}
611 
612 	////////////////////////////////////////////////////////////////////
613 	// Methods specific to SphericalPolygon
614 	//! Set the contours defining the SphericalPolygon.
615 	//! @param contours the list of contours defining the polygon area. The contours are combined using
616 	//! the positive winding rule, meaning that the polygon is the union of the positive contours minus the negative ones.
setContours(const QVector<QVector<Vec3d>> & contours)617 	void setContours(const QVector<QVector<Vec3d> >& contours) {octahedronPolygon = OctahedronPolygon(contours);}
618 
619 	//! Set a single contour defining the SphericalPolygon.
620 	//! @param contour a contour defining the polygon area.
setContour(const QVector<Vec3d> & contour)621 	void setContour(const QVector<Vec3d>& contour) {octahedronPolygon = OctahedronPolygon(contour);}
622 
623 	//! Return the list of closed contours defining the polygon boundaries.
getClosedOutlineContours() const624 	QVector<QVector<Vec3d> > getClosedOutlineContours() const {Q_ASSERT(0); return QVector<QVector<Vec3d> >();}
625 
626 	//! Deserialize the region. This method must allow as fast as possible deserialization.
627 	static SphericalRegionP deserialize(QDataStream& in);
628 
629 	//! Create a new SphericalRegionP which is the union of all the passed ones.
630 	static SphericalRegionP multiUnion(const QList<SphericalRegionP>& regions, bool optimizeByPreGrouping=false);
631 
632 	//! Create a new SphericalRegionP which is the intersection of all the passed ones.
633 	static SphericalRegionP multiIntersection(const QList<SphericalRegionP>& regions);
634 
635 private:
636 	OctahedronPolygon octahedronPolygon;
637 };
638 
639 
640 //! @class SphericalConvexPolygon
641 //! A special case of SphericalPolygon for which the polygon is convex.
642 class SphericalConvexPolygon : public SphericalRegion
643 {
644 public:
645 	// Avoid name hiding when overloading the virtual methods.
646 	using SphericalRegion::intersects;
647 	using SphericalRegion::contains;
648 
649 	//! Default constructor.
SphericalConvexPolygon()650 	SphericalConvexPolygon() {;}
651 
652 	//! Constructor from a list of contours.
SphericalConvexPolygon(const QVector<QVector<Vec3d>> & contours)653 	SphericalConvexPolygon(const QVector<QVector<Vec3d> >& contours) {Q_ASSERT(contours.size()==1); setContour(contours.at(0));}
654 	//! Constructor from one contour.
SphericalConvexPolygon(const QVector<Vec3d> & contour)655 	SphericalConvexPolygon(const QVector<Vec3d>& contour) {setContour(contour);}
656 	//! Special constructor for triangle.
SphericalConvexPolygon(const Vec3d & e0,const Vec3d & e1,const Vec3d & e2)657 	SphericalConvexPolygon(const Vec3d &e0,const Vec3d &e1,const Vec3d &e2) {contour << e0 << e1 << e2; updateBoundingCap();}
658 	//! Special constructor for quads.
SphericalConvexPolygon(const Vec3d & e0,const Vec3d & e1,const Vec3d & e2,const Vec3d & e3)659 	SphericalConvexPolygon(const Vec3d &e0,const Vec3d &e1,const Vec3d &e2, const Vec3d &e3)  {contour << e0 << e1 << e2 << e3; updateBoundingCap();}
660 
getType() const661 	virtual SphericalRegionType getType() const Q_DECL_OVERRIDE {return SphericalRegion::ConvexPolygon;}
getOctahedronPolygon() const662 	virtual OctahedronPolygon getOctahedronPolygon() const Q_DECL_OVERRIDE {return OctahedronPolygon(contour);}
663 	virtual StelVertexArray getFillVertexArray(const Vec3d &observerVelocityForAberration) Q_DECL_OVERRIDE;
664 	virtual StelVertexArray getFillVertexArray() const Q_DECL_OVERRIDE;
665 	virtual StelVertexArray getOutlineVertexArray() const Q_DECL_OVERRIDE;
666 	virtual StelVertexArray getOutlineVertexArray(Vec3d observerVelocityForAberration) Q_DECL_OVERRIDE;
667 	//virtual StelVertexArray getOutlineVertexArray(Vec3d observerVelocityForAberration) const Q_DECL_OVERRIDE;
668 	virtual double getArea() const Q_DECL_OVERRIDE;
isEmpty() const669 	virtual bool isEmpty() const Q_DECL_OVERRIDE {return contour.isEmpty();}
670 	virtual Vec3d getPointInside() const Q_DECL_OVERRIDE;
getBoundingCap() const671 	virtual SphericalCap getBoundingCap() const Q_DECL_OVERRIDE {return cachedBoundingCap;}
672 	QVector<SphericalCap> getBoundingSphericalCaps() const Q_DECL_OVERRIDE;
673 	//! Serialize the region into a QVariant map matching the JSON format.
674 	//! The format is
675 	//! @code["CONVEX_POLYGON", [[ra,dec], [ra,dec], [ra,dec], [ra,dec]]]@endcode
676 	//! where the coords are a closed convex contour, with each points defined by ra dec in degree in the ICRS frame.
677 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
serialize(QDataStream & out) const678 	virtual void serialize(QDataStream& out) const Q_DECL_OVERRIDE {out << contour;}
679 
680 	// Contain and intersect
681 	virtual bool contains(const Vec3d& p) const Q_DECL_OVERRIDE;
682 	virtual bool contains(const SphericalPolygon& r) const Q_DECL_OVERRIDE;
683 	virtual bool contains(const SphericalConvexPolygon& r) const Q_DECL_OVERRIDE;
684 	virtual bool contains(const SphericalCap& r) const Q_DECL_OVERRIDE;
contains(const SphericalPoint & r) const685 	virtual bool contains(const SphericalPoint& r) const Q_DECL_OVERRIDE {return contains(r.n);}
contains(const AllSkySphericalRegion &) const686 	virtual bool contains(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return false;}
intersects(const SphericalCap & r) const687 	virtual bool intersects(const SphericalCap& r) const Q_DECL_OVERRIDE {if (!cachedBoundingCap.intersects(r)) return false; return r.intersects(*this);}
688 	virtual bool intersects(const SphericalPolygon& r) const Q_DECL_OVERRIDE;
689 	virtual bool intersects(const SphericalConvexPolygon& r) const Q_DECL_OVERRIDE;
intersects(const SphericalPoint & r) const690 	virtual bool intersects(const SphericalPoint& r) const Q_DECL_OVERRIDE {return contains(r.n);}
intersects(const AllSkySphericalRegion &) const691 	virtual bool intersects(const AllSkySphericalRegion&) const Q_DECL_OVERRIDE {return true;}
692 
693 	////////////////////////// TODO
694 //	virtual SphericalRegionP getIntersection(const SphericalPolygon& r) const;
695 //	virtual SphericalRegionP getIntersection(const SphericalConvexPolygon& r) const;
696 //	virtual SphericalRegionP getIntersection(const SphericalCap& r) const;
697 //	virtual SphericalRegionP getIntersection(const SphericalPoint& r) const;
698 //	virtual SphericalRegionP getIntersection(const AllSkySphericalRegion& r) const;
699 //	virtual SphericalRegionP getUnion(const SphericalPolygon& r) const;
700 //	virtual SphericalRegionP getUnion(const SphericalConvexPolygon& r) const;
701 //	virtual SphericalRegionP getUnion(const SphericalCap& r) const;
702 //	virtual SphericalRegionP getUnion(const SphericalPoint& r) const;
703 //	virtual SphericalRegionP getUnion(const EmptySphericalRegion& r) const;
704 //	virtual SphericalRegionP getSubtraction(const SphericalPolygon& r) const;
705 //	virtual SphericalRegionP getSubtraction(const SphericalConvexPolygon& r) const;
706 //	virtual SphericalRegionP getSubtraction(const SphericalCap& r) const;
707 //	virtual SphericalRegionP getSubtraction(const SphericalPoint& r) const;
708 //	virtual SphericalRegionP getSubtraction(const EmptySphericalRegion& r) const;
709 
710 	////////////////////////////////////////////////////////////////////
711 	// Methods specific to SphericalConvexPolygon
712 	////////////////////////////////////////////////////////////////////
713 	//! Set a single contour defining the SphericalPolygon.
714 	//! @param acontour a contour defining the polygon area.
setContour(const QVector<Vec3d> & acontour)715 	void setContour(const QVector<Vec3d>& acontour) {contour=acontour; updateBoundingCap();}
716 
717 	//! Get the single contour defining the SphericalConvexPolygon.
getConvexContour() const718 	const QVector<Vec3d>& getConvexContour() const {return contour;}
719 
720 	//! Check if the polygon is valid, i.e. it has no side >180.
721 	bool checkValid() const;
722 
723 	//! Check if the passed contour is convex and valid, i.e. it has no side >180.
724 	static bool checkValidContour(const QVector<Vec3d>& contour);
725 
726 	//! Deserialize the region. This method must allow as fast as possible deserialization.
727 	static SphericalRegionP deserialize(QDataStream& in);
728 
729 protected:
730 	//! A list of vertices of the convex contour.
731 	QVector<Vec3d> contour;
732 	//! A list of vertices, built on the fly from the contour when aberration is required.
733 	QVector<Vec3d> aberratedContour;
734 
735 	//! Cache the bounding cap.
736 	SphericalCap cachedBoundingCap;
737 
738 	//! Update the bounding cap from the vertex list.
739 	void updateBoundingCap();
740 
741 	//! Computes whether the passed points are all outside of at least one SphericalCap defining the polygon boundary.
742 	//! @param thisContour the vertices defining the contour.
743 	//! @param nbThisContour nb of vertice of the contour.
744 	//! @param points the points to test.
745 	//! @param nbPoints the number of points to test.
746 	static bool areAllPointsOutsideOneSide(const Vec3d* thisContour, int nbThisContour, const Vec3d* points, int nbPoints);
747 
748 	//! Computes whether the passed points are all outside of at least one SphericalCap defining the polygon boundary.
areAllPointsOutsideOneSide(const QVector<Vec3d> & points) const749 	bool areAllPointsOutsideOneSide(const QVector<Vec3d>& points) const
750 	{
751 		return areAllPointsOutsideOneSide(contour.constData(), contour.size(), points.constData(), points.size());
752 	}
753 
754 	bool containsConvexContour(const Vec3d* vertice, int nbVertex) const;
755 };
756 
757 
758 // ! @class SphericalConvexPolygonSet
759 // ! A special case of SphericalPolygon for which the polygon is composed of disjoint convex polygons.
760 //class SphericalConvexPolygonSet : public SphericalRegion
761 //{
762 //public:
763 //	// Avoid name hiding when overloading the virtual methods.
764 //	using SphericalRegion::intersects;
765 //	using SphericalRegion::contains;
766 //
767 //	//! Default constructor.
768 //	SphericalConvexPolygonSet() {;}
769 //
770 //	//! Constructor from a list of contours.
771 //	SphericalConvexPolygonSet(const QVector<QVector<Vec3d> >& contours);
772 //
773 //	virtual SphericalRegionType getType() const {return SphericalRegion::ConvexPolygonSet;}
774 //	virtual OctahedronPolygon getOctahedronPolygon() const;
775 //	virtual StelVertexArray getFillVertexArray() const;
776 //	virtual StelVertexArray getOutlineVertexArray() const;
777 //	virtual double getArea() const;
778 //	virtual bool isEmpty() const;
779 //	virtual Vec3d getPointInside() const;
780 //	virtual SphericalCap getBoundingCap() const {return cachedBoundingCap;}
781 //	QVector<SphericalCap> getBoundingSphericalCaps() const;
782 //	//! Serialize the region into a QVariant map matching the JSON format.
783 //	//! The format is
784 //	//! @code["CONVEX_POLYGON_SET", [[ra,dec], [ra,dec], [ra,dec], [ra,dec]], [[ra,dec], [ra,dec], [ra,dec], [ra,dec]]]@endcode
785 //	//! where the coords from a list of closed convex contour, with each points defined by ra dec in degree in the ICRS frame.
786 //	virtual QVariantList toQVariant() const;
787 //	virtual void serialize(QDataStream& out) const;
788 //
789 //	// Contain and intersect
790 //	virtual bool contains(const Vec3d& p) const;
791 //	virtual bool contains(const SphericalPolygon& r) const;
792 //	virtual bool contains(const SphericalConvexPolygon& r) const;
793 //	virtual bool contains(const SphericalCap& r) const;
794 //	virtual bool contains(const SphericalPoint& r) const {return contains(r.n);}
795 //	virtual bool contains(const AllSkySphericalRegion&) const {return false;}
796 //	virtual bool intersects(const SphericalCap& r) const {if (!cachedBoundingCap.intersects(r)) return false; return r.intersects(*this);}
797 //	virtual bool intersects(const SphericalPolygon& r) const;
798 //	virtual bool intersects(const SphericalConvexPolygon& r) const;
799 //	virtual bool intersects(const SphericalPoint& r) const {return contains(r.n);}
800 //	virtual bool intersects(const AllSkySphericalRegion&) const {return true;}
801 //
802 //	////////////////////////////////////////////////////////////////////
803 //	// Methods specific to SphericalConvexPolygonSet
804 //	////////////////////////////////////////////////////////////////////
805 //	//! Deserialize the region. This method must allow as fast as possible deserialization.
806 //	static SphericalRegionP deserialize(QDataStream& in);
807 //
808 //protected:
809 //	QVector<SphericalConvexPolygon> contours;
810 //
811 //	//! Cache the bounding cap.
812 //	SphericalCap cachedBoundingCap;
813 //
814 //	//! Update the bounding cap from the vertex list.
815 //	void updateBoundingCap();
816 //};
817 
818 //! @class SphericalTexturedPolygon
819 //! An extension of SphericalPolygon with addition of texture coordinates.
820 class SphericalTexturedPolygon : public SphericalPolygon
821 {
822 public:
823 	//! @struct TextureVertex
824 	//! A container for 3D vertex + associated texture coordinates
825 	struct TextureVertex
826 	{
827 		Vec3d vertex;
828 		Vec2f texCoord;
829 	};
830 
SphericalTexturedPolygon()831 	SphericalTexturedPolygon() {;}
832 	//! Constructor from a list of contours.
SphericalTexturedPolygon(const QVector<QVector<TextureVertex>> & contours)833 	SphericalTexturedPolygon(const QVector<QVector<TextureVertex> >& contours) {Q_UNUSED(contours); Q_ASSERT(0);}
834 	//! Constructor from one contour.
SphericalTexturedPolygon(const QVector<TextureVertex> & contour)835 	SphericalTexturedPolygon(const QVector<TextureVertex>& contour) {Q_UNUSED(contour); Q_ASSERT(0);}
836 
837 	//! Return an OpenGL compatible array of texture coords to be used using vertex arrays.
838 	//! This implementation never should appear in practice.
getFillVertexArray() const839 	virtual StelVertexArray getFillVertexArray() const Q_DECL_OVERRIDE {Q_ASSERT(0); return StelVertexArray();}
getFillVertexArray(const Vec3d & observerVelocityForAberration)840 	virtual StelVertexArray getFillVertexArray(const Vec3d &observerVelocityForAberration) Q_DECL_OVERRIDE {Q_ASSERT(0); Q_UNUSED(observerVelocityForAberration) return StelVertexArray();}
841 	//! Serialize the region into a QVariant map matching the JSON format.
842 	//! The format is:
843 	//! @code["TEXTURED_POLYGON", [[[ra,dec], [ra,dec], [ra,dec], [ra,dec]], [[ra,dec], [ra,dec], [ra,dec]],[...]],
844 	//! [[[u,v],[u,v],[u,v],[u,v]], [[u,v],[u,v],[u,v]], [...]]]@endcode
845 	//! where the two lists are a list of closed contours, with each points defined by ra dec in degree in the ICRS frame
846 	//! followed by a list of texture coordinates in the u,v texture space (between 0 and 1).
847 	//! There must be one texture coordinate for each vertex.
848 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
serialize(QDataStream & out) const849 	virtual void serialize(QDataStream& out) const Q_DECL_OVERRIDE {Q_UNUSED(out); Q_ASSERT(0);}
850 
851 	////////////////////////////////////////////////////////////////////
852 	// Methods specific to SphericalTexturedPolygon
853 	//! Set the contours defining the SphericalPolygon.
854 	//! @param contours the list of contours defining the polygon area using the WindingPositive winding rule.
setContours(const QVector<QVector<TextureVertex>> & contours)855 	void setContours(const QVector<QVector<TextureVertex> >& contours) {Q_UNUSED(contours); Q_ASSERT(0);}
856 
857 	//! Set a single contour defining the SphericalPolygon.
858 	//! @param contour a contour defining the polygon area.
setContour(const QVector<TextureVertex> & contour)859 	void setContour(const QVector<TextureVertex>& contour) {Q_UNUSED(contour); Q_ASSERT(0);}
860 
861 private:
862 	//! A list of uv textures coordinates corresponding to the triangle vertices.
863 	//! There should be 1 uv position per vertex.
864 	QVector<Vec2f> textureCoords;
865 };
866 
867 
868 Q_DECLARE_TYPEINFO(SphericalTexturedPolygon::TextureVertex, Q_PRIMITIVE_TYPE);
869 
870 //! @class SphericalTexturedConvexPolygon
871 //! Extension of SphericalConvexPolygon for textured polygon.
872 class SphericalTexturedConvexPolygon : public SphericalConvexPolygon
873 {
874 public:
875 	//! Default constructor.
SphericalTexturedConvexPolygon()876 	SphericalTexturedConvexPolygon() {;}
877 
878 	//! Constructor from one contour.
SphericalTexturedConvexPolygon(const QVector<Vec3d> & contour,const QVector<Vec2f> & texCoord)879 	SphericalTexturedConvexPolygon(const QVector<Vec3d>& contour, const QVector<Vec2f>& texCoord) {setContour(contour, texCoord);}
880 
881 	//! Special constructor for quads.
882 	//! Use the 4 textures corners for the 4 vertices.
SphericalTexturedConvexPolygon(const Vec3d & e0,const Vec3d & e1,const Vec3d & e2,const Vec3d & e3)883 	SphericalTexturedConvexPolygon(const Vec3d &e0,const Vec3d &e1,const Vec3d &e2, const Vec3d &e3) : SphericalConvexPolygon(e0,e1,e2,e3)
884 	{
885 		textureCoords << Vec2f(0.f, 0.f) << Vec2f(1.f, 0.f) << Vec2f(1.f, 1.f) << Vec2f(0.f, 1.f);
886 	}
887 
888 	//! Return an OpenGL compatible array to be displayed using vertex arrays.
889 	//! This method is not optimized for SphericalConvexPolygon instances.
890 	//! Return an OpenGL compatible array to be displayed using vertex arrays.
891 	//! @param observerVelocityForAberration a vector to add to all contour vertices.
892 	virtual StelVertexArray getFillVertexArray(const Vec3d &observerVelocityForAberration) Q_DECL_OVERRIDE;
893 	//! Return array without any aberration.
894 	virtual StelVertexArray getFillVertexArray() const Q_DECL_OVERRIDE;
895 
896 	//! Set a single contour defining the SphericalPolygon.
897 	//! @param acontour a contour defining the polygon area.
898 	//! @param texCoord a list of texture coordinates matching the vertices of the contour.
setContour(const QVector<Vec3d> & acontour,const QVector<Vec2f> & texCoord)899 	virtual void setContour(const QVector<Vec3d>& acontour, const QVector<Vec2f>& texCoord) {SphericalConvexPolygon::setContour(acontour); textureCoords=texCoord;}
900 
901 	//! Serialize the region into a QVariant map matching the JSON format.
902 	//! The format is:
903 	//! @code["TEXTURED_CONVEX_POLYGON", [[ra,dec], [ra,dec], [ra,dec], [ra,dec]], [[u,v],[u,v],[u,v],[u,v]]]@endcode
904 	//! where the two lists are a closed convex contours, with each points defined by ra dec in degree in the ICRS frame
905 	//! followed by a list of texture coordinates in the u,v texture space (between 0 and 1).
906 	//! There must be one texture coordinate for each vertex.
907 	virtual QVariantList toQVariant() const Q_DECL_OVERRIDE;
908 
serialize(QDataStream & out) const909 	virtual void serialize(QDataStream& out) const Q_DECL_OVERRIDE {out << contour << textureCoords;}
910 
911 protected:
912 	//! A list of uv textures coordinates corresponding to the triangle vertices.
913 	//! There should be 1 uv position per vertex.
914 	QVector<Vec2f> textureCoords;
915 };
916 
917 
918 //! Compute the intersection of 2 great circles segments.
919 //! @param ok is set to false if no intersection was found.
920 //! @return the intersection point on the sphere (normalized) if ok is true, or undefined of ok is false.
921 Vec3d greatCircleIntersection(const Vec3d& p1, const Vec3d& p2, const Vec3d& p3, const Vec3d& p4, bool& ok);
922 
923 //! Compute the intersection of a great circles segment with another great circle.
924 //! @param ok is set to false if no intersection was found.
925 //! @return the intersection point on the sphere (normalized) if ok is true, or undefined of ok is false.
926 Vec3d greatCircleIntersection(const Vec3d& p1, const Vec3d& p2, const Vec3d& nHalfSpace, bool& ok);
927 
928 #endif // STELSPHEREGEOMETRY_HPP
929 
930