/*
* Copyright (c) 2002-2006 Samit Basu
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "HandleSurface.hpp"
#include "HandleAxis.hpp"
#include <qgl.h>
HandleSurface::HandleSurface() {
ConstructProperties();
SetupDefaults();
}
HandleSurface::~HandleSurface() {
}
std::vector<double> HandleSurface::GetLimits() {
std::vector<double> limits;
UpdateState();
Array xdata(ArrayPropertyLookup("xdata"));
Array ydata(ArrayPropertyLookup("ydata"));
Array zdata(ArrayPropertyLookup("zdata"));
Array cdata(ArrayPropertyLookup("cdata"));
limits.push_back(ArrayMin(xdata));
limits.push_back(ArrayMax(xdata));
limits.push_back(ArrayMin(ydata));
limits.push_back(ArrayMax(ydata));
limits.push_back(ArrayMin(zdata));
limits.push_back(ArrayMax(zdata));
limits.push_back(ArrayMin(cdata));
limits.push_back(ArrayMax(cdata));
std::vector<double> alphadata(VectorPropertyLookup("alphadata"));
limits.push_back(VecMin(alphadata));
limits.push_back(VecMax(alphadata));
return limits;
}
void HandleSurface::ConstructProperties() {
//!
//@Module SURFACEPROPERTIES Surface Object Properties
//@@Section HANDLE
//@@Usage
//Below is a summary of the properties for the axis.
//\begin{itemize}
// \item @|alphadata| - @|vector| - This is a vector that
// should contain as many elements as the surface data itself @|cdata|,
// or a single scalar. For a single scalar, all values of the surface
// take on the same transparency. Otherwise, the transparency of
// each pixel is determined by the corresponding value from the @|alphadata|
// vector.
// \item @|alphadatamapping| - @|{'scaled','direct','none'}| - For @|none|
// mode (the default), no transparency is applied to the data. For @|direct|
// mode, the vector @|alphadata| contains values between @[0,M-1]| where
// @|M| is the length of the alpha map stored in the figure. For @|scaled|
// mode, the @|alim| vector for the figure is used to linearly rescale the
// alpha data prior to lookup in the alpha map.
// \item @|ambientstrength| - Not used.
// \item @|backfacelighting| - Not used.
// \item @|cdata| - @|array| - This is either a @|M x N| array or an
// @|M x N x 3| array. If the data is @|M x N| the surface is a scalar
// surface (indexed mode), where the color associated with each surface pixel
// is computed using the colormap and the @|cdatamapping| mode. If the
// data is @|M x N x 3| the surface is assumed to be in RGB mode, and the
// colorpanes are taken directly from @|cdata| (the colormap is ignored).
// Note that in this case, the data values must be between @[0,1]| for each
// color channel and each point on the surface.
// \item @|cdatamapping| - @|{'scaled','direct'}| - For @|scaled| (the
// default), the pixel values are scaled using the @|clim| vector for the
// figure prior to looking up in the colormap. For @|direct| mode, the
// pixel values must be in the range @|[0,N-1| where @|N| is the number of
// colors in the colormap.
// \item @|children| - Not used.
// \item @|diffusestrength| - Not used.
// \item @|edgealpha| - @|{'flat','interp','scalar'}| - Controls how the
// transparency is mapped for the edges of the surface.
// \item @|edgecolor| - @|{'flat','interp','none',colorspec}| - Specifies
// how the edges are colored. For @|'flat'| the edges are flat colored,
// meaning that the line segments that make up the edges are not shaded.
// The color for the line is determined by the first edge point it is connected
// to.
// \item @|edgelighting| - Not used.
// \item @|facealpha| - @|{'flat','interp','texturemap',scalar}| - Controls
// how the transparency of the faces of the surface are controlled. For
// flat shading, the faces are constant transparency. For interp mode, the faces
// are smoothly transparently mapped. If set to a scalar, all faces have the
// same transparency.
// \item @|facecolor| - @|{'none','flat','interp',colorspec}| - Controls
// how the faces are colored. For @|'none'| the faces are uncolored, and
// the surface appears as a mesh without hidden lines removed. For @|'flat'|
// the surface faces have a constant color. For @|'interp'| smooth shading
// is applied to the surface. And if a colorspec is provided, then the
// faces all have the same color.
// \item @|facelighting| - Not used.
// \item @|linestyle| - @|{'-','--',':','-.','none'}| - The style of the line used
// to draw the edges.
// \item @|linewidth| - @|scalar| - The width of the line used to draw the edges.
// \item @|marker| - @|{'+','o','*','.','x','square','s','diamond','d','^','v','>','<'}| -
// The marker for data points on the line. Some of these are redundant, as @|'square'|
// @|'s'| are synonyms, and @|'diamond'| and @|'d'| are also synonyms.
// \item @|markeredgecolor| - @|colorspec| - The color used to draw the marker. For some
// of the markers (circle, square, etc.) there are two colors used to draw the marker.
// This property controls the edge color (which for unfilled markers) is the primary
// color of the marker.
// \item @|markerfacecolor| - @|colorspec| - The color used to fill the marker. For some
// of the markers (circle, square, etc.) there are two colors used to fill the marker.
// \item @|markersize| - @|scalar| - Control the size of the marker. Defaults to 6, which
// is effectively the radius (in pixels) of the markers.
// \item @|meshstyle| - @|{'both','rows','cols}| - This property controls how the mesh is
// drawn for the surface. For @|rows| and @|cols| modes, only one set of edges is drawn.
// \item @|normalmode| - Not used.
// \item @|parent| - @|handle| - The axis containing the surface.
// \item @|specularcolorreflectance| - Not used.
// \item @|specularexponent| - Not used.
// \item @|specularstrength| - Not used.
// \item @|tag| - @|string| - You can set this to any string you want.
// \item @|type| - @|string| - Set to the string @|'surface'|.
// \item @|userdata| - @|array| - Available to store any variable you
// want in the handle object.
// \item @|vertexnormals| - Not used.
// \item @|xdata| - @|array| - Must be a numeric array of size @|M x N| which contains
// the x location of each point in the defined surface. Must be the same size as @|ydata|
// and @|zdata|. Alternately, you can specify an array of size @|1 x N| in which case
// FreeMat replicates the vector to fill out an @|M x N| matrix.
// \item @|xdatamode| - @|{'auto','manual'}| - When set to @|auto| then FreeMat will
// automatically generate the x coordinates.
// \item @|ydata| - @|array| - Must be a numeric array of size @|M x N| which contains
// the y location of each point in the defined surface. Must be the same size as @|xdata|
// and @|zdata|. Alternately, you can specify an array of size @|M x 1| in which case
// FreeMat replicates the vector to fill out an @|M x N| matrix.
// \item @|ydatamode| - @|{'auto','manual'}| - When set to @|auto| then FreeMat will
// automatically generate the y coordinates.
// \item @|zdata| - @|array| - Must be a numeric array of size @|M x N| which contains
// the y location of each point in the defined surface. Must be the same size as @|xdata|
// and @|ydata|.
// \item @|visible| - @|{'on','off'}| - Controls whether the surface is
// visible or not.
//\end{itemize}
//!
AddProperty(new HPVector, "alphadata");
AddProperty(new HPMappingMode, "alphadatamapping");
AddProperty(new HPScalar,"ambientstrength");
AddProperty(new HPBackFaceLighting,"backfacelighting");
AddProperty(new HPArray, "cdata");
AddProperty(new HPDataMappingMode, "cdatamapping");
AddProperty(new HPAutoManual, "cdatamode");
AddProperty(new HPHandles,"children");
AddProperty(new HPScalar,"diffusestrength");
AddProperty(new HPEdgeAlpha,"edgealpha");
AddProperty(new HPColorInterp,"edgecolor");
AddProperty(new HPLightingMode,"edgelighting");
AddProperty(new HPFaceAlpha,"facealpha");
AddProperty(new HPColorInterp,"facecolor");
AddProperty(new HPLightingMode,"facelighting");
AddProperty(new HPLineStyle,"linestyle");
AddProperty(new HPScalar,"linewidth");
AddProperty(new HPSymbol,"marker");
AddProperty(new HPAutoFlatColor,"markeredgecolor");
AddProperty(new HPAutoFlatColor,"markerfacecolor");
AddProperty(new HPScalar,"markersize");
AddProperty(new HPRowColumns,"meshstyle");
AddProperty(new HPAutoManual,"normalmode");
AddProperty(new HPHandles,"parent");
AddProperty(new HPScalar,"specularcolorreflectance");
AddProperty(new HPScalar,"specularexponent");
AddProperty(new HPScalar,"specularstrength");
AddProperty(new HPString,"tag");
AddProperty(new HPString,"type");
AddProperty(new HPArray,"userdata");
AddProperty(new HPArray,"vertexnormals");
AddProperty(new HPArray,"xdata");
AddProperty(new HPAutoManual,"xdatamode");
AddProperty(new HPArray,"ydata");
AddProperty(new HPAutoManual,"ydatamode");
AddProperty(new HPArray,"zdata");
AddProperty(new HPOnOff,"visible");
}
void HandleSurface::SetupDefaults() {
HPVector *hp = (HPVector*) LookupProperty("alphadata");
std::vector<double> gp;
gp.push_back(1.0);
hp->Data(gp);
SetConstrainedStringDefault("alphadatamapping","none");
SetScalarDefault("ambientstrength",0.55);
SetConstrainedStringDefault("backfacelighting","unlit");
SetConstrainedStringDefault("cdatamapping","scaled");
SetConstrainedStringDefault("cdatamode","auto");
SetScalarDefault("diffusestrength",0.6);
SetScalarDefault("specularcolorreflectance",0.4);
SetScalarDefault("specularexponent",0.1);
SetScalarDefault("specularstrength",0.5);
SetStringDefault("type","image");
SetConstrainedStringDefault("visible","on");
SetConstrainedStringScalarDefault("edgealpha","scalar",1);
SetConstrainedStringColorDefault("edgecolor","colorspec",0,0,0);
SetConstrainedStringDefault("edgelighting","none");
SetConstrainedStringScalarDefault("facealpha","scalar",1);
SetConstrainedStringDefault("facecolor","flat");
SetConstrainedStringDefault("facelighting","none");
SetConstrainedStringDefault("linestyle","-");
SetScalarDefault("linewidth",0.5);
SetConstrainedStringDefault("marker","none");
SetConstrainedStringColorDefault("markeredgecolor","auto",0,0,0);
SetConstrainedStringColorDefault("markerfacecolor","none",0,0,0);
SetScalarDefault("markersize",6);
SetConstrainedStringDefault("meshstyle","both");
SetConstrainedStringDefault("normalmode","auto");
SetStringDefault("type","surface");
SetStringDefault("xdatamode","auto");
SetStringDefault("ydatamode","auto");
}
void HandleSurface::DoAutoXMode() {
Array zdata(ArrayPropertyLookup("zdata"));
Array xdata(Array::doubleMatrixConstructor(zdata.rows(),zdata.columns()));
double *dp = (double*) xdata.getReadWriteDataPointer();
int cols(zdata.columns());
int rows(zdata.rows());
for (int j=0;j<cols;j++)
for (int i=0;i<rows;i++)
dp[i+j*rows] = j+1;
HPArray *hp = (HPArray*) LookupProperty("xdata");
hp->Data(xdata);
}
void HandleSurface::DoAutoYMode() {
Array zdata(ArrayPropertyLookup("zdata"));
Array ydata(Array::doubleMatrixConstructor(zdata.rows(),zdata.columns()));
double *dp = (double*) ydata.getReadWriteDataPointer();
int cols(zdata.columns());
int rows(zdata.rows());
for (int j=0;j<cols;j++)
for (int i=0;i<rows;i++)
dp[i+j*rows] = i+1;
HPArray *hp = (HPArray*) LookupProperty("ydata");
hp->Data(ydata);
}
void HandleSurface::DoAutoCMode() {
Array zdata(ArrayPropertyLookup("zdata"));
HPArray *hp = (HPArray*) LookupProperty("cdata");
hp->Data(zdata);
}
void HandleSurface::UpdateState() {
if (HasChanged("xdata"))
ToManual("xdatamode");
if (HasChanged("ydata"))
ToManual("ydatamode");
if (HasChanged("cdata"))
ToManual("cdatamode");
if (IsAuto("xdatamode"))
DoAutoXMode();
if (IsAuto("ydatamode"))
DoAutoYMode();
if (IsAuto("cdatamode"))
DoAutoCMode();
HandleImage::UpdateCAlphaData();
}
/*
0
q1
1
q2
2
*/
Array HandleSurface::GetCoordinateMatrix(std::string name, bool isXcoord) {
// Get the elevation data from the object
Array zdata(ArrayPropertyLookup("zdata"));
int zrows(zdata.rows());
int zcols(zdata.columns());
if (StringCheck(name+"mode","manual")) {
// not auto mode...
Array cdata(ArrayPropertyLookup(name));
if (cdata.isVector() &&
((isXcoord && (cdata.getLength() == zcols)) ||
(!isXcoord && (cdata.getLength() == zrows)))) {
cdata.promoteType(FM_DOUBLE);
const double *qp = (const double*) cdata.getDataPointer();
Array mat(Array::doubleMatrixConstructor(zrows,zcols));
double *dp = (double*) mat.getReadWriteDataPointer();
for (int i=0;i<zcols;i++)
for (int j=0;j<zrows;j++) {
if (isXcoord)
*dp = qp[i];
else
*dp = qp[j];
dp++;
}
return mat;
} else if (cdata.is2D() && (cdata.rows() == zrows) &&
(cdata.columns() == zcols)) {
return cdata;
}
}
// In auto mode, or the given data is bogus...
Array mat(Array::doubleMatrixConstructor(zrows,zcols));
double *dp = (double*) mat.getReadWriteDataPointer();
for (int i=0;i<zcols;i++)
for (int j=0;j<zrows;j++) {
if (isXcoord)
*dp = i+1;
else
*dp = j+1;
dp++;
}
return mat;
}
std::vector<std::vector<cpoint> > HandleSurface::BuildQuadsNoTexMap(HPConstrainedStringColor* cp,
HPConstrainedStringScalar* ap) {
// Get the x,y,z & color data points
std::vector<std::vector<cpoint> > retval;
Array xdata(GetCoordinateMatrix("xdata",true));
xdata.promoteType(FM_DOUBLE);
Array ydata(GetCoordinateMatrix("ydata",false));
ydata.promoteType(FM_DOUBLE);
Array zdata(ArrayPropertyLookup("zdata"));
zdata.promoteType(FM_DOUBLE);
if ((xdata.getLength() != zdata.getLength()) ||
(xdata.getLength() != ydata.getLength())) return retval;
if (zdata.isEmpty()) return retval;
double *xdp = (double*) xdata.getDataPointer();
double *ydp = (double*) ydata.getDataPointer();
double *zdp = (double*) zdata.getDataPointer();
int rows = zdata.rows(); int cols = zdata.columns();
if (cp->Is("interp") && ((img.height() < rows) || (img.width() < cols))) return retval;
if (ap->Is("interp") && ((img.height() < rows) || (img.width() < cols))) return retval;
if (cp->Is("flat") && ((img.height() < rows-1) || (img.width() < cols-1))) return retval;
if (ap->Is("flat") && ((img.height() < rows-1) || (img.width() < cols-1))) return retval;
if (cp->Is("none")) return retval;
QRgb *dummyline;
if (cp->Is("colorspec") || ap->Is("scalar")) {
dummyline = new QRgb[cols];
double r = 0;
double g = 0;
double b = 0;
double alphaval = 1.0;
if (ap->Is("scalar"))
alphaval = ap->Scalar();
if (cp->Is("colorspec")) {
std::vector<double> p(cp->ColorSpec());
if (p[0] == -1) return retval;
r = p[0]; g = p[1]; b = p[2];
}
for (int i=0;i<cols;i++)
dummyline[i] = qRgba((int)(255*r),
(int)(255*g),
(int)(255*b),
(int)(255*alphaval));
}
for (int i=0;i<rows-1;i++) {
QRgb *cbits1, *cbits2, *abits1, *abits2;
int col_lim, alp_lim;
if (cp->Is("interp")) {
cbits1 = (QRgb*) img.scanLine(i);
cbits2 = (QRgb*) img.scanLine(i+1);
col_lim = cols-1;
} else if (cp->Is("flat")) {
cbits1 = (QRgb*) img.scanLine(i);
cbits2 = (QRgb*) img.scanLine(i);
col_lim = cols-2;
} else if (cp->Is("colorspec")) {
cbits1 = (QRgb*) dummyline;
cbits2 = (QRgb*) dummyline;
col_lim = cols-1;
}
if (ap->Is("interp")) {
abits1 = (QRgb*) img.scanLine(i);
abits2 = (QRgb*) img.scanLine(i+1);
alp_lim = cols-1;
} else if (ap->Is("flat")) {
abits1 = (QRgb*) img.scanLine(i);
abits2 = (QRgb*) img.scanLine(i);
alp_lim = cols-2;
} else if (ap->Is("scalar")) {
abits1 = (QRgb*) dummyline;
abits2 = (QRgb*) dummyline;
alp_lim = cols-1;
}
std::vector<cpoint> linequads;
for (int j=0;j<cols;j++) {
int ccol = qMin(j,col_lim);
int acol = qMin(j,alp_lim);
linequads.push_back(cpoint(xdp[i+j*rows],ydp[i+j*rows],zdp[i+j*rows],
qRed(cbits1[ccol])/255.0,qGreen(cbits1[ccol])/255.0,
qBlue(cbits1[ccol])/255.0,qAlpha(abits1[acol])/255.0));
linequads.push_back(cpoint(xdp[i+1+j*rows],ydp[i+1+j*rows],
zdp[i+1+j*rows],qRed(cbits2[ccol])/255.0,
qGreen(cbits2[ccol])/255.0,qBlue(cbits2[ccol])/255.0,
qAlpha(abits2[acol])/255.0));
}
retval.push_back(linequads);
}
// 0
// 1
// 2
// qDebug("retval size is %d",retval.size());
if (cp->Is("colorspec") || ap->Is("scalar"))
delete[] dummyline;
return retval;
}
void HandleSurface::PaintMe(RenderEngine& gc) {
UpdateState();
if (StringCheck("visible","off"))
return;
// Get the x,y,z & color data points
Array xdata(ArrayPropertyLookup("xdata"));
xdata.promoteType(FM_DOUBLE);
Array ydata(ArrayPropertyLookup("ydata"));
ydata.promoteType(FM_DOUBLE);
Array zdata(ArrayPropertyLookup("zdata"));
zdata.promoteType(FM_DOUBLE);
if (zdata.isEmpty()) return;
double *xdp = (double*) xdata.getDataPointer();
double *ydp = (double*) ydata.getDataPointer();
double *zdp = (double*) zdata.getDataPointer();
int rows = zdata.rows(); int cols = zdata.columns();
// There are many render styles...
// edgealpha, edgecolor, facealpha, facecolor
// facecolor
// Texture mapping not supported yet
if (StringCheck("facecolor","texturemap")) return;
if (StringCheck("facealpha","texturemap")) return;
// A quadstrip is defined by its
std::vector<std::vector<cpoint> > surfquads(BuildQuadsNoTexMap((HPConstrainedStringColor*)
LookupProperty("facecolor"),
(HPConstrainedStringScalar*)
LookupProperty("facealpha")));
std::vector<std::vector<cpoint> > edgequads(BuildQuadsNoTexMap((HPConstrainedStringColor*)
LookupProperty("edgecolor"),
(HPConstrainedStringScalar*)
LookupProperty("edgealpha")));
gc.quadStrips(surfquads,StringCheck("facecolor","flat"),
edgequads,StringCheck("edgecolor","flat"));
#if 0
HPAutoFlatColor *ec = (HPAutoFlatColor*) LookupProperty("markeredgecolor");
HPAutoFlatColor *fc = (HPAutoFlatColor*) LookupProperty("markerfacecolor");
std::vector<double> edgecolor;
std::vector<double> facecolor;
if (ec->Is("colorspec"))
edgecolor = ec->ColorSpec();
else
edgecolor.push_back(-1);
if (fc->Is("colorspec"))
facecolor = fc->ColorSpec();
else
facecolor.push_back(-1);
RenderEngine::SymbolType typ = StringToSymbol(StringPropertyLookup("marker"));
double sze = ScalarPropertyLookup("markersize")/2.0;
// Make sure there's something to draw...
if ((typ != RenderEngine::None) || (edgecolor[0] != -1) || (facecolor[0] != -1)) {
// Calculate the u/v coordinates (pixels)
std::vector<double> uc;
std::vector<double> vc;
std::vector<double> zc;
for (int i=0;i<rows*cols;i++) {
double u, v;
bool clipped;
gc.toPixels(xdp[i],ydp[i],zdp[i],u,v,clipped);
if (!clipped) {
uc.push_back(u); vc.push_back(v); zc.push_back(zdp[i]);
}
}
// gc.setupDirectDraw();
// gc.depth(true);
// for (int i=0;i<uc.size();i++)
// DrawSymbol(gc,typ,uc[i],vc[i],zc[i],sze,edgecolor,facecolor,width);
// for (int i=0;i<uc.size();i++)
// DrawSymbol(gc,typ,xdp[i],ydp[i],zdp[i],sze,edgecolor,facecolor,width);
// gc.releaseDirectDraw();
}
// glColor3f(0,0,0);
// glBegin(GL_LINE_LOOP);
// for (int j=0;j<cols-1;j++) {
// glVertex3f(xdp[i+j*rows],ydp[i+j*rows],zdp[i+j*rows]);
// glVertex3f(xdp[i+1+j*rows],ydp[i+1+j*rows],zdp[i+1+j*rows]);
// glVertex3f(xdp[i+1+(j+1)*rows],ydp[i+1+(j+1)*rows],
// zdp[i+1+(j+1)*rows]);
// glVertex3f(xdp[i+(j+1)*rows],ydp[i+(j+1)*rows],zdp[i+(j+1)*rows]);
// }
// glEnd();
// }
#endif
}
syntax highlighted by Code2HTML, v. 0.9.1