mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
597 lines
20 KiB
C++
597 lines
20 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkBoostDividedEdgeBundling.cxx
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
/*-------------------------------------------------------------------------
|
|
Copyright 2008 Sandia Corporation.
|
|
Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
the U.S. Government retains certain rights in this software.
|
|
-------------------------------------------------------------------------*/
|
|
#include "vtkBoostDividedEdgeBundling.h"
|
|
|
|
#include "vtkBoostGraphAdapter.h"
|
|
#include "vtkDataSetAttributes.h"
|
|
#include "vtkDirectedGraph.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkNew.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPoints.h"
|
|
#include "vtkVectorOperators.h"
|
|
|
|
#include <boost/property_map/property_map.hpp>
|
|
#include <boost/graph/johnson_all_pairs_shortest.hpp>
|
|
#include <algorithm>
|
|
|
|
vtkStandardNewMacro(vtkBoostDividedEdgeBundling);
|
|
|
|
vtkBoostDividedEdgeBundling::vtkBoostDividedEdgeBundling()
|
|
{
|
|
}
|
|
|
|
class vtkBundlingMetadata
|
|
{
|
|
public:
|
|
vtkBundlingMetadata(vtkBoostDividedEdgeBundling *alg, vtkDirectedGraph *g)
|
|
: Outer(alg), Graph(g)
|
|
{
|
|
this->Nodes = reinterpret_cast<vtkVector3f*>(
|
|
vtkFloatArray::SafeDownCast(g->GetPoints()->GetData())->GetPointer(0));
|
|
this->Edges.resize(g->GetNumberOfEdges());
|
|
for (vtkIdType e = 0; e < g->GetNumberOfEdges(); ++e)
|
|
{
|
|
this->Edges[e] = std::make_pair(g->GetSourceVertex(e), g->GetTargetVertex(e));
|
|
}
|
|
this->VelocityDamping = 0.1f;
|
|
this->EdgeCoulombConstant = 0.5f;
|
|
//this->EdgeCoulombConstant = 50.0f;
|
|
this->EdgeCoulombDecay = 35.0f;
|
|
this->EdgeSpringConstant = 0.1f;
|
|
//this->EdgeSpringConstant = 0.0005f;
|
|
this->EdgeLaneWidth = 25.0f;
|
|
this->UseNewForce = true;
|
|
}
|
|
|
|
void ProjectOnto(vtkIdType e1, vtkIdType e2, vtkVector3f& s, vtkVector3f& t);
|
|
void NormalizeNodePositions();
|
|
void DenormalizeNodePositions();
|
|
void CalculateNodeDistances();
|
|
float AngleCompatibility(vtkIdType e1, vtkIdType e2);
|
|
float ScaleCompatibility(vtkIdType e1, vtkIdType e2);
|
|
float PositionCompatibility(vtkIdType e1, vtkIdType e2);
|
|
float VisibilityCompatibility(vtkIdType e1, vtkIdType e2);
|
|
float ConnectivityCompatibility(vtkIdType e1, vtkIdType e2);
|
|
void CalculateEdgeLengths();
|
|
void CalculateEdgeCompatibilities();
|
|
void InitializeEdgeMesh();
|
|
void DoubleEdgeMeshResolution();
|
|
void SimulateEdgeStep();
|
|
void LayoutEdgePoints();
|
|
void SmoothEdges();
|
|
|
|
float SimulationStep;
|
|
int CycleIterations;
|
|
int MeshCount;
|
|
float VelocityDamping;
|
|
float EdgeCoulombConstant;
|
|
float EdgeCoulombDecay;
|
|
float EdgeSpringConstant;
|
|
float EdgeLaneWidth;
|
|
bool UseNewForce;
|
|
vtkBoostDividedEdgeBundling *Outer;
|
|
vtkDirectedGraph *Graph;
|
|
vtkVector3f *Nodes;
|
|
std::vector<std::pair<vtkIdType, vtkIdType> > Edges;
|
|
std::vector<std::vector<float> > NodeDistances;
|
|
std::vector<float> EdgeLengths;
|
|
std::vector<std::vector<float> > EdgeCompatibilities;
|
|
std::vector<std::vector<float> > EdgeDots;
|
|
std::vector<std::vector<vtkVector3f> > EdgeMesh;
|
|
std::vector<std::vector<vtkVector3f> > EdgeMeshVelocities;
|
|
std::vector<std::vector<vtkVector3f> > EdgeMeshAccelerations;
|
|
//std::vector<std::vector<float> > EdgeMeshGroupCounts;
|
|
vtkVector2f XRange;
|
|
vtkVector2f YRange;
|
|
vtkVector2f ZRange;
|
|
float Scale;
|
|
};
|
|
|
|
void vtkBundlingMetadata::NormalizeNodePositions()
|
|
{
|
|
this->XRange = vtkVector2f(VTK_FLOAT_MAX, VTK_FLOAT_MIN);
|
|
this->YRange = vtkVector2f(VTK_FLOAT_MAX, VTK_FLOAT_MIN);
|
|
this->ZRange = vtkVector2f(VTK_FLOAT_MAX, VTK_FLOAT_MIN);
|
|
for (vtkIdType i = 0; i < this->Graph->GetNumberOfVertices(); ++i)
|
|
{
|
|
vtkVector3f p = this->Nodes[i];
|
|
this->XRange[0] = std::min(this->XRange[0], p[0]);
|
|
this->XRange[1] = std::max(this->XRange[1], p[0]);
|
|
this->YRange[0] = std::min(this->YRange[0], p[1]);
|
|
this->YRange[1] = std::max(this->YRange[1], p[1]);
|
|
this->ZRange[0] = std::min(this->ZRange[0], p[2]);
|
|
this->ZRange[1] = std::max(this->ZRange[1], p[2]);
|
|
}
|
|
float dx = this->XRange[1] - this->XRange[0];
|
|
float dy = this->YRange[1] - this->YRange[0];
|
|
float dz = this->ZRange[1] - this->ZRange[0];
|
|
this->Scale = std::max(dx, std::max(dy, dz));
|
|
for (vtkIdType i = 0; i < this->Graph->GetNumberOfVertices(); ++i)
|
|
{
|
|
vtkVector3f p = this->Nodes[i];
|
|
this->Nodes[i] = vtkVector3f(
|
|
(p[0] - this->XRange[0])/this->Scale * 1000.0f,
|
|
(p[1] - this->YRange[0])/this->Scale * 1000.0f,
|
|
(p[2] - this->ZRange[0])/this->Scale * 1000.0f);
|
|
}
|
|
}
|
|
|
|
void vtkBundlingMetadata::DenormalizeNodePositions()
|
|
{
|
|
for (vtkIdType i = 0; i < this->Graph->GetNumberOfVertices(); ++i)
|
|
{
|
|
vtkVector3f p = this->Nodes[i];
|
|
this->Nodes[i] = vtkVector3f(
|
|
p[0] / 1000.0f * this->Scale + this->XRange[0],
|
|
p[1] / 1000.0f * this->Scale + this->YRange[0],
|
|
p[2] / 1000.0f * this->Scale + this->ZRange[0]);
|
|
}
|
|
for (vtkIdType i = 0; i < (int)this->EdgeMesh.size(); ++i)
|
|
{
|
|
for (vtkIdType j = 0; j < (int)this->EdgeMesh[i].size(); ++j)
|
|
{
|
|
vtkVector3f p = this->EdgeMesh[i][j];
|
|
this->EdgeMesh[i][j] = vtkVector3f(
|
|
p[0] / 1000.0f * this->Scale + this->XRange[0],
|
|
p[1] / 1000.0f * this->Scale + this->YRange[0],
|
|
p[2] / 1000.0f * this->Scale + this->ZRange[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkBundlingMetadata::CalculateNodeDistances()
|
|
{
|
|
vtkIdType numVerts = this->Graph->GetNumberOfVertices();
|
|
vtkIdType numEdges = this->Graph->GetNumberOfEdges();
|
|
this->NodeDistances.resize(numVerts, std::vector<float>(numVerts, VTK_FLOAT_MAX));
|
|
std::vector<float> weights(numVerts, 1.0f);
|
|
vtkNew<vtkFloatArray> weightMap;
|
|
weightMap->SetNumberOfTuples(numEdges);
|
|
for (vtkIdType e = 0; e < numEdges; ++e)
|
|
{
|
|
weightMap->SetValue(e, 1.0f);
|
|
}
|
|
boost::vtkGraphEdgePropertyMapHelper<vtkFloatArray*> weightProp(weightMap.GetPointer());
|
|
boost::johnson_all_pairs_shortest_paths(
|
|
this->Graph, this->NodeDistances,
|
|
boost::weight_map(weightProp));
|
|
}
|
|
|
|
float vtkBundlingMetadata::AngleCompatibility(vtkIdType e1, vtkIdType e2)
|
|
{
|
|
if (this->EdgeLengths[e1] == 0.0f || this->EdgeLengths[e2] == 0.0f)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
vtkVector3f s1 = this->Nodes[this->Edges[e1].first];
|
|
vtkVector3f t1 = this->Nodes[this->Edges[e1].second];
|
|
vtkVector3f s2 = this->Nodes[this->Edges[e2].first];
|
|
vtkVector3f t2 = this->Nodes[this->Edges[e2].second];
|
|
vtkVector3f p1 = s1 - t1;
|
|
vtkVector3f p2 = s2 - t2;
|
|
float compatibility = p1.Dot(p2) / (this->EdgeLengths[e1]*this->EdgeLengths[e2]);
|
|
return fabs(compatibility);
|
|
}
|
|
|
|
float vtkBundlingMetadata::ScaleCompatibility(vtkIdType e1, vtkIdType e2)
|
|
{
|
|
float len1 = this->EdgeLengths[e1];
|
|
float len2 = this->EdgeLengths[e2];
|
|
float average = (len1 + len2) / 2.0f;
|
|
if (average == 0.0f)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
return 2.0f / (average / std::min(len1, len2) + std::max(len1, len2) / average);
|
|
}
|
|
|
|
float vtkBundlingMetadata::PositionCompatibility(vtkIdType e1, vtkIdType e2)
|
|
{
|
|
float len1 = this->EdgeLengths[e1];
|
|
float len2 = this->EdgeLengths[e2];
|
|
float average = (len1 + len2) / 2.0f;
|
|
if (average == 0.0f)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
vtkVector3f s1 = this->Nodes[this->Edges[e1].first];
|
|
vtkVector3f t1 = this->Nodes[this->Edges[e1].second];
|
|
vtkVector3f s2 = this->Nodes[this->Edges[e2].first];
|
|
vtkVector3f t2 = this->Nodes[this->Edges[e2].second];
|
|
vtkVector3f mid1 = 0.5*(s1 + t1);
|
|
vtkVector3f mid2 = 0.5*(s2 + t2);
|
|
return average / (average + (mid1 - mid2).Norm());
|
|
}
|
|
|
|
void vtkBundlingMetadata::ProjectOnto(vtkIdType e1, vtkIdType e2, vtkVector3f& s, vtkVector3f& t)
|
|
{
|
|
vtkVector3f s1 = this->Nodes[this->Edges[e1].first];
|
|
vtkVector3f t1 = this->Nodes[this->Edges[e1].second];
|
|
vtkVector3f s2 = this->Nodes[this->Edges[e2].first];
|
|
vtkVector3f t2 = this->Nodes[this->Edges[e2].second];
|
|
vtkVector3f norm = t2 - s2;
|
|
norm.Normalize();
|
|
vtkVector3f toHead = s1 - s2;
|
|
vtkVector3f toTail = t1 - s2;
|
|
vtkVector3f headOnOther = norm * norm.Dot(toHead);
|
|
vtkVector3f tailOnOther = norm * norm.Dot(toTail);
|
|
s = s2 + headOnOther;
|
|
t = s2 + tailOnOther;
|
|
}
|
|
|
|
float vtkBundlingMetadata::VisibilityCompatibility(vtkIdType e1, vtkIdType e2)
|
|
{
|
|
vtkVector3f is;
|
|
vtkVector3f it;
|
|
vtkVector3f js;
|
|
vtkVector3f jt;
|
|
this->ProjectOnto(e1, e2, is, it);
|
|
this->ProjectOnto(e2, e1, js, jt);
|
|
float ilen = (is - it).Norm();
|
|
float jlen = (js - jt).Norm();
|
|
if (ilen == 0.0f || jlen == 0.0f)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
vtkVector3f s1 = this->Nodes[this->Edges[e1].first];
|
|
vtkVector3f t1 = this->Nodes[this->Edges[e1].second];
|
|
vtkVector3f s2 = this->Nodes[this->Edges[e2].first];
|
|
vtkVector3f t2 = this->Nodes[this->Edges[e2].second];
|
|
vtkVector3f mid1 = 0.5*(s1 + t1);
|
|
vtkVector3f mid2 = 0.5*(s2 + t2);
|
|
vtkVector3f imid = 0.5*(is + it);
|
|
vtkVector3f jmid = 0.5*(js + jt);
|
|
float midQI = (mid2 - imid).Norm();
|
|
float vpq = std::max(0.0f, 1.0f - (2.0f * midQI) / ilen);
|
|
float midPJ = (mid1 - jmid).Norm();
|
|
float vqp = std::max(0.0f, 1.0f - (2.0f * midPJ) / jlen);
|
|
|
|
return std::min(vpq, vqp);
|
|
}
|
|
|
|
float vtkBundlingMetadata::ConnectivityCompatibility(vtkIdType e1, vtkIdType e2)
|
|
{
|
|
vtkIdType s1 = this->Edges[e1].first;
|
|
vtkIdType t1 = this->Edges[e1].second;
|
|
vtkIdType s2 = this->Edges[e2].first;
|
|
vtkIdType t2 = this->Edges[e2].second;
|
|
if (s1 == s2 || s1 == t2 || t1 == s2 || t1 == t2)
|
|
{
|
|
return 1.0f;
|
|
}
|
|
float minPath = std::min(this->NodeDistances[s1][s2], std::min(this->NodeDistances[s1][t2],
|
|
std::min(this->NodeDistances[t1][s2], this->NodeDistances[t1][t2])));
|
|
return 1.0f / (minPath + 1.0f);
|
|
}
|
|
|
|
void vtkBundlingMetadata::CalculateEdgeLengths()
|
|
{
|
|
vtkIdType numEdges = this->Graph->GetNumberOfEdges();
|
|
this->EdgeLengths.resize(numEdges);
|
|
for (vtkIdType e = 0; e < numEdges; ++e)
|
|
{
|
|
vtkVector3f s = this->Nodes[this->Edges[e].first];
|
|
vtkVector3f t = this->Nodes[this->Edges[e].second];
|
|
this->EdgeLengths[e] = (s - t).Norm();
|
|
}
|
|
}
|
|
|
|
void vtkBundlingMetadata::CalculateEdgeCompatibilities()
|
|
{
|
|
vtkIdType numEdges = this->Graph->GetNumberOfEdges();
|
|
this->EdgeCompatibilities.resize(numEdges, std::vector<float>(numEdges, 1.0f));
|
|
this->EdgeDots.resize(numEdges, std::vector<float>(numEdges, 1.0f));
|
|
for (vtkIdType e1 = 0; e1 < numEdges; ++e1)
|
|
{
|
|
vtkVector3f s1 = this->Nodes[this->Edges[e1].first];
|
|
vtkVector3f t1 = this->Nodes[this->Edges[e1].second];
|
|
vtkVector3f r1 = s1 - t1;
|
|
r1.Normalize();
|
|
for (vtkIdType e2 = e1 + 1; e2 < numEdges; ++e2)
|
|
{
|
|
float compatibility = 1.0f;
|
|
compatibility *= this->AngleCompatibility(e1, e2);
|
|
compatibility *= this->ScaleCompatibility(e1, e2);
|
|
compatibility *= this->PositionCompatibility(e1, e2);
|
|
compatibility *= this->VisibilityCompatibility(e1, e2);
|
|
compatibility *= this->ConnectivityCompatibility(e1, e2);
|
|
this->EdgeCompatibilities[e1][e2] = compatibility;
|
|
this->EdgeCompatibilities[e2][e1] = compatibility;
|
|
|
|
vtkVector3f s2 = this->Nodes[this->Edges[e2].first];
|
|
vtkVector3f t2 = this->Nodes[this->Edges[e2].second];
|
|
vtkVector3f r2 = s2 - t2;
|
|
r2.Normalize();
|
|
float dot = r1.Dot(r2);
|
|
this->EdgeDots[e1][e2] = dot;
|
|
this->EdgeDots[e2][e1] = dot;
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkBundlingMetadata::InitializeEdgeMesh()
|
|
{
|
|
this->MeshCount = 2;
|
|
vtkIdType numEdges = this->Graph->GetNumberOfEdges();
|
|
this->EdgeMesh.resize(numEdges, std::vector<vtkVector3f>(2));
|
|
this->EdgeMeshVelocities.resize(numEdges, std::vector<vtkVector3f>(2));
|
|
this->EdgeMeshAccelerations.resize(numEdges, std::vector<vtkVector3f>(2));
|
|
//this->EdgeMeshGroupCounts.resize(numEdges, std::vector<float>(2, 1.0f));
|
|
for (vtkIdType e = 0; e < numEdges; ++e)
|
|
{
|
|
this->EdgeMesh[e][0] = this->Nodes[this->Edges[e].first];
|
|
this->EdgeMesh[e][1] = this->Nodes[this->Edges[e].second];
|
|
}
|
|
}
|
|
|
|
void vtkBundlingMetadata::DoubleEdgeMeshResolution()
|
|
{
|
|
int newMeshCount = (this->MeshCount - 1)*2 + 1;
|
|
vtkIdType numEdges = this->Graph->GetNumberOfEdges();
|
|
std::vector<std::vector<vtkVector3f> > newEdgeMesh(
|
|
numEdges, std::vector<vtkVector3f>(newMeshCount));
|
|
std::vector<std::vector<vtkVector3f> > newEdgeMeshVelocities(
|
|
numEdges, std::vector<vtkVector3f>(newMeshCount, vtkVector3f(0.0f, 0.0f, 0.0f)));
|
|
std::vector<std::vector<vtkVector3f> > newEdgeMeshAccelerations(
|
|
numEdges, std::vector<vtkVector3f>(newMeshCount, vtkVector3f(0.0f, 0.0f, 0.0f)));
|
|
//std::vector<std::vector<float> > newEdgeMeshGroupCounts(
|
|
// numEdges, std::vector<float>(newMeshCount, 1.0f));
|
|
for (vtkIdType e = 0; e < numEdges; ++e)
|
|
{
|
|
for (int m = 0; m < newMeshCount; ++m)
|
|
{
|
|
float indexFloat = (this->MeshCount - 1.0f)*m/(newMeshCount - 1.0f);
|
|
int index = static_cast<int>(indexFloat);
|
|
float alpha = indexFloat - index;
|
|
vtkVector3f before = this->EdgeMesh[e][index];
|
|
if (alpha > 0)
|
|
{
|
|
vtkVector3f after = this->EdgeMesh[e][index+1];
|
|
newEdgeMesh[e][m] = before + alpha*(after - before);
|
|
}
|
|
else
|
|
{
|
|
newEdgeMesh[e][m] = before;
|
|
}
|
|
}
|
|
}
|
|
this->MeshCount = newMeshCount;
|
|
this->EdgeMesh = newEdgeMesh;
|
|
this->EdgeMeshVelocities = newEdgeMeshVelocities;
|
|
this->EdgeMeshAccelerations = newEdgeMeshAccelerations;
|
|
//this->EdgeMeshGroupCounts = newEdgeMeshGroupCounts;
|
|
}
|
|
|
|
void vtkBundlingMetadata::SimulateEdgeStep()
|
|
{
|
|
vtkIdType numEdges = this->Graph->GetNumberOfEdges();
|
|
|
|
for (vtkIdType e1 = 0; e1 < numEdges; ++e1)
|
|
{
|
|
float weight1 = 1.0f;
|
|
for (int m1 = 0; m1 < this->MeshCount; ++m1)
|
|
{
|
|
// Immovable
|
|
if (m1 <= 0 || m1 >= this->MeshCount - 1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Move the point according to dynamics
|
|
vtkVector3f position = this->EdgeMesh[e1][m1];
|
|
vtkVector3f velocity = this->EdgeMeshVelocities[e1][m1];
|
|
vtkVector3f acceleration = this->EdgeMeshAccelerations[e1][m1];
|
|
velocity = velocity + acceleration * this->SimulationStep * 0.5f;
|
|
velocity = velocity * this->VelocityDamping;
|
|
position = position + velocity * this->SimulationStep;
|
|
this->EdgeMesh[e1][m1] = position;
|
|
|
|
acceleration = vtkVector3f(0.0f, 0.0f, 0.0f);
|
|
|
|
// Spring force
|
|
vtkVector3f prevPosition = this->EdgeMesh[e1][m1-1];
|
|
vtkVector3f prevDirection = prevPosition - position;
|
|
float prevDist = prevDirection.Norm();
|
|
float prevForce = this->EdgeSpringConstant / 1000.0f * (this->MeshCount - 1) * prevDist * weight1;
|
|
prevDirection.Normalize();
|
|
acceleration = acceleration + prevForce * prevDirection;
|
|
|
|
vtkVector3f nextPosition = this->EdgeMesh[e1][m1+1];
|
|
vtkVector3f nextDirection = nextPosition - position;
|
|
float nextDist = nextDirection.Norm();
|
|
float nextForce = this->EdgeSpringConstant / 1000.0f * (this->MeshCount - 1) * nextDist * weight1;
|
|
nextDirection.Normalize();
|
|
acceleration = acceleration + nextForce * nextDirection;
|
|
|
|
// Coulomb force
|
|
float normalizedEdgeCoulombConstant = this->EdgeCoulombConstant / sqrt(static_cast<float>(numEdges));
|
|
|
|
for (vtkIdType e2 = 0; e2 < numEdges; ++e2)
|
|
{
|
|
if (e1 == e2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float compatibility = this->EdgeCompatibilities[e1][e2];
|
|
if (compatibility <= 0.05)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float dot = this->EdgeDots[e1][e2];
|
|
float weight2 = 1.0f;
|
|
|
|
int m2;
|
|
if (dot >= 0.0f)
|
|
{
|
|
m2 = m1;
|
|
}
|
|
else
|
|
{
|
|
m2 = this->MeshCount - 1 - m1;
|
|
}
|
|
|
|
vtkVector3f position2;
|
|
// If we're going the same direction is edge1, then the potential minimum is at the point.
|
|
if (dot >= 0.0f)
|
|
{
|
|
position2 = this->EdgeMesh[e2][m2];
|
|
}
|
|
// If we're going the opposite direction, the potential minimum is edgeLaneWidth to the "right."
|
|
else
|
|
{
|
|
vtkVector3f tangent = this->EdgeMesh[e2][m2+1] - this->EdgeMesh[e2][m2-1];
|
|
tangent.Normalize();
|
|
// This assumes 2D
|
|
vtkVector3f normal(-tangent[1], tangent[0], 0.0f);
|
|
position2 = this->EdgeMesh[e2][m2] + normal*this->EdgeLaneWidth;
|
|
}
|
|
|
|
vtkVector3f direction = position2 - position;
|
|
float distance = direction.Norm();
|
|
|
|
// Inverse force.
|
|
float force;
|
|
if (!this->UseNewForce)
|
|
{
|
|
force = normalizedEdgeCoulombConstant * 30.0f / (this->MeshCount - 1) / (distance + 0.01f);
|
|
}
|
|
// New force.
|
|
else
|
|
{
|
|
force = 4.0f * 10000.0f / (this->MeshCount - 1) * this->EdgeCoulombDecay * normalizedEdgeCoulombConstant * distance / (3.1415926f * pow(this->EdgeCoulombDecay * this->EdgeCoulombDecay + distance * distance, 2));
|
|
}
|
|
force *= weight2;
|
|
force *= compatibility;
|
|
|
|
if (distance > 0.0f)
|
|
{
|
|
direction.Normalize();
|
|
acceleration = acceleration + force * direction;
|
|
}
|
|
}
|
|
|
|
velocity = velocity + acceleration * this->SimulationStep * 0.5f;
|
|
this->EdgeMeshVelocities[e1][m1] = velocity;
|
|
this->EdgeMeshAccelerations[e1][m1] = acceleration;
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkBundlingMetadata::SmoothEdges()
|
|
{
|
|
// From Mathematica Total[GaussianMatrix[{3, 3}]]
|
|
int kernelSize = 3;
|
|
// Has to sum to 1.0 to be correct.
|
|
float gaussianKernel[] = {0.10468, 0.139936, 0.166874, 0.177019, 0.166874, 0.139936, 0.10468};
|
|
vtkIdType numEdges = this->Graph->GetNumberOfEdges();
|
|
std::vector<std::vector<vtkVector3f> > smoothedEdgeMesh(
|
|
numEdges, std::vector<vtkVector3f>(this->MeshCount));
|
|
for (vtkIdType e = 0; e < numEdges; ++e)
|
|
{
|
|
for (int m = 1; m < this->MeshCount - 1; ++m)
|
|
{
|
|
vtkVector3f smoothed(0.0f, 0.0f, 0.0f);
|
|
for (int kernelIndex = 0; kernelIndex < kernelSize * 2 + 1; kernelIndex++)
|
|
{
|
|
int m2 = m + kernelIndex - kernelSize;
|
|
m2 = std::max(0, std::min(this->MeshCount - 1, m2));
|
|
|
|
vtkVector3f pt = this->EdgeMesh[e][m2];
|
|
smoothed = smoothed + gaussianKernel[kernelIndex] * pt;
|
|
}
|
|
smoothedEdgeMesh[e][m] = smoothed;
|
|
}
|
|
}
|
|
this->EdgeMesh = smoothedEdgeMesh;
|
|
}
|
|
|
|
void vtkBundlingMetadata::LayoutEdgePoints()
|
|
{
|
|
this->InitializeEdgeMesh();
|
|
this->SimulationStep = 40.0f;
|
|
this->CycleIterations = 30;
|
|
for (int i = 0; i < 5; ++i)
|
|
{
|
|
vtkDebugWithObjectMacro(this->Outer, "vtkBoostDividedEdgeBundling cycle " << i);
|
|
this->CycleIterations = this->CycleIterations * 2 / 3;
|
|
this->SimulationStep = 0.85f*this->SimulationStep;
|
|
this->DoubleEdgeMeshResolution();
|
|
for (int j = 0; j < this->CycleIterations; ++j)
|
|
{
|
|
vtkDebugWithObjectMacro(this->Outer, "vtkBoostDividedEdgeBundling iteration " << j);
|
|
this->SimulateEdgeStep();
|
|
}
|
|
}
|
|
this->SmoothEdges();
|
|
}
|
|
|
|
int vtkBoostDividedEdgeBundling::RequestData(
|
|
vtkInformation *vtkNotUsed(request),
|
|
vtkInformationVector **inputVector,
|
|
vtkInformationVector *outputVector)
|
|
{
|
|
// get the info objects
|
|
vtkInformation *graphInfo = inputVector[0]->GetInformationObject(0);
|
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
|
|
|
// get the input and output
|
|
vtkDirectedGraph *g = vtkDirectedGraph::SafeDownCast(
|
|
graphInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
vtkDirectedGraph *output = vtkDirectedGraph::SafeDownCast(
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
|
|
vtkBundlingMetadata *meta = new vtkBundlingMetadata(this, g);
|
|
|
|
meta->NormalizeNodePositions();
|
|
meta->CalculateEdgeLengths();
|
|
meta->CalculateNodeDistances();
|
|
meta->CalculateEdgeCompatibilities();
|
|
meta->LayoutEdgePoints();
|
|
meta->DenormalizeNodePositions();
|
|
|
|
output->ShallowCopy(g);
|
|
|
|
for (vtkIdType e = 0; e < g->GetNumberOfEdges(); ++e)
|
|
{
|
|
output->ClearEdgePoints(e);
|
|
for (int m = 1; m < meta->MeshCount-1; ++m)
|
|
{
|
|
vtkVector3f edgePoint = meta->EdgeMesh[e][m];
|
|
output->AddEdgePoint(e, edgePoint[0], edgePoint[1], edgePoint[2]);
|
|
}
|
|
}
|
|
|
|
delete meta;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void vtkBoostDividedEdgeBundling::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
}
|
|
|