diff options
| author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-07-11 14:15:27 -0500 | 
|---|---|---|
| committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-07-11 14:15:27 -0500 | 
| commit | b85a292ce06475d560bfa1195b63a8bfe211f22d (patch) | |
| tree | 463d71be55ff807513139f1de106aef6bdd7b4db /lib/tqwtplot3d/src | |
| parent | ce039289815e2802fdeca8d384126c807ca9cb58 (diff) | |
| download | ulab-b85a292ce06475d560bfa1195b63a8bfe211f22d.tar.gz ulab-b85a292ce06475d560bfa1195b63a8bfe211f22d.zip | |
Add 0.2.7 release of qwtplot3d for future TQt3 conversion and use
Diffstat (limited to 'lib/tqwtplot3d/src')
24 files changed, 6329 insertions, 0 deletions
| diff --git a/lib/tqwtplot3d/src/qwt3d_autoscaler.cpp b/lib/tqwtplot3d/src/qwt3d_autoscaler.cpp new file mode 100644 index 0000000..6e785cf --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_autoscaler.cpp @@ -0,0 +1,253 @@ +#include "qwt3d_helper.h" 
 +#include "qwt3d_autoscaler.h" 
 +
 +using namespace Qwt3D;
 +
 +namespace
 +{
 +
 +double floorExt( int& exponent, double x, std::vector<double>& sortedmantissi)
 +{
 +    if (x == 0.0) 
 +    {
 +			exponent = 0;
 +			return 0.0;
 +		}
 +    
 +    double sign = (x > 0) ? 1.0 : -1.0;
 +    double lx = log10(fabs(x));
 +    exponent = (int)floor(lx);
 +
 +    double fr = pow(10.0, lx - exponent);
 +    if (fr >= 10.0)
 +		{
 +			fr = 1.0;
 +			++exponent;
 +    }
 +		else
 +    {
 +      for (int i=(int)sortedmantissi.size()-1; i>=0;--i)
 +      {
 +        if (fr>=sortedmantissi[i])
 +        {   
 +          fr = sortedmantissi[i];
 +          break;
 +        }
 +      }
 +    }
 +    return sign * fr;
 +} 
 +
 +/*
 +  \brief Find the largest value out of {1,2,5}*10^n with an integer number n
 +  which is smaller than or equal to x
 +  \param exponent n
 +  \param x Input value
 +  \return Mantissa
 +*/
 +double floor125( int& exponent, double x)
 +{
 +  std::vector<double> m(2);
 +  m[0] = 1;
 +  m[1] = 2;
 +  m[2] = 5;
 +  return floorExt(exponent, x, m);
 +}
 +
 +} // anon ns
 +
 +
 +//! Initializes with an {1,2,5} sequence of mantissas
 +LinearAutoScaler::LinearAutoScaler()
 +{
 +  init(0,1,1);
 +  mantissi_ = std::vector<double>(3);
 +  mantissi_[0] = 1;
 +  mantissi_[1] = 2;
 +  mantissi_[2] = 5;
 +}
 +//! Initialize with interval [0,1] and one requested interval 
 +/*!
 +val mantisse A increasing ordered vector of values representing 
 +mantisse values between 1 and 9. 
 +*/
 +LinearAutoScaler::LinearAutoScaler(std::vector<double>& mantisse)
 +{
 +  init(0,1,1);
 +  if (mantisse.empty())
 +  {
 +    mantissi_ = std::vector<double>(3);
 +    mantissi_[0] = 1;
 +    mantissi_[1] = 2;
 +    mantissi_[2] = 5;
 +    return;
 +  }
 +  mantissi_ = mantisse;
 +}
 +
 +
 +//! Initialize with interval [start,stop] and number of requested intervals
 +/**
 +	Switchs start and stop, if stop < start and sets intervals = 1 if ivals < 1
 +*/
 +void LinearAutoScaler::init(double start, double stop, int ivals)
 +{
 +	start_ = start;
 +	stop_ = stop;
 +	intervals_ = ivals;
 +
 +	if (start_ > stop_)
 +	{
 +		double tmp = start_;
 +		start_ = stop_;
 +		stop_ = tmp;
 +	}
 +	if (intervals_ < 1)
 +		intervals_ = 1;
 +}
 +
 +/*!
 +\return Anchor value
 +
 +\verbatim
 +|_______|____________ _ _ _ _  _____|_____________|________________
 +
 +0     m*10^n                      start         anchor := c*m*10^n	     
 +	 
 +c 'minimal' (anchor-start < m*10^n)
 +\endverbatim
 +*/
 +double LinearAutoScaler::anchorvalue(double start, double m, int n)
 +{
 +	double stepval = m * pow(10.0, n);
 +	return  stepval * ceil(start / stepval);
 +}
 +
 +/*!
 +\return New number of intervals (:= l_intervals + r_intervals)
 +\param l_intervals  Number of intervals left from anchor
 +\param r_intervals  Number of intervals right from anchor
 +
 +\verbatim
 +                          -l_intervals * i    -2 * i    -i                 +r_intervals * i
 +                                                                                   |
 +|______|_______ _ _ _ ____|____|___ _ _ _ _ _ _ _|_______|_______|_ _ _ _ _ _ _____|__|_____
 +       |                  |                                      |                    | 
 +0   i := m*10^n         start                                  anchor	              stop
 +	 
 +c 'minimal' (anchor-start < m*10^n)
 +\endverbatim
 +*/
 +int LinearAutoScaler::segments(int& l_intervals, int& r_intervals, double start, double stop, double anchor, double m, int n)
 +{
 +	double val =  m * pow(10.0, n);
 +	double delta = (stop - anchor) / val;
 +	
 +	r_intervals = (int)floor(delta); // right side intervals
 +	
 +	delta = (anchor - start) / val;
 +
 +	l_intervals = (int)floor(delta); // left side intervals
 +
 +	return r_intervals + l_intervals; 
 +}
 +
 +
 +/*!
 +	\brief Does the actual scaling
 +	\return Number of intervals after rescaling. This will in the most cases differ 
 +	from the requested interval number!  Always >0.
 +	\param a Start value after scaling (always >= start)
 +	\param b Stop value after scaling  (always <= stop)
 +  \param start Start value
 +  \param stop Stop value
 +  \param ivals Requested intervals
 +  \return Number of intervals after autoscaling
 +
 +	If the given interval has zero length the function returns the current 
 +	interval number and a and b remain unchanged.
 +*/
 +int LinearAutoScaler::execute(double& a, double& b, double start, double stop, int ivals)
 +{
 +  init(start,stop,ivals);
 +  
 +  double delta = stop_ - start_;
 +
 +	if (isPracticallyZero(delta))
 +		return intervals_;
 +
 +	double c; 
 +	int n;
 +
 +	c = floorExt(n, delta, mantissi_);
 +	
 +	int l_ival, r_ival;
 +
 +	double anchor = anchorvalue(start_, c, n); 
 +	int ival = segments(l_ival, r_ival, start_, stop_, anchor, c, n); 
 +
 +	if (ival >= intervals_)
 +	{
 +		a = anchor - l_ival * c * pow(10.0,n);
 +		b = anchor + r_ival * c * pow(10.0,n);
 +		intervals_ = ival;
 +		return intervals_;
 +	}
 +	
 +	int prev_ival, prev_l_ival, prev_r_ival;
 +	double prev_anchor; 
 +	double prev_c;
 +	int prev_n;
 +
 +	while(1)
 +	{
 +		prev_c = c;
 +		prev_n = n;
 +		prev_anchor = anchor;
 +		prev_ival = ival;
 +		prev_l_ival = l_ival;
 +		prev_r_ival = r_ival;
 +	
 +		
 +    if (int(c) == 1)
 +		{
 +			c = mantissi_.back();
 +			--n;
 +		}
 +    else
 +    {
 +      for (unsigned int i=mantissi_.size()-1; i>0; --i)
 +      {
 +        if (int(c) == mantissi_[i])
 +        {
 +          c = mantissi_[i-1];
 +          break;
 +        }
 +      }
 +    }
 +
 +    anchor = anchorvalue(start_, c, n); 
 +		ival = segments(l_ival, r_ival, start_, stop_, anchor, c, n); 		
 +
 +		int prev_diff = intervals_ - prev_ival;
 +		int actual_diff = ival - intervals_;
 +		
 +		if (prev_diff >= 0 && actual_diff >= 0) 
 +		{
 +			if (prev_diff < actual_diff)
 +			{
 +				c = prev_c;
 +				n = prev_n;
 +				anchor = prev_anchor;
 +				ival = prev_ival;
 +				l_ival = prev_l_ival;
 +				r_ival = prev_r_ival;
 +			}
 +			a = anchor - l_ival * c * pow(10.0,n);
 +			b = anchor + r_ival * c * pow(10.0,n);
 +			intervals_ = ival;
 +			break;
 +		}
 +	}
 +	return intervals_;
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_axis.cpp b/lib/tqwtplot3d/src/qwt3d_axis.cpp new file mode 100644 index 0000000..fe45f37 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_axis.cpp @@ -0,0 +1,386 @@ +#include "qwt3d_axis.h"
 +
 +using namespace Qwt3D;
 +
 +Axis::Axis()
 +{
 +  init();
 +};
 +
 +Axis::~Axis()
 +{
 +}
 +
 +Axis::Axis(Triple beg, Triple end)
 +{
 + 	init();
 +	setPosition(beg,end);
 +}
 +
 +void Axis::init()
 +{
 +	detachAll();
 +
 +  scale_ = qwt3d_ptr<Scale>(new LinearScale);
 +
 +  beg_ = Triple(0.0, 0.0, 0.0);  
 +  end_ = beg_;
 +	
 +	majorintervals_ = 0;
 +	minorintervals_ = 0;
 +	setMajors(1);	
 +	setMinors(1);	
 +	setLimits(0,0);
 +
 +	setTicOrientation(0.0, 0.0, 0.0);
 +	setTicLength(0.0, 0.0);
 +	setColor(0.0, 0.0, 0.0);
 +	setLineWidth(1.0);
 +	symtics_ = false;
 +	drawNumbers_ = false;
 +	drawLabel_ = false;
 +
 +	drawTics_ = false;
 +	autoscale_ = true;
 +	markerLabel_.clear();
 +	numberfont_ = QFont("Courier",12);
 +	setLabelFont(QFont("Courier",14));
 +
 +  numbercolor_ = RGBA(0,0,0,0);
 +
 +	setNumberAnchor(Center);
 +
 +	numbergap_ = 0;
 +	labelgap_ = 0;
 +}
 +
 +void Axis::setPosition(const Triple& beg, const Triple& end)
 +{
 +	beg_ = beg;
 +	end_ = end;
 +}
 +
 +void Axis::setMajors(int val)
 +{
 +	if (val == majorintervals_)
 +		return;
 +	
 +	majorintervals_ = (val<=0) ? 1 : val; // always >= 1
 +}
 +
 +/*!
 +\see LogScale::setMinors().
 +*/
 +void Axis::setMinors(int val)
 +{
 +	if (val == minorintervals_)
 +		return;
 +
 +	minorintervals_ = (val<=0) ? 1 : val; // always >= 1
 +}
 +
 +void Axis::setTicLength(double majorl, double minorl)
 +{
 +	lmaj_ = majorl;
 +	lmin_ = minorl;
 +}
 +
 +void Axis::setTicOrientation(double tx, double ty, double tz)
 +{
 +	setTicOrientation(Triple(tx,ty,tz));
 +}
 +
 +void Axis::setTicOrientation(const Triple& val)
 +{
 +	orientation_ = val;
 +	orientation_.normalize();
 +}
 +
 +/**
 +\param val thickness for axis base line
 +\param majfac relative thickness for axis major tics (majfac*val)
 +\param minfac relative thickness for axis minor tics (minfac*val)
 +*/
 +void Axis::setLineWidth(double val, double majfac, double minfac)
 +{
 +	lineWidth_ = val;
 +	majLineWidth_ = majfac * lineWidth_;
 +	minLineWidth_ = minfac * lineWidth_;
 +}
 +
 +void Axis::draw()
 +{
 +	Drawable::draw();
 +
 +	saveGLState();
 +
 +//	GLStateBewarer sb(GL_LINE_SMOOTH, true);
 +//	glBlendFunc(GL_ONE, GL_ZERO);
 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +	glColor4d(color.r,color.g,color.b,color.a);		
 +
 +	drawBase();
 +	drawTics();
 +	drawLabel();	
 +
 +	restoreGLState();
 +}
 +
 +/**
 +Always use AFTER drawNumbers() ! (Needs length of number string)
 +*/
 +void Axis::drawLabel()
 +{
 +	if (!drawLabel_)
 +		return;
 +
 +  Triple diff = end() - begin();
 +	Triple center = begin() + diff/2;
 +	
 +	Triple bnumber = biggestNumberString(); 
 +//	double fac = 6*(second()-first()).length() / 100;
 +	
 +	switch (scaleNumberAnchor_) 
 +	{
 +		case BottomLeft:
 +		case TopLeft:
 +		case CenterLeft:
 +			bnumber.y = 0;
 +			break;
 +		case BottomRight:
 +		case TopRight:
 +		case CenterRight:
 +			bnumber.x = -bnumber.x;
 +			bnumber.y = 0;
 +			break;
 +		case TopCenter:
 +			bnumber.x = 0;
 +			bnumber.y = -bnumber.y;
 +			break;
 +		case BottomCenter:
 +			bnumber.x = 0;
 +			break;
 +		default:
 +			break;
 +	}
 +	
 +	Triple pos = ViewPort2World(World2ViewPort(center + ticOrientation() * lmaj_) + bnumber);
 +	setLabelPosition(pos, scaleNumberAnchor_);
 +
 +	label_.adjust(labelgap_);
 +	label_.draw();
 +}
 +
 +void Axis::drawBase()
 +{
 +	setDeviceLineWidth( lineWidth_ );
 +	glBegin( GL_LINES );
 +		glVertex3d( beg_.x, beg_.y, beg_.z); 
 +		glVertex3d( end_.x, end_.y, end_.z);
 +	glEnd();
 +}	
 +
 +bool Axis::prepTicCalculation(Triple& startpoint)
 +{
 +  if (isPracticallyZero(start_, stop_))
 +		return false;
 +
 +	autostart_ = start_;
 +	autostop_ = stop_;
 +
 + 	if (autoScale()) 
 +  {  
 +    setMajors(scale_->autoscale(autostart_, autostop_, start_, stop_, majors()));
 +    if (isPracticallyZero(autostart_, autostop_))
 +		  return false;
 +  }
 +  
 +  scale_->setLimits(start_,stop_);
 +  scale_->setMajors(majors());
 +  scale_->setMinors(minors());
 +  scale_->setMajorLimits(autostart_,autostop_);
 +  scale_->calculate();
 +
 +	Triple normal = (end_ - beg_);
 +	//normal.normalize();
 +	Triple beg = beg_ + ((autostart_ - start_) / (stop_ - start_)) * normal;
 +	Triple end = end_ - ((stop_ - autostop_) / (stop_ - start_))* normal;
 +
 +	startpoint = end_ - beg_;
 +
 +	majorpos_.clear();
 +	minorpos_.clear();
 +
 +  return true;
 +}
 +
 +void Axis::recalculateTics()
 +{
 +  Triple runningpoint;
 +  if (false==prepTicCalculation(runningpoint))
 +    return;
 +
 +	unsigned int i;
 +	
 +	for (i = 0; i != scale_->majors_p.size(); ++i) 
 +	{
 +		double t = (scale_->majors_p[i] - start_) / (stop_-start_);
 +		majorpos_.push_back(beg_ + t * runningpoint);
 +	}
 +	for (i = 0; i != scale_->minors_p.size(); ++i) 
 +	{
 +		double t = (scale_->minors_p[i] - start_) / (stop_-start_);
 +		minorpos_.push_back(beg_ + t * runningpoint);
 +	}
 +}
 +
 +void Axis::drawTics()
 +{
 +	Triple runningpoint;
 +  if (!drawTics_ || false==prepTicCalculation(runningpoint))
 +		return;
 +  
 +	unsigned int i;
 +  Triple nadir;
 +	
 +  markerLabel_.resize(scale_->majors_p.size());
 +	setDeviceLineWidth(majLineWidth_);
 +	for (i = 0; i != scale_->majors_p.size(); ++i) 
 +	{
 +		double t = (scale_->majors_p[i] - start_) / (stop_-start_);
 +    nadir = beg_ + t * runningpoint;
 +    majorpos_.push_back(drawTic(nadir, lmaj_));
 +		drawTicLabel(nadir + 1.2 * lmaj_ * orientation_, i);
 +  }
 +	setDeviceLineWidth(minLineWidth_);
 +	for (i = 0; i != scale_->minors_p.size(); ++i) 
 +	{
 +		double t = (scale_->minors_p[i] - start_) / (stop_-start_);
 +		nadir = beg_ + t * runningpoint;
 +    minorpos_.push_back(drawTic(nadir, lmin_));
 +  }
 +}
 +
 +void Axis::drawTicLabel(Triple pos, int mtic)
 +{
 +	if (!drawNumbers_ || (mtic < 0))
 +		return;
 +	
 +	markerLabel_[mtic].setFont(numberfont_.family(), numberfont_.pointSize(), numberfont_.weight(), numberfont_.italic());
 +	markerLabel_[mtic].setColor(numbercolor_);
 +  markerLabel_[mtic].setString(scale_->ticLabel(mtic));	  
 +  markerLabel_[mtic].setPosition(pos, scaleNumberAnchor_);
 +	markerLabel_[mtic].adjust(numbergap_);
 +	markerLabel_[mtic].draw();
 +}
 +
 +Triple Axis::drawTic(Triple nadir, double length)
 +{
 +	double ilength = (symtics_) ? -length : 0.0;
 +
 +	glBegin( GL_LINES );
 +	glVertex3d( nadir.x  + ilength * orientation_.x,
 +				      nadir.y  + ilength * orientation_.y,
 +							nadir.z  + ilength * orientation_.z) ; 
 +	glVertex3d( nadir.x  + length * orientation_.x,
 +							nadir.y  + length * orientation_.y,
 +							nadir.z  + length * orientation_.z);
 +	glEnd();
 +	return nadir;
 +}
 +
 +void Axis::setNumberFont(QString const& family, int pointSize, int weight, bool italic)
 +{
 +	numberfont_ = QFont(family, pointSize, weight, italic );
 +}
 +
 +void Axis::setNumberFont(QFont const& font)
 +{
 +	numberfont_ = font;
 +}
 +
 +void Axis::setNumberColor(RGBA col)
 +{
 +	numbercolor_ = col;
 +}
 +
 +void Axis::setLabelFont(QString const& family, int pointSize, int weight, bool italic)
 +{
 +	labelfont_ = QFont(family, pointSize, weight, italic );
 +  label_.setFont(family, pointSize, weight, italic);
 +}
 +
 +void Axis::setLabelFont(QFont const& font)
 +{
 +	setLabelFont(font.family(), font.pointSize(), font.weight(), font.italic());
 +}
 +
 +void Axis::setLabelString(QString const& name)
 +{
 +	label_.setString(name);
 +}
 +
 +/*!
 +  Sets label position in conjunction with an anchoring strategy
 +*/
 +void Axis::setLabelPosition(const Triple& pos,Qwt3D::ANCHOR an)
 +{
 +	label_.setPosition(pos, an);
 +}
 +
 +//! Sets color for label
 +void Axis::setLabelColor(RGBA col)
 +{
 +	label_.setColor(col);
 +}
 +
 +Triple Axis::biggestNumberString()
 +{
 +	Triple ret;
 +	unsigned size = markerLabel_.size();
 +
 +	double width, height;
 +
 +	for (unsigned i=0; i!=size; ++i)
 +	{
 +		width = fabs( (World2ViewPort(markerLabel_[i].second())-World2ViewPort(markerLabel_[i].first())).x );
 +		height = fabs( (World2ViewPort(markerLabel_[i].second())-World2ViewPort(markerLabel_[i].first())).y );
 +
 +		if (width > ret.x)
 +			ret.x = width + markerLabel_[i].gap();
 +		if (height > ret.y)
 +			ret.y = height + markerLabel_[i].gap();;
 +	}
 +	return ret;
 +}
 +
 +/*! 
 +  This variant sets a user-defined scale object.
 +  Use with a heap based initialized pointer only.
 +  The axis adopts ownership. 
 +*/
 +void Axis::setScale(Scale* val)
 +{
 +  scale_ = qwt3d_ptr<Scale>(val); 
 +}
 +
 +/*!
 +  Sets one of the predefined scaling types.
 +  \warning Too small intervals in logarithmic scales lead to  
 +  empty scales (or perhaps a scale only containing an isolated 
 +  major tic). Better switch to linear scales in such cases.
 +*/
 +void Axis::setScale(Qwt3D::SCALETYPE val)
 +{
 +  switch(val) {
 +  case Qwt3D::LINEARSCALE:
 +    setScale(new LinearScale);
 +  	break;
 +  case Qwt3D::LOG10SCALE:
 +    setScale(new LogScale);
 +    setMinors(9);
 +  	break;
 +  default:
 +    break;
 +  }
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_color.cpp b/lib/tqwtplot3d/src/qwt3d_color.cpp new file mode 100644 index 0000000..5543a8a --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_color.cpp @@ -0,0 +1,63 @@ +#include "qwt3d_color.h"
 +#include "qwt3d_plot.h"
 +
 +using namespace Qwt3D;
 +
 +StandardColor::StandardColor(Plot3D* data, unsigned size)
 +			: data_(data)
 +{
 +	Q_ASSERT(data_);
 +	
 +	reset(size);
 +}
 +
 +void StandardColor::reset(unsigned size)
 +{
 +	colors_ = ColorVector(size);
 +	RGBA elem;
 +
 +	double dsize = size;
 +	
 +	for (unsigned int i=0; i!=size; ++i)
 +	{
 +		elem.r = i / dsize;
 +		elem.g = i / dsize / 4;
 +		elem.b = 1 - i/dsize;
 +		elem.a = 1.0;
 +		colors_[i] = elem;
 +	}
 +}
 +
 +/**
 +	Assigns a new ColorVector (Also overwrites the constructors size argument)
 +*/
 +void StandardColor::setColorVector(ColorVector const& cv)
 +{
 +	colors_ = cv;
 +}
 +
 +void StandardColor::setAlpha(double a)
 +{
 +	if (a<0 || a>1)
 +		return;
 +	
 +	RGBA elem;
 +
 +	for (unsigned int i=0; i!=colors_.size(); ++i)
 +	{
 +		elem = colors_[i];
 +		elem.a = a;
 +		colors_[i] = elem;
 +	}	
 +}	
 +
 +RGBA StandardColor::operator()(double, double, double z) const
 +{
 +	Q_ASSERT(data_);
 +	int index = (int)((colors_.size()-1) * (z - data_->hull().minVertex.z) / (data_->hull().maxVertex.z-data_->hull().minVertex.z));
 +	if (index < 0)
 +		index = 0;
 +	if ((unsigned int)index > colors_.size() - 1)
 +		index = (int)(colors_.size() - 1);
 +	return colors_[index];
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_colorlegend.cpp b/lib/tqwtplot3d/src/qwt3d_colorlegend.cpp new file mode 100644 index 0000000..2b114aa --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_colorlegend.cpp @@ -0,0 +1,223 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4305 )
 +#endif
 +
 +#include "qwt3d_colorlegend.h"
 +
 +using namespace Qwt3D;
 +
 +/**
 +Contructs a legend object with an axis at the left
 +side. The legend resides in the top-right area 
 +and has no caption. Scale numbering is shown.
 +*/
 +ColorLegend::ColorLegend()
 +{
 +	axis_.setNumbers(true);
 +	axis_.setScaling(true);
 +	axis_.setNumberColor(RGBA(0,0,0,1));
 +	axis_.setNumberAnchor(CenterRight);
 +	axis_.setNumberFont(QFont("Courier",8));
 +
 +	caption_.setFont("Courier", 10, QFont::Bold);
 +	caption_.setColor(RGBA(0,0,0,1));
 +	axisposition_ = ColorLegend::Left;
 +	orientation_ = ColorLegend::BottomTop;
 +	showaxis_ = true;
 +	setRelPosition(Tuple(0.94, 1-0.36),Tuple(0.97, 1-0.04));
 +}
 +
 +void ColorLegend::setTitleString(QString const& s) 
 +{ 
 +	caption_.setString(s); 
 +}
 +
 +void ColorLegend::setTitleFont(QString const& family, int pointSize, int weight, bool italic) 
 +{ 
 +	caption_.setFont(family, pointSize, weight, italic);
 +}
 +
 +void ColorLegend::setLimits(double start, double stop)
 +{
 +	axis_.setLimits(start, stop);
 +}
 +
 +void ColorLegend::setMajors(int majors)
 +{
 +	axis_.setMajors(majors);
 +}
 +
 +void ColorLegend::setMinors(int minors)
 +{
 +	axis_.setMinors(minors);
 +}
 +
 +void ColorLegend::setAutoScale(bool val)
 +{
 +	axis_.setAutoScale(val);
 +}
 +
 +void ColorLegend::setScale(SCALETYPE val)
 +{
 +	axis_.setScale(val);
 +}
 +
 +void ColorLegend::setScale(Scale* val)
 +{
 +	axis_.setScale(val);
 +}
 +
 +
 +void ColorLegend::setOrientation(ORIENTATION orientation, SCALEPOSITION pos)
 +{
 +	orientation_ = orientation;
 +	axisposition_ = pos;
 +
 +	if (orientation_==BottomTop)
 +	{
 +		if (axisposition_ == Bottom || axisposition_ == Top)
 +			axisposition_ = Left;
 +	}
 +	else
 +	{
 +		if (axisposition_ == Left || axisposition_ == Right)
 +			axisposition_ = Bottom;
 +	}
 +}
 +
 +void ColorLegend::setRelPosition(Tuple relMin, Tuple relMax)
 +{
 +	relMin_ = relMin;
 +	relMax_ = relMax;
 +}
 +
 +void ColorLegend::setGeometryInternal()
 +{
 +	double ot = .99;
 +
 +	getMatrices(modelMatrix, projMatrix, viewport);
 +	pe_.minVertex = relativePosition(Triple(relMin_.x, relMin_.y, ot));
 +	pe_.maxVertex = relativePosition(Triple(relMax_.x, relMax_.y, ot));
 +
 +	double diff = 0;
 +	Triple b;
 +	Triple e;
 +
 +	switch (axisposition_) 
 +	{
 +	case ColorLegend::Left:
 +		b = pe_.minVertex;
 +		e = pe_.maxVertex; e.x = b.x;
 +		axis_.setTicOrientation(-1,0,0);
 +		axis_.setNumberAnchor(CenterRight);
 +		diff = pe_.maxVertex.x - pe_.minVertex.x;
 +		break;
 +	case ColorLegend::Right:
 +		e = pe_.maxVertex;
 +		b = pe_.minVertex; b.x = e.x; 
 +		axis_.setTicOrientation(+1,0,0);
 +		axis_.setNumberAnchor(CenterLeft);
 +		diff = pe_.maxVertex.x - pe_.minVertex.x;
 +		break;
 +	case ColorLegend::Top:
 +		e = pe_.maxVertex;
 +		b = pe_.minVertex; b.z = e.z; 
 +		axis_.setTicOrientation(0,0,+1);
 +		axis_.setNumberAnchor(BottomCenter);
 +		diff = pe_.maxVertex.z - pe_.minVertex.z;
 +		break;
 +	case ColorLegend::Bottom:
 +		b = pe_.minVertex;
 +		e = pe_.maxVertex; e.z = b.z;
 +		axis_.setTicOrientation(0,0,-1);
 +		axis_.setNumberAnchor(TopCenter);
 +		diff = pe_.maxVertex.z - pe_.minVertex.z;
 +		break;
 +	default:
 +		break;
 +	}
 +	
 +	axis_.setPosition(b,e);
 +	diff /= 10;
 +	
 +	axis_.setTicLength(diff, 0.6*diff);
 +
 +	Triple c;
 +	c.x = pe_.minVertex.x + ((pe_.maxVertex-pe_.minVertex) / 2).x;
 +	c.z = pe_.maxVertex.z;
 +	c.z += (pe_.maxVertex.z-pe_.minVertex.z)/20;
 +	c.y = pe_.maxVertex.y;
 +
 +	caption_.setPosition(c, BottomCenter);	
 +}
 +
 +void ColorLegend::draw()
 +{
 +	if (colors.empty())
 +		return;
 +
 +	setGeometryInternal();
 +
 +	saveGLState();
 +  	
 +	Triple one = pe_.minVertex;
 +	Triple two = pe_.maxVertex; 
 +	
 +	double h = (orientation_ == ColorLegend::BottomTop)
 +	         ? (two-one).z / colors.size()
 +					 : (two-one).x / colors.size(); 
 +
 +	//glEnable(GL_DEPTH_TEST);
 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +	GLStateBewarer(GL_POLYGON_OFFSET_FILL,true);
 +//	glPolygonOffset(0.0, 0.0);
 +
 +	glColor4d(0, 0, 0, 1);
 +	glBegin(GL_LINE_LOOP);
 +		glVertex3d(one.x, one.y, one.z);
 +		glVertex3d(one.x, one.y, two.z);
 +		glVertex3d(two.x, one.y, two.z);
 +		glVertex3d(two.x, one.y, one.z);
 +	glEnd();
 +
 +
 +	unsigned size = colors.size();
 +	RGBA rgb;
 +	
 +	if (orientation_ == ColorLegend::BottomTop)
 +	{
 +		for (unsigned i=1; i<=size; ++i) 
 +		{
 +			rgb = colors[i-1];
 +			glColor4d(rgb.r,rgb.g,rgb.b,rgb.a);
 +	 		glBegin( GL_POLYGON );
 +				glVertex3d( one.x, one.y, one.z+(i-1)*h );
 +				glVertex3d( one.x, one.y, one.z+i*h );
 +				glVertex3d( two.x, one.y, one.z+i*h );
 +				glVertex3d( two.x, one.y, one.z+(i-1)*h );
 +			glEnd();
 +		}
 +	}
 +	else
 +	{
 +		for (unsigned i=1; i<=size; ++i) 
 +		{
 +			rgb = colors[i-1];
 +			glColor4d(rgb.r,rgb.g,rgb.b,rgb.a);
 +	 		glBegin( GL_POLYGON );
 +				glVertex3d( one.x+(i-1)*h, one.y, one.z );
 +				glVertex3d( one.x+i*h, one.y, one.z );
 +				glVertex3d( one.x+i*h, one.y, two.z );
 +				glVertex3d( one.x+(i-1)*h, one.y, two.z );
 +			glEnd();
 +		}
 +	}
 +			
 +	restoreGLState();
 +	
 +	if (showaxis_)
 +		axis_.draw();
 +	
 +	caption_.draw();
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_coordsys.cpp b/lib/tqwtplot3d/src/qwt3d_coordsys.cpp new file mode 100644 index 0000000..2aae28d --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_coordsys.cpp @@ -0,0 +1,633 @@ +#include "qwt3d_coordsys.h"
 +
 +using namespace std;
 +using namespace Qwt3D;
 +
 +
 +CoordinateSystem::CoordinateSystem(Triple first, Triple second, COORDSTYLE st)
 +{
 +	autodecoration_ = true;
 +	axes = std::vector<Axis>(12);
 +  setStyle(st);
 +	setLineSmooth(true);
 +	init(first,second);
 +
 +	setAxesColor(RGBA(0,0,0,1));
 +	setGridLinesColor(RGBA(0.2,0.2,0.2,1));
 +	setNumberFont("Courier", 12);
 +	setNumberColor(RGBA(0,0,0));
 +	setLabelFont("Courier", 14, QFont::Bold);
 +	setGridLines(false, false);
 +}
 +
 +CoordinateSystem::~CoordinateSystem()
 +{
 +	destroy();
 +}
 +
 +void CoordinateSystem::destroy()
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setLabelString("");
 +
 +	detachAll();
 +}
 +
 +void CoordinateSystem::init(Triple first, Triple second)
 +{
 +	destroy();
 +	
 +  for (unsigned i=0; i!=axes.size(); ++i)
 +    axes[i].setScale(LINEARSCALE);
 +		
 +	Triple dv = second - first;
 +	
 +	setPosition(first, second);
 +	
 +	double majl =  dv.length() / 100; // 1 %
 +	setTicLength(majl, 0.6 * majl);
 +
 +	axes[X1].setPosition(first, first+Triple(dv.x,    0,     0));												// front bottom x
 +	axes[Y1].setPosition(first, first+Triple(   0, dv.y,     0));												// bottom left  y
 +	axes[Z1].setPosition (first+Triple(   0, dv.y, 0), first+Triple(   0, dv.y, dv.z));	// back left z
 +	axes[X1].setTicOrientation(0,-1,0);
 +	axes[Y1].setTicOrientation(-1,0,0);
 +	axes[Z1].setTicOrientation(-1,0,0);
 +	
 +	axes[X1].setLimits(first.x, second.x);
 +	axes[X2].setLimits(first.x, second.x);
 +	axes[X3].setLimits(first.x, second.x);
 +	axes[X4].setLimits(first.x, second.x);
 +	
 +	axes[Y1].setLimits(first.y, second.y);
 +	axes[Y2].setLimits(first.y, second.y);
 +	axes[Y3].setLimits(first.y, second.y);
 +	axes[Y4].setLimits(first.y, second.y);
 +	
 +	axes[Z1].setLimits(first.z, second.z);
 +	axes[Z2].setLimits(first.z, second.z);
 +	axes[Z3].setLimits(first.z, second.z);
 +	axes[Z4].setLimits(first.z, second.z);
 +
 +	// remaining x axes 
 +	axes[X2].setPosition(first+Triple( 0,    0, dv.z), first+Triple( dv.x,    0, dv.z));	// front top x
 +	axes[X3].setPosition(first+Triple( 0, dv.y, dv.z), second);		  											// back top x
 +	axes[X4].setPosition(first+Triple( 0, dv.y,    0), first+Triple( dv.x, dv.y,    0));	// back bottom x
 +	axes[X2].setTicOrientation(0,-1,0);
 +	axes[X3].setTicOrientation(0,1,0);
 +	axes[X4].setTicOrientation(0,1,0);
 +	
 +	// remaining y axes 
 +	axes[Y2].setPosition(first+Triple(dv.x, 0,    0), first+Triple(dv.x, dv.y,  0)); // bottom right y
 +	axes[Y3].setPosition(first+Triple(dv.x, 0, dv.z), second);											 // top right y
 +	axes[Y4].setPosition(first+Triple(0,    0, dv.z), first+Triple(0,  dv.y, dv.z)); // top left y
 +	axes[Y2].setTicOrientation(1,0,0);
 +	axes[Y3].setTicOrientation(1,0,0);
 +	axes[Y4].setTicOrientation (-1,0,0);
 +
 +	// remaining z axes 
 +	axes[Z2].setPosition(first, first+Triple(   0,    0,  dv.z));												// front left z
 +	axes[Z4].setPosition(first+Triple(dv.x, dv.y, 0), second );                         // back right z
 +	axes[Z3].setPosition(first+Triple(dv.x,    0, 0), first+Triple(dv.x,    0, dv.z));	// front right z
 +	axes[Z2].setTicOrientation(-1,0,0);
 +	axes[Z4].setTicOrientation(1,0,0);
 +	axes[Z3].setTicOrientation(1,0,0);
 +	
 +	setStyle(style_);
 +}
 +
 +void CoordinateSystem::draw()
 +{	
 +//	saveGLState();
 +	
 +	GLStateBewarer sb(GL_LINE_SMOOTH, true);
 +	
 +	if (!lineSmooth())
 +		sb.turnOff();
 +		
 +
 +	if (autoDecoration())
 +		chooseAxes();
 +	
 +	Drawable::draw();
 +
 +	if( style_ == NOCOORD)
 +		return;
 +
 +  if (majorgridlines_ || minorgridlines_)
 +    recalculateAxesTics();
 +  if (majorgridlines_)
 +    drawMajorGridLines();
 +	if (minorgridlines_)
 +		drawMinorGridLines();
 +	
 +	//	restoreGLState();
 +}
 +
 +
 +//! build convex hull (6 axes: 2 x, 2 y, 2 z) and choose one of them at a time for scales, labels etc.  
 +void CoordinateSystem::chooseAxes()
 +{
 +	vector<Triple> beg(axes.size());
 +	vector<Triple> end(axes.size());
 +	vector<Tuple> src(2*axes.size());
 +
 +	unsigned i;
 +	// collect axes viewport coordinates and initialize
 +	for (i=0; i!=axes.size(); ++i)
 +	{
 +		if (style() != NOCOORD)
 +			attach(&axes[i]);
 +		
 +		beg[i] = World2ViewPort(axes[i].begin());
 +		end[i] = World2ViewPort(axes[i].end());
 +		src[i] = Tuple(beg[i].x, beg[i].y);
 +		src[axes.size()+i] = Tuple(end[i].x, end[i].y);
 +
 +		axes[i].setScaling(false);
 +		axes[i].setNumbers(false);
 +		axes[i].setLabel(false);
 +	}
 +
 +	vector<unsigned> idx;
 +	convexhull2d(idx,src);
 +
 +	int rem_x = -1;
 +	int rem_y = -1;
 +	int rem_z = -1;
 +
 +
 +	bool left;
 +
 +	int choice_x = -1; 
 +	int	choice_y = -1;
 +	int choice_z = -1;
 +
 +  int other_x = -1;
 +  int other_y = -1;
 +  int other_z = -1;
 +
 +	//traverse convex hull
 +	for (unsigned k=0; k!=idx.size(); ++k)
 +	{
 +		Triple one, two;
 +		
 +		if (idx[k] >= axes.size()) // is end point
 +			one = end[idx[k]-axes.size()];
 +		else                       // is begin point  
 +			one = beg[idx[k]];
 +
 +		unsigned int next = idx[(k+1) % idx.size()];  // next point in cv (considered as ring buffer of points)
 +
 +		if (next >= axes.size()) 
 +			two = end[next-axes.size()];
 +		else
 +			two = beg[next];
 +		
 +		for (i=0; i!=axes.size(); ++i)
 +		{			
 +			if (
 +					(one == beg[i] && two == end[i])
 +					||
 +					(two == beg[i] && one == end[i])
 +				 )
 +			{
 +				if (i==X1 || i==X2 || i==X3 || i==X4)  // x Achsen
 +				{
 +					if (rem_x>=0) // schon zweite Achse der konvexen Huelle ?
 +					{
 +						// untere der beiden x Achsen
 +						double y = min(min(end[rem_x].y,end[i].y),min(beg[rem_x].y,beg[i].y));
 +						choice_x = (y == beg[i].y || y == end[i].y) ? i : rem_x;
 +												
 +						other_x = (choice_x == (int)i) ? rem_x : (int)i;
 +						left = (beg[choice_x].x < beg[other_x].x || end[choice_x].x < end[other_x].x) 
 +							? true
 +							: false;
 +						
 +						autoDecorateExposedAxis(axes[choice_x], left);
 +
 +						rem_x = -1;
 +					}
 +					else
 +					{
 +						rem_x = i;
 +					}
 +				}
 +				else if (i==Y1 || i==Y2 || i==Y3 || i==Y4)
 +				{
 +					if (rem_y>=0)
 +					{
 +						// untere der beiden y Achsen
 +						double y = min(min(end[rem_y].y,end[i].y),min(beg[rem_y].y,beg[i].y));
 +						choice_y = (y == beg[i].y || y == end[i].y) ? i : rem_y;
 +						
 +						other_y = (choice_y == (int)i) ? rem_y : (int)i;
 +						left = (beg[choice_y].x < beg[other_y].x || end[choice_y].x < end[other_y].x) 
 +							? true
 +							: false;
 +						autoDecorateExposedAxis(axes[choice_y], left);
 +
 +						rem_y = -1;
 +					}
 +					else
 +					{
 +						rem_y = i;
 +					}
 +				}
 +				else if (i==Z1 || i==Z2 || i==Z3 || i==Z4)
 +				{
 +					if (rem_z>=0)
 +					{
 +						// hintere der beiden z Achsen
 +						double z = max(max(end[rem_z].z,end[i].z),max(beg[rem_z].z,beg[i].z));
 +						choice_z = (z == beg[i].z || z == end[i].z) ? i : rem_z;
 +
 +						other_z = (choice_z == (int)i) ? rem_z : (int)i;
 +												
 +						rem_z = -1;
 +
 +					}
 +					else
 +					{
 +						rem_z = i;
 +					}
 +				}
 +			}
 +		} // for axes
 +	} // for idx
 +
 +	// fit z axis in - the onthewall axis if the decorated axes build a continous line, the opposite else 
 +	if (choice_x>=0 && choice_y>=0 && choice_z>=0)
 +	{
 +		left = (beg[choice_z].x < beg[other_z].x || end[choice_z].x < end[other_z].x) 
 +			? true
 +			: false;
 +		
 +
 +		if (
 +					axes[choice_z].begin() == axes[choice_x].begin() 
 +			||	axes[choice_z].begin() == axes[choice_x].end()
 +			||	axes[choice_z].begin() == axes[choice_y].begin() 
 +			||	axes[choice_z].begin() == axes[choice_y].end()
 +			||	axes[choice_z].end() == axes[choice_x].begin() 
 +			||	axes[choice_z].end() == axes[choice_x].end()
 +			||	axes[choice_z].end() == axes[choice_y].begin() 
 +			||	axes[choice_z].end() == axes[choice_y].end()
 +			
 +			)
 +		{
 +			autoDecorateExposedAxis(axes[choice_z], left);
 +		}
 +
 +		else
 +		{
 +			autoDecorateExposedAxis(axes[other_z], !left);
 +			choice_z = other_z; // for FRAME
 +		}
 +	}
 +	
 +	if (style() == FRAME)
 +	{
 +		for (i=0; i!=axes.size(); ++i)
 +		{
 +			if ((int)i!=choice_x && (int)i!=choice_y && (int)i!=choice_z)
 +				detach(&axes[i]);
 +		}
 +	}
 +
 +}
 +
 +
 +void CoordinateSystem::autoDecorateExposedAxis(Axis& ax, bool left)
 +{
 +	Triple diff = World2ViewPort(ax.end()) - World2ViewPort(ax.begin());
 +
 +	diff = Triple(diff.x,diff.y,0); // projection
 +	
 +	double s = diff.length();
 +	
 +	if (!s)
 +		return;
 +
 +	ax.setScaling(true);
 +	ax.setNumbers(true);
 +	ax.setLabel(true);
 +
 +	const double SQRT_2 = 0.7071067;
 +	double sina = fabs(diff.y / s);
 +
 +
 +	if (left) // leftmost (compared with antagonist in CV)  axis -> draw decorations on the left side
 +	{
 +		if ( diff.x >= 0 && diff.y >= 0 && sina < SQRT_2)          // 0..Pi/4 
 +		{
 +			ax.setNumberAnchor(BottomCenter);
 +		}
 +		else if ( diff.x >= 0 && diff.y >= 0  && !left)            // octant 2
 +		{
 +			ax.setNumberAnchor(CenterRight);
 +		}
 +		else if ( diff.x <= 0 && diff.y >= 0  && sina >= SQRT_2)    // octant 3
 +		{
 +			ax.setNumberAnchor(CenterRight);
 +		}
 +		else if ( diff.x <= 0 && diff.y >= 0 )                      // octant 4
 +		{
 +			ax.setNumberAnchor(TopCenter);
 +		}
 +		else if ( diff.x <= 0 && diff.y <= 0  && sina <= SQRT_2)    // octant 5
 +		{
 +			ax.setNumberAnchor(BottomCenter);
 +		}
 +		else if ( diff.x <= 0 && diff.y <= 0)                      // octant 6
 +		{
 +			ax.setNumberAnchor(CenterRight);
 +		}
 +		else if ( diff.x >= 0 && diff.y <= 0  && sina >= SQRT_2)    // octant 7
 +		{
 +			ax.setNumberAnchor(CenterRight);
 +		}
 +		else if ( diff.x >= 0 && diff.y <= 0)                      // octant 8
 +		{
 +			ax.setNumberAnchor(TopCenter);
 +		}
 +	}	
 +	else // rightmost axis
 +	{
 +		if ( diff.x >= 0 && diff.y >= 0 && sina <= SQRT_2)
 +		{
 +			ax.setNumberAnchor(TopCenter);
 +		}
 +		else if ( diff.x >= 0 && diff.y >= 0  && !left) 
 +		{
 +			ax.setNumberAnchor(CenterLeft);
 +		}
 +		else if ( diff.x <= 0 && diff.y >= 0  && sina >= SQRT_2) 
 +		{
 +			ax.setNumberAnchor(CenterLeft);
 +		}
 +		else if ( diff.x <= 0 && diff.y >= 0) 
 +		{
 +			ax.setNumberAnchor(BottomCenter);
 +		}
 +		else if ( diff.x <= 0 && diff.y <= 0  && sina <= SQRT_2) 
 +		{
 +			ax.setNumberAnchor(TopCenter);
 +		}
 +		else if ( diff.x <= 0 && diff.y <= 0) 
 +		{
 +			ax.setNumberAnchor(CenterLeft);
 +		}
 +		else if ( diff.x >= 0 && diff.y <= 0  && sina >= SQRT_2) 
 +		{
 +			ax.setNumberAnchor(CenterLeft);
 +		}
 +		else if ( diff.x >= 0 && diff.y <= 0) 
 +		{
 +			ax.setNumberAnchor(BottomCenter);
 +		}
 +	}
 +}
 +
 +
 +void CoordinateSystem::setPosition(Triple first, Triple second)
 +{
 +	first_ = first;
 +	second_ = second;
 +}
 +
 +void CoordinateSystem::setTicLength(double major, double minor)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setTicLength(major, minor);
 +}
 +
 +void CoordinateSystem::adjustNumbers(int val)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].adjustNumbers(val);
 +}
 +
 +void CoordinateSystem::adjustLabels(int val)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].adjustLabel(val);
 +}
 +
 +void CoordinateSystem::setAutoScale(bool val)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setAutoScale(val);
 +}
 +
 +void CoordinateSystem::setAxesColor(RGBA val)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setColor(val);
 +}
 +
 +void CoordinateSystem::recalculateAxesTics()
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].recalculateTics();
 +}
 +
 +void CoordinateSystem::setNumberFont(QString const& family, int pointSize, int weight, bool italic)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setNumberFont(family,pointSize,weight,italic);
 +}
 +
 +void CoordinateSystem::setNumberFont(QFont const& font)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setNumberFont(font);
 +}
 +
 +void CoordinateSystem::setNumberColor(RGBA val)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setNumberColor( val);
 +}
 +
 +void CoordinateSystem::setStandardScale()
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +    axes[i].setScale(LINEARSCALE);
 +}
 +
 +void CoordinateSystem::setLabelFont(QFont const& font)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setLabelFont(font);
 +}
 +
 +
 +void CoordinateSystem::setLabelFont(QString const& family, int pointSize, int weight, bool italic)
 +{
 +	setLabelFont(QFont(family,pointSize,weight,italic));
 +}
 +
 +void CoordinateSystem::setLabelColor(RGBA val)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setLabelColor(val);
 +}
 +
 +void CoordinateSystem::setLineWidth(double val, double majfac, double minfac)
 +{
 +	for (unsigned i=0; i!=axes.size(); ++i)
 +		axes[i].setLineWidth(val, majfac, minfac);
 +}
 +
 +void CoordinateSystem::setStyle(COORDSTYLE s, AXIS frame_1, AXIS frame_2, AXIS frame_3) 
 +{ 
 +	style_ = s;
 +
 +	switch (s)
 +	{
 +		case NOCOORD:
 +			{
 +				for (unsigned i=0; i!=axes.size(); ++i)
 +					detach (&axes[i]);
 +			}
 +			break;
 +		case BOX:
 +			{
 +				for (unsigned i=0; i!=axes.size(); ++i)
 +					attach (&axes[i]);
 +			}
 +			break;
 +		case FRAME:
 +			{
 +				for (unsigned i=0; i!=axes.size(); ++i)
 +					detach (&axes[i]);
 +				if (!autoDecoration())
 +				{
 +					attach(&axes[frame_1]);
 +					attach(&axes[frame_2]);
 +					attach(&axes[frame_3]);
 +				}
 +			}
 +			break;
 +		default:
 +			break;
 +	}
 +}
 +
 +/**
 +The axis used for tic calculation is chosen randomly from the respective pair.
 +For most cases an identical tic distribution is therefore recommended.
 +\param majors  Draw grid between major tics
 +\param minors  Draw grid between minor tics
 +\param sides   Side(s), where the grid should be drawn
 +*/
 +void CoordinateSystem::setGridLines(bool majors, bool minors, int sides) 
 +{
 +	sides_ = sides;
 +  majorgridlines_ = majors; 
 +	minorgridlines_ = minors;
 +} 
 +
 +void CoordinateSystem::drawMajorGridLines()
 +{
 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +	glColor4d(gridlinecolor_.r,gridlinecolor_.g,gridlinecolor_.b,gridlinecolor_.a);		
 +	setDeviceLineWidth(axes[X1].majLineWidth());
 +
 +  glBegin( GL_LINES );
 +  if (sides_ & Qwt3D::FLOOR)  
 +  {
 +		drawMajorGridLines(axes[X1],axes[X4]);
 +		drawMajorGridLines(axes[Y1],axes[Y2]);
 +  }
 +  if (sides_ & Qwt3D::CEIL)  
 +  {
 +		drawMajorGridLines(axes[X2],axes[X3]);
 +		drawMajorGridLines(axes[Y3],axes[Y4]);
 +  }
 +  if (sides_ & Qwt3D::LEFT)  
 +  {
 +		drawMajorGridLines(axes[Y1],axes[Y4]);
 +		drawMajorGridLines(axes[Z1],axes[Z2]);
 +  }
 +  if (sides_ & Qwt3D::RIGHT)  
 +  {
 +		drawMajorGridLines(axes[Y2],axes[Y3]);
 +		drawMajorGridLines(axes[Z3],axes[Z4]);
 +  }
 +  if (sides_ & Qwt3D::FRONT)  
 +  {
 +		drawMajorGridLines(axes[X1],axes[X2]);
 +		drawMajorGridLines(axes[Z2],axes[Z3]);
 +  }
 +  if (sides_ & Qwt3D::BACK) 
 +  {
 +		drawMajorGridLines(axes[X3],axes[X4]);
 +		drawMajorGridLines(axes[Z4],axes[Z1]);
 +  }
 +  glEnd();
 +}
 +
 +void CoordinateSystem::drawMinorGridLines()
 +{
 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +	glColor4d(gridlinecolor_.r,gridlinecolor_.g,gridlinecolor_.b,gridlinecolor_.a);		
 +	setDeviceLineWidth(axes[X1].minLineWidth());
 +
 +  glBegin( GL_LINES );
 +  if (sides_ & Qwt3D::FLOOR)  
 +  {
 +		drawMinorGridLines(axes[X1],axes[X4]);
 +		drawMinorGridLines(axes[Y1],axes[Y2]);
 +  }
 +  if (sides_ & Qwt3D::CEIL)  
 +  {
 +		drawMinorGridLines(axes[X2],axes[X3]);
 +		drawMinorGridLines(axes[Y3],axes[Y4]);
 +  }
 +  if (sides_ & Qwt3D::LEFT)  
 +  {
 +		drawMinorGridLines(axes[Y1],axes[Y4]);
 +		drawMinorGridLines(axes[Z1],axes[Z2]);
 +  }
 +  if (sides_ & Qwt3D::RIGHT)  
 +  {
 +		drawMinorGridLines(axes[Y2],axes[Y3]);
 +		drawMinorGridLines(axes[Z3],axes[Z4]);
 +  }
 +  if (sides_ & Qwt3D::FRONT)  
 +  {
 +		drawMinorGridLines(axes[X1],axes[X2]);
 +		drawMinorGridLines(axes[Z2],axes[Z3]);
 +  }
 +  if (sides_ & Qwt3D::BACK)  
 +  {
 +		drawMinorGridLines(axes[X3],axes[X4]);
 +		drawMinorGridLines(axes[Z4],axes[Z1]);
 +  }
 +  glEnd();
 +}
 +
 +void CoordinateSystem::drawMajorGridLines(Axis& a0, Axis& a1)
 +{
 +  Triple d = a1.begin()-a0.begin();
 +
 +  for (unsigned int i=0; i!=a0.majorPositions().size(); ++i)
 +	{
 +		glVertex3d( a0.majorPositions()[i].x, a0.majorPositions()[i].y, a0.majorPositions()[i].z ); 
 +		glVertex3d( a0.majorPositions()[i].x + d.x, a0.majorPositions()[i].y + d.y, a0.majorPositions()[i].z +d.z); 
 +	}
 +}
 +
 +void CoordinateSystem::drawMinorGridLines(Axis& a0, Axis& a1)
 +{
 +  Triple d = a1.begin()-a0.begin();
 +
 +  for (unsigned int i=0; i!=a0.minorPositions().size(); ++i)
 +	{
 +		glVertex3d( a0.minorPositions()[i].x, a0.minorPositions()[i].y, a0.minorPositions()[i].z ); 
 +		glVertex3d( a0.minorPositions()[i].x + d.x, a0.minorPositions()[i].y + d.y, a0.minorPositions()[i].z +d.z); 
 +	}
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_dataviews.cpp b/lib/tqwtplot3d/src/qwt3d_dataviews.cpp new file mode 100644 index 0000000..7a022dd --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_dataviews.cpp @@ -0,0 +1,10 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4305 )
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include "qwt3d_plot.h"
 +
 +using namespace std;
 +using namespace Qwt3D;
 +
 diff --git a/lib/tqwtplot3d/src/qwt3d_drawable.cpp b/lib/tqwtplot3d/src/qwt3d_drawable.cpp new file mode 100644 index 0000000..4025817 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_drawable.cpp @@ -0,0 +1,140 @@ +#include "qwt3d_drawable.h"
 +
 +using namespace Qwt3D;
 +
 +Drawable::~Drawable()
 +{
 +  detachAll();
 +}
 +
 +void Drawable::saveGLState()
 +{
 +	glGetBooleanv(GL_LINE_SMOOTH, &ls);
 +	glGetBooleanv(GL_POLYGON_SMOOTH, &pols);
 +	glGetFloatv(GL_LINE_WIDTH, &lw);
 +	glGetIntegerv(GL_BLEND_SRC, &blsrc);
 +	glGetIntegerv(GL_BLEND_DST, &bldst);
 +	glGetDoublev(GL_CURRENT_COLOR, col);
 +	glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &pattern);
 +	glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &factor);
 +	glGetBooleanv(GL_LINE_STIPPLE, &sallowed);
 +	glGetBooleanv(GL_TEXTURE_2D, &tex2d);
 +	glGetIntegerv(GL_POLYGON_MODE, polmode);
 +	glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
 +	glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &poloffs[0]);
 +	glGetFloatv(GL_POLYGON_OFFSET_UNITS, &poloffs[1]);
 +	glGetBooleanv(GL_POLYGON_OFFSET_FILL, &poloffsfill);
 +}
 +
 +void Drawable::restoreGLState()
 +{
 +	Enable(GL_LINE_SMOOTH, ls);
 +	Enable(GL_POLYGON_SMOOTH, pols);
 +	
 +	setDeviceLineWidth(lw);
 +	glBlendFunc(blsrc, bldst);
 +	glColor4dv(col);
 +
 +	glLineStipple(factor,pattern);
 +	Enable(GL_LINE_STIPPLE,sallowed);
 +	Enable(GL_TEXTURE_2D,tex2d);
 +	glPolygonMode(polmode[0], polmode[1]);
 +	glMatrixMode(matrixmode);
 +	glPolygonOffset(poloffs[0], poloffs[1]);
 +	setDevicePolygonOffset(poloffs[0], poloffs[1]);
 +
 +	Enable(GL_POLYGON_OFFSET_FILL, poloffsfill);
 +}
 +
 +void Drawable::Enable(GLenum what, GLboolean val)
 +{
 +	if (val)
 +		glEnable(what);
 +  else
 +		glDisable(what);
 +}
 +
 +void Drawable::attach(Drawable* dr)
 +{
 +	if ( dlist.end() == std::find( dlist.begin(), dlist.end(), dr ) )
 +		if (dr)
 +		{
 +			dlist.push_back(dr);
 +		}
 +}
 +
 +void Drawable::detach(Drawable* dr)
 +{
 +	std::list<Drawable*>::iterator it = std::find(dlist.begin(), dlist.end(), dr);
 +	
 +	if ( it != dlist.end() )
 +	{
 +		dlist.erase(it);
 +	}
 +}
 +void Drawable::detachAll()
 +{
 +	dlist.clear();
 +}
 +
 +
 +//! simplified glut routine (glUnProject): windows coordinates_p --> object coordinates_p 
 +/**
 +	Don't rely on (use) this in display lists !
 +*/
 +Triple Drawable::ViewPort2World(Triple win, bool* err)
 +{
 +  Triple obj;
 +	
 +	getMatrices(modelMatrix, projMatrix, viewport);
 +	int res = gluUnProject(win.x, win.y, win.z, modelMatrix, projMatrix, viewport, &obj.x, &obj.y, &obj.z);
 +
 +	if (err)
 +		*err = (res) ? false : true;
 +	return obj;
 +}
 +
 +//! simplified glut routine (glProject): object coordinates_p --> windows coordinates_p 
 +/**
 +	Don't rely on (use) this in display lists !
 +*/
 +Triple Drawable::World2ViewPort(Triple obj,	bool* err)
 +{
 +  Triple win;
 +	
 +	getMatrices(modelMatrix, projMatrix, viewport);
 +	int res = gluProject(obj.x, obj.y, obj.z, modelMatrix, projMatrix, viewport, &win.x, &win.y, &win.z);
 +
 +	if (err)
 +		*err = (res) ? false : true;
 +	return win;
 +}
 +
 +/**
 +	Don't rely on (use) this in display lists !
 +*/
 +Triple Drawable::relativePosition(Triple rel)
 +{
 +	return ViewPort2World(Triple((rel.x-viewport[0])*viewport[2],(rel.y-viewport[1])*viewport[3],rel.z));
 +}
 +
 +void Drawable::draw()
 +{
 +	saveGLState();
 +
 +	for (std::list<Drawable*>::iterator it = dlist.begin(); it!=dlist.end(); ++it)
 +	{
 +		(*it)->draw();
 +	}
 +	restoreGLState();
 +}
 +
 +void Drawable::setColor(double r, double g, double b, double a)
 +{
 +	color = RGBA(r,g,b,a);
 +}	
 +
 +void Drawable::setColor(RGBA rgba)
 +{
 +	color = rgba;
 +}	
 diff --git a/lib/tqwtplot3d/src/qwt3d_enrichment_std.cpp b/lib/tqwtplot3d/src/qwt3d_enrichment_std.cpp new file mode 100644 index 0000000..d20ffc2 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_enrichment_std.cpp @@ -0,0 +1,347 @@ +#include <math.h>
 +#include "qwt3d_color.h"
 +#include "qwt3d_plot.h"
 +#include "qwt3d_enrichment_std.h"
 +
 +using namespace Qwt3D;
 +
 +
 +/////////////////////////////////////////////////////////////////
 +//
 +//   CrossHair
 +//
 +/////////////////////////////////////////////////////////////////
 +
 +CrossHair::CrossHair()
 +{
 +  configure(0, 1, false, false);
 +}
 +
 +CrossHair::CrossHair(double rad, double linewidth, bool smooth, bool boxed)
 +{
 +  configure(rad, linewidth, smooth, boxed);
 +}
 +
 +void CrossHair::configure(double rad, double linewidth, bool smooth, bool boxed)
 +{
 +  plot = 0;
 +  radius_ = rad;
 +  linewidth_ = linewidth;
 +  smooth_ = smooth;
 +  boxed_ = boxed;
 +}
 +
 +void CrossHair::drawBegin()
 +{
 +  setDeviceLineWidth( linewidth_ );
 +  oldstate_ = glIsEnabled(GL_LINE_SMOOTH);
 +  if (smooth_)
 +    glEnable(GL_LINE_SMOOTH);
 +  else
 +    glDisable(GL_LINE_SMOOTH);
 +	glBegin( GL_LINES );
 +}
 +
 +void CrossHair::drawEnd()
 +{
 +  glEnd();
 +
 +  if (oldstate_)
 +    glEnable(GL_LINE_SMOOTH);
 +  else
 +    glDisable(GL_LINE_SMOOTH);
 +}
 +
 +void CrossHair::draw(Qwt3D::Triple const& pos)
 +{
 +	RGBA rgba = (*plot->dataColor())(pos);
 +	glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
 +
 +  double diag = (plot->hull().maxVertex-plot->hull().minVertex).length() * radius_;
 +
 +  glVertex3d( pos.x - diag, pos.y, pos.z); 
 +	glVertex3d( pos.x + diag, pos.y, pos.z); 
 +	
 +  glVertex3d( pos.x, pos.y - diag, pos.z); 
 +	glVertex3d( pos.x, pos.y + diag, pos.z); 
 +  
 +  glVertex3d( pos.x, pos.y, pos.z - diag); 
 +	glVertex3d( pos.x, pos.y, pos.z + diag); 
 +
 +  // hull
 +  
 +  if (!boxed_)
 +    return;
 +
 +  glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag); 
 +	glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag); 
 +  glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag); 
 +	glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag); 
 +  
 +  glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag); 
 +	glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag); 
 +  glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag); 
 +	glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag); 
 +
 +  glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag); 
 +	glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag); 
 +  glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag); 
 +	glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag); 
 +  
 +  glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag); 
 +	glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag); 
 +  glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag); 
 +	glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag); 
 +
 +  glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag); 
 +	glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag); 
 +  glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag); 
 +	glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag); 
 +  
 +  glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag); 
 +	glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag); 
 +  glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag); 
 +	glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag); 
 +}
 +
 +/////////////////////////////////////////////////////////////////
 +//
 +//   Dot
 +//
 +/////////////////////////////////////////////////////////////////
 +
 +Dot::Dot()
 +{
 +  configure(1, false);
 +}
 +
 +Dot::Dot(double pointsize, bool smooth)
 +{
 +  configure(pointsize, smooth);
 +}
 +
 +void Dot::configure(double pointsize, bool smooth)
 +{
 +  plot = 0;
 +  pointsize_ = pointsize;
 +  smooth_ = smooth;
 +}
 +
 +void Dot::drawBegin()
 +{
 +  setDevicePointSize( pointsize_ );
 +  oldstate_ = glIsEnabled(GL_POINT_SMOOTH);
 +  if (smooth_)
 +    glEnable(GL_POINT_SMOOTH);
 +  else
 +    glDisable(GL_POINT_SMOOTH);
 +
 +  //glPointSize(10);
 +	glBegin( GL_POINTS );
 +}
 +
 +void Dot::drawEnd()
 +{
 +  glEnd();
 +
 +  if (oldstate_)
 +    glEnable(GL_POINT_SMOOTH);
 +  else
 +    glDisable(GL_POINT_SMOOTH);
 +}
 +
 +void Dot::draw(Qwt3D::Triple const& pos)
 +{
 +	RGBA rgba = (*plot->dataColor())(pos);
 +  glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
 +  glVertex3d( pos.x, pos.y, pos.z);   
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////
 +//
 +//   Cone
 +//
 +/////////////////////////////////////////////////////////////////
 +
 +Cone::Cone()
 +{
 +	hat      = gluNewQuadric();
 +	disk     = gluNewQuadric();
 +
 +  configure(0, 3);
 +}
 +
 +Cone::Cone(double rad, unsigned quality)
 +{
 +	hat      = gluNewQuadric();
 +	disk     = gluNewQuadric();
 +
 +  configure(rad, quality);
 +}
 +
 +Cone::~Cone()
 +{
 +	gluDeleteQuadric(hat);
 +	gluDeleteQuadric(disk);
 +}
 +
 +void Cone::configure(double rad, unsigned quality)
 +{
 +  plot = 0;
 +  radius_ = rad;
 +  quality_ = quality;
 +  oldstate_ = GL_FALSE;
 +
 +	gluQuadricDrawStyle(hat,GLU_FILL);
 +	gluQuadricNormals(hat,GLU_SMOOTH);
 +	gluQuadricOrientation(hat,GLU_OUTSIDE);
 +	gluQuadricDrawStyle(disk,GLU_FILL);
 +	gluQuadricNormals(disk,GLU_SMOOTH);
 +	gluQuadricOrientation(disk,GLU_OUTSIDE);
 +}
 +
 +void Cone::draw(Qwt3D::Triple const& pos)
 +{  
 +	RGBA rgba = (*plot->dataColor())(pos);
 +  glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
 +
 +  GLint mode;
 +	glGetIntegerv(GL_MATRIX_MODE, &mode);
 +	glMatrixMode( GL_MODELVIEW );
 +  glPushMatrix();
 +
 +  glTranslatef(pos.x, pos.y, pos.z);
 +
 +  gluCylinder(hat, 0.0, radius_, radius_*2, quality_, 1);
 +  glTranslatef(0, 0, radius_*2);
 +	gluDisk(disk, 0.0, radius_, quality_, 1);
 +
 +  glPopMatrix();
 +	glMatrixMode(mode);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////
 +//
 +//   Arrow
 +//
 +/////////////////////////////////////////////////////////////////
 +
 +Arrow::Arrow()
 +{	
 +	hat      = gluNewQuadric();
 +	disk     = gluNewQuadric();
 +	base    = gluNewQuadric();
 +	bottom   = gluNewQuadric();
 +
 +	gluQuadricDrawStyle(hat,GLU_FILL);
 +	gluQuadricNormals(hat,GLU_SMOOTH);
 +	gluQuadricOrientation(hat,GLU_OUTSIDE);
 +	gluQuadricDrawStyle(disk,GLU_FILL);
 +	gluQuadricNormals(disk,GLU_SMOOTH);
 +	gluQuadricOrientation(disk,GLU_OUTSIDE);
 +	gluQuadricDrawStyle(base,GLU_FILL);
 +	gluQuadricNormals(base,GLU_SMOOTH);
 +	gluQuadricOrientation(base,GLU_OUTSIDE);
 +	gluQuadricDrawStyle(bottom,GLU_FILL);
 +	gluQuadricNormals(bottom,GLU_SMOOTH);
 +	gluQuadricOrientation(bottom,GLU_OUTSIDE);
 +
 +	configure(3, 0.4, 0.06, 0.02);
 +}
 +
 +Arrow::~Arrow()
 +{
 +	gluDeleteQuadric(hat);
 +	gluDeleteQuadric(disk);
 +	gluDeleteQuadric(base);
 +	gluDeleteQuadric(bottom);
 +}
 +
 +/**
 +\param segs number of faces for the fields arrows (see the gallery for examples)
 +\param relconelength see picture
 +\param relconerad see picture
 +\param relstemrad see picture
 +\image html arrowanatomy.png 
 +*/
 +void Arrow::configure(int segs, double relconelength, double relconerad, double relstemrad)
 +{
 +	plot = 0;
 +  segments_ = segs;
 +  oldstate_ = GL_FALSE;
 +	rel_cone_length = relconelength;
 +	rel_cone_radius = relconerad;
 +	rel_stem_radius = relstemrad;	
 +}
 +
 +void Arrow::draw(Qwt3D::Triple const& pos)
 +{	
 +	Triple end = top_;
 +	Triple beg = pos;
 +	Triple vdiff = end-beg;
 +	double length = vdiff.length();
 +	glColor4d(rgba_.r,rgba_.g,rgba_.b,rgba_.a);
 +
 +	double radius[2];
 +	radius[0] = rel_cone_radius * length;
 +	radius[1] = rel_stem_radius * length;
 +	
 +	GLint mode;
 +	glGetIntegerv(GL_MATRIX_MODE, &mode);
 +
 +	glMatrixMode( GL_MODELVIEW );
 +  glPushMatrix();
 +
 +
 +	Triple axis;
 +	double phi = calcRotation(axis, FreeVector(beg,end));
 +	
 +	glTranslatef(beg.x, beg.y, beg.z);
 +  glRotatef(phi, axis.x, axis.y, axis.z);
 +
 +	double baseheight = (1-rel_cone_length) * length;
 +	
 +	glTranslatef(0, 0, baseheight);
 +
 +	gluCylinder(hat, radius[0], 0.0, rel_cone_length * length, segments_,1);
 +	gluDisk(disk,radius[1],radius[0], segments_,1);
 +	
 +	glTranslatef(0, 0, -baseheight);
 +	
 +	gluCylinder(base, radius[1],radius[1], baseheight,segments_,1);
 +	gluDisk(disk,0,radius[1],segments_,1);
 +
 +  glPopMatrix();
 +	glMatrixMode(mode);
 +}
 +
 +
 +//! transform a vector on the z axis with length |beg-end|, to get them in coincidence with the vector(beg,end)
 +/**
 +	\return Angle in degree to rotate
 +	\param axis   The axis to rotate around
 +	\param beg    result vector base point
 +	\param end    result vector top point
 +*/ 
 +double Arrow::calcRotation(Triple& axis, FreeVector const& vec)
 +{
 +	
 +	Triple end = vec.top;
 +	Triple beg = vec.base;
 +
 +	Triple firstbeg(0.0,0.0,0.0);
 +	Triple firstend(0.0,0.0,(end-beg).length());
 +	
 +	Triple first = firstend - firstbeg;
 +	first.normalize();
 +
 +	Triple second = end-beg;
 +	second.normalize();
 +
 +	axis = normalizedcross(first,second);
 +	double cosphi = dotProduct(first,second);
 +	
 +	return 180 * acos(cosphi) / Qwt3D::PI;
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_function.cpp b/lib/tqwtplot3d/src/qwt3d_function.cpp new file mode 100644 index 0000000..28d874e --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_function.cpp @@ -0,0 +1,101 @@ +#include "qwt3d_surfaceplot.h"
 +#include "qwt3d_function.h"
 +
 +using namespace Qwt3D;
 +
 +Function::Function()
 +:GridMapping()
 +{
 +}
 +
 +Function::Function(SurfacePlot& pw)
 +:GridMapping()
 +{
 +  plotwidget_p = &pw;
 +}
 +
 +Function::Function(SurfacePlot* pw)
 +:GridMapping()
 +{
 +  plotwidget_p = pw;
 +}
 +
 +void Function::assign(SurfacePlot& plotWidget)
 +{
 +	if (&plotWidget != plotwidget_p)
 +		plotwidget_p = &plotWidget;
 +}
 +
 +void Function::assign(SurfacePlot* plotWidget)
 +{
 +	if (plotWidget != plotwidget_p)
 +		plotwidget_p = plotWidget;
 +}
 +
 +void Function::	setMinZ(double val)
 +{
 +	range_p.minVertex.z = val;
 +}
 +
 +void Function::	setMaxZ(double val)
 +{
 +	range_p.maxVertex.z = val;
 +}
 +
 +bool Function::create()
 +{
 +	if ((umesh_p<=2) || (vmesh_p<=2) || !plotwidget_p)
 +		return false;
 +	
 +	/* allocate some space for the mesh */
 + 	double** data         = new double* [umesh_p] ;
 +
 +	unsigned i,j;
 +	for ( i = 0; i < umesh_p; i++) 
 +	{
 +		data[i]         = new double [vmesh_p];
 +	}
 +	
 +	/* get the data */
 +
 +	double dx = (maxu_p - minu_p) / (umesh_p - 1);
 +	double dy = (maxv_p - minv_p) / (vmesh_p - 1);
 +	
 +	for (i = 0; i < umesh_p; ++i) 
 +	{
 +		for (j = 0; j < vmesh_p; ++j) 
 +		{
 +			data[i][j] = operator()(minu_p + i*dx, minv_p + j*dy);
 +			
 +			if (data[i][j] > range_p.maxVertex.z)
 +				data[i][j] = range_p.maxVertex.z;
 +			else if (data[i][j] < range_p.minVertex.z)
 +				data[i][j] = range_p.minVertex.z;
 +		}
 +	}
 +
 +	Q_ASSERT(plotwidget_p);
 +	if (!plotwidget_p)
 +	{
 +		fprintf(stderr,"Function: no valid Plot3D Widget assigned");
 +	}
 +	else
 +	{
 +		((SurfacePlot*)plotwidget_p)->loadFromData(data, umesh_p, vmesh_p, minu_p, maxu_p, minv_p, maxv_p);
 +	}
 +
 +	for ( i = 0; i < umesh_p; i++) 
 +	{
 +		delete [] data[i];
 +	}
 +
 +	delete [] data;
 +
 +	return true;
 +}
 +
 +bool Function::create(SurfacePlot& pl)
 +{
 +  assign(pl);
 +  return create();
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_gridmapping.cpp b/lib/tqwtplot3d/src/qwt3d_gridmapping.cpp new file mode 100644 index 0000000..4de521b --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_gridmapping.cpp @@ -0,0 +1,32 @@ +#include "qwt3d_gridmapping.h"
 +#include "qwt3d_surfaceplot.h"
 +
 +using namespace Qwt3D;
 +
 +GridMapping::GridMapping()
 +{
 +	plotwidget_p = 0;
 +	setMesh(0,0);
 +	setDomain(0,0,0,0);
 +  restrictRange(ParallelEpiped(Triple(-DBL_MAX,-DBL_MAX,-DBL_MAX),Triple(DBL_MAX,DBL_MAX,DBL_MAX)));
 +}
 +
 +void GridMapping::setMesh(unsigned int columns,unsigned int rows)
 +{
 +	umesh_p = columns;
 +	vmesh_p = rows;
 +}
 +
 +void GridMapping::setDomain(double minu, double maxu, double minv, double maxv)
 +{
 +	minu_p = minu;
 +	maxu_p = maxu;
 +	minv_p = minv;
 +	maxv_p = maxv;
 +}
 +
 +void GridMapping::restrictRange(Qwt3D::ParallelEpiped const& p)
 +{
 +	range_p = p;
 +}
 +
 diff --git a/lib/tqwtplot3d/src/qwt3d_gridplot.cpp b/lib/tqwtplot3d/src/qwt3d_gridplot.cpp new file mode 100644 index 0000000..6543785 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_gridplot.cpp @@ -0,0 +1,596 @@ +#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();
 +  
 +  
 +}*/
 +
 diff --git a/lib/tqwtplot3d/src/qwt3d_io.cpp b/lib/tqwtplot3d/src/qwt3d_io.cpp new file mode 100644 index 0000000..c9ce46b --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_io.cpp @@ -0,0 +1,355 @@ +#include <time.h>
 +
 +#include "qwt3d_plot.h"
 +#include "qwt3d_io_gl2ps.h"
 +#include "qwt3d_io_reader.h"
 +#if QT_VERSION < 0x040000
 +#else
 +  #include <QImageWriter>
 +#endif
 +
 +using namespace Qwt3D;
 +
 +IO::Entry::Entry() : iofunc(0) 
 +{
 +}
 +
 +IO::Entry::~Entry() 
 +{
 +  delete iofunc;
 +}
 +
 +IO::Entry::Entry(IO::Entry const& e)
 +{
 +  if (this==&e)
 +    return;
 +
 +  fmt = e.fmt;
 +  iofunc = e.iofunc->clone();
 +}
 +
 +void IO::Entry::operator=(IO::Entry const& e)
 +{
 +  if (this==&e)
 +    return;
 +
 +  delete iofunc;
 +  fmt = e.fmt;
 +  iofunc = e.iofunc->clone();
 +}
 +
 +IO::Entry::Entry(QString const& s, Functor const& f)
 +  : fmt(s) 
 +{ 
 +  iofunc = f.clone();
 +}
 +
 +IO::Entry::Entry(QString const& s, Function f)
 +  : fmt(s) 
 +{ 
 +  Wrapper  w(f);
 +  iofunc = w.clone();
 +}
 +
 +
 +IO::FormatCompare::FormatCompare(IO::Entry const& e) 
 +{
 +  e_ = e;
 +}
 +
 +bool IO::FormatCompare::operator() (IO::Entry const& e)
 +{
 +  return ( e.fmt == e_.fmt);
 +}
 +
 +IO::FormatCompare2::FormatCompare2(QString s) 
 +{
 +  s_ = s;
 +}
 +
 +bool IO::FormatCompare2::operator() (IO::Entry const& e)
 +{
 +  return( e.fmt == s_);
 +}
 +
 +
 +
 +
 +bool IO::add_unique(Container& l, Entry const& e)
 +{
 +  FormatCompare comp(e);
 +  l.erase(std::remove_if(l.begin(), l.end(), comp), l.end());
 +  l.push_back(e);
 +
 +  return true;
 +}
 +
 +IO::IT IO::find(Container& l, QString const& fmt)
 +{
 +  FormatCompare2 comp(fmt);
 +  return std::find_if(l.begin(), l.end(), comp); 
 +}
 +
 +IO::Container& IO::rlist()
 +{
 +  static Container rl = Container();
 +  static bool rfirst = true;
 +  bool f = false;
 +  f = rfirst;
 +  if (rfirst)
 +  {
 +    rfirst = false;
 +    setupHandler();
 +  }
 +  return rl;
 +}
 +
 +IO::Container& IO::wlist()
 +{
 +  static Container wl = Container();
 +  static bool wfirst = true;
 +  bool f = false;
 +  f = wfirst;
 +  if (wfirst)
 +  {
 +    wfirst = false;
 +    setupHandler();
 +  }
 +  return wl;
 +}
 +
 +/*! 
 +  Registers a new IO::Function for data input.\n
 +  Every call overwrites a formerly registered handler for the same format string
 +  (case sensitive).
 +*/
 +bool IO::defineInputHandler(QString const& format, IO::Function func)
 +{
 +  return add_unique(rlist(), Entry(format, func));
 +}
 +
 +/*! 
 +  Registers a new Functor for data input.\n
 +  Every call overwrites a formerly registered handler for the same format string
 +  (case sensitive).
 +*/
 +bool IO::defineInputHandler(QString const& format, IO::Functor const& func)
 +{
 +  return add_unique(rlist(), Entry(format, func));
 +}
 +
 +/*! 
 +  Registers a new IO::Function for data output.  
 +  Every call overwrites a formerly registered handler for the same format string
 +  (case sensitive).
 + */
 +bool IO::defineOutputHandler(QString const& format, IO::Function func)
 +{
 +  return add_unique(wlist(), Entry(format, func));
 +}
 +
 +/*! 
 +  Registers a new Functor for data output.\n
 +  Every call overwrites a formerly registered handler for the same format string
 +  (case sensitive).
 +*/
 +bool IO::defineOutputHandler(QString const& format, IO::Functor const& func)
 +{
 +  return add_unique(wlist(), Entry(format, func));
 +}
 +
 +/*!
 +  Applies a reading IO::Function or IO::Functor.
 +  \param plot Plot with the content that should be loaded
 +  \param fname File name 
 +  \param format Input format
 +  \return The return value from the called Function/Functor. 
 +  The function returns false, if no registered handler could be found.
 +*/
 +bool IO::load(Plot3D* plot, QString const& fname, QString const& format)
 +{
 +  IT it = IO::find(rlist(), format);
 +
 +  if (it == rlist().end())
 +    return false;
 +
 +  return (*it->iofunc)(plot, fname);
 +}
 +
 +/*!
 +  Applies a writing IO::Function or IO::Functor.
 +  \param plot Plot with the content that should be saved
 +  \param fname File name
 +  \param format Output format
 +  \return The return value from the called Function/Functor.
 +  The function returns false, if no registered handler could be found.
 +*/
 +bool IO::save(Plot3D* plot, QString const& fname, QString const& format)
 +{
 +  IT it = IO::find(wlist(), format);
 +
 +  if (it == wlist().end())
 +    return false;
 +
 +  return (*it->iofunc)(plot, fname);
 +}
 +
 +/*!
 +  Returns a list of currently registered input formats. 
 +*/
 +QStringList IO::inputFormatList()
 +{
 +  QStringList list;
 +  for ( IT it = rlist().begin(); it!=rlist().end(); ++it )
 +    list.append(it->fmt);
 +  
 +  return list;
 +}
 +
 +/*!
 +  Returns a list of currently registered output formats. 
 +*/
 +QStringList IO::outputFormatList()
 +{
 +  QStringList list;  
 +  for ( IT it = wlist().begin(); it!=wlist().end(); ++it )
 +    list.append(it->fmt);
 +  
 +  return list;
 +}
 +
 +/*! 
 +  Returns the input functor in charge for format and 0 if non-existent. 
 +*/
 +IO::Functor* IO::inputHandler(QString const& format)
 +{
 +  IO::IT it = IO::find(rlist(), format);
 +  
 +  if (it==rlist().end())
 +    return 0;
 +
 +  return it->iofunc;
 +}
 +
 +/*! 
 +  Returns the output functor in charge for format and 0 if non-existent. 
 +*/
 +IO::Functor* IO::outputHandler(QString const& format)
 +{
 +  IO::IT it = IO::find(wlist(), format);
 +  
 +  if (it==wlist().end())
 +    return 0;
 +
 +  return it->iofunc;
 +}
 +
 +bool PixmapWriter::operator()(Plot3D* plot, QString const& fname)
 +{
 +  QImage im = plot->grabFrameBuffer(true);
 +  
 +#if QT_VERSION < 0x040000
 +  QImageIO iio;
 +  iio.setImage(im);
 +#else
 +  QImageWriter iio;
 +#endif
 +  iio.setFormat(QWT3DLOCAL8BIT(fmt_));
 +  iio.setQuality(quality_);
 +  iio.setFileName(fname);
 +#if QT_VERSION < 0x040000
 +  return iio.write();
 +#else
 +  return iio.write(im);
 +#endif
 +}
 +
 +//! Calls Qt's QImageIO::setQuality() function.
 +void PixmapWriter::setQuality(int val)
 +{
 +  quality_ = val;  
 +}
 +
 +void IO::setupHandler()
 +{
 +#if QT_VERSION < 0x040000
 +  QStringList list = QImage::outputFormatList();
 +  QStringList::Iterator it = list.begin();
 +#else
 +  QList<QByteArray> list = QImageWriter::supportedImageFormats();
 +  QList<QByteArray>::Iterator it = list.begin();
 +#endif
 +  PixmapWriter qtw;
 +  while( it != list.end() ) 
 +  {
 +    qtw.fmt_ = *it;
 +    defineOutputHandler(*it, qtw);
 +    ++it;
 +  }
 +  VectorWriter vecfunc; 
 +  vecfunc.setCompressed(false);
 +  vecfunc.setFormat("EPS");
 +  defineOutputHandler("EPS", vecfunc);
 +  vecfunc.setFormat("PS");
 +  defineOutputHandler("PS", vecfunc);
 +  
 +#ifdef GL2PS_HAVE_ZLIB
 +  vecfunc.setCompressed(true);
 +  vecfunc.setFormat("EPS_GZ");
 +  defineOutputHandler("EPS_GZ", vecfunc);
 +  vecfunc.setFormat("PS_GZ");
 +  defineOutputHandler("PS_GZ", vecfunc);
 +#endif
 +  vecfunc.setFormat("PDF");
 +  defineOutputHandler("PDF", vecfunc);
 +
 +  defineInputHandler("mes", NativeReader());
 +  defineInputHandler("MES", NativeReader());
 +}
 +
 +/*!
 +	\deprecated  Use Plot3D::save or IO::save instead.
 +	
 +  Writes vector data supported by gl2ps. The corresponding format types are "EPS","PS"or "PDF".
 +  If zlib has been configured this will be extended by "EPS_GZ" and "PS_GZ". 
 +	\b Beware: BSPSORT turns out to behave very slowly and memory consuming, especially in cases where
 +	many polygons appear. It is still more exact than SIMPLESORT.
 +*/
 +bool Plot3D::saveVector(QString const& fileName, QString const& format, VectorWriter::TEXTMODE text, VectorWriter::SORTMODE sortmode)
 +{
 +  if (format == "EPS" || format == "EPS_GZ" || format == "PS" 
 +    || format == "PS_GZ" || format == "PDF")
 +  {  
 +    VectorWriter* gl2ps = (VectorWriter*)IO::outputHandler(format);
 +    if (gl2ps)
 +    {
 +      gl2ps->setSortMode(sortmode);
 +      gl2ps->setTextMode(text);
 +    }
 +    return IO::save(this, fileName, format);
 +  }
 +  return false;
 +}	
 +/*!
 +	\deprecated  Use Plot3D::save or IO::save instead.
 +  
 +  Saves the framebuffer to the file fileName using one of the image file formats supported by Qt.
 +*/
 +bool Plot3D::savePixmap(QString const& fileName, QString const& format)
 +{
 +  if (format == "EPS" || format == "EPS_GZ" || format == "PS" 
 +    || format == "PS_GZ" || format == "PDF")
 +    return false;
 +  
 +  return IO::save(this, fileName, format);
 +}
 +
 +/*! 
 +  Saves content in one of the registered output formats. To modify the 
 +  behaviour for more complex output handling use IO::outputHandler.
 +*/
 +bool Plot3D::save(QString const& fileName, QString const& format)
 +{
 +  return IO::save(this, fileName, format);
 +}
 +
 diff --git a/lib/tqwtplot3d/src/qwt3d_io_gl2ps.cpp b/lib/tqwtplot3d/src/qwt3d_io_gl2ps.cpp new file mode 100644 index 0000000..be94e51 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_io_gl2ps.cpp @@ -0,0 +1,387 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include <time.h>
 +#include "qwt3d_openglhelper.h"
 +#include "../3rdparty/gl2ps/gl2ps.h"
 +#include "qwt3d_io_gl2ps.h"
 +#include "qwt3d_plot.h"
 +
 +using namespace Qwt3D;
 +
 +//! Provides a new VectorWriter object. 
 +IO::Functor* VectorWriter::clone() const
 +{
 +  return new VectorWriter(*this);
 +}
 +  
 +VectorWriter::VectorWriter() 
 +    : gl2ps_format_(GL2PS_EPS), 
 +    formaterror_(false),
 +#ifdef GL2PS_HAVE_ZLIB
 +    compressed_(true),
 +#else
 +    compressed_(false),
 +#endif
 +    sortmode_(SIMPLESORT),
 +    landscape_(VectorWriter::AUTO),
 +    textmode_(VectorWriter::PIXEL),
 +    texfname_("")
 +  {}
 +
 +  
 +/*!
 +  Sets the mode for text output:\n
 +  \param val The underlying format for the generated output:\n
 +  PIXEL - poor quality but exact positioning\n
 +  NATIVE - high quality but inexact positioning\n
 +  TEX - high quality and exact positioning, arbitrary TeX strings as content for
 +  the saved labels are possible. The disadvantage is the need for an additionally TeX run
 +  to get the final output.\n
 +  \param fname Optional, used only in conjunction with TeX output; file name
 +  for the generated TeX file. If not set, a file called "OUTPUT.FOR.tex" 
 +  will be generated, where "OUTPUT.FOR" describes the file name argument for IO::save().\n\n
 +  (04/05/27: On Linux platforms, pdflatex seems a file named 'dump_0.pdf.tex' mistakenly to 
 +  identify as PDF file.)
 +*/
 +void VectorWriter::setTextMode(TEXTMODE val, QString fname)
 +{
 +  textmode_ = val;
 +  texfname_ = (fname.isEmpty()) ? QString("") : fname;
 +}
 +
 +
 +#ifdef GL2PS_HAVE_ZLIB
 +//! Turns compressed output on or off (no effect if zlib support has not been set)
 +void VectorWriter::setCompressed(bool val)
 +{
 +  compressed_ = val;
 +}
 +#else
 +//! Turns compressed output on or off (no effect if zlib support has not been set)
 +void VectorWriter::setCompressed(bool)
 +{
 +  compressed_ = false;
 +}
 +#endif
 +
 +
 +/*! 
 +Set output format, must be one of "EPS_GZ", "PS_GZ", "EPS", 
 +"PS", "PDF" (case sensitive)
 +*/
 +bool VectorWriter::setFormat(QString const& format)
 +{
 +	if (format == QString("EPS"))
 +	{
 +		gl2ps_format_ = GL2PS_EPS;
 +	}
 +	else if (format == QString("PS"))
 +	{
 +		gl2ps_format_ = GL2PS_PS;
 +	}
 +	else if (format == QString("PDF"))
 +	{
 +		gl2ps_format_ = GL2PS_PDF;
 +	}
 +#ifdef GL2PS_HAVE_ZLIB
 +	else if (format == QString("EPS_GZ"))
 +	{
 +		gl2ps_format_ = GL2PS_EPS;
 +	}
 +	else if (format == QString("PS_GZ"))
 +	{
 +		gl2ps_format_ = GL2PS_PS;
 +	}
 +#endif
 +	else
 +	{
 +    formaterror_ = true;
 +		return false;
 +	}
 +  formaterror_ = false;
 +  return true;
 +}
 +
 +//! Performs actual output
 +bool VectorWriter::operator()(Plot3D* plot, QString const& fname)
 +{
 +  if (formaterror_)
 +    return false;
 +
 +  plot->makeCurrent();
 + 	
 +
 +	GLint bufsize = 0, state = GL2PS_OVERFLOW;
 +	GLint viewport[4];
 +
 +	glGetIntegerv(GL_VIEWPORT, viewport);
 +
 +	GLint options = GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | GL2PS_DRAW_BACKGROUND |
 +										 GL2PS_OCCLUSION_CULL | GL2PS_BEST_ROOT;
 +
 +
 +  if (compressed_)
 +    options |= GL2PS_COMPRESS;
 +
 +  switch (landscape_) 
 +  {
 +    case VectorWriter::AUTO:
 +  	  if (viewport[2] - viewport[0] > viewport[3] - viewport[0])
 +        options |= GL2PS_LANDSCAPE;
 +      break;
 +    case VectorWriter::ON:
 +      options |= GL2PS_LANDSCAPE;
 +  	  break;
 +    default:
 +      break;
 +  }
 +  
 +  int sortmode = GL2PS_SIMPLE_SORT;
 +  switch (sortmode_) 
 +  {
 +    case VectorWriter::NOSORT:
 +      sortmode = GL2PS_NO_SORT;
 +      break;
 +    case VectorWriter::SIMPLESORT:
 +      sortmode = GL2PS_SIMPLE_SORT;
 +  	  break;
 +    case VectorWriter::BSPSORT:
 +      sortmode = GL2PS_BSP_SORT;
 +  	  break;
 +    default:
 +      break;
 +  }
 +  
 +  switch (textmode_) 
 +  {
 +    case NATIVE:
 +      Label::useDeviceFonts(true);
 +  	  break;
 +    case PIXEL:
 +      Label::useDeviceFonts(false);
 +  	  break;
 +    case TEX:
 +		  options |= GL2PS_NO_PIXMAP | GL2PS_NO_TEXT;
 +  	  break;
 +    default:
 +      break;
 +  }
 +  
 +	QString version = QString::number(QWT3D_MAJOR_VERSION) + "."
 +		+ QString::number(QWT3D_MINOR_VERSION) + "."
 +		+ QString::number(QWT3D_PATCH_VERSION); 
 +	    
 +	QString producer = QString("QwtPlot3D ") + version + 
 +		" (beta) , (C) 2002";
 +
 +  // calculate actual year
 +  time_t now;
 +  struct tm *newtime;
 +  time(&now);
 +  newtime = gmtime(&now);
 +	if (newtime && newtime->tm_year + 1900 > 2002)
 +	  producer += "-" + QString::number(newtime->tm_year+1900); 
 +
 +  producer += " Micha Bieber <krischnamurti@users.sourceforge.net>";
 +
 +	FILE *fp = fopen(QWT3DLOCAL8BIT(fname), "wb");	
 +	if (!fp)
 +  {
 +    Label::useDeviceFonts(false);
 +		return false;
 +  }
 +  while( state == GL2PS_OVERFLOW )
 +	{ 
 +		bufsize += 2*1024*1024;
 +		gl2psBeginPage ( "---", QWT3DLOCAL8BIT(producer), viewport,
 +										 gl2ps_format_, sortmode,
 +										 options, GL_RGBA, 0, NULL, 0, 0, 0, bufsize,
 +										 fp, QWT3DLOCAL8BIT(fname) );
 +		
 +	  plot->updateData();
 +	  plot->updateGL(); 
 +		state = gl2psEndPage();
 +	}
 +	fclose(fp);
 +
 +  // extra TeX file
 +  if (textmode_ == TEX)
 +  {
 +    QString fn = (texfname_.isEmpty()) 
 +      ? fname + ".tex"
 +      : texfname_;
 +
 +    fp = fopen(QWT3DLOCAL8BIT(fn), "wb");	
 +    if (!fp)
 +    {
 +      Label::useDeviceFonts(false);
 +      return false;
 +    }    
 +    Label::useDeviceFonts(true);
 +		options &= ~GL2PS_NO_PIXMAP & ~GL2PS_NO_TEXT;
 +    state = GL2PS_OVERFLOW;
 +    while( state == GL2PS_OVERFLOW )
 +    { 
 +      bufsize += 2*1024*1024;
 +      gl2psBeginPage ( "---", QWT3DLOCAL8BIT(producer), viewport,
 +        GL2PS_TEX, sortmode,
 +        options, GL_RGBA, 0, NULL, 0, 0, 0, bufsize,
 +        fp, QWT3DLOCAL8BIT(fn) );
 +      
 +      plot->updateData();
 +      plot->updateGL(); 
 +      state = gl2psEndPage();
 +    }
 +    fclose(fp);
 +  }
 +
 +
 +  Label::useDeviceFonts(false);
 +
 +	return true;
 +}	    
 +
 +
 +// moved
 +
 +GLint Qwt3D::setDeviceLineWidth(GLfloat val)
 +{
 +	if (val<0) 
 +		val=0;
 +
 +	GLint ret = gl2psLineWidth(val);
 +
 +	GLfloat lw[2];
 +	glGetFloatv(GL_LINE_WIDTH_RANGE, lw);
 +	
 +	if (val < lw[0])
 +		val = lw[0];
 +	else if (val > lw[1])
 +		val = lw[1];
 +
 +	glLineWidth(val);
 +	return ret;
 +}
 +
 +GLint Qwt3D::setDevicePointSize(GLfloat val)
 +{
 +	if (val<0) 
 +		val=0;
 +
 +	GLint ret = gl2psPointSize(val);
 +
 +	GLfloat lw[2];
 +	glGetFloatv(GL_POINT_SIZE_RANGE, lw);
 +	
 +	if (val < lw[0])
 +		val = lw[0];
 +	else if (val > lw[1])
 +		val = lw[1];
 +
 +	glPointSize(val);
 +	return ret;
 +}
 +
 +GLint Qwt3D::drawDevicePixels(GLsizei width, GLsizei height,
 +                       GLenum format, GLenum type,
 +                       const void *pixels)
 +{
 +  glDrawPixels(width, height, format, type, pixels);
 +
 +  if(format != GL_RGBA || type != GL_UNSIGNED_BYTE)
 +		return GL2PS_ERROR;
 +	
 +	GLfloat* convertedpixel = (GLfloat*)malloc(3 * width * height * sizeof(GLfloat));
 +	if (!convertedpixel)
 +		return GL2PS_ERROR;
 +	
 +	GLubyte* px = (GLubyte*)pixels; 
 +	for (int i=0; i!=3*width*height; i+=3)
 +	{
 +		int pxi = (4*i)/3;
 +		convertedpixel[i] = px[pxi] / float(255);
 +		convertedpixel[i+1] = px[pxi+1] / float(255);
 +		convertedpixel[i+2] = px[pxi+2] / float(255);
 +	}
 +	GLint ret = gl2psDrawPixels(width, height, 0, 0, GL_RGB, GL_FLOAT, convertedpixel);
 +	free(convertedpixel);
 +	return ret;
 +}
 +
 +GLint Qwt3D::drawDeviceText(const char* str, const char* fontname, int fontsize, Triple pos, RGBA /*rgba*/, ANCHOR align, double gap)
 +{
 +	double vp[3];
 +
 +	World2ViewPort(vp[0], vp[1], vp[2], pos.x, pos.y, pos.z);
 +	Triple start(vp[0],vp[1],vp[2]);
 +
 +	GLdouble fcol[4];
 +	glGetDoublev(GL_CURRENT_COLOR, fcol);
 +	GLdouble bcol[4];
 +	glGetDoublev(GL_COLOR_CLEAR_VALUE, bcol);
 +	
 +//	glColor4d(color.r, color.g, color.b, color.a);
 +//		glClearColor(color.r, color.g, color.b, color.a);
 +
 +	GLint ret = GL2PS_SUCCESS;
 +
 +	GLint a = GL2PS_TEXT_BL;
 +	switch(align)
 +	{
 +		case Center:
 +			a = GL2PS_TEXT_C;
 +			break;
 +		case CenterLeft:
 +			a = GL2PS_TEXT_CL;
 +			start += Triple(gap,0,0);
 +			break;
 +		case CenterRight:
 +			a = GL2PS_TEXT_CR;
 +			start += Triple(-gap,0,0);
 +			break;
 +		case BottomCenter:
 +			a = GL2PS_TEXT_B;
 +			start += Triple(0,gap,0);
 +			break;
 +		case BottomLeft:
 +			a = GL2PS_TEXT_BL;
 +			start += Triple(gap,gap,0);
 +			break;
 +		case BottomRight:
 +			a = GL2PS_TEXT_BR;
 +			start += Triple(-gap,gap,0);
 +			break;
 +		case TopCenter:
 +			a = GL2PS_TEXT_T;
 +			start += Triple(0,-gap,0);
 +			break;
 +		case TopLeft:
 +			a = GL2PS_TEXT_TL;
 +			start += Triple(gap,-gap,0);
 +			break;
 +		case TopRight:
 +			a = GL2PS_TEXT_TR;
 +			start += Triple(-gap,-gap,0);
 +			break;
 +		default:
 +			break;
 +	}
 +	
 +	ViewPort2World(vp[0], vp[1], vp[2], start.x, start.y, start.z);
 +	Triple adjpos(vp[0],vp[1],vp[2]);
 +	
 +	glRasterPos3d(adjpos.x, adjpos.y, adjpos.z);
 +	ret = gl2psTextOpt(str, fontname, (int)fontsize, a, 0);
 +	glColor4dv(fcol);
 +	glClearColor(bcol[0], bcol[1], bcol[2], bcol[3]);
 +  return ret;
 +}
 +
 +void Qwt3D::setDevicePolygonOffset(GLfloat factor, GLfloat units)
 +{
 +	glPolygonOffset(factor, units);
 +	gl2psEnable(GL2PS_POLYGON_OFFSET_FILL);
 +}
 +
 diff --git a/lib/tqwtplot3d/src/qwt3d_io_reader.cpp b/lib/tqwtplot3d/src/qwt3d_io_reader.cpp new file mode 100644 index 0000000..2cc57a7 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_io_reader.cpp @@ -0,0 +1,225 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include <float.h>
 +#include <stdio.h>
 +#include <qtextstream.h>
 +
 +#include "qwt3d_surfaceplot.h"
 +#include "qwt3d_io_reader.h"
 +
 +using namespace std;
 +using namespace Qwt3D;
 +
 +const char* NativeReader::magicstring = "jk:11051895-17021986";
 +
 +namespace
 +{
 +	FILE* open(QString fname)
 +	{
 +		FILE* file = fopen(QWT3DLOCAL8BIT(fname), "r");
 +		if (!file) 
 +		{
 +			fprintf(stderr, "NativeReader::read: cannot open data file \"%s\"\n", QWT3DLOCAL8BIT(fname));
 +		}
 +		return file;
 +	}
 +
 +  int read_char (FILE * fp, bool skipcomments = true)
 +  {
 +    int c;
 +  
 +    if ((c = fgetc (fp)) == EOF)
 +      return (c);
 +    if (skipcomments)
 +		{
 +			if (c == '#')
 +			{
 +				do
 +				{
 +					if ((c = fgetc (fp)) == EOF)
 +						return (c);
 +				}
 +				while (c != '\n' && c != '\r');
 +			}
 +		}
 +    return (c);
 +  }
 +
 +  char* read_field (FILE * fp, bool skipcomments = true)
 +  {
 +    static char buf[71];
 +    int c, i;
 +  
 +    do
 +    {
 +      if ((c = read_char (fp,skipcomments)) == EOF)
 +        return (NULL);
 +    }
 +    while (isspace (c));
 +    for (i = 0; i < 70 && !isspace (c); ++i)
 +    {
 +      buf[i] = c;
 +      if ((c = read_char (fp,skipcomments)) == EOF)
 +        break;
 +    }
 +    buf[i] = '\0';
 +    return (buf);
 +  }
 +
 +
 +  //! set to data begin
 +  bool extract_info(FILE* fp, unsigned int& xmesh, unsigned int& ymesh, double& xmin, double& xmax, double& ymin, double& ymax)
 +  {
 +    char* p;
 +  
 +    // find out the size
 +    if ((p = read_field (fp)) == 0)
 +      return false;
 +    xmesh = (unsigned int)atoi(p);
 +
 +    if ((p = read_field (fp)) == 0)
 +      return false;
 +    ymesh = (unsigned int)atoi (p);
 +
 +    if (xmesh < 1 || ymesh < 1)
 +      return false;
 +    
 +		// ... and the limits
 +    if ((p = read_field (fp)) == 0)
 +      return false;
 +    xmin = atof (p);
 +
 +    if ((p = read_field (fp)) == 0)
 +      return false;
 +    xmax = atof (p);
 +    
 +		if ((p = read_field (fp)) == 0)
 +      return false;
 +    ymin = atof (p);
 +
 +    if ((p = read_field (fp)) == 0)
 +      return false;
 +    ymax = atof (p);
 +
 +    if (xmin > xmax || ymin > ymax)
 +      return false;
 +
 +    return true;
 +  }
 +
 +  //! find out what the magic string is and compare
 +	bool check_magic(FILE* fp, const char* val)
 +	{
 +    char* p;
 +    if ((p = read_field (fp,false)) == 0)
 +        return false;
 +  
 +    if (strcmp (p, val ) != 0)
 +        return false;	
 +		return true;
 +	}
 +
 +	//! find out what the type is
 +	bool check_type(FILE* fp, const char* val)
 +	{
 +    char* p;
 +    if ((p = read_field (fp)) == 0)
 +        return false;
 +  
 +    if (strcmp (p, val ) != 0)
 +        return false;	
 +		return true;
 +	}
 +
 +	double** allocateData(int columns, int rows)
 +	{
 + 		double** data         = new double* [columns] ;
 + 
 +		for ( int i = 0; i < columns; ++i) 
 +		{
 +			data[i]         = new double [rows];
 +		}
 +		return data;
 +	}
 +
 +	void deleteData(double**data, int columns)
 +	{
 +		for ( int i = 0; i < columns; i++) 
 +		{
 +			delete [] data[i];
 +		}
 +		delete [] data;
 +	}
 +}
 +
 +NativeReader::NativeReader()
 +: minz_(-DBL_MAX), maxz_(DBL_MAX) 
 +{
 +}
 +
 +bool NativeReader::collectInfo(FILE*& file, QString const& fname, unsigned& xmesh, unsigned& ymesh, 
 +															 double& minx, double& maxx, double& miny, double& maxy)
 +{
 +	if (fname.isEmpty())
 +		return false;
 +	
 +	file = open(fname);
 +	
 +	if (!file)
 +		return false;
 +	
 +	
 +	if (
 +				(!check_magic(file, magicstring))
 +			||(!check_type(file, "MESH"))
 +			||(!extract_info(file, xmesh, ymesh, minx, maxx, miny, maxy))
 +		 )
 +	{
 +		fclose(file);
 +		return false;
 +	}
 + 
 +	return true;
 +}
 +
 +
 +bool NativeReader::operator()(Plot3D* plot, QString const& fname)
 +{
 +	
 +	FILE* file;
 +	unsigned int xmesh, ymesh;
 +	double minx, maxx, miny, maxy;
 +	
 +	if ( !collectInfo(file, fname, xmesh, ymesh, minx, maxx, miny, maxy) )
 +		return false;
 +	
 +	/* allocate some space for the mesh */
 + 	double** data = allocateData(xmesh, ymesh);
 +
 +	for (unsigned int j = 0; j < ymesh; j++) 
 +	{
 +    for (unsigned int i = 0; i < xmesh; i++) 
 +		{
 +      if (fscanf(file, "%lf", &data[i][j]) != 1) 
 +			{
 +				fprintf(stderr, "NativeReader::read: error in data file \"%s\"\n", QWT3DLOCAL8BIT(fname));
 +				return false;
 +      }
 +
 +			if (data[i][j] > maxz_)
 +				data[i][j] = maxz_;
 +			else if (data[i][j] < minz_)
 +				data[i][j] = minz_;
 +    }
 +  }
 +
 +  /* close the file */
 +  fclose(file);
 +
 +	((SurfacePlot*)plot)->loadFromData(data, xmesh, ymesh, minx, maxx, miny, maxy);
 +	deleteData(data,xmesh);
 +
 +	return true;
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_label.cpp b/lib/tqwtplot3d/src/qwt3d_label.cpp new file mode 100644 index 0000000..eb8b8c0 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_label.cpp @@ -0,0 +1,262 @@ +#include <qbitmap.h>
 +#include "qwt3d_label.h"
 +
 +using namespace Qwt3D;
 +
 +bool Label::devicefonts_ = false;
 +
 +Label::Label()
 +{
 +	init();
 +}
 +
 +Label::Label(const QString & family, int pointSize, int weight, bool italic)
 +{
 +	init(family, pointSize, weight, italic);
 +}
 +
 +
 +void Label::init(const QString & family, int pointSize, int weight, bool italic)
 +{
 +	init();
 +	font_ = QFont(family, pointSize, weight, italic );
 +}
 +
 +void Label::init()
 +{
 +	beg_ = Triple(0.0, 0.0, 0.0);
 +	end_ = beg_;
 +	pos_ = beg_;
 +	setColor(0,0,0);
 +	pm_ = QPixmap(0, 0);
 +	font_ = QFont();
 +	anchor_ = BottomLeft;
 +	gap_ = 0;
 +	flagforupdate_ = true;
 +}
 +
 +void Label::useDeviceFonts(bool val)
 +{
 +	devicefonts_ = val;
 +}
 +
 +void Label::setFont(const QString & family, int pointSize, int weight, bool italic)
 +{
 +	font_ = QFont(family, pointSize, weight, italic );
 +	flagforupdate_ = true;
 +}
 +
 +void Label::setString(QString const& s)
 +{
 +  text_ = s;
 +	flagforupdate_ = true;
 +}
 +
 +void Label::setColor(double r, double g, double b, double a)
 +{
 +  Drawable::setColor(r,g,b,a);
 +  flagforupdate_ = true;
 +}	
 +
 +void Label::setColor(Qwt3D::RGBA rgba)
 +{
 +  Drawable::setColor(rgba);
 +  flagforupdate_ = true;
 +}
 +
 +/**
 +example:
 +
 +\verbatim
 +
 +   Anchor TopCenter (*)  resp. BottomRight(X) 
 +
 +   +----*----+
 +   |  Pixmap |
 +   +---------X
 +
 +\endverbatim
 +*/
 +void Label::setPosition(Triple pos, ANCHOR a)
 +{
 +	anchor_ = a;
 +	pos_ = pos;
 +}
 +
 +void Label::setRelPosition(Tuple rpos, ANCHOR a)
 +{
 +	double ot = 0.99;
 +
 +	getMatrices(modelMatrix, projMatrix, viewport);
 +	beg_ = relativePosition(Triple(rpos.x, rpos.y, ot));
 +	setPosition(beg_, a);	
 +}
 +
 +void Label::update()
 +{
 +	QPainter p;
 +	QFontMetrics fm(font_);
 +
 +  QFontInfo info(font_);
 +
 +  QRect r = 	QRect(QPoint(0,0),fm.size(Qwt3D::SingleLine, text_));//fm.boundingRect(text_)  misbehaviour under linux;
 +  
 +#if QT_VERSION < 0x040000
 + 		r.moveBy(0, -r.top());
 +#else
 + 		r.translate(0, -r.top());
 +#endif
 +	
 +	pm_ = QPixmap(r.width(), r.bottom());
 +
 +	if (pm_.isNull()) // else crash under linux
 +	{
 +		r = 	QRect(QPoint(0,0),fm.size(Qwt3D::SingleLine, QString(" "))); // draw empty space else //todo
 +#if QT_VERSION < 0x040000
 + 		r.moveBy(0, -r.top());
 +#else
 + 		r.translate(0, -r.top());
 +#endif
 +		pm_ = QPixmap(r.width(), r.bottom());		
 +	}
 +	
 +	QBitmap bm(pm_.width(),pm_.height());
 +  bm.fill(Qt::color0);
 +	p.begin( &bm );
 +		p.setPen(Qt::color1);
 +		p.setFont(font_);
 +		p.drawText(0,r.height() - fm.descent() -1 , text_);
 +	p.end();
 +
 +	pm_.setMask(bm);
 +  
 +  // avoids uninitialized areas in some cases
 +#if QT_VERSION < 0x040000
 +	pm_.fill();
 +#endif
 +	p.begin( &pm_ );
 +	  p.setFont( font_ );
 +	  p.setPen( Qt::SolidLine );
 +	  p.setPen( GL2Qt(color.r, color.g, color.b) );
 +
 +	  p.drawText(0,r.height() - fm.descent() -1 , text_);
 +	p.end();
 +#if QT_VERSION < 0x040000
 +  buf_ = pm_.convertToImage();
 +#else
 +  buf_ = pm_.toImage();
 +#endif
 +	tex_ = QGLWidget::convertToGLFormat( buf_ );	  // flipped 32bit RGBA ?		
 +}
 +
 +/**
 +Adds an additional shift to the anchor point. This happens in a more or less intelligent manner
 +depending on the nature of the anchor:
 +\verbatim
 +anchor type         shift
 +
 +left aligned         -->
 +right aligned        <--
 +top aligned          top-down            
 +bottom aligned       bottom-up
 +\endverbatim
 +The unit is user space dependend (one pixel on screen - play around to get satisfying results)
 +*/
 +void Label::adjust(int gap)
 +{
 +	gap_ = gap;
 +}
 +
 +void Label::convert2screen()
 +{
 +	Triple start = World2ViewPort(pos_);
 +	
 +	switch (anchor_)
 +	{
 +		case BottomLeft :
 +			beg_ = pos_;
 +			break;
 +		case BottomRight:
 +			beg_ = ViewPort2World(start - Triple(width() + gap_, 0, 0));
 +			break;
 +		case BottomCenter:
 +			beg_ = ViewPort2World(start - Triple(width() / 2, -gap_, 0));
 +			break;
 +		case TopRight:
 +			beg_ = ViewPort2World(start - Triple(width() + gap_, height(), 0));
 +			break;
 +		case TopLeft:
 +			beg_ = ViewPort2World(start - Triple(-gap_, height(), 0));
 +			break;
 +		case TopCenter:
 +			beg_ = ViewPort2World(start - Triple(width() / 2, height() + gap_, 0));
 +			break;
 +		case CenterLeft:
 +			beg_ = ViewPort2World(start - Triple(-gap_, height() / 2, 0));
 +			break;
 +		case CenterRight:
 +			beg_ = ViewPort2World(start - Triple(width() + gap_, height() / 2, 0));
 +			break;
 +		case Center:
 +			beg_ = ViewPort2World(start - Triple(width() / 2, height() / 2, 0));
 +			break;
 +		default:
 +			break;
 +	}
 +	start = World2ViewPort(beg_);
 +	end_ = ViewPort2World(start + Triple(width(), height(), 0));	
 +}
 +
 +void Label::draw()
 +{
 +	if (flagforupdate_)
 +	{
 +		update();
 +		flagforupdate_ = false;
 +	}
 +
 +	if (buf_.isNull())
 +		return;
 +		
 +	GLboolean b;
 +	GLint func;
 +	GLdouble v;
 +	glGetBooleanv(GL_ALPHA_TEST, &b);
 +	glGetIntegerv(GL_ALPHA_TEST_FUNC, &func);
 +	glGetDoublev(GL_ALPHA_TEST_REF, &v);
 +	
 +	glEnable (GL_ALPHA_TEST);
 +  glAlphaFunc (GL_NOTEQUAL, 0.0);
 +	
 +	convert2screen();
 +	glRasterPos3d(beg_.x, beg_.y, beg_.z);
 + 
 +	
 +	int w = tex_.width();
 +	int h = tex_.height();
 + 
 +	if (devicefonts_)
 +	{		
 +		drawDeviceText(QWT3DLOCAL8BIT(text_), "Courier", font_.pointSize(), pos_, color, anchor_, gap_);
 +	}
 +	else
 +	{
 +		drawDevicePixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());
 +//    glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());	
 +	}
 +
 +
 +	glAlphaFunc(func,v);
 +	Enable(GL_ALPHA_TEST, b);
 +}
 +
 +
 +double Label::width() const 
 +{ 
 +	return pm_.width(); 
 +}
 +
 +double Label::height() const 
 +{ 
 +	return pm_.height(); 
 +}	
 diff --git a/lib/tqwtplot3d/src/qwt3d_lighting.cpp b/lib/tqwtplot3d/src/qwt3d_lighting.cpp new file mode 100644 index 0000000..2f368a0 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_lighting.cpp @@ -0,0 +1,192 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4305 )
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include <float.h>
 +#include "qwt3d_plot.h"
 +
 +using namespace Qwt3D;
 +
 +namespace {
 +inline GLenum lightEnum(unsigned idx)
 +{
 +  switch(idx) {
 +  case 0:
 +  	return GL_LIGHT0;
 +  case 1:
 +  	return GL_LIGHT1;
 +  case 2:
 +  	return GL_LIGHT2;
 +  case 3:
 +  	return GL_LIGHT3;
 +  case 4:
 +  	return GL_LIGHT4;
 +  case 5:
 +  	return GL_LIGHT5;
 +  case 6:
 +  	return GL_LIGHT6;
 +  case 7:
 +  	return GL_LIGHT7;
 +  default:
 +  	return GL_LIGHT0;
 +  }
 +}
 +
 +}
 +
 +void Plot3D::enableLighting(bool val)
 +{
 +  if (lighting_enabled_ == val)
 +    return;
 +  
 +  lighting_enabled_ = val;
 +  makeCurrent();
 +  if (val)
 +    glEnable(GL_LIGHTING);
 +  else
 +    glDisable(GL_LIGHTING);
 +
 +  if (!initializedGL())
 +    return;
 +  updateGL();
 +}
 +
 +void Plot3D::disableLighting(bool val)
 +{
 +  enableLighting(!val);
 +}
 +
 +bool Plot3D::lightingEnabled() const
 +{
 +  return lighting_enabled_;
 +}
 +
 +/** 
 +  \param light light number [0..7]
 +  \see setLight 
 +*/
 +void Plot3D::illuminate(unsigned light)
 +{
 +  if (light>7)
 +    return;  
 +  lights_[light].unlit = false;  
 +}
 +/**
 +  \param light light number [0..7]
 +  \see setLight  
 +*/
 +void Plot3D::blowout(unsigned light)
 +{
 +  if (light>7)
 +    return;
 +  lights_[light].unlit = false;  
 +}
 +
 +/** 
 +  Sets GL material properties
 +*/
 +void Plot3D::setMaterialComponent(GLenum property, double r, double g, double b, double a)
 +{
 +  GLfloat rgba[4] = {(GLfloat)r, (GLfloat)g, (GLfloat)b, (GLfloat)a};
 +  makeCurrent();
 +  glMaterialfv(GL_FRONT_AND_BACK, property, rgba);  
 +}    
 +
 +/** 
 +  This function is for convenience. It sets GL material properties with the equal r,g,b values 
 +  and a blending alpha with value 1.0 
 +*/
 +void Plot3D::setMaterialComponent(GLenum property, double intensity)
 +{
 +  setMaterialComponent(property,intensity,intensity,intensity,1.0);
 +}    
 +
 +/** 
 +  Sets GL shininess
 +*/
 +void Plot3D::setShininess(double exponent)
 +{
 +  makeCurrent();
 +  glMaterialf(GL_FRONT, GL_SHININESS, exponent);
 +}
 +
 +/** 
 +  Sets GL light properties for light 'light'
 +*/
 +void Plot3D::setLightComponent(GLenum property, double r, double g, double b, double a, unsigned light)
 +{
 +  GLfloat rgba[4] = {(GLfloat)r, (GLfloat)g, (GLfloat)b, (GLfloat)a};
 +  makeCurrent();
 +  glLightfv(lightEnum(light), property, rgba);
 +}    
 +
 +/** 
 +  This function is for convenience. It sets GL light properties with the equal r,g,b values 
 +  and a blending alpha with value 1.0 
 +*/
 +void Plot3D::setLightComponent(GLenum property, double intensity, unsigned light)
 +{
 +  setLightComponent(property,intensity,intensity,intensity,1.0, lightEnum(light));
 +}    
 +
 +/**
 +  Set the rotation angle of the light source. If you look along the respective axis towards ascending values,
 +	the rotation is performed in mathematical \e negative sense 
 +	\param xVal angle in \e degree to rotate around the X axis
 +	\param yVal angle in \e degree to rotate around the Y axis
 +	\param zVal angle in \e degree to rotate around the Z axis
 +  \param light light number
 +*/
 +void Plot3D::setLightRotation( double xVal, double yVal, double zVal, unsigned light )
 +{
 +	if (light>7)
 +    return; 
 +  lights_[light].rot.x = xVal;
 +  lights_[light].rot.y = yVal;
 +  lights_[light].rot.z = zVal;
 +}
 +
 +/**
 +  Set the shift in light source (world) coordinates.
 +	\param xVal shift along (world) X axis
 +	\param yVal shift along (world) Y axis
 +	\param zVal shift along (world) Z axis
 +  \param light light number
 +	\see setViewportShift()
 +*/
 +void Plot3D::setLightShift( double xVal, double yVal, double zVal, unsigned light )
 +{
 +	if (light>7)
 +    return; 
 +  lights_[light].shift.x = xVal;
 +  lights_[light].shift.y = yVal;
 +  lights_[light].shift.z = zVal;
 +}
 +
 +void Plot3D::applyLight(unsigned light)
 +{
 +	if (lights_[light].unlit)
 +    return;
 +
 +  glEnable(lightEnum(light));
 +  glLoadIdentity();
 +  
 +  glRotatef( lights_[light].rot.x-90, 1.0, 0.0, 0.0 ); 
 +  glRotatef( lights_[light].rot.y   , 0.0, 1.0, 0.0 ); 
 +  glRotatef( lights_[light].rot.z   , 0.0, 0.0, 1.0 );
 +  GLfloat lightPos[4] = { lights_[light].shift.x, lights_[light].shift.y, lights_[light].shift.z, 1.0};
 +  GLenum le = lightEnum(light);
 +  glLightfv(le, GL_POSITION, lightPos);  
 +}
 +
 +void Plot3D::applyLights()
 +{
 +  glMatrixMode( GL_MODELVIEW );
 +	glPushMatrix();
 +  for (unsigned i=0; i<8; ++i)
 +  {
 +    applyLight(i);
 +  }
 +  glPopMatrix();
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_meshplot.cpp b/lib/tqwtplot3d/src/qwt3d_meshplot.cpp new file mode 100644 index 0000000..0c975fe --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_meshplot.cpp @@ -0,0 +1,320 @@ +#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;
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////
 +//
 +//     cell specific
 +//
 +
 +
 +void SurfacePlot::createDataC()
 +{		
 +	createFloorDataC();
 +  
 +  if (plotStyle() == NOPLOT)
 +    return;
 +
 +  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);
 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +	int idx = 0;
 +	if (plotStyle() != WIREFRAME)
 +	{
 +		glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
 +
 +		bool hl = (plotStyle() == HIDDENLINE);
 +		if (hl)
 +		{
 +			RGBA col = backgroundRGBAColor();
 +			glColor4d(col.r, col.g, col.b, col.a);
 +		}
 +		
 +		for (unsigned i=0; i!=actualDataC_->cells.size(); ++i)
 +		{
 +			glBegin(GL_POLYGON);
 +			for (unsigned j=0; j!=actualDataC_->cells[i].size(); ++j)
 +			{
 +				idx = actualDataC_->cells[i][j];
 +				setColorFromVertexC(idx, hl);
 +				glVertex3d( actualDataC_->nodes[idx].x, actualDataC_->nodes[idx].y, actualDataC_->nodes[idx].z );
 +				glNormal3d( actualDataC_->normals[idx].x, actualDataC_->normals[idx].y, actualDataC_->normals[idx].z );
 +			}
 +			glEnd();
 +		}
 +	}
 +
 +	if (plotStyle() == FILLEDMESH || plotStyle() == WIREFRAME || plotStyle() == HIDDENLINE)
 +	{
 +		glColor4d(meshColor().r, meshColor().g, meshColor().b, meshColor().a);
 +		{
 +			for (unsigned i=0; i!=actualDataC_->cells.size(); ++i)
 +			{
 +				glBegin(GL_LINE_LOOP);
 +				for (unsigned j=0; j!=actualDataC_->cells[i].size(); ++j)
 +				{
 +					idx = actualDataC_->cells[i][j];
 +					glVertex3d( actualDataC_->nodes[idx].x, actualDataC_->nodes[idx].y, actualDataC_->nodes[idx].z );
 +				}
 +				glEnd();
 +			}
 +		}
 +	}
 +}
 +
 +// ci = cell index
 +// cv = vertex index in cell ci
 +void SurfacePlot::setColorFromVertexC(int node, bool skip)
 +{
 +	if (skip)
 +		return;
 +
 +	RGBA col = (*datacolor_p)(
 +		actualDataC_->nodes[node].x, actualDataC_->nodes[node].y, actualDataC_->nodes[node].z);
 +		
 +	glColor4d(col.r, col.g, col.b, col.a);
 +}
 +
 +void SurfacePlot::createFloorDataC()
 +{
 +	switch (floorStyle())
 +	{
 +	case FLOORDATA:
 +		Data2FloorC();
 +		break;
 +	case FLOORISO:
 +		Isolines2FloorC();
 +		break;
 +	default:
 +		break;
 +	}
 +}
 +
 +void SurfacePlot::Data2FloorC()
 +{	
 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +	
 +	double zshift = actualDataC_->hull().minVertex.z;
 +	int idx;
 +
 +	for (unsigned i = 0; i!=actualDataC_->cells.size(); ++i)
 +	{
 +		glBegin(GL_POLYGON);
 +		for (unsigned j=0; j!=actualDataC_->cells[i].size(); ++j)
 +		{
 +			idx = actualDataC_->cells[i][j];
 +			setColorFromVertexC(idx);
 +			glVertex3d( actualDataC_->nodes[idx].x, actualDataC_->nodes[idx].y, zshift );
 +		}
 +		glEnd();
 +	}
 +}
 +
 +void SurfacePlot::Isolines2FloorC()
 +{
 +	if (isolines() <= 0 || actualData_p->empty())
 +		return;
 +
 +	double step = (actualData_p->hull().maxVertex.z - actualData_p->hull().minVertex.z) / isolines();		
 +
 +	RGBA col;
 +
 +	double zshift = actualData_p->hull().minVertex.z;
 +		
 +	TripleField nodes;
 +	TripleField intersection;
 +	
 +	double lambda = 0;
 +	
 +	GLStateBewarer sb2(GL_LINE_SMOOTH, false);
 +
 +	for (int k = 0; k != isolines(); ++k) 
 +	{
 +		double val = zshift + k * step;		
 +				
 +		for (unsigned i=0; i!=actualDataC_->cells.size(); ++i)
 +		{
 +			nodes.clear();
 +			unsigned cellnodes = actualDataC_->cells[i].size();
 +			for (unsigned j=0; j!=cellnodes; ++j)
 +			{
 +				nodes.push_back(actualDataC_->nodes[actualDataC_->cells[i][j]]);
 +			}
 +			
 +			double diff = 0;
 +			for (unsigned m = 0; m!=cellnodes; ++m)
 +			{
 +				unsigned mm = (m+1)%cellnodes;
 +				if ((val>=nodes[m].z && val<=nodes[mm].z) || (val>=nodes[mm].z && val<=nodes[m].z))
 +				{
 +					diff = nodes[mm].z - nodes[m].z;
 +					
 +					if (isPracticallyZero(diff)) // degenerated
 +					{
 +						intersection.push_back(nodes[m]);
 +						intersection.push_back(nodes[mm]);
 +						continue;
 +					}
 +					
 +					lambda =  (val - nodes[m].z) / diff;
 +					intersection.push_back(Triple(nodes[m].x + lambda * (nodes[mm].x-nodes[m].x), nodes[m].y + lambda * (nodes[mm].y-nodes[m].y), val));
 +				}
 +			}
 +
 +			if (!intersection.empty())
 +			{
 +				col = (*datacolor_p)(nodes[0].x,nodes[0].y,nodes[0].z);
 +  			glColor4d(col.r, col.g, col.b, col.a);
 +				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::createNormalsC()
 +{
 +	if (!normals() || actualData_p->empty())
 +		return;
 +
 +	if (actualDataC_->nodes.size() != actualDataC_->normals.size())
 +		return;
 +  Arrow arrow;
 +  arrow.setQuality(normalQuality());
 +
 +	Triple basev, topv, norm;	
 +		
 +	double diag = (actualData_p->hull().maxVertex-actualData_p->hull().minVertex).length() * normalLength();
 +
 +  RGBA col;
 +  arrow.assign(*this);
 +  arrow.drawBegin();
 +	for (unsigned i = 0; i != actualDataC_->normals.size(); ++i) 
 +	{
 +		basev = actualDataC_->nodes[i];
 +		topv = basev + actualDataC_->normals[i];
 +		
 +			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();
 +}
 +
 +/*! 
 +	Convert user (non-rectangular) mesh based data to internal structure.
 +	See also Qwt3D::TripleField and Qwt3D::CellField
 +*/
 +bool SurfacePlot::loadFromData(TripleField const& data, CellField const& poly)
 +{	
 +	actualDataG_->clear();
 +  actualData_p = actualDataC_;
 +		
 +	actualDataC_->nodes = data;
 +	actualDataC_->cells = poly;
 +	actualDataC_->normals = TripleField(actualDataC_->nodes.size());
 +
 +	unsigned i;
 +
 +//  normals for the moment
 +	Triple n, u, v;
 +	for ( i = 0; i < poly.size(); ++i) 
 +	{
 +		if (poly[i].size() < 3)
 +			n = Triple(0,0,0);
 +		else
 +		{
 +			for (unsigned j = 0; j < poly[i].size(); ++j) 
 +			{
 +				unsigned jj = (j+1) % poly[i].size(); 
 +				unsigned pjj = (j) ? j-1 : poly[i].size()-1;
 +				u = actualDataC_->nodes[poly[i][jj]]-actualDataC_->nodes[poly[i][j]];		
 +				v = actualDataC_->nodes[poly[i][pjj]]-actualDataC_->nodes[poly[i][j]];
 +				n = normalizedcross(u,v);
 +				actualDataC_->normals[poly[i][j]] += n;
 +			}
 +		}
 +	}
 +	for ( i = 0; i != actualDataC_->normals.size(); ++i) 
 +	{
 +		actualDataC_->normals[i].normalize();
 +	}  
 +	
 +	ParallelEpiped hull(Triple(DBL_MAX,DBL_MAX,DBL_MAX),Triple(-DBL_MAX,-DBL_MAX,-DBL_MAX));
 +
 +	for (i = 0; i!=data.size(); ++i)
 +	{
 +		if (data[i].x < hull.minVertex.x)
 +			hull.minVertex.x = data[i].x;
 +		if (data[i].y < hull.minVertex.y)
 +			hull.minVertex.y = data[i].y;
 +		if (data[i].z < hull.minVertex.z)
 +			hull.minVertex.z = data[i].z;
 +		
 +		if (data[i].x > hull.maxVertex.x)
 +			hull.maxVertex.x = data[i].x;
 +		if (data[i].y > hull.maxVertex.y)
 +			hull.maxVertex.y = data[i].y;
 +		if (data[i].z > hull.maxVertex.z)
 +			hull.maxVertex.z = data[i].z;
 +	}
 +
 +	actualDataC_->setHull(hull);
 +
 +	updateData();
 +	updateNormals();
 +	createCoordinateSystem();
 +
 +	return true;
 +}	
 +
 +
 diff --git a/lib/tqwtplot3d/src/qwt3d_mousekeyboard.cpp b/lib/tqwtplot3d/src/qwt3d_mousekeyboard.cpp new file mode 100644 index 0000000..800bc06 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_mousekeyboard.cpp @@ -0,0 +1,387 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4305 )
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include "qwt3d_plot.h"
 +
 +using namespace std;
 +using namespace Qwt3D;
 +
 +
 +/**
 +	Standard mouse button Function. Prepares the call to mouseMoveEvent
 +	\see mouseMoveEvent()
 +*/
 +void Plot3D::mousePressEvent( QMouseEvent *e )
 +{
 +	lastMouseMovePosition_ = e->pos();
 +	mpressed_ = true;
 +}
 +
 +/**
 +	Standard mouse button Function. Completes the call to mouseMoveEvent
 +	\see mouseMoveEvent()
 +*/
 +void Plot3D::mouseReleaseEvent( QMouseEvent* )
 +{
 +	mpressed_ = false;
 +}
 +
 +/**
 +	Standard mouse button Function
 +	\see assignMouse()
 +*/
 +void Plot3D::mouseMoveEvent( QMouseEvent *e )
 +{
 +	if (!mpressed_ || !mouseEnabled())
 +  {
 +    e->ignore();
 +		return;
 +  }
 +	
 +#if QT_VERSION < 0x040000
 +	MouseState bstate = e->state();
 +#else
 +  MouseState bstate(e->buttons(),e->modifiers());
 +#endif
 +
 +	QPoint diff = e->pos() - lastMouseMovePosition_;
 +
 +	setRotationMouse(bstate, 3, diff);	
 +	setScaleMouse(bstate, 5, diff);	
 +	setShiftMouse(bstate, 2, diff);	
 +		
 +	lastMouseMovePosition_ = e->pos();
 +}
 +
 +void Plot3D::setRotationMouse(MouseState bstate, double accel, QPoint diff)
 +{
 +	// Rotation
 +	double w = max(1,width());
 +	double h = max(1,height());
 +		
 +	double relx = accel*360 * diff.x() / w; 
 +	double relyz = accel*360 * diff.y() / h; 
 +	
 +	double new_xrot = xRotation();
 +	double new_yrot = yRotation();
 +	double new_zrot = zRotation();
 +	
 +	if ( bstate == xrot_mstate_ )
 +		new_xrot = round(xRotation() + relyz) % 360; 
 +	if ( bstate == yrot_mstate_ )
 +		new_yrot = round(yRotation() + relx) % 360; 
 +	if ( bstate == zrot_mstate_ )
 +		new_zrot = round(zRotation() + relx) % 360; 
 +		
 +	setRotation(new_xrot, new_yrot, new_zrot); 
 +}
 +
 +void Plot3D::setScaleMouse(MouseState bstate, double accel, QPoint diff)
 +{
 +	// Scale
 +		double w = max(1,width());
 +		double h = max(1,height());
 +
 +		double relx = diff.x() * accel / w; relx = exp(relx) - 1;
 +		double relyz = diff.y() * accel / h; relyz = exp(relyz) - 1; 
 +
 +		double new_xscale = xScale();
 +		double new_yscale = yScale();
 +		double new_zscale = zScale();
 +
 +		if ( bstate == xscale_mstate_)
 +			new_xscale = max(0.0,xScale() + relx);
 +		if ( bstate == yscale_mstate_)
 +			new_yscale = max(0.0,yScale() - relyz);
 +		if ( bstate == zscale_mstate_)
 +			new_zscale = max(0.0,zScale() - relyz);
 +
 +		setScale(new_xscale, new_yscale, new_zscale); 
 +
 +		if ( bstate == zoom_mstate_)
 +			setZoom(max(0.0,zoom() - relyz));
 +}
 +
 +void Plot3D::setShiftMouse(MouseState bstate, double accel, QPoint diff)
 +{
 +	// Shift
 +	double w = max(1,width());
 +	double h = max(1,height());
 +
 +	double relx = diff.x() * accel / w; 
 +	double relyz = diff.y() * accel / h;
 +
 +	double new_xshift = xViewportShift();
 +	double new_yshift = yViewportShift();
 +
 +	if ( bstate == xshift_mstate_)
 +		new_xshift = xViewportShift() + relx;
 +	if ( bstate == yshift_mstate_)
 +		new_yshift = yViewportShift() - relyz;
 +
 +	setViewportShift(new_xshift, new_yshift); 
 +}
 +
 +/**
 +	Standard wheel Function - zoom (wheel only) or z-scale (shift+wheel)
 +*/
 +void Plot3D::wheelEvent( QWheelEvent *e )
 +{
 +	if (!mouseEnabled())
 +		return;
 +	
 +	double accel = 0.05;
 +	
 +	double step =  accel * e->delta() / WHEEL_DELTA ;
 +	step = exp(step)-1;
 +
 +#if QT_VERSION < 0x040000
 +	if ( e->state() & Qt::ShiftButton )
 +#else
 +	if ( e->modifiers() & Qt::ShiftModifier )
 +#endif
 +		setScale(xScale(),yScale(), max(0.0,zScale() + step));
 +	else
 +		setZoom(max(0.0,zoom() + step ));
 +}
 +
 +/**
 +	Sets the key/mousebutton combination for data/coordinatesystem moves inside the widget\n\n
 +	default behaviour:\n
 +
 +	\verbatim
 +	rotate around x axis: Qt::LeftButton 
 +	rotate around y axis: Qt::LeftButton | Qt::ShiftButton
 +	rotate around z axis: Qt::LeftButton 
 +	scale x:              Qt::LeftButton | Qt::AltButton 
 +	scale y:              Qt::LeftButton | Qt::AltButton 
 +	scale z:              Qt::LeftButton | Qt::AltButton | Qt::ShiftButton
 +	zoom:                 Qt::LeftButton | Qt::AltButton | Qt::ControlButton
 +	shifting along x:     Qt::LeftButton | Qt::ControlButton 
 +	shifting along y:     Qt::LeftButton | Qt::ControlButton
 +	\endverbatim
 +
 +	mouseMoveEvent() evaluates this function - if overridden, their usefulness becomes somehow limited
 +*/
 +void Plot3D::assignMouse(MouseState xrot, MouseState yrot, MouseState zrot,
 +											 MouseState xscale, MouseState yscale, MouseState zscale,
 +											 MouseState zoom, MouseState xshift, MouseState yshift)
 +{
 +	xrot_mstate_   = 	xrot;  
 +  yrot_mstate_   =  yrot;  
 +  zrot_mstate_   =  zrot;  
 +  xscale_mstate_ =  xscale;
 +  yscale_mstate_ =  yscale;
 +  zscale_mstate_ =  zscale;
 +  zoom_mstate_   =  zoom;  
 +  xshift_mstate_ =  xshift;
 +  yshift_mstate_ =  yshift;
 +}
 +
 +/** 
 +The function has no effect if you derive from Plot3D and overrides the mouse Function too careless.
 +In this case check first against mouseEnabled() in your version of mouseMoveEvent() and wheelEvent().
 +A more fine grained input control can be achieved by combining assignMouse() with enableMouse(). 
 +*/
 +void Plot3D::enableMouse(bool val) {mouse_input_enabled_ = val;}
 +
 +/** 
 +\see enableMouse()
 +*/
 +void Plot3D::disableMouse(bool val) {mouse_input_enabled_ = !val;}
 +bool Plot3D::mouseEnabled() const {return mouse_input_enabled_;}
 +
 +
 +
 +
 +void Plot3D::keyPressEvent( QKeyEvent *e )
 +{
 +	if (!keyboardEnabled())
 +  {
 +    e->ignore();
 +    return;
 +  }	
 +
 +#if QT_VERSION < 0x040000
 +  int bstate = e->state() & Qt::KeyButtonMask; // filter kbd modifier only
 +  KeyboardState keyseq = bstate + e->key();
 +#else
 +  KeyboardState keyseq(e->key(), e->modifiers());
 +#endif
 +
 +	setRotationKeyboard(keyseq, kbd_rot_speed_);	
 +	setScaleKeyboard(keyseq, kbd_scale_speed_);	
 +	setShiftKeyboard(keyseq, kbd_shift_speed_);	
 +}
 +
 +void Plot3D::setRotationKeyboard(KeyboardState kseq, double speed)
 +{
 +	// Rotation
 +	double w = max(1,width());
 +	double h = max(1,height());
 +		
 +	double relx = speed*360 / w; 
 +	double relyz = speed*360 / h; 
 +	
 +	double new_xrot = xRotation();
 +	double new_yrot = yRotation();
 +	double new_zrot = zRotation();
 +	
 +	if ( kseq == xrot_kstate_[0] )
 +		new_xrot = round(xRotation() + relyz) % 360; 
 +	if ( kseq == xrot_kstate_[1] )
 +		new_xrot = round(xRotation() - relyz) % 360; 
 +	if ( kseq == yrot_kstate_[0] )
 +		new_yrot = round(yRotation() + relx) % 360; 
 +	if ( kseq == yrot_kstate_[1] )
 +		new_yrot = round(yRotation() - relx) % 360; 
 +	if ( kseq == zrot_kstate_[0] )
 +		new_zrot = round(zRotation() + relx) % 360; 
 +	if ( kseq == zrot_kstate_[1] )
 +		new_zrot = round(zRotation() - relx) % 360; 
 +		
 +	setRotation(new_xrot, new_yrot, new_zrot); 
 +}
 +
 +void Plot3D::setScaleKeyboard(KeyboardState kseq, double speed)
 +{
 +	// Scale
 +		double w = max(1,width());
 +		double h = max(1,height());
 +
 +		double relx = speed / w; relx = exp(relx) - 1;
 +		double relyz = speed / h; relyz = exp(relyz) - 1; 
 +
 +		double new_xscale = xScale();
 +		double new_yscale = yScale();
 +		double new_zscale = zScale();
 +
 +		if ( kseq == xscale_kstate_[0])
 +			new_xscale = max(0.0,xScale() + relx);
 +		if ( kseq == xscale_kstate_[1])
 +			new_xscale = max(0.0,xScale() - relx);
 +		if ( kseq == yscale_kstate_[0])
 +			new_yscale = max(0.0,yScale() - relyz);
 +		if ( kseq == yscale_kstate_[1])
 +			new_yscale = max(0.0,yScale() + relyz);
 +		if ( kseq == zscale_kstate_[0])
 +			new_zscale = max(0.0,zScale() - relyz);
 +		if ( kseq == zscale_kstate_[1])
 +			new_zscale = max(0.0,zScale() + relyz);
 +
 +		setScale(new_xscale, new_yscale, new_zscale); 
 +
 +		if ( kseq == zoom_kstate_[0])
 +			setZoom(max(0.0,zoom() - relyz));
 +		if ( kseq == zoom_kstate_[1])
 +			setZoom(max(0.0,zoom() + relyz));
 +}
 +
 +void Plot3D::setShiftKeyboard(KeyboardState kseq, double speed)
 +{
 +	// Shift
 +	double w = max(1,width());
 +	double h = max(1,height());
 +
 +	double relx = speed / w; 
 +	double relyz = speed / h;
 +
 +	double new_xshift = xViewportShift();
 +	double new_yshift = yViewportShift();
 +
 +	if ( kseq == xshift_kstate_[0])
 +		new_xshift = xViewportShift() + relx;
 +	if ( kseq == xshift_kstate_[1])
 +		new_xshift = xViewportShift() - relx;
 +	if ( kseq == yshift_kstate_[0])
 +		new_yshift = yViewportShift() - relyz;
 +	if ( kseq == yshift_kstate_[1])
 +		new_yshift = yViewportShift() + relyz;
 +
 +	setViewportShift(new_xshift, new_yshift); 
 +}
 +
 +/**
 +	Sets the keybutton combination for data/coordinatesystem moves inside the widget\n\n
 +	default behaviour:\n
 +
 +	\verbatim
 +	rotate around x axis: [Key_Down, Key_Up] 
 +	rotate around y axis: SHIFT+[Key_Right, Key_Left]
 +	rotate around z axis: [Key_Right, Key_Left] 
 +	scale x:              ALT+[Key_Right, Key_Left] 
 +	scale y:              ALT+[Key_Up, Key_Down] 
 +	scale z:              ALT+SHIFT[Key_Down, Key_Up] 
 +	zoom:                 ALT+CTRL+[Key_Down, Key_Up]
 +	shifting along x:     CTRL+[Key_Right, Key_Left] 
 +	shifting along z:     CTRL+[Key_Down, Key_Up]
 +	\endverbatim
 +*/
 +void Plot3D::assignKeyboard(
 +       KeyboardState xrot_n, KeyboardState xrot_p
 +      ,KeyboardState yrot_n, KeyboardState yrot_p
 +      ,KeyboardState zrot_n, KeyboardState zrot_p
 +			,KeyboardState xscale_n, KeyboardState xscale_p 
 +      ,KeyboardState yscale_n, KeyboardState yscale_p
 +      ,KeyboardState zscale_n, KeyboardState zscale_p
 +			,KeyboardState zoom_n, KeyboardState zoom_p
 +      ,KeyboardState xshift_n, KeyboardState xshift_p
 +      ,KeyboardState yshift_n, KeyboardState yshift_p
 +      )
 +{
 +	xrot_kstate_[0]   =  xrot_n;  
 +  yrot_kstate_[0]   =  yrot_n;  
 +  zrot_kstate_[0]   =  zrot_n;  
 +	xrot_kstate_[1]   =  xrot_p;  
 +  yrot_kstate_[1]   =  yrot_p;  
 +  zrot_kstate_[1]   =  zrot_p;  
 +  
 +  xscale_kstate_[0] =  xscale_n;
 +  yscale_kstate_[0] =  yscale_n;
 +  zscale_kstate_[0] =  zscale_n;
 +  xscale_kstate_[1] =  xscale_p;
 +  yscale_kstate_[1] =  yscale_p;
 +  zscale_kstate_[1] =  zscale_p;
 +
 +  zoom_kstate_[0]   =  zoom_n;  
 +  xshift_kstate_[0] =  xshift_n;
 +  yshift_kstate_[0] =  yshift_n;
 +  zoom_kstate_[1]   =  zoom_p;  
 +  xshift_kstate_[1] =  xshift_p;
 +  yshift_kstate_[1] =  yshift_p;
 +}
 +
 +/** 
 +The function has no effect if you derive from Plot3D and overrides the keyboard Functions too careless.
 +In this case check first against keyboardEnabled() in your version of keyPressEvent()
 +A more fine grained input control can be achieved by combining assignKeyboard() with enableKeyboard(). 
 +*/
 +void Plot3D::enableKeyboard(bool val) {kbd_input_enabled_ = val;}
 +
 +/** 
 +\see enableKeyboard()
 +*/
 +void Plot3D::disableKeyboard(bool val) {kbd_input_enabled_ = !val;}
 +bool Plot3D::keyboardEnabled() const {return kbd_input_enabled_;}
 +
 +/**
 +Values < 0 are ignored. Default is (3,5,5)
 +*/
 +void Plot3D::setKeySpeed(double rot, double scale, double shift)
 +{
 +  if (rot > 0)
 +    kbd_rot_speed_ = rot;
 +  if (scale > 0)
 +    kbd_scale_speed_ = scale;
 +  if (shift > 0)
 +    kbd_shift_speed_ = shift;
 +}
 +
 +void Plot3D::keySpeed(double& rot, double& scale, double& shift) const
 +{
 +  rot = kbd_rot_speed_;
 +  scale = kbd_scale_speed_;
 +  shift = kbd_shift_speed_;
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_movements.cpp b/lib/tqwtplot3d/src/qwt3d_movements.cpp new file mode 100644 index 0000000..73ff9b1 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_movements.cpp @@ -0,0 +1,106 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4305 )
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include <float.h>
 +#include "qwt3d_plot.h"
 +
 +using namespace Qwt3D;
 +
 +
 +/**
 +  Set the rotation angle of the object. If you look along the respective axis towards ascending values,
 +	the rotation is performed in mathematical \e negative sense 
 +	\param xVal angle in \e degree to rotate around the X axis
 +	\param yVal angle in \e degree to rotate around the Y axis
 +	\param zVal angle in \e degree to rotate around the Z axis
 +*/
 +void Plot3D::setRotation( double xVal, double yVal, double zVal )
 +{
 +  if (xRot_ == xVal && yRot_ == yVal && zRot_ == zVal)
 +		return;
 +	
 +	xRot_ = xVal;
 +	yRot_ = yVal;
 +	zRot_ = zVal;
 +  
 +	updateGL();
 +	emit rotationChanged(xVal, yVal, zVal);
 +}
 +
 +/**
 +  Set the shift in object (world) coordinates.
 +	\param xVal shift along (world) X axis
 +	\param yVal shift along (world) Y axis
 +	\param zVal shift along (world) Z axis
 +	\see setViewportShift()
 +*/
 +void Plot3D::setShift( double xVal, double yVal, double zVal )
 +{
 +  if (xShift_ == xVal && yShift_ == yVal && zShift_ == zVal)
 +		return;
 +	
 +	xShift_ = xVal;
 +	yShift_ = yVal;
 +	zShift_ = zVal;
 +	updateGL();
 +	emit shiftChanged(xVal, yVal, zVal);
 +}
 +
 +/**
 +  Performs shifting along screen axes. 
 +  The shift moves points inside a sphere, 
 +  which encloses the unscaled and unzoomed data
 +	by multiples of the spheres diameter
 +	
 +	\param xVal shift along (view) X axis
 +	\param yVal shift along (view) Y axis
 +	\see setShift()
 +*/
 +void Plot3D::setViewportShift( double xVal, double yVal )
 +{
 +  if (xVPShift_ == xVal && yVPShift_ == yVal)
 +		return;
 +	
 +  xVPShift_ = xVal;
 +	yVPShift_ = yVal;
 +		
 +	updateGL();
 +	emit vieportShiftChanged(xVPShift_, yVPShift_);
 +}
 +
 +/**
 +  Set the scale in object (world) coordinates.
 +	\param xVal scaling for X values
 +	\param yVal scaling for Y values
 +	\param zVal scaling for Z values 
 +
 +	A respective value of 1 represents no scaling;
 +*/
 +void Plot3D::setScale( double xVal, double yVal, double zVal )
 +{
 +  if (xScale_ == xVal && yScale_ == yVal && zScale_ == zVal)
 +		return;
 +	
 +	xScale_ = (xVal < DBL_EPSILON ) ? DBL_EPSILON : xVal;
 +	yScale_ = (yVal < DBL_EPSILON ) ? DBL_EPSILON : yVal;
 +	zScale_ = (zVal < DBL_EPSILON ) ? DBL_EPSILON : zVal;
 +
 +	updateGL();
 +	emit scaleChanged(xVal, yVal, zVal);
 +}
 +
 +/**
 +  Set the (zoom in addition to scale).
 +	\param val zoom value (value == 1 indicates no zooming)
 +*/
 +void Plot3D::setZoom( double val )
 +{
 +  if (zoom_ == val)
 +		return;
 +
 +	zoom_ = (val < DBL_EPSILON ) ? DBL_EPSILON : val;
 + 	updateGL();
 +	emit zoomChanged(val);
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_parametricsurface.cpp b/lib/tqwtplot3d/src/qwt3d_parametricsurface.cpp new file mode 100644 index 0000000..c3103c9 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_parametricsurface.cpp @@ -0,0 +1,104 @@ +#include "qwt3d_parametricsurface.h"
 +#include "qwt3d_surfaceplot.h"
 +
 +using namespace Qwt3D;
 +
 +ParametricSurface::ParametricSurface()
 +:GridMapping()
 +{
 +}
 +
 +ParametricSurface::ParametricSurface(SurfacePlot& pw)
 +:GridMapping()
 +{
 +	plotwidget_p = &pw;
 +  uperiodic_ = false;
 +  vperiodic_ = false;
 +}
 +
 +ParametricSurface::ParametricSurface(SurfacePlot* pw)
 +:GridMapping()
 +{
 +	plotwidget_p = pw;
 +  uperiodic_ = false;
 +  vperiodic_ = false;
 +}
 +
 +void ParametricSurface::setPeriodic(bool u, bool v)
 +{
 +  uperiodic_ = u;
 +  vperiodic_ = v;
 +}
 +
 +void ParametricSurface::assign(SurfacePlot& plotWidget)
 +{
 +	if (&plotWidget != plotwidget_p)
 +		plotwidget_p = &plotWidget;
 +}
 +
 +void ParametricSurface::assign(SurfacePlot* plotWidget)
 +{
 +	if (plotWidget != plotwidget_p)
 +		plotwidget_p = plotWidget;
 +}
 +
 +/**
 +For plotWidget != 0 the function permanently assigns her argument (In fact, assign(plotWidget) is called)
 +*/
 +bool ParametricSurface::create()
 +{
 +	if ((umesh_p<=2) || (vmesh_p<=2) || !plotwidget_p)
 +		return false;
 +	
 +	/* allocate some space for the mesh */
 + 	Triple** data         = new Triple* [umesh_p] ;
 +
 +	unsigned i,j;
 +	for ( i = 0; i < umesh_p; i++) 
 +	{
 +		data[i]         = new Triple [vmesh_p];
 +	}
 +	
 +	/* get the data */
 +
 +	double du = (maxu_p - minu_p) / (umesh_p - 1);
 +	double dv = (maxv_p - minv_p) / (vmesh_p - 1);
 +	
 +  for (i = 0; i < umesh_p; ++i) 
 +	{
 +		for (j = 0; j < vmesh_p; ++j) 
 +		{
 +			data[i][j] = operator()(minu_p + i*du, minv_p + j*dv);
 +			
 +			if (data[i][j].x > range_p.maxVertex.x)
 +				data[i][j].x = range_p.maxVertex.x;
 +			else if (data[i][j].y > range_p.maxVertex.y)
 +				data[i][j].y = range_p.maxVertex.y;
 +			else if (data[i][j].z > range_p.maxVertex.z)
 +				data[i][j].z = range_p.maxVertex.z;
 +			else if (data[i][j].x < range_p.minVertex.x)
 +				data[i][j].x = range_p.minVertex.x;
 +			else if (data[i][j].y < range_p.minVertex.y)
 +				data[i][j].y = range_p.minVertex.y;
 +			else if (data[i][j].z < range_p.minVertex.z)
 +				data[i][j].z = range_p.minVertex.z;
 +		}
 +	}
 +
 +	((SurfacePlot*)plotwidget_p)->loadFromData(data, umesh_p, vmesh_p, uperiodic_, vperiodic_);
 +
 +	for ( i = 0; i < umesh_p; i++) 
 +	{
 +		delete [] data[i];
 +	}
 +
 +	delete [] data;
 +
 +	return true;
 +}
 +
 +bool ParametricSurface::create(SurfacePlot& pl)
 +{
 +  assign(pl);
 +  return create();
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_plot.cpp b/lib/tqwtplot3d/src/qwt3d_plot.cpp new file mode 100644 index 0000000..e61b125 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_plot.cpp @@ -0,0 +1,498 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4305 )
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include "qwt3d_plot.h"
 +#include "qwt3d_enrichment.h"
 +
 +
 +using namespace Qwt3D;
 +	
 +/*!
 +  This should be the first call in your derived classes constructors.  
 +*/
 +#if QT_VERSION < 0x040000
 +Plot3D::Plot3D( QWidget* parent, const char* name )
 +    : QGLWidget( parent, name )
 +#else
 +Plot3D::Plot3D( QWidget * parent, const QGLWidget * shareWidget)
 +    : QGLWidget( parent, shareWidget) 
 +#endif
 +{  
 +  initializedGL_ = false;
 +  renderpixmaprequest_ = false;
 +  xRot_ = yRot_ = zRot_ = 0.0;		// default object rotation
 +  
 +	xShift_ = yShift_ = zShift_ = xVPShift_ = yVPShift_ = 0.0;
 +	xScale_ = yScale_ = zScale_ = 1.0;
 +	zoom_ = 1;
 +	ortho_ = true;
 +	plotstyle_ = FILLEDMESH;
 +  userplotstyle_p = 0;
 +	shading_ = GOURAUD;
 +	floorstyle_ = NOFLOOR;
 +	isolines_ = 10;
 +	displaylegend_ = false;
 +	smoothdatamesh_p = false;
 +  actualData_p = 0;
 +
 +	lastMouseMovePosition_ = QPoint(0,0);
 +	mpressed_ = false;
 +	mouse_input_enabled_ = true;
 +
 +	setPolygonOffset(0.5);
 +	setMeshColor(RGBA(0.0,0.0,0.0));
 +	setMeshLineWidth(1);
 +	setBackgroundColor(RGBA(1.0,1.0,1.0,1.0));
 +
 +	displaylists_p = std::vector<GLuint>(DisplayListSize);
 +	for (unsigned k=0; k!=displaylists_p.size(); ++k)
 +	{
 +		displaylists_p[k] = 0;
 +	}
 +
 +	datacolor_p = new StandardColor(this, 100);
 +	title_.setFont("Courier", 16, QFont::Bold);
 +	title_.setString("");
 +
 +	setTitlePosition(0.95);
 +	
 +  kbd_input_enabled_ = true;
 +
 +#if QT_VERSION < 0x040000
 +  setFocusPolicy(QWidget::StrongFocus);
 +  assignMouse(Qt::LeftButton, 
 +							Qt::LeftButton | Qt::ShiftButton,
 +							Qt::LeftButton, 
 +							Qt::LeftButton | Qt::AltButton, 
 +							Qt::LeftButton | Qt::AltButton, 
 +							Qt::LeftButton | Qt::AltButton | Qt::ShiftButton,
 +							Qt::LeftButton | Qt::AltButton | Qt::ControlButton,
 +							Qt::LeftButton | Qt::ControlButton, 
 +							Qt::LeftButton | Qt::ControlButton);
 +
 +
 +  assignKeyboard(Qt::Key_Down, Qt::Key_Up,
 +    Qt::ShiftButton + Qt::Key_Right, Qt::ShiftButton + Qt::Key_Left,
 +    Qt::Key_Right, Qt::Key_Left,
 +    Qt::AltButton + Qt::Key_Right, Qt::AltButton + Qt::Key_Left,
 +    Qt::AltButton + Qt::Key_Down, Qt::AltButton + Qt::Key_Up,
 +    Qt::AltButton + Qt::ShiftButton + Qt::Key_Down, Qt::AltButton + Qt::ShiftButton + Qt::Key_Up,
 +    Qt::AltButton + Qt::ControlButton + Qt::Key_Down, Qt::AltButton + Qt::ControlButton + Qt::Key_Up,
 +    Qt::ControlButton + Qt::Key_Right, Qt::ControlButton + Qt::Key_Left,
 +    Qt::ControlButton + Qt::Key_Down, Qt::ControlButton + Qt::Key_Up
 +   );
 +#else
 +  setFocusPolicy(Qt::StrongFocus);
 +  assignMouse(Qt::LeftButton, 
 +							MouseState(Qt::LeftButton, Qt::ShiftModifier),
 +							Qt::LeftButton, 
 +							MouseState(Qt::LeftButton, Qt::AltModifier), 
 +							MouseState(Qt::LeftButton, Qt::AltModifier), 
 +							MouseState(Qt::LeftButton, Qt::AltModifier | Qt::ShiftModifier),
 +							MouseState(Qt::LeftButton, Qt::AltModifier | Qt::ControlModifier),
 +							MouseState(Qt::LeftButton, Qt::ControlModifier), 
 +							MouseState(Qt::LeftButton, Qt::ControlModifier)
 +              );
 +
 +
 +  assignKeyboard(Qt::Key_Down, Qt::Key_Up,
 +    KeyboardState(Qt::Key_Right, Qt::ShiftModifier), KeyboardState(Qt::Key_Left, Qt::ShiftModifier),
 +    Qt::Key_Right, Qt::Key_Left,
 +    KeyboardState(Qt::Key_Right, Qt::AltModifier), KeyboardState(Qt::Key_Left, Qt::AltModifier),
 +    KeyboardState(Qt::Key_Down, Qt::AltModifier), KeyboardState(Qt::Key_Up, Qt::AltModifier),
 +    KeyboardState(Qt::Key_Down, Qt::AltModifier|Qt::ShiftModifier), KeyboardState(Qt::Key_Up, Qt::AltModifier|Qt::ShiftModifier),
 +    KeyboardState(Qt::Key_Down, Qt::AltModifier|Qt::ControlModifier), KeyboardState(Qt::Key_Up, Qt::AltModifier|Qt::ControlModifier),
 +    KeyboardState(Qt::Key_Right, Qt::ControlModifier), KeyboardState(Qt::Key_Left, Qt::ControlModifier),
 +    KeyboardState(Qt::Key_Down, Qt::ControlModifier), KeyboardState(Qt::Key_Up, Qt::ControlModifier)
 +   );
 +#endif
 +  setKeySpeed(3,5,5);
 +
 +	legend_.setLimits(0, 100);
 +	legend_.setMajors(10);
 +	legend_.setMinors(2);
 +	legend_.setOrientation(ColorLegend::BottomTop, ColorLegend::Left);
 +
 +  lighting_enabled_ = false;
 +  disableLighting();
 +  lights_ = std::vector<Light>(8);
 +}
 +
 +/*!
 +  Release allocated resources
 +*/
 +
 +Plot3D::~Plot3D()
 +{
 +	makeCurrent();
 +	SaveGlDeleteLists( displaylists_p[0], displaylists_p.size() );
 +	datacolor_p->destroy();
 +  delete userplotstyle_p;
 +  for (ELIT it = elist_p.begin(); it!=elist_p.end(); ++it)
 +    delete (*it);
 +
 +  elist_p.clear();
 +}
 +
 +
 +/*!
 +  Set up the OpenGL rendering state
 +*/
 +void Plot3D::initializeGL()
 +{
 +  glEnable( GL_BLEND );
 +  glEnable(GL_DEPTH_TEST);
 +	glShadeModel(GL_SMOOTH);
 +	
 +  // Set up the lights
 +
 +  disableLighting();
 +	
 +  GLfloat whiteAmb[4] = {1.0, 1.0, 1.0, 1.0};
 +    
 +  setLightShift(0, 0, 3000);
 +  glEnable(GL_COLOR_MATERIAL);
 +
 +	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
 +  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, whiteAmb);
 +
 +  setMaterialComponent(GL_DIFFUSE, 1.0);
 +  setMaterialComponent(GL_SPECULAR, 0.3);
 +  setMaterialComponent(GL_SHININESS, 5.0);
 +  setLightComponent(GL_DIFFUSE, 1.0);
 +  setLightComponent(GL_SPECULAR, 1.0);
 +
 +  initializedGL_ = true;	
 +  if (renderpixmaprequest_)
 +  {
 +    updateData();
 +    renderpixmaprequest_ = false;
 +  }
 +}
 +
 +/*!
 +  Paint the widgets content.
 +*/
 +void Plot3D::paintGL()
 +{
 +	glClearColor(bgcolor_.r, bgcolor_.g, bgcolor_.b, bgcolor_.a);
 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 +	
 +  glMatrixMode( GL_MODELVIEW );
 +	glPushMatrix();
 +  applyLights();
 +
 +  glRotatef( -90, 1.0, 0.0, 0.0 ); 
 +  glRotatef( 0.0, 0.0, 1.0, 0.0 ); 
 +  glRotatef( 0.0, 0.0, 0.0, 1.0 );
 +
 +	if (displaylegend_)
 +	{		
 +		legend_.draw();
 +	}
 +	title_.setRelPosition(titlerel_, titleanchor_);
 +	title_.draw();
 +	
 +	Triple beg = coordinates_p.first();
 +	Triple end = coordinates_p.second();
 +	
 +	Triple center = beg + (end-beg) / 2;
 +	double radius = (center-beg).length();
 +	
 +	glLoadIdentity();
 +
 +  glRotatef( xRot_-90, 1.0, 0.0, 0.0 ); 
 +  glRotatef( yRot_, 0.0, 1.0, 0.0 ); 
 +  glRotatef( zRot_, 0.0, 0.0, 1.0 );
 +
 +	glScalef( zoom_ * xScale_, zoom_ * yScale_, zoom_ * zScale_ );
 +	
 +	glTranslatef(xShift_-center.x, yShift_-center.y, zShift_-center.z);
 +  
 +  glMatrixMode( GL_PROJECTION );
 +  glLoadIdentity();
 +
 +	if (beg != end)
 +	{		
 +		if (ortho_)
 +    {	
 +      glOrtho( -radius, +radius, -radius, +radius, 0, 40 * radius);
 +    }
 +    else
 +    {	
 +      glFrustum( -radius, +radius, -radius, +radius, 5 * radius, 400 * radius );
 +    }
 +  }
 +	else
 +	{
 +		if (ortho_)
 +			glOrtho( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
 +		else
 +			glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
 +	}
 +
 +  glTranslatef( xVPShift_ * 2 * radius , yVPShift_ * 2 * radius , -7 * radius );
 +  
 +  if (lighting_enabled_)
 +    glEnable(GL_NORMALIZE);
 +
 +  for (unsigned i=0; i!= displaylists_p.size(); ++i)
 +	{
 +		if (i!=LegendObject)
 +			glCallList( displaylists_p[i] );
 +	}
 +  coordinates_p.draw();
 +	
 +  if (lighting_enabled_)
 +    glDisable(GL_NORMALIZE);
 +  
 +  glMatrixMode( GL_MODELVIEW );
 +  glPopMatrix();
 +}
 +
 +
 +/*!
 +  Set up the OpenGL view port
 +*/
 +void Plot3D::resizeGL( int w, int h )
 +{
 +	glViewport( 0, 0, w, h );
 +	paintGL();
 +}
 +
 +/*!
 +  Reimplemented from QGLWidget
 +*/
 +QPixmap Plot3D::renderPixmap(int w/* =0 */, int h/* =0 */, bool useContext/* =false */)
 +{
 +  renderpixmaprequest_ = true;
 +  return QGLWidget::renderPixmap(w,h,useContext);
 +}
 +
 +/*!
 +	Create a coordinate system with generating corners beg and end 
 +*/
 +void Plot3D::createCoordinateSystem( Triple beg, Triple end )
 +{
 +	if (beg != coordinates_p.first() || end != coordinates_p.second())
 +		coordinates_p.init(beg, end);
 +}
 +
 +/*!
 +	Create a coordinate system from data
 +*/
 +void Plot3D::createCoordinateSystem()
 +{
 +	calculateHull();
 +  Triple beg = hull().minVertex; // Irix 6.5 compiler bug
 +  Triple end = hull().maxVertex;
 +  createCoordinateSystem(beg, end);
 +}
 +
 +/*!
 +  Show a color legend
 +*/
 +void Plot3D::showColorLegend( bool show )
 +{
 + 	displaylegend_ = show;
 +	if (show)
 +    datacolor_p->createVector(legend_.colors);
 +	updateGL();
 +}
 +
 +void Plot3D::setMeshColor(RGBA rgba)
 +{
 +	meshcolor_ = rgba;
 +}
 +
 +void Plot3D::setBackgroundColor(RGBA rgba)
 +{
 +	bgcolor_ = rgba;
 +}
 +
 +
 +/*!
 +	assign a new coloring object for the data.
 +*/
 +void Plot3D::setDataColor( Color* col )
 +{
 +	Q_ASSERT(datacolor_p);
 +
 +	datacolor_p->destroy();
 +	datacolor_p = col;
 +}
 +
 +/*!
 +  Set up ortogonal or perspective mode and updates widget
 +*/
 +void Plot3D::setOrtho( bool val )
 +{
 +	if (val == ortho_)
 +		return;
 +	ortho_ = val;
 +	updateGL();
 +	
 +	emit projectionChanged(val);
 +}
 +
 +/*!
 +  Set style of coordinate system
 +*/
 +void Plot3D::setCoordinateStyle(COORDSTYLE st)
 +{
 +	coordinates_p.setStyle(st);
 +	updateGL();
 +}
 +
 +/*!
 +  Set plotstyle for the standard plotting types. An argument of value Qwt3D::USER
 +  is ignored.
 +*/
 +void Plot3D::setPlotStyle( PLOTSTYLE val )
 +{
 +  if (val == Qwt3D::USER)
 +    return;
 +  delete userplotstyle_p;
 +  userplotstyle_p = 0;
 +  plotstyle_ = val;
 +}
 +
 +/*!
 +  Set plotstyle to Qwt3D::USER and an associated enrichment object.
 +*/
 +Qwt3D::Enrichment* Plot3D::setPlotStyle( Qwt3D::Enrichment const& obj )
 +{
 +  if (&obj == userplotstyle_p)
 +    return userplotstyle_p;
 +  
 +  delete userplotstyle_p;
 +  userplotstyle_p = obj.clone();
 +  plotstyle_ = Qwt3D::USER;
 +  return userplotstyle_p;
 +}
 +
 +/*!
 +  Set shading style
 +*/
 +void Plot3D::setShading( SHADINGSTYLE val )
 +{
 +	if (val == shading_)
 +		return;
 +	
 +	shading_ = val;
 +	
 +	switch (shading_)
 +	{
 +		case FLAT:
 +			glShadeModel(GL_FLAT);
 +			break;
 +		case GOURAUD:
 +			glShadeModel(GL_SMOOTH);
 +			break;
 +		default:
 +			break;
 +	}
 +	updateGL();
 +}
 +
 +/*!
 +  Set number of isolines. The lines are equidistant between minimal and maximal Z value
 +*/
 +void Plot3D::setIsolines(int steps)
 +{
 +	if (steps < 0)
 +		return;
 +
 +	isolines_ = steps;
 +}
 +
 +/*!
 +  Set Polygon offset. The function affects the OpenGL rendering process. 
 +	Try different values for surfaces with polygons only and with mesh and polygons
 +*/
 +void Plot3D::setPolygonOffset( double val )
 +{
 +	polygonOffset_ = val;
 +}
 +
 +void Plot3D::setMeshLineWidth( double val )
 +{
 +	Q_ASSERT(val>=0);
 +
 +	if (val < 0)
 +		return;
 +	
 +	meshLineWidth_ = val;
 +}
 +
 +
 +/*!
 +Set relative caption position (0.5,0.5) means, the anchor point lies in the center of the screen
 +*/
 +void Plot3D::setTitlePosition(double rely, double relx, Qwt3D::ANCHOR anchor)
 +{
 +	titlerel_.y = (rely<0 || rely>1) ? 0.5 : rely;
 +	titlerel_.x = (relx<0 || relx>1) ? 0.5 : relx;
 +
 +	titleanchor_ = anchor;
 +}
 +
 +/*!
 +Set caption font
 +*/
 +void Plot3D::setTitleFont(const QString& family, int pointSize, int weight, bool italic)
 +{ 
 +	title_.setFont(family, pointSize, weight, italic);
 +}
 +
 +Enrichment* Plot3D::addEnrichment(Enrichment const& e)
 +{
 +  if ( elist_p.end() == std::find( elist_p.begin(), elist_p.end(), &e ) )
 +    elist_p.push_back(e.clone());
 +  return elist_p.back();
 +}
 +
 +bool Plot3D::degrade(Enrichment* e)
 +{
 +	ELIT it = std::find(elist_p.begin(), elist_p.end(), e);
 +	
 +	if ( it != elist_p.end() )
 +	{
 +		delete (*it);
 +    elist_p.erase(it);
 +    return true;
 +	}
 +  return false;
 +}
 +
 +void Plot3D::createEnrichments()
 +{
 +  for (ELIT it = elist_p.begin(); it!=elist_p.end(); ++it)
 +  {
 +    this->createEnrichment(**it);
 +  } 
 +}
 +
 +/*!
 +  Update OpenGL data representation
 +*/
 +void Plot3D::updateData()
 +{
 +	makeCurrent();
 +  GLStateBewarer dt(GL_DEPTH_TEST, true);
 +	GLStateBewarer ls(GL_LINE_SMOOTH, true);
 +
 +	calculateHull();	
 +
 +	SaveGlDeleteLists(displaylists_p[DataObject], 1); // nur Daten
 +	
 +	displaylists_p[DataObject] = glGenLists(1);
 +	glNewList(displaylists_p[DataObject], GL_COMPILE);
 +	
 +  this->createEnrichments();
 +	this->createData();
 +		
 +	glEndList();
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_scale.cpp b/lib/tqwtplot3d/src/qwt3d_scale.cpp new file mode 100644 index 0000000..ecac454 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_scale.cpp @@ -0,0 +1,304 @@ +#include "qwt3d_scale.h"
 +
 +using namespace Qwt3D;
 +
 +Scale::Scale() 
 +: start_p(0.), stop_p(0.), 
 +  majorintervals_p(0), minorintervals_p(0),
 +  mstart_p(0.), mstop_p(0.) 
 +{
 +}
 +
 +/*! The function maps the double value at tic-position idx to a final
 +representation. The default return value is simply the tic values QString 
 +representation. Overwrite this function, if you plan to transform the value 
 +in some way. See e.g. LogScale::ticLabel.
 +\param idx the current major tic index
 +\return The QString representation for the value corresponding to a valid index, 
 +an empty QString else.
 +*/
 +QString Scale::ticLabel(unsigned int idx) const
 +{
 +  if (idx<majors_p.size())
 +  {
 +    return QString::number(majors_p[idx]);
 +  }
 +  return QString("");
 +}
 +
 +//! Sets start and stop value for the scale;
 +void Scale::setLimits(double start, double stop) 
 +{
 +  if (start < stop)
 +  {
 +    start_p = start;
 +    stop_p = stop;
 +    return;
 +  }
 +  start_p = stop;
 +  stop_p = start;
 +}
 +
 +//! Sets value of first major tic
 +void Scale::setMajorLimits(double start, double stop) 
 +{
 +  if (start < stop)
 +  {
 +    mstart_p = start;
 +    mstop_p = stop;
 +    return;
 +  }
 +  mstart_p = stop;
 +  mstop_p = start;
 +} 
 +
 +/*!
 +  \param a First major tic after applying autoscaling
 +  \param b Last major tic after applying autoscaling
 +  \param start Scale begin
 +  \param stop Scale end
 +  \param ivals Requested number of major intervals
 +  \return Number of major intervals after autoscaling\n
 +  
 +  The default implementation sets a=start, b=stop and returns ivals.
 +*/
 +int Scale::autoscale(double& a, double& b, double start, double stop, int ivals)
 +{
 +  a = start;
 +  b = stop;
 +  return ivals;
 +}
 +
 +/***************************
 +*
 +* linear scales
 +*
 +***************************/
 +
 +
 +//! Applies LinearAutoScaler::execute()
 +int LinearScale::autoscale(double& a, double& b, double start, double stop, int ivals)
 +{
 +  return autoscaler_p.execute(a, b, start, stop, ivals);
 +}
 +
 +//! Creates the major and minor vector for the scale
 +void LinearScale::calculate()
 +{		
 +  majors_p.clear();
 +	minors_p.clear();
 +  
 +  double interval = mstop_p-mstart_p;
 +
 +	double runningval;
 +  int i=0;
 +
 +  // majors
 +
 +  // first tic
 +//  if (mstart_p<start_p || mstop_p>stop_p)
 +//    return;  
 +    
 +  majors_p.push_back(mstart_p);
 +  
 +  // remaining tics
 +  for (i = 1; i <= majorintervals_p; ++i) 
 +	{
 +		double t = double(i) / majorintervals_p;
 +		runningval = mstart_p + t * interval;
 +    if (runningval>stop_p)
 +      break;
 +    if (isPracticallyZero(mstart_p, -t*interval)) // prevent rounding errors near 0
 +      runningval = 0.0;
 +    majors_p.push_back(runningval);
 +	}
 +  majorintervals_p = majors_p.size();
 +  if (majorintervals_p)
 +    --majorintervals_p;
 +
 +
 +	// minors
 +
 +  if (!majorintervals_p || !minorintervals_p) // no valid interval
 +  {
 +    minorintervals_p = 0;
 +    return;
 +  }
 +  
 +  // start_p      mstart_p
 +  //  |_____________|_____ _ _ _
 +
 +  double step = (majors_p[1]-majors_p[0]) / minorintervals_p;
 +  if (isPracticallyZero(step))
 +    return;
 +
 +  runningval = mstart_p-step;
 +	while (runningval>start_p)
 +	{
 +		minors_p.push_back(runningval);								
 +		runningval -= step;
 +	}
 +
 +  //       mstart_p            mstop_p
 +  //  ________|_____ _ _ _ _ _ ___|__________
 +
 +  for (i=0; i!=majorintervals_p; ++i)
 +  {
 +    runningval = majors_p[i] + step;
 +    for (int j=0; j!=minorintervals_p; ++j)
 +    {
 +		  minors_p.push_back(runningval);								
 +		  runningval += step;
 +	  }
 +  }
 +  
 +  //    mstop_p       stop_p
 +  // _ _ _|_____________|
 +
 +  runningval = mstop_p + step;
 +  while (runningval<stop_p)
 +  {
 +	  minors_p.push_back(runningval);								
 +	  runningval += step;
 +  }
 +}
 +
 +void LogScale::setupCounter(double& k, int& step)
 +{
 +  switch(minorintervals_p) 
 +  {
 +  case 9:
 +  	k=9;
 +    step=1;
 +    break;
 +  case 5:
 +    k=8;
 +    step=2;
 +  	break;
 +  case 3:
 +    k=5;
 +    step=3;
 +  	break;
 +  case 2:
 +    k=5;
 +    step=5;
 +  	break;
 +  default:
 +    k=9;
 +    step=1;
 +  }
 +}
 +
 +/*! Creates major and minor vectors for the scale.
 +\warning If the interval is too small, the scale becomes empty
 +or will contain only a single major tic. There is no automatism 
 +(also not planned for now) for an 'intelligent' guess, what to do. 
 +Better switch manually to linear to scales in such cases.
 +*/
 +void LogScale::calculate()
 +{
 +  majors_p.clear();
 +	minors_p.clear();
 +
 +  if (start_p < DBL_MIN_10_EXP)
 +    start_p = DBL_MIN_10_EXP;
 +  if (stop_p > DBL_MAX_10_EXP)
 +    stop_p = DBL_MAX_10_EXP;
 +
 +  double interval = stop_p-start_p;
 +  if (interval<=0)
 +    return;
 +  
 +  double runningval = floor(start_p);
 +  while(runningval<=stop_p) 
 +	{
 +    if (runningval>=start_p)
 +      majors_p.push_back(runningval);
 +    ++runningval;
 +	}
 +  majorintervals_p = majors_p.size();
 +  if (majorintervals_p)
 +    --majorintervals_p;
 +
 +  if (majors_p.size()<1) // not even a single major tic
 +  {
 +    return;
 +  }
 +  
 +  
 +  // minors
 +
 +  // start_p      mstart_p
 +  //  |_____________|_____ _ _ _
 +
 +  double k;
 +  int step;
 +  setupCounter(k,step);
 +	runningval = log10(k)+(majors_p[0]-1);
 +  while (runningval>start_p && k>1)
 +	{
 +		minors_p.push_back(runningval);								
 +    k -=step;
 +    runningval = log10(k)+(majors_p[0]-1);
 +	}
 +
 +  //       mstart_p            mstop_p
 +  //  ________|_____ _ _ _ _ _ ___|__________
 +
 +  for (int i=0; i!=majorintervals_p; ++i)
 +  {
 +    setupCounter(k,step);
 +    runningval = log10(k)+(majors_p[i]);
 +    while (k>1)
 +	  {
 +		  minors_p.push_back(runningval);
 +      k-=step;
 +      runningval = log10(k)+(majors_p[i]);
 +	  }
 +  }
 +
 +  //    mstop_p       stop_p
 +  // _ _ _|_____________|
 +
 +  setupCounter(k,step);
 +	runningval = log10(k)+(majors_p.back());
 +  do 
 +  {
 +    k-=step; 
 +    runningval = log10(k)+(majors_p.back());
 +  } 
 +  while(runningval>=stop_p);
 +  while (k>1)
 +	{
 +		minors_p.push_back(runningval);								
 +    k-=step;
 +    runningval = log10(k)+(majors_p.back());
 +	}
 +}
 +
 +/*!
 +Sets the minor intervals for the logarithmic scale. Only values of 9,5,3 or 2 
 +are accepted as arguments. They will produce mantissa sets of {2,3,4,5,6,7,8,9}, 
 +{2,4,6,8}, {2,5} or {5} respectively.
 +*/
 +void LogScale::setMinors(int val)
 +{
 +  if ((val == 2) || (val == 3) || (val == 5) || (val == 9))
 +    minorintervals_p = val;
 +}
 +
 +LogScale::LogScale()
 +{
 +  minorintervals_p = 9;
 +}
 +
 +//! Returns a power of 10 associated to the major value at index idx.
 +QString LogScale::ticLabel(unsigned int idx) const
 +{
 +  if (idx<majors_p.size())
 +  {
 +    double val = majors_p[idx];
 +    return QString::number(pow(double(10), val));
 +  }
 +  return QString("");
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_surfaceplot.cpp b/lib/tqwtplot3d/src/qwt3d_surfaceplot.cpp new file mode 100644 index 0000000..3caae31 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_surfaceplot.cpp @@ -0,0 +1,183 @@ +#include "qwt3d_surfaceplot.h"
 +
 +using namespace std;
 +using namespace Qwt3D;
 +
 +/**
 +Initializes with dataNormals()==false, NOFLOOR, resolution() == 1
 +*/
 +#if QT_VERSION < 0x040000
 +SurfacePlot::SurfacePlot( QWidget* parent, const char* name )
 +    : Plot3D( parent, name )
 +#else
 +SurfacePlot::SurfacePlot( QWidget * parent, const QGLWidget * shareWidget)
 +    : Plot3D( parent, shareWidget) 
 +#endif
 +{
 +	datanormals_p = false;
 +	normalLength_p = 0.02;
 +	normalQuality_p = 3;
 +
 +	resolution_p = 1;
 +	actualDataG_ = new GridData();
 +	actualDataC_ = new CellData();
 +
 +  actualData_p = actualDataG_;
 +
 +  floorstyle_ = NOFLOOR;
 +}
 +
 +SurfacePlot::~SurfacePlot()
 +{
 +	delete actualDataG_;
 +	delete actualDataC_;
 +}
 +
 +void SurfacePlot::showNormals(bool b)
 +{
 +  datanormals_p = b;
 +}
 +
 +/**
 +Values < 0 or > 1 are ignored
 +*/
 +void SurfacePlot::setNormalLength(double val)
 +{
 +	if (val<0 || val>1)
 +		return;
 +	normalLength_p = val;
 +}
 +
 +/**
 +Values < 3 are ignored 
 +*/
 +void SurfacePlot::setNormalQuality(int val) 
 +{
 +	if (val<3)
 +		return;
 +	normalQuality_p = val;
 +}
 +
 +/**
 +	Calculates the smallest x-y-z parallelepiped enclosing the data.
 +	It can be accessed by hull();
 +*/
 +void SurfacePlot::calculateHull()
 +{
 +	if (actualData_p->empty())
 +		return;
 +	setHull(actualData_p->hull());
 +}
 +
 +/*!
 +  Sets data resolution (res == 1 original resolution) and updates widget
 +	If res < 1, the function does nothing
 +*/
 +void SurfacePlot::setResolution( int res )
 +{
 +  if (!actualData_p || actualData_p->datatype == Qwt3D::POLYGON)
 +    return;
 +  
 +  if ((resolution_p == res) || res < 1)
 +		return;
 +	
 +	resolution_p = res;
 +	updateNormals();
 +	updateData();
 +	if (initializedGL())
 +    updateGL();
 +
 +	emit resolutionChanged(res);
 +}
 +
 +void SurfacePlot::updateNormals()
 +{
 +	SaveGlDeleteLists(displaylists_p[NormalObject], 1); 
 +	
 +	if (plotStyle() == NOPLOT && !normals() || !actualData_p)
 +		return;
 +
 +	displaylists_p[NormalObject] = glGenLists(1);
 +	glNewList(displaylists_p[NormalObject], GL_COMPILE);
 +
 +  if (actualData_p->datatype == Qwt3D::POLYGON)
 +    createNormalsC();
 +  else if (actualData_p->datatype == Qwt3D::GRID)
 +    createNormalsG();
 +		
 +	glEndList();
 +}
 +
 +void SurfacePlot::createData()
 +{
 +	if (!actualData_p)
 +		return;
 +  if (actualData_p->datatype == Qwt3D::POLYGON)
 +    createDataC();
 +  else if (actualData_p->datatype == Qwt3D::GRID)
 +    createDataG();
 +}
 +
 +
 +void SurfacePlot::createFloorData()
 +{
 +	if (!actualData_p)
 +    return;
 +  if (actualData_p->datatype == Qwt3D::POLYGON)
 +    createFloorDataC();
 +  else if (actualData_p->datatype == Qwt3D::GRID)
 +   createFloorDataG();  
 +}
 +
 +/**
 +	The returned value is not affected by resolution(). The pair gives (columns,rows) for grid data
 +, (number of cells,1) for free formed data (datatype() == POLYGON) and (0,0) else
 +*/
 +pair<int,int> SurfacePlot::facets() const
 +{
 +	if (!hasData())
 +		return pair<int,int>(0,0);
 +
 +  if (actualData_p->datatype == Qwt3D::POLYGON)
 +  	return pair<int,int>(int(actualDataC_->cells.size()), 1);
 +  else if (actualData_p->datatype == Qwt3D::GRID)
 +  	return pair<int,int>(actualDataG_->columns(), actualDataG_->rows()); 	
 +  else
 +    return pair<int,int>(0,0);    
 +}
 +
 +void SurfacePlot::createPoints()
 +{
 +  Dot pt;
 +  createEnrichment(pt);
 +}
 +
 +void SurfacePlot::createEnrichment(Enrichment& p)
 +{
 +	if (!actualData_p)
 +    return;
 +  
 +  //todo future work
 +  if (p.type() != Enrichment::VERTEXENRICHMENT)
 +    return;
 +  
 +  p.assign(*this);
 +	p.drawBegin();
 +
 +  VertexEnrichment* ve = (VertexEnrichment*)&p; 
 +  if (actualData_p->datatype == Qwt3D::POLYGON)
 +  {	
 +    for (unsigned i = 0; i != actualDataC_->normals.size(); ++i) 
 +	    ve->draw(actualDataC_->nodes[i]);
 +  }
 +  else if (actualData_p->datatype == Qwt3D::GRID)
 + 	{
 +    int step = resolution();
 +    for (int i = 0; i <= actualDataG_->columns() - step; i += step) 
 +      for (int j = 0; j <= actualDataG_->rows() - step; j += step) 
 +  			ve->draw(Triple(actualDataG_->vertices[i][j][0],
 +										              actualDataG_->vertices[i][j][1],
 +                                  actualDataG_->vertices[i][j][2]));
 +  }
 +  p.drawEnd(); 
 +}
 diff --git a/lib/tqwtplot3d/src/qwt3d_types.cpp b/lib/tqwtplot3d/src/qwt3d_types.cpp new file mode 100644 index 0000000..b6f3a4d --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_types.cpp @@ -0,0 +1,222 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
 +#pragma warning ( disable : 4786 )
 +#endif
 +
 +#include <stdlib.h> // qsort
 +#include <algorithm>
 +#include <float.h>
 +#include "qwt3d_types.h"
 +
 +using namespace Qwt3D;
 +
 +#ifndef QWT3D_NOT_FOR_DOXYGEN
 +
 +namespace {
 +  // convex hull
 +  
 +  typedef double coordinate_type;
 +
 +  int ccw(coordinate_type **P, int i, int j, int k) {
 +    coordinate_type	a = P[i][0] - P[j][0],
 +      b = P[i][1] - P[j][1],
 +      c = P[k][0] - P[j][0],
 +      d = P[k][1] - P[j][1];
 +    return a*d - b*c <= 0;	   /* true if points i, j, k counterclockwise */
 +  }
 +
 +
 +#define CMPM(c,A,B) \
 +  v = (*(coordinate_type**)A)[c] - (*(coordinate_type**)B)[c];\
 +  if (v>0) return 1;\
 +  if (v<0) return -1;
 +
 +  int cmpl(const void *a, const void *b) {
 +    double v;
 +    CMPM(0,a,b);
 +    CMPM(1,b,a);
 +    return 0;
 +  }
 +
 +  int cmph(const void *a, const void *b) {return cmpl(b,a);}
 +
 +
 +  int make_chain(coordinate_type** V, int n, int (*cmp)(const void*, const void*)) {
 +    int i, j, s = 1;
 +    coordinate_type* t;
 +
 +    qsort(V, n, sizeof(coordinate_type*), cmp);
 +    for (i=2; i<n; i++) {
 +      for (j=s; j>=1 && ccw(V, i, j, j-1); j--){}
 +      s = j+1;
 +      t = V[s]; V[s] = V[i]; V[i] = t;
 +    }
 +    return s;
 +  }
 +
 +  int _ch2d(coordinate_type **P, int n)  {
 +    int u = make_chain(P, n, cmpl);		/* make lower hull */
 +    if (!n) return 0;
 +    P[n] = P[0];
 +    return u+make_chain(P+u, n-u+1, cmph);	/* make upper hull */
 +  }
 +
 +
 +} // ns anon
 +
 +
 +GridData::GridData()
 +{
 +  datatype = Qwt3D::GRID;
 +  setSize(0,0);
 +  setPeriodic(false,false);
 +}
 +
 +GridData::GridData(unsigned int columns, unsigned int rows)
 +{
 +  datatype = Qwt3D::GRID;
 +	setSize(columns,rows);
 +  setPeriodic(false,false);
 +}
 +
 +int GridData::columns() const 
 +{ 
 +	return (int)vertices.size();
 +}
 +
 +int GridData::rows() const 
 +{ 
 +	return (empty()) ? 0 : (int)vertices[0].size();	
 +}
 +
 +void GridData::clear()
 +{
 +	setHull(ParallelEpiped());
 +	{
 +		for (unsigned i=0; i!=vertices.size(); ++i)
 +		{	
 +			for (unsigned j=0; j!=vertices[i].size(); ++j)
 +			{	
 +				delete [] vertices[i][j];	
 +			}
 +			vertices[i].clear();
 +		}
 +	}
 +
 +	vertices.clear();
 +
 +	{
 +		for (unsigned i=0; i!=normals.size(); ++i)
 +		{	
 +			for (unsigned j=0; j!=normals[i].size(); ++j)
 +			{	
 +				delete [] normals[i][j];	
 +			}
 +			normals[i].clear();
 +		}
 +	}
 +	
 +	normals.clear();
 +}
 +
 +
 +void GridData::setSize(unsigned int columns, unsigned int rows)
 +{
 +	this->clear();
 +	vertices = std::vector<DataRow>(columns);
 +	{
 +		for (unsigned int i=0; i!=vertices.size(); ++i)
 +		{
 +			vertices[i] = DataRow(rows);
 +			for (unsigned int j=0; j!=vertices[i].size(); ++j)
 +			{
 +				vertices[i][j] = new GLdouble[3];
 +			}
 +		}
 +	}
 +	normals = std::vector<DataRow>(columns);
 +	{
 +		for (unsigned int i=0; i!=normals.size(); ++i)
 +		{
 +			normals[i] = DataRow(rows);
 +			for (unsigned int j=0; j!=normals[i].size(); ++j)
 +			{
 +				normals[i][j] = new GLdouble[3];
 +			}
 +		}
 +	}
 +}
 +
 +Triple const& CellData::operator()(unsigned cellnumber, unsigned vertexnumber)
 +{
 +	return nodes[cells[cellnumber][vertexnumber]];
 +}
 +
 +void CellData::clear()
 +{
 +	setHull(ParallelEpiped());
 +  cells.clear();
 +	nodes.clear();
 +	normals.clear();
 +}
 +
 +QColor Qwt3D::GL2Qt(GLdouble r, GLdouble g, GLdouble b)
 +{
 +	return QColor(round(r * 255), round(g * 255), round(b * 255));	
 +}
 +
 +RGBA Qwt3D::Qt2GL(QColor col)
 +{
 +	QRgb qrgb = col.rgb();
 +	RGBA rgba;
 +	rgba.r = qRed(qrgb) / 255.0;
 +	rgba.g = qGreen(qrgb) / 255.0;
 +	rgba.b = qBlue(qrgb) / 255.0;
 +	rgba.a = qAlpha(qrgb) / 255.0;
 +	return rgba;	
 +}
 +
 +
 +void Qwt3D::convexhull2d( std::vector<unsigned>& idx, const std::vector<Tuple>& src )
 +{
 +    idx.clear();
 +    if (src.empty())
 +        return;
 +    if (src.size()==1)
 +    {
 +        idx.push_back(0);
 +        return;
 +    }
 +    coordinate_type** points = new coordinate_type*[src.size()+1] ;
 +    coordinate_type* P = new coordinate_type[src.size()*2];
 +
 +    int i;
 +		for (i=0; i<(int)src.size(); ++i)
 +    {
 +        points[i] = &P[2*i];
 +        points[i][0] = src[i].x;
 +        points[i][1] = src[i].y;
 +    }
 +
 +    coordinate_type* start = points[0];
 +    int m = _ch2d( points, src.size() );
 +    idx.resize(m);
 +    
 +		for (i=0; i<m; ++i)
 + 		{
 +			idx[i] = (points[i] - start)/2;
 +		}
 +    delete [] points;
 +		delete [] P;
 +}
 +
 +unsigned Qwt3D::tesselationSize(CellField const& t)
 +{
 +	unsigned ret = 0;
 +	
 +	for (unsigned i=0; i!=t.size(); ++i)
 +		ret += t[i].size();
 +	
 +	return ret;
 +}
 +
 +#endif // QWT3D_NOT_FOR_DOXYGEN
 | 
