All pastes #495203 Raw Edit

Viki

public text v1 · immutable
·published 2007-05-18 17:00 UTC
rendered paste body
#define _CRT_SECURE_NO_WARNINGS
#include "Edge.h"
#include "Node.h"

#include "Graph.h"

#include <math.h>


Graph::Graph()
{

}

Graph::~Graph()
{
	//delete [] nodeLink;
	//delete [] edges;
}

void Graph::setVars(int nodecnt,int edgecnt,int SpringEmbedderIterations,double K,double C,
		double MaxRepulsiveForceDistance, double MaxNodeMovement,int MinDiagramSize, int BorderSize,
		int width,int height)
{
	//nodeLink = new Node * [nodecnt];
	//edges = new Edge[edgecnt];
	gc.nodeCount = nodecnt;
	gc.edgeCount = edgecnt;
	gc.SpringEmbedderIterations = SpringEmbedderIterations;
	gc.K = K;
	gc.C = C;
	gc.MaxRepulsiveForceDistance = MaxRepulsiveForceDistance;
	gc.MaxNodeMovement = MaxNodeMovement;
	gc.MinDiagramSize = MinDiagramSize;
	gc.BorderSize = BorderSize;

	gc.width = width;
	gc.height = height;
}

void Graph::doLayout()
{
	std::list <Node>::iterator c = nodes.begin();
	c++;
	for (int it = 0;it < gc.SpringEmbedderIterations;it++)
		for (std::list <Node>::iterator a = nodes.begin();a != nodes.end();a++,c++)
			for (std::list <Node>::iterator b = c;b != nodes.end();b++)
			{
				Node *nodeA = &(*a);
				Node *nodeB = &(*b);
				double deltaX = nodeB->getX() - nodeA->getX();
				double deltaY = nodeB->getY() - nodeA->getY();

				double distanceSquared = deltaX * deltaX + deltaY * deltaY;

				if (distanceSquared < 0.01) 
				{
					deltaX = (rand() % 2) / 10 + 0.1;
					deltaY = (rand() % 2) / 10 + 0.1;
					distanceSquared = deltaX * deltaX + deltaY * deltaY;
				}
				double distance = sqrt(distanceSquared);

				if (distance < gc.MaxRepulsiveForceDistance) 
				{
					double repulsiveForce = (gc.K * gc.K / distance);
						                        
					nodeB->setFX(nodeB->getFX() + (repulsiveForce * deltaX / distance));
					nodeB->setFY(nodeB->getFY() + (repulsiveForce * deltaY / distance));
					nodeA->setFX(nodeA->getFX() - (repulsiveForce * deltaX / distance));
					nodeA->setFY(nodeA->getFY() - (repulsiveForce * deltaY / distance));
				}
		// Calculate forces acting on nodes due to edge attractions.
		for (ei = edges.begin(); ei != edges.end(); ei++) 
		{
			Edge edge = *ei;
			Node nodeA = ei->getSource();
			Node nodeB = ei->getTarget();
			double deltaX = nodeB.getX() - nodeA.getX();
			double deltaY = nodeB.getY() - nodeA.getY();

			double distanceSquared = deltaX * deltaX + deltaY * deltaY;

			// Avoid division by zero error or Nodes flying off to
			// infinity.  Pretend there is an arbitrary distance between
			// the Nodes.
			if (distanceSquared < 0.01) 
			{
				deltaX = (rand() % 2) / 10 + 0.1;
				deltaY = (rand() % 2) / 10 + 0.1;
				distanceSquared = deltaX * deltaX + deltaY * deltaY;
			}

			double distance = sqrt(distanceSquared);

			if (distance > gc.MaxRepulsiveForceDistance) 
				distance = gc.MaxRepulsiveForceDistance;

			distanceSquared = distance * distance;

			double attractiveForce = (distanceSquared - gc.K * gc.K) / gc.K;

			// Make edges stronger if people know each other.
			double weight = edge.getWeight();
			if (weight < 1)
				weight = 1;

			attractiveForce *= (log(weight) * 0.5) + 1;
			nodeB.setFX(nodeB.getFX() - attractiveForce * deltaX / distance);
			nodeB.setFY(nodeB.getFY() - attractiveForce * deltaY / distance);
			nodeA.setFX(nodeA.getFX() + attractiveForce * deltaX / distance);
			nodeA.setFY(nodeA.getFY() + attractiveForce * deltaY / distance);
			ei->copyNodes(nodeA,nodeB);
		}
		// Now move each node to its new location...
		for (std::list <Node>::iterator a = nodes.begin();a != nodes.end();a++)
		{
			Node *node = &(*a);

			double xMovement = gc.C * node->getFX();
			double yMovement = gc.C * node->getFY();

			// Limit movement values to stop nodes flying into oblivion.
			double max = gc.MaxNodeMovement;
			if (xMovement > max)
				xMovement = max;
			else if (xMovement < -max)
				xMovement = -max;
			if (yMovement > max)
				yMovement = max;
			else if (yMovement < -max)
				yMovement = -max;

			node->setX(node->getX() + xMovement);
			node->setY(node->getY() + yMovement);

			// Reset the forces
			node->setFX(0);
			node->setFY(0);
		}
	}
}

