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

453 lines
12 KiB

/*
* Kivio - Visual Modelling and Flowcharting
* Copyright (C) 2000-2001 theKompany.com & Dave Marotti
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kivio_common.h"
#include "kivio_connector_point.h"
#include <kdebug.h>
#include <qstringlist.h>
#include <math.h>
#include <KoPoint.h>
#include <KoRect.h>
/**
* Read a floating point value from a @ref QDomElement.
*
* @param e The @ref QDomElement to read from
* @param att The attribute to locate
* @param def The default value to return if the attribute is not found
*
* This will read a floating point attribute from a @ref QDomElement, and
* if it is not found, return the default value.
*/
float XmlReadFloat( const QDomElement &e, const QString &att, const float &def)
{
// Check if this value exists, if not, return the default
if( e.hasAttribute( att )==false )
return def;
// Read the attribute
QString val = e.attribute( att );
bool ok=false;
// Make sure it is a floating point value. If not, return the default
float fVal = val.toFloat( &ok );
if( !ok )
{
kdDebug(43000) << "Invalid XML-value read for " << att.ascii() << ", expected float\n" << endl;
return 1.0;
}
// Return the value
return fVal;
}
/**
* Write a floating point value to a @ref QDomElement
*
* @param e The @ref QDomElement to write to
* @param att The attribute to write
* @param val The value of the attribute to write
*
* This will write a floating point value to a @ref QDomElement.
*/
void XmlWriteFloat( QDomElement &e, const QString &att, const float &val )
{
e.setAttribute( att, (double)val );
}
/**
* Read an int value from a @ref QDomElement.
*
* @param e The @ref QDomElement to read from
* @param att The attribute to locate
* @param def The default value to return if the attribute is not found
*
* This will read an int attribute from a @ref QDomElement, and
* if it is not found, return the default value.
*/
int XmlReadInt( const QDomElement &e, const QString &att, const int &def)
{
// Check if this value exists, if not, return the default
if( e.hasAttribute( att )==false )
return def;
// Read the attribute
QString val = e.attribute( att, "1" );
bool ok=false;
// Make sure it is a floating point value. If not, return the default
int iVal = val.toInt( &ok );
if( !ok )
{
kdDebug(43000) << "Invalid XML-value read for " << att << " expected int\n" << endl;
return 1;
}
// Return the value
return iVal;
}
/**
* Write a int value to a @ref QDomElement
*
* @param e The @ref QDomElement to write to
* @param att The attribute to write
* @param val The value of the attribute to write
*
* This will write an int value to a @ref QDomElement.
*/
void XmlWriteInt( QDomElement &e, const QString &att, const int &val )
{
e.setAttribute( att, (int)val );
}
/**
* Read an uint value from a @ref QDomElement.
*
* @param e The @ref QDomElement to read from
* @param att The attribute to locate
* @param def The default value to return if the attribute is not found
*
* This will read an uint attribute from a @ref QDomElement, and
* if it is not found, return the default value.
*/
uint XmlReadUInt( const QDomElement &e, const QString &att, const uint &def)
{
// Check if this value exists, if not, return the default
if( e.hasAttribute( att )==false )
return def;
// Read the attribute
QString val = e.attribute( att, "1" );
bool ok=false;
// Make sure it is a floating point value. If not, return the default
uint iVal = val.toUInt( &ok );
if( !ok )
{
kdDebug(43000) << "Invalid XML-value read for " << att.ascii() << ", expected uint\n" << endl;
return 1;
}
// Return the value
return iVal;
}
/**
* Write an uint value to a @ref QDomElement
*
* @param e The @ref QDomElement to write to
* @param att The attribute to write
* @param val The value of the attribute to write
*
* This will write an uint value to a @ref QDomElement.
*/
void XmlWriteUInt( QDomElement &e, const QString &att, const uint &val )
{
e.setAttribute( att, (uint)val );
}
/**
* Read a @ref QString from a @ref QDomElement.
*
* @param e The @ref QDomElement to read from
* @param att The attribute to locate
* @param def The default value to return if the attribute is not found
*
* This will read a QString attribute from a @ref QDomElement, and
* if it is not found, return the default value.
*/
QString XmlReadString( const QDomElement &e, const QString &att, const QString &def )
{
// Check if the attribute exists, if not, return the default
if( e.hasAttribute( att )==false )
return QString(def);
// Otherwise return the attribute
else return e.attribute( att );
}
/**
* Write a QString to a @ref QDomElement
*
* @param e The @ref QDomElement to write to
* @param att The attribute to write
* @param val The value of the attribute to write
*
* This will write a QString to a @ref QDomElement.
*/
void XmlWriteString( QDomElement &e, const QString &att, const QString &val )
{
e.setAttribute( att, val );
}
/**
* Read a QColor value from a @ref QDomElement.
*
* @param e The @ref QDomElement to read from
* @param att The attribute to locate
* @param def The default value to return if the attribute is not found
*
* This will read a QColor attribute from a @ref QDomElement, and
* if it is not found, return the default value.
*/
QColor XmlReadColor( const QDomElement &e, const QString &att, const QColor &def)
{
// Check if this value exists, if not, return the default
if( e.hasAttribute( att )==false )
return def;
// Read the attribute
QString val = e.attribute( att, "1" );
bool ok=false;
QColor newColor;
if( val.contains("#") ) // Is it #RRGGBB format?
{
newColor.setNamedColor(val);
return newColor;
}
// Otherwise it is a #xxxxxxxx color (rgb format)
// Make sure it is a uint value. If not, return the default
uint iVal = val.toUInt( &ok );
if( !ok )
{
kdDebug(43000) << "Invalid XML-value read for " << att.ascii() << ", expected QColor" << endl;
return 1;
}
// Return the value
return QColor(iVal);
}
/**
* Write a QColor value to a @ref QDomElement
*
* @param e The @ref QDomElement to write to
* @param att The attribute to write
* @param val The value of the attribute to write
*
* This will write a QColor value to a @ref QDomElement.
*/
void XmlWriteColor( QDomElement &e, const QString &att, const QColor &val )
{
// Write it out in #RRGGBB format
e.setAttribute( att, val.name() );
}
/**
* Read a double value from a @ref QDomElement.
*
* @param e The @ref QDomElement to read from
* @param att The attribute to locate
* @param def The default value to return if the attribute is not found
*
* This will read a double attribute from a @ref QDomElement, and
* if it is not found, return the default value.
*/
double XmlReadDouble( const QDomElement &e, const QString &att, const double &def)
{
// Check if this value exists, if not, return the default
if( e.hasAttribute( att )==false )
return def;
// Read the attribute
QString val = e.attribute( att, "1.0" );
bool ok=false;
// Make sure it is a floating point value. If not, return the default
double dVal = val.toDouble( &ok );
if( !ok )
{
kdDebug(43000) << "Invalid XML-value read for ," << att.ascii() << " expected double" << endl;
return 1.0;
}
// Return the value
return dVal;
}
/**
* Write a double value to a @ref QDomElement
*
* @param e The @ref QDomElement to write to
* @param att The attribute to write
* @param val The value of the attribute to write
*
* This will write a double value to a @ref QDomElement.
*/
void XmlWriteDouble( QDomElement &e, const QString &att, const double &val )
{
e.setAttribute( att, (double)val );
}
#define WHICH_QUAD( vertex, hitPos ) \
( (vertex.x() > hitPos->x()) ? ((vertex.y() > hitPos->y()) ? 1 : 4 ) : ((vertex.y() > hitPos->y())?2:3))
#define X_INTERCEPT( point1, point2, hitY ) \
(point2.x() - (((point2.y()-hitY)*(point1.x()-point2.x()))/(point1.y()-point2.y())))
/**
* Determines if a point is inside a given polygon
* @param points An array of points representing the polygon
* @param numPoints The number of points in the array
* @param hitPos The point we are to check
*
* Code taken from Game Developer magazine page 22, January 1999 issue
* Explaination:
*
* A better strategy is to divide the polygon into quadrants centered on the test point.
* Start at the first vertex in the polygon and set a counter to 0. Anytime an edge crosses
* from one quadrant to the next, add one to the counter if it crosses clockwise around the
* test point and subtract one if it crosses counter-clockwise. If the edge crosses diagonally
* across two quadrants, you need to determine which side of the test point it crossed, and then
* either add or subtract 2.
*
* Quad layout:
* 1 2
* 4 3
*/
bool PointInPoly( KoPoint *points, int numPoints, KoPoint *hitPos )
{
int edge, next;
int quad, next_quad, delta, total;
edge = 0;
quad = WHICH_QUAD( points[ edge ], hitPos );
total = 0; // count of absolute sectors crossed
// Loop through all the vertices
do {
next = (edge + 1) % numPoints;
next_quad = WHICH_QUAD( points[ next ], hitPos );
// Calculate how many quads have been crossed
delta = next_quad - quad;
// Special case to handle crossings of more than one quad
switch( delta )
{
case 2: // If we crossed the middle, figure out if it was clockwise or counter clockwise
case -2: // Use the X-position at the hit point to determine which way around
if( X_INTERCEPT( points[edge], points[next], hitPos->y() ) > hitPos->x() )
delta = -delta;
break;
case 3: // Moving 3 quads is like moving back 1
delta = -1;
break;
case -3: // Moving back 3 is like moving forward 1
delta = 1;
break;
}
// Add in the delta
total += delta;
quad = next_quad;
edge = next;
} while( edge != 0 );
// After everything, if the total is 4, then we are inside
if((total==4) || (total==-4))
return true;
else
return false;
}
KoRect XmlReadRect( const QDomElement &e, const QString &att, const KoRect &def )
{
// Check if this value exists, if not, return the default
if( e.hasAttribute( att )==false )
return def;
// Read the attribute
QString val = e.attribute( att );
if (val.find("[") == 0 && val.find("]") == (int)val.length()-1) {
val.remove(0,1);
val.remove(val.length()-1,1);
QStringList vlist = QStringList::split(",",val);
if (vlist.count() == 4) {
bool allOk = true;
bool ok = false;
double x = vlist[0].toDouble(&ok);
allOk = allOk & ok;
double y = vlist[1].toDouble(&ok);
allOk = allOk & ok;
double w = vlist[2].toDouble(&ok);
allOk = allOk & ok;
double h = vlist[3].toDouble(&ok);
allOk = allOk & ok;
if (allOk)
return KoRect(x, y, w, h);
}
}
return def;
}
void XmlWriteRect( QDomElement &e, const QString &att, const KoRect &val )
{
e.setAttribute( att, QString("[%1,%2,%3,%4]").arg(val.x()).arg(val.y()).arg(val.width()).arg(val.height()) );
}
float shortestDistance( KivioConnectorPoint *pStart, KivioConnectorPoint *pEnd, KivioConnectorPoint *q )
{
float uX, uY;
float pqX, pqY;
uX = pStart->x() - pEnd->x();
uY = pStart->y() - pEnd->y();
pqX = pStart->x() - q->x();
pqY = pStart->y() - q->y();
float magTop = fabs(pqX*uY - (pqY*uX));
float magU = sqrt( uX*uX + uY*uY );
if( magU == 0.0f )
{
kdDebug(43000) << "shortestDistance() - SERIOUS ERROR: magU is 0.0f!\n";
return 10.0f;
}
return magTop / magU;
}