StelSphereGeometry.cpp   StelSphereGeometry.cpp 
skipping to change at line 24 skipping to change at line 24
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*/ */
#include <QDebug> #include <QDebug>
#include <QBuffer> #include <QBuffer>
#include <stdexcept> #include <stdexcept>
#include "StelJsonParser.hpp"
#include "StelSphereGeometry.hpp" #include "StelSphereGeometry.hpp"
#include "StelUtils.hpp" #include "StelUtils.hpp"
#include "StelJsonParser.hpp" #include "StelProjector.hpp"
#include "TriangleIterator.hpp"
#include "renderer/StelCircleArcRenderer.hpp"
#include "renderer/StelRenderer.hpp"
// Definition of static constants. // Definition of static constants.
int SphericalRegionP::metaTypeId = SphericalRegionP::initialize(); int SphericalRegionP::metaTypeId = SphericalRegionP::initialize();
int SphericalRegionP::initialize() int SphericalRegionP::initialize()
{ {
int id = qRegisterMetaType<SphericalRegionP>("SphericalRegionP"); int id = qRegisterMetaType<SphericalRegionP>("SphericalRegionP");
qRegisterMetaTypeStreamOperators<SphericalRegionP>("SphericalRegionP "); qRegisterMetaTypeStreamOperators<SphericalRegionP>("SphericalRegionP ");
return id; return id;
} }
skipping to change at line 77 skipping to change at line 81
return in; return in;
default: default:
Q_ASSERT(0); // Unknown region type Q_ASSERT(0); // Unknown region type
} }
return in; return in;
} }
/////////////////////////////////////////////////////////////////////////// //////////////////// /////////////////////////////////////////////////////////////////////////// ////////////////////
// Default implementations of methods for SphericalRegion // Default implementations of methods for SphericalRegion
/////////////////////////////////////////////////////////////////////////// //////////////////// /////////////////////////////////////////////////////////////////////////// ////////////////////
QByteArray SphericalRegion::toJSON() const QByteArray SphericalRegion::toJSON() const
{ {
QByteArray res; QByteArray res;
QBuffer buf1(&res); QBuffer buf1(&res);
buf1.open(QIODevice::WriteOnly); buf1.open(QIODevice::WriteOnly);
StelJsonParser::write(toQVariant(), &buf1); StelJsonParser::write(toQVariant(), &buf1);
buf1.close(); buf1.close();
return res; return res;
} }
skipping to change at line 299 skipping to change at line 304
} }
// Return a new SphericalPolygon consisting of the subtraction of the given SphericalPolygon from this. // Return a new SphericalPolygon consisting of the subtraction of the given SphericalPolygon from this.
SphericalRegionP SphericalRegion::getSubtractionDefault(const SphericalRegi on* r) const SphericalRegionP SphericalRegion::getSubtractionDefault(const SphericalRegi on* r) const
{ {
OctahedronPolygon resOct(getOctahedronPolygon()); OctahedronPolygon resOct(getOctahedronPolygon());
resOct.inPlaceSubtraction(r->getOctahedronPolygon()); resOct.inPlaceSubtraction(r->getOctahedronPolygon());
return SphericalRegionP(new SphericalPolygon(resOct)); return SphericalRegionP(new SphericalPolygon(resOct));
} }
///////////////////////////////////////////////////////////////////////////
////////////////////
// Drawing code for SphericalRegion and derived classes
///////////////////////////////////////////////////////////////////////////
////////////////////
//! Append a triangle to a vertex buffer, PlainVertex overload.
//!
//! Used in projectSphericalTriangle(), which is templated with vertex type
.
//!
//! @param buffer Vertex buffer to add the triangle to.
//! @param vertices Positions of vertices in the triangle.
//! @param texCoords Texture coordinates of vertices in the triangle.
//! Must be NULL for this overload.
void appendTriangle(StelVertexBuffer<SphericalRegion::PlainVertex>* buffer,
const Triplet<Vec3f>& vertices, const Triplet<Vec2f>* t
exCoords)
{
#ifndef NDEBUG
Q_ASSERT_X(texCoords == NULL, Q_FUNC_INFO,
"Got texCoords even though building buffer without textur
e coords");
#else
Q_UNUSED(texCoords);
#endif
buffer->addVertex(SphericalRegion::PlainVertex(vertices.a));
buffer->addVertex(SphericalRegion::PlainVertex(vertices.b));
buffer->addVertex(SphericalRegion::PlainVertex(vertices.c));
}
//! Append a triangle to a vertex buffer, TexturedVertex overload.
//!
//! Used in projectSphericalTriangle(), which is templated with vertex type
.
//!
//! @param buffer Vertex buffer to add the triangle to.
//! @param vertices Positions of vertices in the triangle.
//! @param texCoords Texture coordinates of vertices in the triangle.
void appendTriangle(StelVertexBuffer<SphericalRegion::TexturedVertex>* buff
er,
const Triplet<Vec3f>& vertices, const Triplet<Vec2f>* t
exCoords)
{
buffer->addVertex(SphericalRegion::TexturedVertex(vertices.a, texCoo
rds->a));
buffer->addVertex(SphericalRegion::TexturedVertex(vertices.b, texCoo
rds->b));
buffer->addVertex(SphericalRegion::TexturedVertex(vertices.c, texCoo
rds->c));
}
//! Project a triangle to the screen ensuring that it will look smooth, eve
n for
//! nonlinear distortions by splitting it into subtriangles.
//! The size of each edge must be < 180 deg.
//!
//! @param projector Used to project the vertices.
//! @param vertices Positions of vertices in the triangle.
//! @param texturePos Texture coordinates of vertices in the triangle.
//! @param buffer Vertex buffer to output resulting vertices to.
//!
//! @todo Needs more complete documentation (non-documented parameters).
template<class V>
void projectSphericalTriangle
(StelProjector* projector,
const SphericalCap* clippingCap,
const Triplet<Vec3d>* vertices,
const Triplet<Vec2f>* texCoords,
StelVertexBuffer<V>* buffer,
double maxSqDistortion,
int nbI = 0,
bool checkDisc1 = true,
bool checkDisc2 = true,
bool checkDisc3 = true)
{
Q_ASSERT(fabs(vertices->a.length()-1.)<0.00001);
Q_ASSERT(fabs(vertices->b.length()-1.)<0.00001);
Q_ASSERT(fabs(vertices->c.length()-1.)<0.00001);
if (clippingCap && clippingCap->containsTriangle(*vertices))
clippingCap = NULL;
// Culling unnecessary triangles
if (clippingCap && !clippingCap->intersectsTriangle(*vertices))
return;
bool cDiscontinuity1 = checkDisc1 && projector->intersectViewportDis
continuity(vertices->a, vertices->b);
bool cDiscontinuity2 = checkDisc2 && projector->intersectViewportDis
continuity(vertices->b, vertices->c);
bool cDiscontinuity3 = checkDisc3 && projector->intersectViewportDis
continuity(vertices->a, vertices->c);
const bool cd1=cDiscontinuity1;
const bool cd2=cDiscontinuity2;
const bool cd3=cDiscontinuity3;
Vec3d e0=vertices->a;
Vec3d e1=vertices->b;
Vec3d e2=vertices->c;
bool valid = projector->projectInPlace(e0);
valid = projector->projectInPlace(e1) || valid;
valid = projector->projectInPlace(e2) || valid;
// Clip polygons behind the viewer
if (!valid)
return;
if (checkDisc1 && cDiscontinuity1==false)
{
// If the distortion at segment e0,e1 is too big, flags it f
or subdivision
Vec3d win3 = vertices->a; win3+=vertices->b;
projector->projectInPlace(win3);
win3[0]-=(e0[0]+e1[0])*0.5; win3[1]-=(e0[1]+e1[1])*0.5;
cDiscontinuity1 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDis
tortion;
}
if (checkDisc2 && cDiscontinuity2==false)
{
// If the distortion at segment e1,e2 is too big, flags it f
or subdivision
Vec3d win3 = vertices->b; win3+=vertices->c;
projector->projectInPlace(win3);
win3[0]-=(e2[0]+e1[0])*0.5; win3[1]-=(e2[1]+e1[1])*0.5;
cDiscontinuity2 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDis
tortion;
}
if (checkDisc3 && cDiscontinuity3==false)
{
// If the distortion at segment e2,e0 is too big, flags it f
or subdivision
Vec3d win3 = vertices->c; win3+=vertices->a;
projector->projectInPlace(win3);
win3[0] -= (e0[0]+e2[0])*0.5;
win3[1] -= (e0[1]+e2[1])*0.5;
cDiscontinuity3 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDis
tortion;
}
if (!cDiscontinuity1 && !cDiscontinuity2 && !cDiscontinuity3)
{
const Triplet<Vec3f> triangle(Vec3f(e0[0], e0[1], e0[2]),
Vec3f(e1[0], e1[1], e1[2]),
Vec3f(e2[0], e2[1], e2[2]));
// The triangle is clean, append it
appendTriangle(buffer, triangle, texCoords);
return;
}
if (nbI > 4)
{
// If we reached the limit number of iterations and still ha
ve a discontinuity,
// discards the triangle.
if (cd1 || cd2 || cd3)
return;
const Triplet<Vec3f> triangle(Vec3f(e0[0], e0[1], e0[2]),
Vec3f(e1[0], e1[1], e2[2]),
Vec3f(e2[0], e2[1], e2[2]));
// Else display it, it will be suboptimal though.
appendTriangle(buffer, triangle, texCoords);
return;
}
// Recursively splits the triangle into sub triangles.
// Depending on which combination of sides of the triangle has to be
split a different strategy is used.
Triplet<Vec3d> va;
Triplet<Vec2f> ta;
// Only 1 side has to be split: split the triangle in 2
if (cDiscontinuity1 && !cDiscontinuity2 && !cDiscontinuity3)
{
va.a=vertices->a;
va.b=vertices->a;va.b+=vertices->b;
va.b.normalize();
va.c=vertices->c;
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=(texCoords->a+texCoords->b)*0.5;
ta.c=texCoords->c;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, true, true, false);
//va.a=vertices->a+vertices->b;
//va.a.normalize();
va.a=va.b;
va.b=vertices->b;
va.c=vertices->c;
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->b)*0.5;
ta.b=texCoords->b;
ta.c=texCoords->c;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, true, false, true);
return;
}
if (!cDiscontinuity1 && cDiscontinuity2 && !cDiscontinuity3)
{
va.a=vertices->a;
va.b=vertices->b;
va.c=vertices->b;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=texCoords->b;
ta.c=(texCoords->b+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, false, true, true);
va.a=vertices->a;
//va.b=vertices->b+vertices->c;
//va.b.normalize();
va.b=va.c;
va.c=vertices->c;
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=(texCoords->b+texCoords->c)*0.5;
ta.c=texCoords->c;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, true, true, false);
return;
}
if (!cDiscontinuity1 && !cDiscontinuity2 && cDiscontinuity3)
{
va.a=vertices->a;
va.b=vertices->b;
va.c=vertices->a;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=texCoords->b;
ta.c=(texCoords->a+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, false, true, true);
//va.a=vertices->a+vertices->c;
//va.a.normalize();
va.a=va.c;
va.b=vertices->b;
va.c=vertices->c;
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->c)*0.5;
ta.b=texCoords->b;
ta.c=texCoords->c;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, true, false, true);
return;
}
// 2 sides have to be split: split the triangle in 3
if (cDiscontinuity1 && cDiscontinuity2 && !cDiscontinuity3)
{
va.a=vertices->a;
va.b=vertices->a;va.b+=vertices->b;
va.b.normalize();
va.c=vertices->b;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=(texCoords->a+texCoords->b)*0.5;
ta.c=(texCoords->b+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1);
//va.a=vertices->a+vertices->b;
//va.a.normalize();
va.a=va.b;
va.b=vertices->b;
//va.c=vertices->b+vertices->c;
//va.c.normalize();
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->b)*0.5;
ta.b=texCoords->b;
ta.c=(texCoords->b+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1);
va.a=vertices->a;
//va.b=vertices->b+vertices->c;
//va.b.normalize();
va.b=va.c;
va.c=vertices->c;
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=(texCoords->b+texCoords->c)*0.5;
ta.c=texCoords->c;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, true, true, false);
return;
}
if (cDiscontinuity1 && !cDiscontinuity2 && cDiscontinuity3)
{
va.a=vertices->a;
va.b=vertices->a;va.b+=vertices->b;
va.b.normalize();
va.c=vertices->a;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=(texCoords->a+texCoords->b)*0.5;
ta.c=(texCoords->a+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1);
//va.a=vertices->a+vertices->b;
//va.a.normalize();
va.a=va.b;
va.b=vertices->c;
//va.c=vertices->a+vertices->c;
//va.c.normalize();
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->b)*0.5;
ta.b=texCoords->c;
ta.c=(texCoords->a+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1);
//va.a=vertices->a+vertices->b;
//va.a.normalize();
va.b=vertices->b;
va.c=vertices->c;
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->b)*0.5;
ta.b=texCoords->b;
ta.c=texCoords->c;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, true, false, true);
return;
}
if (!cDiscontinuity1 && cDiscontinuity2 && cDiscontinuity3)
{
va.a=vertices->a;
va.b=vertices->b;
va.c=vertices->b;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=texCoords->b;
ta.c=(texCoords->b+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1, false, true, true);
//va.a=vertices->b+vertices->c;
//va.a.normalize();
va.a=va.c;
va.b=vertices->c;
va.c=vertices->a;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=(texCoords->b+texCoords->c)*0.5;
ta.b=texCoords->c;
ta.c=(texCoords->a+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1);
va.b=va.a;
va.a=vertices->a;
//va.b=vertices->b+vertices->c;
//va.b.normalize();
//va.c=vertices->a+vertices->c;
//va.c.normalize();
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=(texCoords->b+texCoords->c)*0.5;
ta.c=(texCoords->a+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, b
uffer, maxSqDistortion, nbI+1);
return;
}
// Last case: the 3 sides have to be split: cut in 4 triangles a' la
HTM
va.a=vertices->a;va.a+=vertices->b;
va.a.normalize();
va.b=vertices->b;va.b+=vertices->c;
va.b.normalize();
va.c=vertices->a;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->b)*0.5;
ta.b=(texCoords->b+texCoords->c)*0.5;
ta.c=(texCoords->a+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, buffer, m
axSqDistortion, nbI+1);
va.b=va.a;
va.a=vertices->a;
//va.b=vertices->a+vertices->b;
//va.b.normalize();
//va.c=vertices->a+vertices->c;
//va.c.normalize();
if (NULL != texCoords)
{
ta.a=texCoords->a;
ta.b=(texCoords->a+texCoords->b)*0.5;
ta.c=(texCoords->a+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, buffer, m
axSqDistortion, nbI+1);
//va.a=vertices->a+vertices->b;
//va.a.normalize();
va.a=va.b;
va.b=vertices->b;
va.c=vertices->b;va.c+=vertices->c;
va.c.normalize();
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->b)*0.5;
ta.b=texCoords->b;
ta.c=(texCoords->b+texCoords->c)*0.5;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, buffer, m
axSqDistortion, nbI+1);
va.a=vertices->a;va.a+=vertices->c;
va.a.normalize();
//va.b=vertices->b+vertices->c;
//va.b.normalize();
va.b=va.c;
va.c=vertices->c;
if (NULL != texCoords)
{
ta.a=(texCoords->a+texCoords->c)*0.5;
ta.b=(texCoords->b+texCoords->c)*0.5;
ta.c=texCoords->c;
}
projectSphericalTriangle(projector, clippingCap, &va, &ta, buffer, m
axSqDistortion, nbI+1);
return;
}
//! Prepare a cached vertex buffer for update, constructing it if needed, u
nlocking and clearing.
//!
//! @param buffer Pointer to pointer to buffer to prepare.
//! @param renderer Renderer to construct the buffer if not constructed yet
.
template<class V>
void prepareVertexBufferUpdate(StelVertexBuffer<V>** buffer, StelRenderer*
renderer)
{
if(NULL == (*buffer))
{
(*buffer) = renderer->createVertexBuffer<V>(PrimitiveType_Tr
iangles);
return;
}
(*buffer)->unlock();
(*buffer)->clear();
}
//! Determine whether a triangle instersects a projection discontinuity.
//!
//! @param projector Projector to check against.
//! @param triangle Positions of vertices in the triangle.
bool triangleIntersectsDiscontinuity(StelProjector* projector, const Triple
t<Vec3d>& triangle)
{
return projector->intersectViewportDiscontinuity(triangle.a, triangl
e.b) ||
projector->intersectViewportDiscontinuity(triangle.b, triangl
e.c) ||
projector->intersectViewportDiscontinuity(triangle.c, triangl
e.a);
}
void SphericalRegion::updateFillVertexBuffer(StelRenderer* renderer, const
DrawParams& params, bool handleDiscontinuity)
{
const QVector<Vec3d>& vertices = getOctahedronPolygon().fillVertices
();
StelProjector* projector = params.projector_;
prepareVertexBufferUpdate(&fillPlainVertexBuffer, renderer);
if(!params.subdivide_)
{
// The simplest case, we don't need to iterate through the t
riangles at all.
if (handleDiscontinuity)
{
// We don't use indices here, since we don't have a
vertex buffer yet.
// If we did it as it was done in
// StelPainter::removeDiscontinuousTriangles(), we'd
have to copy _all_
// vertices and then use indices to specify which to
draw.
//
// So we only copy _some_ of the vertices.
// Iterating over triangles,
// adding them to the buffer if they don't cross the
discontinuity.
for (int i = 0; i < vertices.size(); i += 3)
{
const Triplet<Vec3d> triVertices
(vertices.at(i), vertices.at(i + 1),
vertices.at(i + 2));
if(!triangleIntersectsDiscontinuity(projecto
r, triVertices))
{
fillPlainVertexBuffer->addVertex(Pla
inVertex(triVertices.a));
fillPlainVertexBuffer->addVertex(Pla
inVertex(triVertices.b));
fillPlainVertexBuffer->addVertex(Pla
inVertex(triVertices.c));
}
}
}
else
{
// Copy the vertex data to the buffer without subdiv
iding or changing anything.
for (int v = 0; v < vertices.size(); v++)
{
fillPlainVertexBuffer->addVertex(SphericalRe
gion::PlainVertex(vertices[v]));
}
}
fillPlainVertexBuffer->lock();
useProjector = true;
return;
}
useProjector = false;
// Iterating over triangles, projecting/subdividing them
// and appending to the buffer.
for (int i = 0; i < vertices.size(); i += 3)
{
const Triplet<Vec3d> triVertices(vertices.at(i), vertices.at
(i + 1), vertices.at(i + 2));
projectSphericalTriangle(params.projector_, params.clippingC
ap_,
&triVertices, NULL, fillPlainVertex
Buffer,
params.maxSqDistortion_);
}
fillPlainVertexBuffer->lock();
}
void SphericalConvexPolygon::updateFillVertexBuffer(StelRenderer* renderer,
const DrawParams& params, bool handleDiscontinuity)
{
const QVector<Vec3d>& vertices = contour;
StelProjector* projector = params.projector_;
prepareVertexBufferUpdate(&fillPlainVertexBuffer, renderer);
if(!params.subdivide_)
{
if (handleDiscontinuity)
{
// We don't use indices here, since we don't have a
vertex buffer yet.
// If we did it as it was done in
// StelPainter::removeDiscontinuousTriangles(), we'd
have to copy _all_
// vertices and then use indices to specify which to
draw.
//
// So we only copy _some_ of the vertices.
// Iterating over triangles in a triangle fan,
// adding them as separate triangles if they don't c
ross the discontinuity.
const Vec3d v0 = vertices.at(0);
for (int i = 1; i < vertices.size() - 1; ++i)
{
const Triplet<Vec3d> triVertices(v0, vertice
s.at(i), vertices.at(i + 1));
if(!triangleIntersectsDiscontinuity(projecto
r, triVertices))
{
fillPlainVertexBuffer->addVertex(Pla
inVertex(triVertices.a));
fillPlainVertexBuffer->addVertex(Pla
inVertex(triVertices.b));
fillPlainVertexBuffer->addVertex(Pla
inVertex(triVertices.c));
}
}
}
else
{
//Decomposing the triangle fan into triangles.
//
//We could get less overhead with initializing the v
ertex buffer with
//triangle fan primitive type, but we might end up d
eleting/constructing
//a new buffer based on draw parameters (which would
complicate code).
const Vec3d v0 = vertices.at(0);
for (int i = 1; i < vertices.size() - 1; ++i)
{
fillPlainVertexBuffer->addVertex(PlainVertex
(v0));
fillPlainVertexBuffer->addVertex(PlainVertex
(vertices.at(i)));
fillPlainVertexBuffer->addVertex(PlainVertex
(vertices.at(i + 1)));
}
}
fillPlainVertexBuffer->lock();
useProjector = true;
return;
}
useProjector = false;
// Iterating over triangles in a triangle fan, projecting/subdividin
g them
// and appending to the buffer.
const Vec3d v0 = vertices.at(0);
for (int i = 1; i < vertices.size() - 1; ++i)
{
const Triplet<Vec3d> triVertices(v0, vertices.at(i), vertice
s.at(i + 1));
projectSphericalTriangle(params.projector_, params.clippingC
ap_,
&triVertices, NULL, fillPlainVertex
Buffer,
params.maxSqDistortion_);
}
fillPlainVertexBuffer->lock();
}
void SphericalTexturedConvexPolygon::updateFillVertexBuffer(StelRenderer* r
enderer, const DrawParams& params, bool handleDiscontinuity)
{
const QVector<Vec3d>& vertices = contour;
const QVector<Vec2f>& texCoords = textureCoords;
StelProjector* projector = params.projector_;
Q_ASSERT_X(vertices.size() == texCoords.size(), Q_FUNC_INFO,
"Numbers of vertices and texture coordinates do not match
");
prepareVertexBufferUpdate(&fillTexturedVertexBuffer, renderer);
if(!params.subdivide_)
{
if (handleDiscontinuity)
{
// We don't use indices here, since we don't have a
vertex buffer yet.
// If we did it as it was done in
// StelPainter::removeDiscontinuousTriangles(), we'd
have to copy _all_
// vertices and then use indices to specify which to
draw.
//
// So we only copy _some_ of the vertices.
// Iterating over triangles in a triangle fan,
// adding them as separate triangles if they don't c
ross the discontinuity.
const Vec3d v0 = vertices.at(0);
const Vec2f t0 = texCoords.at(0);
for (int i = 1; i < vertices.size() - 1; ++i)
{
const Triplet<Vec3d> triVertices(v0, vertice
s.at(i), vertices.at(i + 1));
if(!triangleIntersectsDiscontinuity(projecto
r, triVertices))
{
fillTexturedVertexBuffer->
addVertex(TexturedVertex(tri
Vertices.a, t0));
fillTexturedVertexBuffer->
addVertex(TexturedVertex(tri
Vertices.b, texCoords.at(i)));
fillTexturedVertexBuffer->
addVertex(TexturedVertex(tri
Vertices.c, texCoords.at(i + 1)));
}
}
}
else
{
//Decomposing the triangle fan into triangles.
//
//We could get less overhead with initializing the v
ertex buffer with
//triangle fan primitive type, but we might end up d
eleting/constructing
//a new buffer based on draw parameters (which would
complicate code).
const Vec3d v0 = vertices.at(0);
const Vec2f t0 = texCoords.at(0);
for (int i = 1; i < vertices.size() - 1; ++i)
{
fillTexturedVertexBuffer->
addVertex(TexturedVertex(v0, t0));
fillTexturedVertexBuffer->
addVertex(TexturedVertex(vertices.at
(i), texCoords.at(i)));
fillTexturedVertexBuffer->
addVertex(TexturedVertex(vertices.at
(i + 1), texCoords.at(i + 1)));
}
}
useProjector = true;
fillTexturedVertexBuffer->lock();
return;
}
useProjector = false;
// Iterating over triangles in a triangle fan, projecting/subdividin
g them
// and appending to the buffer.
const Vec3d v0 = vertices.at(0);
const Vec2f t0 = texCoords.at(0);
for (int i = 1; i < vertices.size() - 1; ++i)
{
const Triplet<Vec3d> triVertices(v0, vertices.at(i), vertice
s.at(i + 1));
const Triplet<Vec2f> triTexCoords(t0, texCoords.at(i), texCo
ords.at(i + 1));
projectSphericalTriangle(params.projector_, params.clippingC
ap_,
&triVertices, &triTexCoords, fillTe
xturedVertexBuffer,
params.maxSqDistortion_);
}
fillTexturedVertexBuffer->lock();
}
void SphericalRegion::drawFill(StelRenderer* renderer, const DrawParams& pa
rams)
{
StelProjector* projector = params.projector_;
//! We don't need to draw stuff outside the view.
if (!projector->getBoundingCap().intersects(getBoundingCap()))
{
return;
}
const bool intersectsDiscontinuity =
projector->intersectViewportDiscontinuity(getBoundingCap());
// We need to update cached vertex data in the following cases:
//
// a) SphericalRegion implementation says so.
// b) Drawing parameters (those that affect vertex generation) have
changed.
// c) We're subdividing the triangles, in which case we're projectin
g them
// manually, outside of StelRenderer, which means any change in p
rojector
// (which we can't determine) invalidates our cache.
if(needToUpdateFillVertexBuffers() ||
params != previousFillDrawParams ||
params.subdivide_)
{
// hasDiscontinuity was removed as if intersectsDiscontinuit
y is true,
// hasDiscontinuity is true as well.
updateFillVertexBuffer(renderer, params, intersectsDiscontin
uity);
fillVertexBuffersUpdated();
}
drawFillVertexBuffer(renderer, useProjector ? projector : NULL);
}
void SphericalRegion::drawFillVertexBuffer(StelRenderer* renderer, StelProj
ector* projector)
{
renderer->drawVertexBuffer(fillPlainVertexBuffer, NULL, projector);
}
void SphericalConvexPolygon::drawFillVertexBuffer(StelRenderer* renderer, S
telProjector* projector)
{
renderer->drawVertexBuffer(fillPlainVertexBuffer, NULL, projector);
}
void SphericalTexturedConvexPolygon::drawFillVertexBuffer(StelRenderer* ren
derer, StelProjector* projector)
{
renderer->drawVertexBuffer(fillTexturedVertexBuffer, NULL, projector
);
}
void SphericalRegion::drawOutline(StelRenderer* renderer, const DrawParams&
params)
{
if(params.subdivide_ || params.projector_->intersectViewportDisconti
nuity(getBoundingCap()))
{
StelCircleArcRenderer circleArcRenderer(renderer, params.pro
jector_);
circleArcRenderer.drawGreatCircleArcs(getOutlineVertexPositi
ons(),
getOutlinePrimitiveTyp
e(), params.clippingCap_);
return;
}
StelVertexBuffer<PlainVertex>* vertices =
renderer->createVertexBuffer<PlainVertex>(getOutlinePrimitiv
eType());
const QVector<Vec3d>& positions = getOutlineVertexPositions();
for (int p = 0; p < positions.size(); p++)
{
vertices->addVertex(PlainVertex(positions[p]));
}
vertices->lock();
renderer->drawVertexBuffer(vertices, NULL, params.projector_);
delete vertices;
}
/////////////////////////////////////////////////////////////////////////// / /////////////////////////////////////////////////////////////////////////// /
// Methods for SphericalCap // Methods for SphericalCap
/////////////////////////////////////////////////////////////////////////// / /////////////////////////////////////////////////////////////////////////// /
// Returns whether a SphericalPolygon is contained into the region. // Returns whether a SphericalPolygon is contained into the region.
bool SphericalCap::contains(const SphericalConvexPolygon& cvx) const bool SphericalCap::contains(const SphericalConvexPolygon& cvx) const
{ {
foreach (const Vec3d& v, cvx.getConvexContour()) foreach (const Vec3d& v, cvx.getConvexContour())
{ {
if (!contains(v)) if (!contains(v))
return false; return false;
} }
return true; return true;
} }
bool SphericalCap::containsTriangle(const Vec3d* v) const bool SphericalCap::containsTriangle(const Triplet<Vec3d> triangle) const
{ {
return contains(*(v++)) && contains(*(v++)) && contains(*v); return contains(triangle.a) && contains(triangle.b) && contains(tria ngle.c);
} }
bool SphericalCap::intersectsTriangle(const Vec3d* v) const bool SphericalCap::intersectsTriangle(const Triplet<Vec3d>& triangle) const
{ {
if (contains(*v) || contains(*(v+1)) || contains(*(v+2))) if (contains(triangle.a) || contains(triangle.b) || contains(triangl e.c))
return true; return true;
// No points of the triangle are inside the cap // No points of the triangle are inside the cap
if (d<=0) if (d<=0)
return false; return false;
if (!sideHalfSpaceIntersects(*v, *(v+1), *this) || !sideHalfSpaceInt if (!sideHalfSpaceIntersects(triangle.a, triangle.b, *this) ||
ersects(*(v+1), *(v+2), *this) || !sideHalfSpaceIntersects(*(v+2), *v, *thi !sideHalfSpaceIntersects(triangle.b, triangle.c, *this) ||
s)) !sideHalfSpaceIntersects(triangle.c, triangle.a, *this))
{
return false; return false;
}
// Warning!!!! There is a last case which is not managed! // Warning!!!! There is a last case which is not managed!
// When all the points of the polygon are outside the circle but the halfspace of the corner the closest to the // When all the points of the polygon are outside the circle but the halfspace of the corner the closest to the
// circle intersects the circle halfspace.. // circle intersects the circle halfspace..
return true; return true;
} }
bool SphericalCap::intersectsConvexContour(const Vec3d* vertice, int nbVert ice) const bool SphericalCap::intersectsConvexContour(const Vec3d* vertice, int nbVert ice) const
{ {
for (int i=0;i<nbVertice;++i) for (int i=0;i<nbVertice;++i)
skipping to change at line 370 skipping to change at line 1107
// Returns whether a SphericalPolygon intersects the region. // Returns whether a SphericalPolygon intersects the region.
bool SphericalCap::intersects(const SphericalConvexPolygon& cvx) const bool SphericalCap::intersects(const SphericalConvexPolygon& cvx) const
{ {
// TODO This algo returns sometimes false positives!! // TODO This algo returns sometimes false positives!!
return intersectsConvexContour(cvx.getConvexContour().constData(), c vx.getConvexContour().size()); return intersectsConvexContour(cvx.getConvexContour().constData(), c vx.getConvexContour().size());
} }
bool SphericalCap::intersects(const SphericalPolygon& polyBase) const bool SphericalCap::intersects(const SphericalPolygon& polyBase) const
{ {
// Go through the full list of triangle // Go through the full list of triangles
const QVector<Vec3d>& vArray = polyBase.getFillVertexArray().vertex; const QVector<Vec3d>& vArray = polyBase.getFillVertexPositions();
for (int i=0;i<vArray.size()/3;++i) for (int i=0;i<vArray.size()/3;++i)
{ {
if (intersectsConvexContour(vArray.constData()+i*3, 3)) if (intersectsConvexContour(vArray.constData()+i*3, 3))
return true; return true;
} }
return false; return false;
} }
bool SphericalCap::clipGreatCircle(Vec3d& v1, Vec3d& v2) const bool SphericalCap::clipGreatCircle(Vec3d& v1, Vec3d& v2) const
{ {
skipping to change at line 698 skipping to change at line 1435
/////////////////////////////////////////////////////////////////////////// //// /////////////////////////////////////////////////////////////////////////// ////
// Methods for SphericalPolygon // Methods for SphericalPolygon
/////////////////////////////////////////////////////////////////////////// //// /////////////////////////////////////////////////////////////////////////// ////
SphericalCap SphericalPolygon::getBoundingCap() const SphericalCap SphericalPolygon::getBoundingCap() const
{ {
SphericalCap res; SphericalCap res;
octahedronPolygon.getBoundingCap(res.n, res.d); octahedronPolygon.getBoundingCap(res.n, res.d);
return res; return res;
} }
struct TriangleSerializer QVariantList SphericalPolygon::toQVariant() const
{ {
TriangleSerializer(const TriangleSerializer& ts) : triangleList(ts.t QVariantList triangleList;
riangleList) {} TriangleIterator<Vec3d> triterator(getFillVertexPositions(), getFill
PrimitiveType());
TriangleSerializer() {} Vec3d a, b, c;
inline void operator()(const Vec3d* v1, const Vec3d* v2, const Vec3d while(triterator.next(a, b, c))
* v3,
const Vec2f* , const Vec2
f* , const Vec2f* ,
unsigned int , unsigned i
nt , unsigned int )
{ {
QVariantList triangle; QVariantList triangle;
double ra, dec; double ra, dec;
QVariantList l; QVariantList l;
StelUtils::rectToSphe(&ra, &dec, *v1); StelUtils::rectToSphe(&ra, &dec, a);
l << ra*180./M_PI << dec*180./M_PI; l << ra * 180. / M_PI << dec * 180. / M_PI;
triangle << QVariant(l); triangle << QVariant(l);
l.clear(); l.clear();
StelUtils::rectToSphe(&ra, &dec, *v2); StelUtils::rectToSphe(&ra, &dec, b);
l << ra*180./M_PI << dec*180./M_PI; l << ra * 180. / M_PI << dec * 180. / M_PI;
triangle << QVariant(l); triangle << QVariant(l);
l.clear(); l.clear();
StelUtils::rectToSphe(&ra, &dec, *v3); StelUtils::rectToSphe(&ra, &dec, c);
l << ra*180./M_PI << dec*180./M_PI; l << ra * 180. / M_PI << dec * 180. / M_PI;
triangle << QVariant(l); triangle << QVariant(l);
Q_ASSERT(triangle.size()==3); Q_ASSERT(triangle.size()==3);
triangleList << QVariant(triangle); triangleList << QVariant(triangle);
} }
QVariantList triangleList; return triangleList;
};
QVariantList SphericalPolygon::toQVariant() const
{
TriangleSerializer result = getFillVertexArray().foreachTriangle(Tri
angleSerializer());
return result.triangleList;
} }
void SphericalPolygon::serialize(QDataStream& out) const void SphericalPolygon::serialize(QDataStream& out) const
{ {
out << octahedronPolygon; out << octahedronPolygon;
} }
SphericalRegionP SphericalPolygon::deserialize(QDataStream& in) SphericalRegionP SphericalPolygon::deserialize(QDataStream& in)
{ {
OctahedronPolygon p; OctahedronPolygon p;
skipping to change at line 812 skipping to change at line 1542
{ {
if (regions.isEmpty()) if (regions.isEmpty())
return EmptySphericalRegion::staticInstance; return EmptySphericalRegion::staticInstance;
SphericalRegionP reg = regions.at(0); SphericalRegionP reg = regions.at(0);
for (int i=1;i<regions.size();++i) for (int i=1;i<regions.size();++i)
reg = reg->getIntersection(regions.at(i)); reg = reg->getIntersection(regions.at(i));
return reg; return reg;
} }
/////////////////////////////////////////////////////////////////////////// //// /////////////////////////////////////////////////////////////////////////// ////
// Methods for SphericalTexturedPolygon
///////////////////////////////////////////////////////////////////////////
////
///////////////////////////////////////////////////////////////////////////
////
// Methods for SphericalConvexPolygon // Methods for SphericalConvexPolygon
/////////////////////////////////////////////////////////////////////////// //// /////////////////////////////////////////////////////////////////////////// ////
// Check if the polygon is valid, i.e. it has no side >180 // Check if the polygon is valid, i.e. it has no side >180
bool SphericalConvexPolygon::checkValid() const bool SphericalConvexPolygon::checkValid() const
{ {
return SphericalConvexPolygon::checkValidContour(contour); return SphericalConvexPolygon::checkValidContour(contour);
} }
bool SphericalConvexPolygon::checkValidContour(const QVector<Vec3d>& contou r) bool SphericalConvexPolygon::checkValidContour(const QVector<Vec3d>& contou r)
skipping to change at line 929 skipping to change at line 1655
if (!cachedBoundingCap.contains(cvx.cachedBoundingCap)) if (!cachedBoundingCap.contains(cvx.cachedBoundingCap))
return false; return false;
return containsConvexContour(cvx.getConvexContour().constData(), cvx .getConvexContour().size()); return containsConvexContour(cvx.getConvexContour().constData(), cvx .getConvexContour().size());
} }
bool SphericalConvexPolygon::contains(const SphericalPolygon& poly) const bool SphericalConvexPolygon::contains(const SphericalPolygon& poly) const
{ {
if (!cachedBoundingCap.contains(poly.getBoundingCap())) if (!cachedBoundingCap.contains(poly.getBoundingCap()))
return false; return false;
// For standard polygons, go through the full list of triangles // For standard polygons, go through the full list of triangles
const QVector<Vec3d>& vArray = poly.getFillVertexArray().vertex; const QVector<Vec3d>& vArray = poly.getFillVertexPositions();
for (int i=0;i<vArray.size()/3;++i) for (int i=0;i<vArray.size()/3;++i)
{ {
if (!containsConvexContour(vArray.constData()+i*3, 3)) if (!containsConvexContour(vArray.constData()+i*3, 3))
return false; return false;
} }
return true; return true;
} }
bool SphericalConvexPolygon::areAllPointsOutsideOneSide(const Vec3d* thisCo ntour, int nbThisContour, const Vec3d* points, int nbPoints) bool SphericalConvexPolygon::areAllPointsOutsideOneSide(const Vec3d* thisCo ntour, int nbThisContour, const Vec3d* points, int nbPoints)
{ {
skipping to change at line 976 skipping to change at line 1702
if (!cachedBoundingCap.intersects(cvx.cachedBoundingCap)) if (!cachedBoundingCap.intersects(cvx.cachedBoundingCap))
return false; return false;
return !areAllPointsOutsideOneSide(cvx.contour) && !cvx.areAllPoints OutsideOneSide(contour); return !areAllPointsOutsideOneSide(cvx.contour) && !cvx.areAllPoints OutsideOneSide(contour);
} }
bool SphericalConvexPolygon::intersects(const SphericalPolygon& poly) const bool SphericalConvexPolygon::intersects(const SphericalPolygon& poly) const
{ {
if (!cachedBoundingCap.intersects(poly.getBoundingCap())) if (!cachedBoundingCap.intersects(poly.getBoundingCap()))
return false; return false;
// For standard polygons, go through the full list of triangles // For standard polygons, go through the full list of triangles
const QVector<Vec3d>& vArray = poly.getFillVertexArray().vertex; const QVector<Vec3d>& vArray = poly.getFillVertexPositions();
for (int i=0;i<vArray.size()/3;++i) for (int i=0;i<vArray.size()/3;++i)
{ {
if (!areAllPointsOutsideOneSide(contour.constData(), contour .size(), vArray.constData()+i*3, 3) && !areAllPointsOutsideOneSide(vArray.c onstData()+i*3, 3, contour.constData(), contour.size())) if (!areAllPointsOutsideOneSide(contour.constData(), contour .size(), vArray.constData()+i*3, 3) && !areAllPointsOutsideOneSide(vArray.c onstData()+i*3, 3, contour.constData(), contour.size()))
return true; return true;
} }
return false; return false;
} }
// This algo is wrong // This algo is wrong
void SphericalConvexPolygon::updateBoundingCap() void SphericalConvexPolygon::updateBoundingCap()
skipping to change at line 1049 skipping to change at line 1775
{ {
QVariantList vv; QVariantList vv;
vv << v[0] << v[1]; vv << v[0] << v[1];
cv.append((QVariant)vv); cv.append((QVariant)vv);
} }
res << cv; res << cv;
return res; return res;
} }
/////////////////////////////////////////////////////////////////////////// //// /////////////////////////////////////////////////////////////////////////// ////
// Methods for SphericalTexturedPolygon
///////////////////////////////////////////////////////////////////////////
////
QVariantList SphericalTexturedPolygon::toQVariant() const
{
Q_ASSERT(0);
// TODO store a tesselated polygon?, including edge flags?
return QVariantList();
}
///////////////////////////////////////////////////////////////////////////
////
// Utility methods // Utility methods
/////////////////////////////////////////////////////////////////////////// //// /////////////////////////////////////////////////////////////////////////// ////
Vec3d greatCircleIntersection(const Vec3d& p1, const Vec3d& p2, const Vec3d & p3, const Vec3d& p4, bool& ok) Vec3d greatCircleIntersection(const Vec3d& p1, const Vec3d& p2, const Vec3d & p3, const Vec3d& p4, bool& ok)
{ {
if (p3*p4>1.-1E-10) if (p3*p4>1.-1E-10)
{ {
// p3 and p4 are too close to avoid floating point problems // p3 and p4 are too close to avoid floating point problems
ok=false; ok=false;
return p3; return p3;
skipping to change at line 1135 skipping to change at line 1851
{ {
const QVariantList& vl = vRaDec.toList(); const QVariantList& vl = vRaDec.toList();
bool ok; bool ok;
if (vl.size()!=2) if (vl.size()!=2)
throw std::runtime_error(qPrintable(QString("invalid Ra,Dec pair: \"%1\" (expect 2 double values in degree, got %2)").arg(vRaDec.toStri ng()).arg(vl.size()))); throw std::runtime_error(qPrintable(QString("invalid Ra,Dec pair: \"%1\" (expect 2 double values in degree, got %2)").arg(vRaDec.toStri ng()).arg(vl.size())));
StelUtils::spheToRect(vl.at(0).toDouble(&ok)*M_PI/180., vl.at(1).toD ouble(&ok)*M_PI/180., v); StelUtils::spheToRect(vl.at(0).toDouble(&ok)*M_PI/180., vl.at(1).toD ouble(&ok)*M_PI/180., v);
if (!ok) if (!ok)
throw std::runtime_error(qPrintable(QString("invalid Ra,Dec pair: \"%1\" (expect 2 double values in degree)").arg(vRaDec.toString()))); throw std::runtime_error(qPrintable(QString("invalid Ra,Dec pair: \"%1\" (expect 2 double values in degree)").arg(vRaDec.toString())));
} }
struct TriangleDumper QVector<QVector<Vec3d > > SphericalRegion::getSimplifiedContours() const
{ {
TriangleDumper(const TriangleDumper& ts) : triangleList(ts.triangleL QVector<QVector<Vec3d > > triangleList;
ist) {} TriangleIterator<Vec3d> triterator(getFillVertexPositions(), getFill
PrimitiveType());
TriangleDumper() {} Vec3d a, b, c;
inline void operator()(const Vec3d* v1, const Vec3d* v2, const Vec3d while(triterator.next(a, b, c))
* v3,
const Vec2f* , const Vec2
f* , const Vec2f* ,
unsigned int , unsigned i
nt , unsigned int )
{ {
QVector<Vec3d> triangle; QVector<Vec3d> triangle;
triangle << *v1 << *v2 << *v3; triangle << a << b << c;
triangleList.append(triangle); triangleList.append(triangle);
} }
QVector<QVector<Vec3d > > triangleList; return triangleList;
};
QVector<QVector<Vec3d > > SphericalRegion::getSimplifiedContours() const
{
TriangleDumper result = getFillVertexArray().foreachTriangle(Triangl
eDumper());
return result.triangleList;
} }
SphericalRegionP capFromQVariantList(const QVariantList& l) SphericalRegionP capFromQVariantList(const QVariantList& l)
{ {
Q_ASSERT(l.at(0).toString()=="CAP"); Q_ASSERT(l.at(0).toString()=="CAP");
// We now parse a cap, the format is "CAP",[ra, dec],aperture // We now parse a cap, the format is "CAP",[ra, dec],aperture
if (l.size()!=3) if (l.size()!=3)
throw std::runtime_error(qPrintable(QString("invalid CAP des cription: %1 (expect \"CAP\",[ra, dec],aperture)").arg(QString::fromUtf8(St elJsonParser::write(l))))); throw std::runtime_error(qPrintable(QString("invalid CAP des cription: %1 (expect \"CAP\",[ra, dec],aperture)").arg(QString::fromUtf8(St elJsonParser::write(l)))));
Vec3d v; Vec3d v;
parseRaDec(l.at(1), v); parseRaDec(l.at(1), v);
skipping to change at line 1320 skipping to change at line 2029
qWarning() << "skyConvexPolygons in preview JSON files is de precated. Replace with worldCoords."; qWarning() << "skyConvexPolygons in preview JSON files is de precated. Replace with worldCoords.";
if (contoursList.empty()) if (contoursList.empty())
throw std::runtime_error("missing sky contours description r equired for Spherical Geometry elements."); throw std::runtime_error("missing sky contours description r equired for Spherical Geometry elements.");
// Load the matching textures positions (if any) // Load the matching textures positions (if any)
QVariantList texCoordList = map.value("textureCoords").toList(); QVariantList texCoordList = map.value("textureCoords").toList();
if (!texCoordList.isEmpty() && contoursList.size()!=texCoordList.siz e()) if (!texCoordList.isEmpty() && contoursList.size()!=texCoordList.siz e())
throw std::runtime_error(qPrintable(QString("the number of s ky contours (%1) does not match the number of texture space contours (%2)") .arg( contoursList.size()).arg(texCoordList.size()))); throw std::runtime_error(qPrintable(QString("the number of s ky contours (%1) does not match the number of texture space contours (%2)") .arg( contoursList.size()).arg(texCoordList.size())));
bool ok;
if (texCoordList.isEmpty()) if (texCoordList.isEmpty())
{ {
// No texture coordinates // No texture coordinates
return loadFromQVariant(contoursList); return loadFromQVariant(contoursList);
} }
else
{
// With texture coordinates
QVector<QVector<SphericalTexturedPolygon::TextureVertex> > c
ontours;
QVector<SphericalTexturedPolygon::TextureVertex> vertices;
for (int i=0;i<contoursList.size();++i)
{
// Load vertices
const QVariantList& polyRaDecToList = contoursList.a
t(i).toList();
if (polyRaDecToList.size()<3)
throw std::runtime_error("a polygon contour
must have at least 3 vertices");
SphericalTexturedPolygon::TextureVertex v;
foreach (const QVariant& vRaDec, polyRaDecToList)
{
parseRaDec(vRaDec, v.vertex);
vertices.append(v);
}
Q_ASSERT(vertices.size()>2);
// Add the texture coordinates Q_ASSERT_X(false, Q_FUNC_INFO, "Code to load textured spherical regi
const QVariantList& polyXYToList = texCoordList.at(i on not yet implemented");
).toList();
if (polyXYToList.size()!=vertices.size())
throw std::runtime_error("texture coordinate
and vertices number mismatch for contour");
for (int n=0;n<polyXYToList.size();++n)
{
const QVariantList& vl = polyXYToList.at(n).
toList();
if (vl.size()!=2)
throw std::runtime_error("invalid te
xture coordinate pair (expect 2 double values in degree)");
vertices[n].texCoord.set(vl.at(0).toDouble(&
ok), vl.at(1).toDouble(&ok));
if (!ok)
throw std::runtime_error("invalid te
xture coordinate pair (expect 2 double values in degree)");
}
contours.append(vertices);
vertices.clear();
}
return SphericalRegionP(new SphericalTexturedPolygon(contour
s));
}
Q_ASSERT(0);
return SphericalRegionP(new SphericalCap()); return SphericalRegionP(new SphericalCap());
} }
void SphericalRegionP::serializeToJson(const QVariant& jsonObject, QIODevic e* output, int indentLevel) void SphericalRegionP::serializeToJson(const QVariant& jsonObject, QIODevic e* output, int indentLevel)
{ {
const SphericalRegionP& reg = jsonObject.value<SphericalRegionP>(); const SphericalRegionP& reg = jsonObject.value<SphericalRegionP>();
StelJsonParser::write(reg->toQVariant(), output, indentLevel); StelJsonParser::write(reg->toQVariant(), output, indentLevel);
} }
 End of changes. 30 change blocks. 
121 lines changed or deleted 895 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/