You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

597 lines
16 KiB

#if defined(_MSC_VER) /* MSVC Compiler */
#pragma warning ( disable : 4305 )
#pragma warning ( disable : 4786 )
#endif
#include "qwt3d_surfaceplot.h"
#include "qwt3d_enrichment_std.h"
using namespace std;
using namespace Qwt3D;
void SurfacePlot::createDataG()
{
createFloorData();
if (plotStyle() == NOPLOT)
return;
int i, j;
RGBA col;
int step = resolution();
if (plotStyle() == Qwt3D::POINTS)
{
createPoints();
return;
}
else if (plotStyle() == Qwt3D::USER)
{
if (userplotstyle_p)
createEnrichment(*userplotstyle_p);
return;
}
setDeviceLineWidth(meshLineWidth());
GLStateBewarer sb(GL_POLYGON_OFFSET_FILL,true);
setDevicePolygonOffset(polygonOffset(),1.0);
GLStateBewarer sb2(GL_LINE_SMOOTH, smoothDataMesh());
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int lastcol = actualDataG_->columns();
int lastrow = actualDataG_->rows();
if (plotStyle() != WIREFRAME)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
bool hl = (plotStyle() == HIDDENLINE);
if (hl)
{
col = backgroundRGBAColor();
glColor4d(col.r, col.g, col.b, col.a);
}
for (i = 0; i < lastcol - step; i += step)
{
glBegin(GL_TRIANGLE_STRIP);
setColorFromVertexG(i, 0, hl);
glNormal3dv(actualDataG_->normals[i][0]);
glVertex3dv(actualDataG_->vertices[i][0]);
setColorFromVertexG(i+step, 0, hl);
glNormal3dv(actualDataG_->normals[i+step][0]);
glVertex3dv(actualDataG_->vertices[i+step][0]);
for (j = 0; j < lastrow - step; j += step)
{
setColorFromVertexG(i,j+step, hl);
glNormal3dv(actualDataG_->normals[i][j+step]);
glVertex3dv(actualDataG_->vertices[i][j+step]);
setColorFromVertexG(i+step, j+step, hl);
glNormal3dv(actualDataG_->normals[i+step][j+step]);
glVertex3dv(actualDataG_->vertices[i+step][j+step]);
}
glEnd();
}
}
if (plotStyle() == FILLEDMESH || plotStyle() == WIREFRAME || plotStyle() == HIDDENLINE)
{
glColor4d(meshColor().r, meshColor().g, meshColor().b, meshColor().a);
if (step < actualDataG_->columns() && step < actualDataG_->rows())
{
glBegin(GL_LINE_LOOP);
for (i = 0; i < actualDataG_->columns() - step; i += step)
glVertex3dv(actualDataG_->vertices[i][0]);
for (j = 0; j < actualDataG_->rows() - step; j += step)
glVertex3dv(actualDataG_->vertices[i][j]);
for (; i >= 0; i -= step)
glVertex3dv(actualDataG_->vertices[i][j]);
for (; j >= 0; j -= step)
glVertex3dv(actualDataG_->vertices[0][j]);
glEnd();
}
// weaving
for (i = step; i < actualDataG_->columns() - step; i += step)
{
glBegin(GL_LINE_STRIP);
for (j = 0; j < actualDataG_->rows(); j += step)
glVertex3dv(actualDataG_->vertices[i][j]);
glEnd();
}
for (j = step; j < actualDataG_->rows() - step; j += step)
{
glBegin(GL_LINE_STRIP);
for (i = 0; i < actualDataG_->columns(); i += step)
glVertex3dv(actualDataG_->vertices[i][j]);
glEnd();
}
}
}
void SurfacePlot::setColorFromVertexG(int ix, int iy, bool skip)
{
if (skip)
return;
RGBA col = (*datacolor_p)(
actualDataG_->vertices[ix][iy][0],
actualDataG_->vertices[ix][iy][1],
actualDataG_->vertices[ix][iy][2]);
glColor4d(col.r, col.g, col.b, col.a);
}
void SurfacePlot::createNormalsG()
{
if (!normals() || actualDataG_->empty())
return;
Arrow arrow;
arrow.setQuality(normalQuality());
Triple basev, topv, norm;
int step = resolution();
double diag = (actualDataG_->hull().maxVertex-actualDataG_->hull().minVertex).length() * normalLength();
arrow.assign(*this);
arrow.drawBegin();
for (int i = 0; i <= actualDataG_->columns() - step; i += step)
{
for (int j = 0; j <= actualDataG_->rows() - step; j += step)
{
basev = Triple(actualDataG_->vertices[i][j][0],actualDataG_->vertices[i][j][1],actualDataG_->vertices[i][j][2]);
topv = Triple(actualDataG_->vertices[i][j][0]+actualDataG_->normals[i][j][0],
actualDataG_->vertices[i][j][1]+actualDataG_->normals[i][j][1],
actualDataG_->vertices[i][j][2]+actualDataG_->normals[i][j][2]);
norm = topv-basev;
norm.normalize();
norm *= diag;
arrow.setTop(basev+norm);
arrow.setColor((*datacolor_p)(basev.x,basev.y,basev.z));
arrow.draw(basev);
}
}
arrow.drawEnd();
}
void SurfacePlot::readIn(GridData& gdata, Triple** data, unsigned int columns, unsigned int rows)
{
gdata.setSize(columns,rows);
ParallelEpiped range(Triple(DBL_MAX,DBL_MAX,DBL_MAX),Triple(-DBL_MAX,-DBL_MAX,-DBL_MAX));
/* fill out the vertex array for the mesh. */
for (unsigned i = 0; i != columns; ++i)
{
for (unsigned j = 0; j != rows; ++j)
{
gdata.vertices[i][j][0] = data[i][j].x;
gdata.vertices[i][j][1] = data[i][j].y;
gdata.vertices[i][j][2] = data[i][j].z;
if (data[i][j].x > range.maxVertex.x)
range.maxVertex.x = data[i][j].x;
if (data[i][j].y > range.maxVertex.y)
range.maxVertex.y = data[i][j].y;
if (data[i][j].z > range.maxVertex.z)
range.maxVertex.z = data[i][j].z;
if (data[i][j].x < range.minVertex.x)
range.minVertex.x = data[i][j].x;
if (data[i][j].y < range.minVertex.y)
range.minVertex.y = data[i][j].y;
if (data[i][j].z < range.minVertex.z)
range.minVertex.z = data[i][j].z;
}
}
gdata.setHull(range);
}
void SurfacePlot::readIn(GridData& gdata, double** data, unsigned int columns, unsigned int rows
, double minx, double maxx, double miny, double maxy)
{
gdata.setPeriodic(false,false);
gdata.setSize(columns,rows);
double dx = (maxx - minx) / (gdata.columns() - 1);
double dy = (maxy - miny) / (gdata.rows() - 1);
double tmin = DBL_MAX;
double tmax = -DBL_MAX;
/* fill out the vertex array for the mesh. */
for (unsigned i = 0; i != columns; ++i)
{
for (unsigned j = 0; j != rows; ++j)
{
gdata.vertices[i][j][0] = minx + i*dx;
gdata.vertices[i][j][1] = miny + j*dy;
gdata.vertices[i][j][2] = data[i][j];
if (data[i][j] > tmax)
tmax = data[i][j];
if (data[i][j] < tmin)
tmin = data[i][j];
}
}
ParallelEpiped hull =
ParallelEpiped(
Triple(
gdata.vertices[0][0][0],
gdata.vertices[0][0][1],
tmin
),
Triple(
gdata.vertices[gdata.columns()-1][gdata.rows()-1][0],
gdata.vertices[gdata.columns()-1][gdata.rows()-1][1],
tmax
)
);
gdata.setHull(hull);
}
void SurfacePlot::calcNormals(GridData& gdata)
{
unsigned int rows = gdata.rows();
unsigned int columns = gdata.columns();
// normals
Triple u, v, n; // for cross product
for (unsigned i = 0; i != columns; ++i)
{
for (unsigned j = 0; j != rows; ++j)
{
n = Triple(0,0,0);
if (i<columns-1 && j<rows-1)
{
/* get two vectors to cross */
u = Triple(
gdata.vertices[i+1][j][0] - gdata.vertices[i][j][0],
gdata.vertices[i+1][j][1] - gdata.vertices[i][j][1],
gdata.vertices[i+1][j][2] - gdata.vertices[i][j][2]
);
v = Triple(
gdata.vertices[i][j+1][0] - gdata.vertices[i][j][0],
gdata.vertices[i][j+1][1] - gdata.vertices[i][j][1],
gdata.vertices[i][j+1][2] - gdata.vertices[i][j][2]
);
/* get the normalized cross product */
n += normalizedcross(u,v); // right hand system here !
}
if (i>0 && j<rows-1)
{
u = Triple(
gdata.vertices[i][j+1][0] - gdata.vertices[i][j][0],
gdata.vertices[i][j+1][1] - gdata.vertices[i][j][1],
gdata.vertices[i][j+1][2] - gdata.vertices[i][j][2]
);
v = Triple(
gdata.vertices[i-1][j][0] - gdata.vertices[i][j][0],
gdata.vertices[i-1][j][1] - gdata.vertices[i][j][1],
gdata.vertices[i-1][j][2] - gdata.vertices[i][j][2]
);
n += normalizedcross(u,v);
}
if (i>0 && j>0)
{
u = Triple(
gdata.vertices[i-1][j][0] - gdata.vertices[i][j][0],
gdata.vertices[i-1][j][1] - gdata.vertices[i][j][1],
gdata.vertices[i-1][j][2] - gdata.vertices[i][j][2]
);
v = Triple(
gdata.vertices[i][j-1][0] - gdata.vertices[i][j][0],
gdata.vertices[i][j-1][1] - gdata.vertices[i][j][1],
gdata.vertices[i][j-1][2] - gdata.vertices[i][j][2]
);
n += normalizedcross(u,v);
}
if (i<columns-1 && j>0)
{
u = Triple(
gdata.vertices[i][j-1][0] - gdata.vertices[i][j][0],
gdata.vertices[i][j-1][1] - gdata.vertices[i][j][1],
gdata.vertices[i][j-1][2] - gdata.vertices[i][j][2]
);
v = Triple(
gdata.vertices[i+1][j][0] - gdata.vertices[i][j][0],
gdata.vertices[i+1][j][1] - gdata.vertices[i][j][1],
gdata.vertices[i+1][j][2] - gdata.vertices[i][j][2]
);
n += normalizedcross(u,v);
}
n.normalize();
gdata.normals[i][j][0] = n.x;
gdata.normals[i][j][1] = n.y;
gdata.normals[i][j][2] = n.z;
}
}
}
void SurfacePlot::sewPeriodic(GridData& gdata)
{
// sewing
Triple n;
unsigned int columns = gdata.columns();
unsigned int rows = gdata.rows();
if (gdata.uperiodic())
{
for (unsigned i = 0; i != columns; ++i)
{
n = Triple(
gdata.normals[i][0][0] + gdata.normals[i][rows-1][0],
gdata.normals[i][0][1] + gdata.normals[i][rows-1][1],
gdata.normals[i][0][2] + gdata.normals[i][rows-1][2]
);
n.normalize();
gdata.normals[i][0][0] = gdata.normals[i][rows-1][0] = n.x;
gdata.normals[i][0][1] = gdata.normals[i][rows-1][1] = n.y;
gdata.normals[i][0][2] = gdata.normals[i][rows-1][2] = n.z;
}
}
if (gdata.vperiodic())
{
for (unsigned j = 0; j != rows; ++j)
{
n = Triple(
gdata.normals[0][j][0] + gdata.normals[columns-1][j][0],
gdata.normals[0][j][1] + gdata.normals[columns-1][j][1],
gdata.normals[0][j][2] + gdata.normals[columns-1][j][2]
);
n.normalize();
gdata.normals[0][j][0] = gdata.normals[columns-1][j][0] = n.x;
gdata.normals[0][j][1] = gdata.normals[columns-1][j][1] = n.y;
gdata.normals[0][j][2] = gdata.normals[columns-1][j][2] = n.z;
}
}
}
/*!
Convert user grid data to internal vertex structure.
See also NativeReader::read() and Function::create()
*/
bool SurfacePlot::loadFromData(Triple** data, unsigned int columns, unsigned int rows, bool uperiodic, bool vperiodic)
{
actualDataC_->clear();
actualData_p = actualDataG_;
readIn(*actualDataG_, data, columns, rows);
calcNormals(*actualDataG_);
actualDataG_->setPeriodic(uperiodic,vperiodic);
sewPeriodic(*actualDataG_);
updateData();
updateNormals();
createCoordinateSystem();
return true;
}
/*!
Convert user grid data to internal vertex structure.
See also NativeReader::read() and Function::create()
*/
bool SurfacePlot::loadFromData(double** data, unsigned int columns, unsigned int rows
, double minx, double maxx, double miny, double maxy)
{
actualDataC_->clear();
actualData_p = actualDataG_;
actualDataG_->setPeriodic(false,false);
actualDataG_->setSize(columns,rows);
readIn(*actualDataG_,data,columns,rows,minx,maxx,miny,maxy);
calcNormals(*actualDataG_);
updateData();
updateNormals();
createCoordinateSystem();
return true;
}
void SurfacePlot::createFloorDataG()
{
switch (floorStyle())
{
case FLOORDATA:
Data2FloorG();
break;
case FLOORISO:
Isolines2FloorG();
break;
default:
break;
}
}
void SurfacePlot::Data2FloorG()
{
if (actualData_p->empty())
return;
int step = resolution();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
double zshift = actualData_p->hull().minVertex.z;
for (int i = 0; i < actualDataG_->columns() - step; i += step)
{
glBegin(GL_TRIANGLE_STRIP);
setColorFromVertexG(i, 0);
glVertex3d(actualDataG_->vertices[i][0][0], actualDataG_->vertices[i][0][1], zshift);
setColorFromVertexG(i+step, 0);
glVertex3d(actualDataG_->vertices[i+step][0][0],actualDataG_->vertices[i+step][0][1], zshift);
for (int j = 0; j < actualDataG_->rows() - step; j += step)
{
setColorFromVertexG(i, j+step);
glVertex3d(actualDataG_->vertices[i][j+step][0],actualDataG_->vertices[i][j+step][1], zshift);
setColorFromVertexG(i+step, j+step);
glVertex3d(actualDataG_->vertices[i+step][j+step][0],actualDataG_->vertices[i+step][j+step][1], zshift);
}
glEnd();
}
}
void SurfacePlot::Isolines2FloorG()
{
if (isolines() <= 0 || actualData_p->empty())
return;
double count = (actualData_p->hull().maxVertex.z - actualData_p->hull().minVertex.z) / isolines();
RGBA col;
int step = resolution();
double zshift = actualData_p->hull().minVertex.z;
int cols = actualDataG_->columns();
int rows = actualDataG_->rows();
Triple t[4];
vector<Triple> intersection;
double lambda = 0;
GLStateBewarer sb2(GL_LINE_SMOOTH, false);
for (int k = 0; k != isolines(); ++k)
{
double val = zshift + k * count;
for (int i = 0; i < cols-step; i += step)
{
for (int j = 0; j < rows-step; j += step)
{
t[0] = Triple( actualDataG_->vertices[i][j][0],
actualDataG_->vertices[i][j][1],
actualDataG_->vertices[i][j][2]);
col = (*datacolor_p)(t[0].x,t[0].y,t[0].z);
glColor4d(col.r, col.g, col.b, col.a);
// glColor4d(0,0,0,1);
t[1] = Triple( actualDataG_->vertices[i+step][j][0],
actualDataG_->vertices[i+step][j][1],
actualDataG_->vertices[i+step][j][2]);
t[2] = Triple( actualDataG_->vertices[i+step][j+step][0],
actualDataG_->vertices[i+step][j+step][1],
actualDataG_->vertices[i+step][j+step][2]);
t[3] = Triple( actualDataG_->vertices[i][j+step][0],
actualDataG_->vertices[i][j+step][1],
actualDataG_->vertices[i][j+step][2]);
double diff = 0;
for (int m = 0; m!=4; ++m)
{
int mm = (m+1)%4;
if ((val>=t[m].z && val<=t[mm].z) || (val>=t[mm].z && val<=t[m].z))
{
diff = t[mm].z - t[m].z;
if (isPracticallyZero(diff)) // degenerated
{
intersection.push_back(t[m]);
intersection.push_back(t[mm]);
continue;
}
lambda = (val - t[m].z) / diff;
intersection.push_back(Triple(t[m].x + lambda * (t[mm].x-t[m].x), t[m].y + lambda * (t[mm].y-t[m].y), val));
}
}
if (!intersection.empty())
{
if (intersection.size()>2)
{
glBegin(GL_LINE_STRIP);
for (unsigned dd = 0; dd!=intersection.size(); ++dd)
{
glVertex3d(intersection[dd].x, intersection[dd].y, zshift);
}
glEnd();
glBegin(GL_POINTS);
glVertex3d(intersection[0].x,intersection[0].y,zshift);
glEnd();
}
else if (intersection.size() == 2)
{
glBegin(GL_LINES);
glVertex3d(intersection[0].x,intersection[0].y,zshift);
glVertex3d(intersection[1].x,intersection[1].y,zshift);
// small pixel gap problem (see OpenGL spec.)
glVertex3d(intersection[1].x,intersection[1].y,zshift);
glVertex3d(intersection[0].x,intersection[0].y,zshift);
glEnd();
}
intersection.clear();
}
}
}
}
}
/*
void SurfacePlot::calcLowResolution()
{
if (!actualDataG_)
return;
int res = resolution();
if (res == 1)
{
lowresData_p = *actualDataG_;
return;
}
GridData const& src = *actualDataG_;
result.clear();
}*/