/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM 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 3 of the License, or
(at your option) any later version.
OpenFOAM 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 OpenFOAM. If not, see .
Description
\*---------------------------------------------------------------------------*/
#include "router.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::label Foam::router::count(const label weight) const
{
label cnt = 0;
forAll(weights_, nodeI)
{
cnt += weights_[nodeI];
}
return cnt;
}
// Given connections between nodes set minimum distance from nodeI
void Foam::router::setWeights
(
const label weight,
const label nodeI
)
{
// Set weight at current node
weights_[nodeI] = weight;
const labelList& myNeighbours = connections_[nodeI];
forAll(myNeighbours, neighbourI)
{
if (weights_[myNeighbours[neighbourI]] > weight + 1)
{
// Distribute weight+1 to neighbours
setWeights
(
weight+1,
myNeighbours[neighbourI]
);
}
}
}
// Mark shortest path from endNode to startNode by setting the weights
// to 0.
void Foam::router::fixWeights
(
const label startNodeI,
const label endNodeI,
const label nodeI,
const label prevNodeI
)
{
// Mark this node
weights_[nodeI] = 0;
label minNodeI = -1;
label minDist = labelMax;
label nMinNodes = 0;
const labelList& myNeighbours = connections_[nodeI];
forAll(myNeighbours, neighbourI)
{
label nbrNodeI = myNeighbours[neighbourI];
if (nbrNodeI != prevNodeI)
{
if (weights_[nbrNodeI] == 0)
{
// Reached end
minDist = 0;
break;
}
else if (weights_[nbrNodeI] > 0)
{
if (weights_[nbrNodeI] < minDist)
{
minDist = weights_[nbrNodeI];
minNodeI = nbrNodeI;
nMinNodes = 1;
}
else if (weights_[nbrNodeI] == minDist)
{
nMinNodes++;
}
}
}
}
if (minDist == 0)
{
// Reached starting point.
return;
}
if (minNodeI == -1)
{
WarningInFunction
<< "Cannot route from node " << nodeI
<< " since all neighbours of node "
<< "already allocated:" << endl;
forAll(myNeighbours, neighbourI)
{
label nbrNodeI = myNeighbours[neighbourI];
WarningInFunction
<< " weight:" << weights_[nbrNodeI] << endl;
}
return;
}
if (nMinNodes > 1)
{
// Multiple paths, all with same weight. Use some heuristic
// to choose one. Here: smallest angle to vector end-start
vector n(coords_[endNodeI] - coords_[startNodeI]);
scalar maxCosAngle = -GREAT;
forAll(myNeighbours, neighbourI)
{
label nbrNodeI = myNeighbours[neighbourI];
if (weights_[nbrNodeI] == minDist)
{
vector n2(coords_[nbrNodeI] - coords_[startNodeI]);
scalar magN2 = mag(n2);
if (magN2 > SMALL)
{
n2 /= mag(n2);
scalar cosAngle = n & n2;
if (cosAngle > maxCosAngle)
{
maxCosAngle = cosAngle;
minNodeI = nbrNodeI;
}
}
}
}
}
// Recursively go mark the path at minNode
fixWeights
(
startNodeI,
endNodeI,
minNodeI,
nodeI
);
}
Foam::label Foam::router::getValue(const label pathValue) const
{
forAll(weights_, nodeI)
{
if (weights_[nodeI] == pathValue)
{
return nodeI;
}
}
return -1;
}
// Find node which has no neighbours with pathValue
Foam::label Foam::router::findEndNode
(
const label startNodeI,
const label prevNodeI,
const label pathValue
) const
{
const labelList& myNeighbours = connections_[startNodeI];
forAll(myNeighbours, neighbourI)
{
label nodeI = myNeighbours[neighbourI];
if (nodeI != prevNodeI)
{
if (weights_[nodeI] == pathValue)
{
return findEndNode(nodeI, startNodeI, pathValue);
}
}
}
// No neighbours with pathValue found. Return this node
return startNodeI;
}
// Append all pathValue weights to route.
void Foam::router::storeRoute
(
const label startNodeI,
const label prevNodeI,
const label pathValue,
DynamicList