From bc4a28675ab06e969e4ab4ca151feb50895a7b2d Mon Sep 17 00:00:00 2001 From: James Hogan Date: Sun, 1 Mar 2009 00:30:23 +0000 Subject: [PATCH] Made it possible to display normals in output channels 4-6 (A,B,C) --- geo/CMakeLists.txt | 1 + geo/tcGeo.h | 13 ++++ geo/tcGeoImageData.cpp | 36 ++++++++-- geo/tcGeoImageData.h | 11 +++ geo/tcGlobe.cpp | 181 ++++++++++++++++++++++++++++++++--------------- geo/tcGlobe.h | 5 +- geo/tcNormals.cpp | 87 +++++++++++++++++++++++ geo/tcNormals.h | 71 +++++++++++++++++++ geo/tcPixelData.h | 30 ++++++++ geo/tcProcessingData.cpp | 4 ++ geo/tcSrtmModel.cpp | 28 +++++--- 11 files changed, 396 insertions(+), 71 deletions(-) create mode 100644 geo/tcNormals.cpp create mode 100644 geo/tcNormals.h diff --git a/geo/CMakeLists.txt b/geo/CMakeLists.txt index 1679504..cca4f55 100644 --- a/geo/CMakeLists.txt +++ b/geo/CMakeLists.txt @@ -32,6 +32,7 @@ set(tecorrec_geo_SRCS tcShadowDepth.cpp tcLambertianShading.cpp tcRaytracedShadowMap.cpp + tcNormals.cpp tcElevation.cpp tcElevationDifference.cpp tcElevationOptimization.cpp diff --git a/geo/tcGeo.h b/geo/tcGeo.h index 6943bf3..2c35884 100644 --- a/geo/tcGeo.h +++ b/geo/tcGeo.h @@ -278,6 +278,19 @@ class tcGeo return tcGeo(m_longitude * other[0], m_latitude * other[1]); } + template + maths::Vector<3,T> operator * (const maths::Vector<3,T>& other) const + { + return (maths::Vector<3,T>)((maths::Vector<3,double>)other * operator maths::Matrix<3,double>()); + float sinLon = sinf(m_longitude); + float cosLon = cosf(m_longitude); + float sinLat = sinf(m_latitude); + float cosLat = cosf(m_latitude); + return maths::Vector<3,T>(other[0]*cosLon + other[2]*sinLon*cosLat, + other[0]*sinLon - other[2]*cosLon*cosLat, + other[1]*cosLat + other[2]*sinLat); + } + float angle() const { return sqrt(m_longitude*m_longitude + m_latitude*m_latitude); diff --git a/geo/tcGeoImageData.cpp b/geo/tcGeoImageData.cpp index 15e5f88..96f3a65 100644 --- a/geo/tcGeoImageData.cpp +++ b/geo/tcGeoImageData.cpp @@ -47,6 +47,7 @@ tcGeoImageData::tcGeoImageData() , m_name(QObject::tr("Unamed geographical image data")) , m_sunDirection(0.0, 1.0, 0.0) , m_channelSetup() +, m_effectiveNormals() { for (int i = 0; i < 3; ++i) { @@ -188,6 +189,7 @@ void tcGeoImageData::setupDetailedRendering(int numChannels, int* channels, if (channels[i] >= 0 && channels[i] < channelManager()->numChannels()) { Reference data = channelManager()->channel(channels[i])->portion(&r1x, &r1y, &r2x, &r2y); + m_effectiveNormals[i-3] = dynamicCast >*>(data); } } for (int i = 0; i < 3; ++i) @@ -240,6 +242,18 @@ void tcGeoImageData::setupDetailedRendering(int numChannels, int* channels, setEffectiveTexToGeo(tcAffineTransform2(nwCorner, seCorner-nwCorner)); } +void tcGeoImageData::setupNormalRendering() +{ + for (int i = 0; i < 3; ++i) + { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + m_channelSetup[i] = false; + } + glActiveTexture(GL_TEXTURE0); +} + void tcGeoImageData::texCoord(const tcGeo& coord) { // Coordinates need offsetting and scaling @@ -253,16 +267,26 @@ void tcGeoImageData::texCoord(const tcGeo& coord) } } +maths::Vector<3,float> tcGeoImageData::normalAt(int norm, const tcGeo& coord) +{ + Q_ASSERT(norm >= 0 && norm < 3); + if (0 != m_effectiveNormals[norm]) + { + maths::Vector<2,double> texCoord = geoToEffectiveTex() * coord; + return m_effectiveNormals[norm]->interpolateLinear(texCoord[0], texCoord[1]); + } + else + { + return maths::Vector<3,float>(0.0f); + } +} + void tcGeoImageData::finishRendering() { for (int i = 0; i < 3; ++i) { - glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - m_channelSetup[i] = false; + m_effectiveNormals[i] = 0; } - glActiveTexture(GL_TEXTURE0); } /* @@ -292,5 +316,5 @@ void tcGeoImageData::setName(const QString& name) /// Set the sun direction. void tcGeoImageData::setSunDirection(const tcGeo& sunDirection, const tcGeo& sunReference) { - m_sunDirection = (maths::Vector<3,double>)sunDirection * sunReference.operator maths::Matrix<3,double>(); + m_sunDirection = sunReference * (maths::Vector<3,double>)sunDirection; } diff --git a/geo/tcGeoImageData.h b/geo/tcGeoImageData.h index 4b2abbe..57ddd32 100644 --- a/geo/tcGeoImageData.h +++ b/geo/tcGeoImageData.h @@ -27,6 +27,8 @@ #include "tcGeoData.h" #include "tcAffineTransform.h" +#include "tcPixelData.h" +#include "CountedReference.h" #include #include @@ -90,9 +92,15 @@ class tcGeoImageData : public tcGeoData virtual void setupDetailedRendering(int numChannels, int* channels, const tcGeo& swCorner, const tcGeo& neCorner); + /// Set up rendering for normals. + virtual void setupNormalRendering(); + /// Provide a geographical texture coordinate. virtual void texCoord(const tcGeo& coord); + /// Finds the normal at a geographical coordinate during rendering. + virtual maths::Vector<3,float> normalAt(int norm, const tcGeo& coord); + /// Unbind any textures etc. virtual void finishRendering(); @@ -146,6 +154,9 @@ class tcGeoImageData : public tcGeoData /// Whether each channel is set up for rendering. bool m_channelSetup[3]; + + /// The current normal data. + Reference > > m_effectiveNormals[3]; }; #endif diff --git a/geo/tcGlobe.cpp b/geo/tcGlobe.cpp index c3ce3c3..13060aa 100644 --- a/geo/tcGlobe.cpp +++ b/geo/tcGlobe.cpp @@ -147,7 +147,7 @@ void tcGlobe::drawLineOfLatitude(double latitude) const } /// Render a cell. -void tcGlobe::renderCell(tcObserver* const observer, const tcGeo& swCorner, const tcGeo& neCorner, int samples, +void tcGlobe::renderCell(tcObserver* const observer, const tcGeo& swCorner, const tcGeo& neCorner, int samples, bool normals, bool northEdge, bool eastEdge, bool southEdge, bool westEdge) const { // Sample at a sensible level @@ -206,34 +206,34 @@ void tcGlobe::renderCell(tcObserver* const observer, const tcGeo& swCorner, cons if (tall && !wide) { // bottom - renderCell(observer, geoCorners[0], (geoCorners[3] + geoCorners[2]) * 0.5, samples, + renderCell(observer, geoCorners[0], (geoCorners[3] + geoCorners[2]) * 0.5, samples, normals, false, eastEdge, southEdge, westEdge); // top - renderCell(observer, (geoCorners[0] + geoCorners[1]) * 0.5, geoCorners[2], samples, + renderCell(observer, (geoCorners[0] + geoCorners[1]) * 0.5, geoCorners[2], samples, normals, northEdge, eastEdge, false, westEdge); } else if (wide && !tall) { // left - renderCell(observer, geoCorners[0], (geoCorners[1] + geoCorners[2]) * 0.5, samples, + renderCell(observer, geoCorners[0], (geoCorners[1] + geoCorners[2]) * 0.5, samples, normals, northEdge, false, southEdge, westEdge); // right - renderCell(observer, (geoCorners[0] + geoCorners[3]) * 0.5, geoCorners[2], samples, + renderCell(observer, (geoCorners[0] + geoCorners[3]) * 0.5, geoCorners[2], samples, normals, northEdge, eastEdge, southEdge, false); } else { // bottom left - renderCell(observer, geoCorners[0], (geoCorners[0] + geoCorners[2]) * 0.5, samples, + renderCell(observer, geoCorners[0], (geoCorners[0] + geoCorners[2]) * 0.5, samples, normals, false, false, southEdge, westEdge); // bottom right - renderCell(observer, (geoCorners[0] + geoCorners[3]) * 0.5, (geoCorners[3] + geoCorners[2]) * 0.5, samples, + renderCell(observer, (geoCorners[0] + geoCorners[3]) * 0.5, (geoCorners[3] + geoCorners[2]) * 0.5, samples, normals, false, eastEdge, southEdge, false); // top left - renderCell(observer, (geoCorners[0] + geoCorners[1]) * 0.5, (geoCorners[1] + geoCorners[2]) * 0.5, samples, + renderCell(observer, (geoCorners[0] + geoCorners[1]) * 0.5, (geoCorners[1] + geoCorners[2]) * 0.5, samples, normals, northEdge, false, false, westEdge); // top right - renderCell(observer, (geoCorners[0] + geoCorners[2]) * 0.5, geoCorners[2], samples, + renderCell(observer, (geoCorners[0] + geoCorners[2]) * 0.5, geoCorners[2], samples, normals, northEdge, eastEdge, false, false); } return; @@ -298,72 +298,109 @@ void tcGlobe::renderCell(tcObserver* const observer, const tcGeo& swCorner, cons EDGE_KERNEL(STAGE, south, state.samplesLon, i, 0); \ EDGE_KERNEL(STAGE, west, state.samplesLat, 0, i); -#if 0 - // Render the solid rock walls - glDisable(GL_CULL_FACE); - EDGE(1) - EDGE(2) - EDGE(3) - EDGE(4) - glEnable(GL_CULL_FACE); -#endif - - // Render this cell - /// @todo cache one edge of strip to save time on other - for (int i = 0; i < state.samplesLon-1; ++i) + if (normals) { - glBegin(GL_TRIANGLE_STRIP); + // Draw normals + float normColours[3][2][3] = { + { { 1.0f, 1.0f, 1.0f }, { 1.0f, 0.0f, 0.0f } }, + { { 1.0f, 1.0f, 1.0f }, { 0.0f, 1.0f, 0.0f } }, + { { 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f, 1.0f } } + }; + glBegin(GL_LINES); + for (int i = 0; i < state.samplesLon; ++i) { for (int j = 0; j < state.samplesLat; ++j) { - for (int k = 0; k < 2; ++k) + tcGeo coord; + bool accurate = true; + double alt = altitudeAt(state, i, j, &coord, &accurate); + for (int n = 0; n < 3; ++n) { - tcGeo coord; - bool accurate = true; - double alt = altitudeAt(state, i+k, j, &coord, &accurate); - - // Get colour - foreach (tcGeoImageData* imagery, m_imagery) + GLvec3f norm = normalAt(n, coord); + if (!norm.zero()) { - imagery->texCoord(coord); + norm = coord * norm; + GLvec3d dir = coord; + double rad = m_meanRadius + alt; + glColor3fv(normColours[n][0]); + glVertex3(dir * rad); + glColor3fv(normColours[n][1]); + glVertex3(dir * rad + norm*50.0f); } + } + } + } + glEnd(); + } + else + { +#if 0 + // Render the solid rock walls + glDisable(GL_CULL_FACE); + EDGE(1) + EDGE(2) + EDGE(3) + EDGE(4) + glEnable(GL_CULL_FACE); +#endif - if (!accurate) - { - glColor4f(0.5f, 0.5f, 1.0f, 1.0f); - } - else - { - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - //glColor4f(1.0f, 1.0f-(float)alt/3278.0f, 0.0f, 1.0f); - } - // Colour code if applicable - if (m_colourCoding == ElevationSampleAlignment) + // Render this cell + /// @todo cache one edge of strip to save time on other + for (int i = 0; i < state.samplesLon-1; ++i) + { + glBegin(GL_TRIANGLE_STRIP); + { + for (int j = 0; j < state.samplesLat; ++j) + { + for (int k = 0; k < 2; ++k) { - if (state.moreAvailableLon && state.moreAvailableLat) + tcGeo coord; + bool accurate = true; + double alt = altitudeAt(state, i+k, j, &coord, &accurate); + + // Get colour + foreach (tcGeoImageData* imagery, m_imagery) { - glColor3f(1.0f, 0.0f, 1.0f); + imagery->texCoord(coord); } - else if (state.moreAvailableLon) + + if (!accurate) { - glColor3f(1.0f, 0.0f, 0.0f); + glColor4f(0.5f, 0.5f, 1.0f, 1.0f); } - else if (state.moreAvailableLat) + else { - glColor3f(0.0f, 0.0f, 1.0f); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + //glColor4f(1.0f, 1.0f-(float)alt/3278.0f, 0.0f, 1.0f); } - else + // Colour code if applicable + if (m_colourCoding == ElevationSampleAlignment) { - glColor3f(0.0f, 1.0f, 0.0f); + if (state.moreAvailableLon && state.moreAvailableLat) + { + glColor3f(1.0f, 0.0f, 1.0f); + } + else if (state.moreAvailableLon) + { + glColor3f(1.0f, 0.0f, 0.0f); + } + else if (state.moreAvailableLat) + { + glColor3f(0.0f, 0.0f, 1.0f); + } + else + { + glColor3f(0.0f, 1.0f, 0.0f); + } } + GLvec3d dir = coord; + double rad = m_meanRadius + alt; + glVertex3(dir * rad); } - GLvec3d dir = coord; - double rad = m_meanRadius + alt; - glVertex3(dir * rad); } } + glEnd(); } - glEnd(); } } @@ -458,7 +495,20 @@ void tcGlobe::render(tcObserver* const observer, bool adaptive, const tcGeo* ext { tcGeo sw(M_PI/180 * (lon), M_PI/180 * (lat)); tcGeo ne(M_PI/180 * (lon+dlon), M_PI/180 * (lat+dlat)); - renderCell(observer, sw, ne, adaptive ? 5 : 0); + renderCell(observer, sw, ne, adaptive ? 5 : 0, false); + } + } + foreach (tcGeoImageData* imagery, m_imagery) + { + imagery->setupNormalRendering(); + } + for (int lon = -180; lon < 180; lon += dlon) + { + for (int lat = -90; lat < 90; lat += dlat) + { + tcGeo sw(M_PI/180 * (lon), M_PI/180 * (lat)); + tcGeo ne(M_PI/180 * (lon+dlon), M_PI/180 * (lat+dlat)); + renderCell(observer, sw, ne, adaptive ? 5 : 0, true); } } } @@ -487,7 +537,12 @@ void tcGlobe::render(tcObserver* const observer, bool adaptive, const tcGeo* ext imagery->setupDetailedRendering(6, colourMapping, sw, ne); } /// @todo If it is really big, split it - renderCell(observer, sw, ne, adaptive ? 16 : 0, true, true, true, true); + renderCell(observer, sw, ne, adaptive ? 16 : 0, false, true, true, true, true); + foreach (tcGeoImageData* imagery, m_imagery) + { + imagery->setupNormalRendering(); + } + renderCell(observer, sw, ne, adaptive ? 16 : 0, true, true, true, true, true); } foreach (tcGeoImageData* imagery, m_imagery) { @@ -652,3 +707,17 @@ maths::Vector<2,double> tcGlobe::textureCoordOfGeo(const tcGeo& coord) const Q_ASSERT(0 && "Reimplement tcGlobe::TextureCoordOfGeo with multiple imagery"); return m_imagery[0]->geoToEffectiveTex() * coord; } + +/// Get the current normal at a coordinate. +maths::Vector<3,float> tcGlobe::normalAt(int norm, const tcGeo& coord) const +{ + Q_ASSERT(norm >= 0 && norm < 3); + if (m_colourMapping[3+norm][0] >= 0) + { + return m_imagery[m_colourMapping[3+norm][0]]->normalAt(norm, coord); + } + else + { + return maths::Vector<3,float>(0.0f); + } +} diff --git a/geo/tcGlobe.h b/geo/tcGlobe.h index 18fef68..4da8d49 100644 --- a/geo/tcGlobe.h +++ b/geo/tcGlobe.h @@ -122,6 +122,9 @@ class tcGlobe /// Get the texture coordinate of the effective texture at a geographical coordinate. maths::Vector<2,double> textureCoordOfGeo(const tcGeo& coord) const; + /// Get the current normal at a coordinate. + maths::Vector<3,float> normalAt(int norm, const tcGeo& coord) const; + private: /* @@ -132,7 +135,7 @@ class tcGlobe void drawLineOfLatitude(double latitude) const; /// Render a cell. - void renderCell(tcObserver* const observer, const tcGeo& swCorner, const tcGeo& neCorner, int samples, + void renderCell(tcObserver* const observer, const tcGeo& swCorner, const tcGeo& neCorner, int samples, bool normals = false, bool northEdge = false, bool eastEdge = false, bool southEdge = false, bool westEdge = false) const; private: diff --git a/geo/tcNormals.cpp b/geo/tcNormals.cpp new file mode 100644 index 0000000..e6fcbdc --- /dev/null +++ b/geo/tcNormals.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * This file is part of Tecorrec. * + * Copyright 2008 James Hogan * + * * + * Tecorrec is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Tecorrec is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Tecorrec. If not, write to the Free Software Foundation, * + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +/** + * @file tcNormals.cpp + * @brief Normal map from elevation data. + */ + +#include "tcNormals.h" +#include "tcGeoImageData.h" + +/* + * Constructors + destructor + */ + +/// Primary constructor. +tcNormals::tcNormals(const tcGeoImageData* refImagery, tcChannel* reference, tcSrtmModel* dem, tcGeoImageData* imagery) +: tcChannelDem(dem, imagery, + tr("Normals"), + tr("Normals from elevation data.")) +, m_referenceChannel(reference) +, m_refTransform(imagery->texToGeo() * refImagery->geoToTex()) +{ +} + +/// Destructor. +tcNormals::~tcNormals() +{ +} + +/* + * Interface for derived class to implement + */ + +void tcNormals::roundPortion(double* x1, double* y1, double* x2, double* y2) +{ + //m_referenceChannel->roundPortion(x1,y1,x2,y2); +} + +tcAbstractPixelData* tcNormals::loadPortion(double x1, double y1, double x2, double y2, bool changed) +{ + maths::Vector<2,double> xy1 = m_refTransform * maths::Vector<2,double>(x1,y1); + maths::Vector<2,double> xy2 = m_refTransform * maths::Vector<2,double>(x2,y2); + Reference channelData = m_referenceChannel->loadPortion(xy1[0], xy1[1], xy2[0], xy2[1], changed); + int width = channelData->width(); + int height = channelData->height(); + + // Create a new pixel buffer + tcTypedPixelData >* data = new tcTypedPixelData >(width, height); + startProcessing("Sampling elevation data"); + int index = 0; + for (int j = 0; j < height; ++j) + { + progress((float)j/(height-1)); + for (int i = 0; i < width; ++i) + { + // Transform coordinates + maths::Vector<2,float> coord(x1 + (x2-x1)*i / (width - 1), + y1 + (y2-y1)*j / (height - 1)); + tcGeo geoCoord = geoAt(coord); + + // Get some elevation data + bool accurate; + maths::Vector<3,float> normal = normalAt(geoCoord, false, &accurate); + data->buffer()[index] = normal; + ++index; + } + } + endProcessing(); + return data; +} diff --git a/geo/tcNormals.h b/geo/tcNormals.h new file mode 100644 index 0000000..804d0a1 --- /dev/null +++ b/geo/tcNormals.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * This file is part of Tecorrec. * + * Copyright 2008 James Hogan * + * * + * Tecorrec is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Tecorrec is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Tecorrec. If not, write to the Free Software Foundation, * + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _tcNormals_h_ +#define _tcNormals_h_ + +/** + * @file tcNormals.h + * @brief Normal map from elevation data. + */ + +#include "tcChannelDem.h" +#include "tcAffineTransform.h" + +/// Normal map from elevation data. +class tcNormals : public tcChannelDem +{ + public: + + /* + * Constructors + destructor + */ + + /// Primary constructor. + tcNormals(const tcGeoImageData* refImagery, tcChannel* reference, tcSrtmModel* dem, tcGeoImageData* imagery); + + /// Destructor. + virtual ~tcNormals(); + + protected: + + /* + * Interface for derived class to implement + */ + + // Reimplemented + virtual void roundPortion(double* x1, double* y1, double* x2, double* y2); + + // Reimplemented + virtual tcAbstractPixelData* loadPortion(double x1, double y1, double x2, double y2, bool changed); + + private: + + /* + * Variables + */ + + /// We'll use the same resolution as this reference channel. + tcChannel* m_referenceChannel; + + /// Transform to reference coordinates. + tcAffineTransform2 m_refTransform; +}; + +#endif diff --git a/geo/tcPixelData.h b/geo/tcPixelData.h index ce59925..2112e96 100644 --- a/geo/tcPixelData.h +++ b/geo/tcPixelData.h @@ -145,6 +145,36 @@ class tcTypedPixelData : public tcAbstractPixelData return m_data; } + T interpolateLinear(float x, float y) const + { + if (x < 0.0) x = 0.0; + if (x > 1.0) x = 1.0; + if (y < 0.0) y = 0.0; + if (y > 1.0) y = 1.0; + + float dx = x*(width()-1); + float dy = y*(height()-1); + int xi = (int)dx; + int yi = (int)dy; + dx -= xi; + dy -= yi; + if (xi >= width()-1) + { + --xi; + dx = 1.0f; + } + if (yi >= height()-1) + { + --yi; + dy = 1.0f; + } + + return buffer()[yi*width() + xi] * (1.0f - dx) * (1.0f - dy) + + buffer()[yi*width() + xi+1] * dx * (1.0f - dy) + + buffer()[(yi+1)*width() + xi] * (1.0f - dx) * dy + + buffer()[(yi+1)*width() + xi+1] * dx * dy; + } + private: /* diff --git a/geo/tcProcessingData.cpp b/geo/tcProcessingData.cpp index a068b2e..ae6d59e 100644 --- a/geo/tcProcessingData.cpp +++ b/geo/tcProcessingData.cpp @@ -30,6 +30,7 @@ #include "tcElevation.h" #include "tcElevationDifference.h" #include "tcElevationOptimization.h" +#include "tcNormals.h" #include "tcPixelOp.h" #include @@ -57,6 +58,9 @@ tcProcessingData::tcProcessingData(const QList& datase tcElevation* elevation2 = new tcElevation(refImagery, reference, dem+1, this); channelManager()->addChannel(elevation2); + tcNormals* normals = new tcNormals(refImagery, reference, dem, this); + channelManager()->addChannel(normals); + tcElevationDifference* elevationDifference = new tcElevationDifference(refImagery, reference, dem, this); channelManager()->addChannel(elevationDifference); diff --git a/geo/tcSrtmModel.cpp b/geo/tcSrtmModel.cpp index fdeea3d..a43b96f 100644 --- a/geo/tcSrtmModel.cpp +++ b/geo/tcSrtmModel.cpp @@ -173,7 +173,8 @@ maths::Vector<3,float> tcSrtmModel::normalAt(const tcGeo& coord, bool corrected, // Sample altitudes a fixed angle in each direction. const double radiusEarth = 6378.137e3; tcGeo angRes = data->sampleResolution(); - bool xpa, xma, ypa, yma; + bool alta, xpa, xma, ypa, yma; + double alt = altitudeAt(coord, corrected, &alta); double xp = altitudeAt(coord + tcGeo(angRes.lon()*0.5, 0.0), corrected, &xpa); double xm = altitudeAt(coord - tcGeo(angRes.lon()*0.5, 0.0), corrected, &xma); double yp = altitudeAt(coord + tcGeo(0.0, angRes.lat()*0.5), corrected, &ypa); @@ -184,13 +185,24 @@ maths::Vector<3,float> tcSrtmModel::normalAt(const tcGeo& coord, bool corrected, { *accurate = xpa && xma && ypa && yma; } - maths::Vector<2,float> res(radiusEarth * angRes.lon() * cos(coord.lat()), - radiusEarth * angRes.lat()); - return maths::Vector<3,float>( - -dx / res[0], - -dy / res[1], - 2.0f - ).normalized(); + maths::Vector<2,float> res((radiusEarth+alt) * angRes.lon() * cos(coord.lat()), + (radiusEarth+alt) * angRes.lat()); + return ( maths::Vector<3,float>( + -dx, + 0.0f, + res[0] + ).normalized() + + maths::Vector<3,float>( + 0.0f, + -dy, + res[1] + ).normalized() + ).normalized(); + /*return maths::Vector<3,float>( + -dx, + -dy, + res[0] + res[1] + ).normalized();*/ } } if (0 != accurate) -- 2.11.4.GIT