void Graph::calcBounds()
{
	minX = 4294967296;
	maxX = -4294967296;
	minY = 4294967296;
	maxY = -4294967296;
	maxWeight = 0;


	for (std::list <Node>::iterator a = nodes.begin();a != nodes.end();a++)
	{
		Node *node = &(*a);

		if (node->getX() > maxX)
		maxX = node->getX();

		if (node->getX() < minX)
		minX = node->getX();

		if (node->getY() > maxY)
		maxY = node->getY();

		if (node->getY() < minY)
		 minY = node->getY();
	}

	// Increase size if too small.
	double minSize = gc.MinDiagramSize;
	if (maxX - minX < minSize) 
	{
		double midX = (maxX + minX) / 2;
		minX = midX - (minSize / 2);
		maxX = midX + (minSize / 2);
	}
	if (maxY - minY < minSize) 
	{
		double midY = (maxY + minY) / 2;
		minY = midY - (minSize / 2);
		maxY = midY + (minSize / 2);
	}

	// Jibble the boundaries to maintain the aspect ratio.
	double xyRatio = ((maxX - minX) / (maxY - minY)) / (gc.width / gc.height);
	if (xyRatio > 1) 
	{
		// diagram is wider than it is high.
		double dy = maxY - minY;
		dy = dy * xyRatio - dy;
		minY = minY - dy / 2;
		maxY = maxY + dy / 2;
	}
	else if (xyRatio < 1) 
	{
		// Diagram is higher than it is wide.
		double dx = maxX - minX;
		dx = dx / xyRatio - dx;
		minX = minX - dx / 2;
		maxX = maxX + dx / 2;
	}
	ni = nodes.begin();
}

void Graph::calcPositions()
{
	for (std::list <Node>::iterator a = nodes.begin();a != nodes.end();a++)
	{
		Node *node = &(*a);
		node->setX((float)((int)((gc.width * (node->getX() - minX) / (maxX - minX)) + gc.BorderSize)));
		node->setY((float)((int)((gc.height * (node->getY() - minY) / (maxY - minY)) + gc.BorderSize)));
	}
}

void Graph::getNode(int slot,char *data)
{
	if (ni == nodes.end())
		ni = nodes.begin();
	sprintf(data,"%d %d",ni->getX(),ni->getY());
	ni++;
}
void Graph::getEdge(int slot, char *data)
{
	ei = edges.begin();
	sprintf(data,"%d %d %d %d",ei[slot].getSource().getX(),ei[slot].getSource().getY(),
		ei[slot].getTarget().getX(),ei[slot].getTarget().getY());
}
void Graph::addNode(std::string nick, double weight, int slot)
{
	Node node;
	node.setVars(nick,weight,slot);
	nodes.push_back(node);
}
void Graph::addEdge(int source, int target, double weight,int slot)
{
	Edge edge;
	Node na;
	Node nb;
	bool f1,f2;
	f1 = false;
	f2 = false;
	for (std::list <Node>::iterator a = nodes.begin();a != nodes.end();a++)
	{
		if (a->getSlot() == source)
		{
			na = *a;
			f1 = true;
		}
		else if (a->getSlot() == target)
		{
			nb = *a;
			f2 = true;
		}
		if ((f1) && (f2))
			break;
	}
	edge.setVars(&na,&nb,weight);
	edges.push_back(edge);
	//edges[slot].setVars(&nodes[source],&nodes[target],weight);
}