https://github.com/ialhashim/topo-blend
Revision 39b13612ebd645a65eda854771b517371f2f858a authored by ennetws on 13 March 2015, 18:17:18 UTC, committed by ennetws on 13 March 2015, 18:17:18 UTC
1 parent c702819
Raw File
Tip revision: 39b13612ebd645a65eda854771b517371f2f858a authored by ennetws on 13 March 2015, 18:17:18 UTC
Create README.md
Tip revision: 39b1361
GraphEmbed.h
#pragma once
#include "StructureGraph.h"

#include <Eigen/Core>
#include <Eigen/Eigenvalues>
using namespace Eigen;

static QString NODE_CENTER = "center2D";

struct GraphEmbed
{
    static void embed( Structure::Graph * graph )
    {
        // Get nodes centers
        QMap<int, Node*> nmap;
        std::vector<Vector3> centers;
        foreach(Node * n, graph->nodes){
            nmap[nmap.size()] = n;
            centers.push_back( Vector3(n->bbox().center()) );
        }
        int N = centers.size();

        // PCA
        Vector3 plane_center(0,0,0), plane_normal(0,0,0); Scalar plane_d = 0;
        planePCA(centers, plane_center, plane_normal, plane_d);

        // Project to PCA plane, to XY plane and assign back to node
        for(int i = 0; i < N; i++)
		{
            Vector3 p = pointOnPlane( centers[i], plane_normal, plane_d );
			nmap[i]->vis_property[NODE_CENTER] = QVector3D( QVector3(RotateFromTo(plane_normal, Vector3(0,0,1), p, plane_center)) );
		}
            
        graph->property["embeded2D"] = true;
    }

	static void sphereRandomEmbed( Structure::Graph * graph )
	{
		// Get nodes centers
		QMap<int, Node*> nmap;
		std::vector<Vector3> centers;
		foreach(Node * n, graph->nodes)
		{
			nmap[nmap.size()] = n;

			double u = uniform(-1,1);
			double theta = uniform(0, 2 * M_PI);
			Vector3 randomCenter(sqrt(1 - (u*u)) * cos(theta), sqrt(1 - (u*u)) * sin(theta), u);

			centers.push_back( randomCenter );
		}
		int N = centers.size();

		// PCA
		Vector3 plane_center(0,0,0), plane_normal(0,0,0); Scalar plane_d = 0;
		planePCA(centers, plane_center, plane_normal, plane_d);

		// Project to PCA plane, to XY plane and assign back to node
		for(int i = 0; i < N; i++)
		{
			Vector3 p = pointOnPlane( centers[i], plane_normal, plane_d );
			nmap[i]->vis_property[NODE_CENTER] = QVector3D( QVector3(RotateFromTo(plane_normal, Vector3(0,0,1), p, plane_center)) );
		}

		graph->property["embeded2D"] = true;
	}

	static void circleEmbed( Structure::Graph * graph )
	{
		int N = graph->nodes.size();

		double theta = (2 * M_PI) / N;

		for(int i = 0; i < N; i++)
		{
			graph->nodes[i]->vis_property[NODE_CENTER] = QVector3D( cos(i * theta), sin(i * theta), 0 );
		}

		graph->property["embeded2D"] = true;
	}

	static double inline uniform(double a = 0.0, double b = 1.0){
		double len = b - a;
		return ((double)rand()/RAND_MAX) * len + a;
	}

    static void planePCA(const std::vector<Vector3> & points, Vector3 & center, Vector3 & normal, Scalar & d)
    {
        int N = points.size();

        Scalar	x, y, z, xx, yy, zz, xy, xz, yz,
            sumX (0), sumY (0), sumZ (0),
            sumX2(0), sumY2(0), sumZ2(0),
            sumXY(0), sumXZ(0), sumYZ(0);

        Vector3 mean(0,0,0);

        foreach(Vector3 p, points){
            x = p.x();	y = p.y();	z = p.z();
            sumX  += x / N		;	sumY  += y / N		;	sumZ  += z / N;
            sumX2 += x * x / N	;	sumY2 += y * y / N	;	sumZ2 += z * z / N;
            sumXY += x * y / N	;	sumXZ += x * z / N	;	sumYZ += y * z / N;
            mean += p;
        }

        mean /= points.size();

        xx = sumX2 - sumX * sumX; yy = sumY2 - sumY * sumY;	zz = sumZ2 - sumZ * sumZ;
        xy = sumXY - sumX * sumY; xz = sumXZ - sumX * sumZ;	yz = sumYZ - sumY * sumZ;

        Matrix3d covariance;
        covariance << xx, xy, xz,
                      xy, yy, yz,
                      xz, yz, zz;

        SelfAdjointEigenSolver<Eigen::Matrix3d> es(covariance);
        Vector3d e_values = es.eigenvalues();;
        Matrix3d e_vectors = es.eigenvectors();

        Vector3d u = e_vectors.col(1).normalized();
        Vector3d v = e_vectors.col(2).normalized();
        Vector3d n = u.cross(v);

        // Output: a plane
        center  = mean;
        normal  = Vector3(n[0], n[1], n[2]);
        d       = -dot(normal, center);
    }

    static Vector3 pointOnPlane(Vector3 q, Vector3 pn, Scalar pd)
    {
        Scalar t = dot(pn, q) - pd;
        return q - t * pn;
    }

    static Vector3 RotateFromTo(Vector3 from, Vector3 to, Vector3 & point, Vector3 pivot = Vector3(0,0,0))
    {
		Vector3 axis = cross(from, to).normalized();
		double theta = acos( qRanged(-1.0, dot(from.normalized(), to.normalized()), 1.0) );

		point -= pivot;
		point = (point * cos(theta) + cross(axis, point) * sin(theta) + axis * dot(axis, point) * (1 - cos(theta)));
		point += pivot;

		return point;
    }

};
back to top