/*
* This file is part of the Trickl Open Source Libraries.
*
* Trickl Open Source Libraries - http://open.trickl.com/
*
* Copyright (C) 2011 Tim Gee.
*
* Trickl Open Source Libraries are 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.
*
* Trickl Open Source Libraries are 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 project. If not, see <http://www.gnu.org/licenses/>.
*/
package com.trickl.graph.planar;
import com.trickl.graph.edges.DirectedEdge;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.jgrapht.EdgeFactory;
import org.jgrapht.VertexFactory;
public class DualGraphVisitor<V1, E1, V2, E2> extends AbstractPlanarFaceTraversalVisitor<V1, E1> {
protected PlanarGraph<V1, E1> inputGraph;
protected PlanarGraph<V2, E2> dualGraph;
protected VertexFactory<V2> vertexFactory;
protected EdgeFactory<V2, E2> edgeFactory;
protected V2 dualTarget;
private Map<DirectedEdge<V1>, V2> faceToVertexMap;
public DualGraphVisitor(PlanarGraph<V1, E1> inputGraph,
PlanarGraph<V2, E2> dualGraph,
VertexFactory<V2> vertexFactory) {
this(inputGraph, dualGraph, vertexFactory, null);
}
public DualGraphVisitor(PlanarGraph<V1, E1> inputGraph,
PlanarGraph<V2, E2> dualGraph,
VertexFactory<V2> vertexFactory,
EdgeFactory<V2, E2> edgeFactory) {
this.inputGraph = inputGraph;
this.dualGraph = dualGraph;
this.vertexFactory = vertexFactory;
this.edgeFactory = edgeFactory == null
? dualGraph.getEdgeFactory() : edgeFactory;
this.faceToVertexMap = new HashMap<>();
}
@Override
public void beginFace(V1 source, V1 target) {
dualTarget = vertexFactory.createVertex();
dualGraph.addVertex(dualTarget);
if (target == null) {
// There are no actual edges to define the face
faceToVertexMap.put(new DirectedEdge<>(source, target), dualTarget);
}
}
@Override
public void endFace(V1 source, V1 target) {
dualTarget = null;
}
@Override
public void nextEdge(V1 inputSource, V1 inputTarget) {
DirectedEdge edge = new DirectedEdge<>(inputSource, inputTarget);
faceToVertexMap.put(edge, dualTarget);
if (faceToVertexMap.containsKey(new DirectedEdge<>(inputTarget, inputSource))) {
V2 dualSource = faceToVertexMap.get(new DirectedEdge<>(inputTarget, inputSource));
V2 dualBefore = null;
V1 inputBefore = inputGraph.getNextVertex(inputTarget, inputSource);
V1 inputLast = inputSource;
V1 inputVertex = inputBefore;
do {
V2 dualVertex = faceToVertexMap.get(new DirectedEdge<>(inputVertex, inputLast));
if (dualVertex != null && dualGraph.containsEdge(dualVertex, dualSource)) {
// First encountered so break on success
dualBefore = dualVertex;
break;
}
V1 temp = inputVertex;
inputVertex = inputGraph.getNextVertex(inputLast, inputVertex);
inputLast = temp;
} while (!inputVertex.equals(inputBefore));
V2 dualAfter = null;
V1 inputAfter = inputTarget;
inputLast = inputSource;
inputVertex = inputAfter;
do {
V2 dualVertex = faceToVertexMap.get(new DirectedEdge<>(inputVertex, inputLast));
if (dualVertex != null && dualGraph.containsEdge(dualVertex, dualTarget)) {
// Last encountered, so overwrite on success
dualAfter = dualVertex;
}
V1 temp = inputVertex;
inputVertex = inputGraph.getNextVertex(inputLast, inputVertex);
inputLast = temp;
} while (!inputVertex.equals(inputAfter));
E2 dualEdge = edgeFactory.createEdge(dualSource, dualTarget);
dualGraph.addEdge(dualSource, dualTarget, dualBefore, dualAfter, dualEdge);
}
}
public Map<DirectedEdge<V1>, V2> getFaceToVertexMap() {
return faceToVertexMap;
}
public Map<V2, Set<DirectedEdge<V1>>> getVertexToFaceMap() {
Set<V2> dualVertices = dualGraph.vertexSet();
Map<V2, Set<DirectedEdge<V1>>> vertexToFaceMap = new HashMap<>(dualVertices.size());
dualVertices.stream().forEach((dualVertex) -> {
vertexToFaceMap.put(dualVertex, new HashSet<>());
});
faceToVertexMap.entrySet().stream().forEach((faceToVertexEntry) -> {
vertexToFaceMap.get(faceToVertexEntry.getValue()).add(faceToVertexEntry.getKey());
});
return vertexToFaceMap;
}
}