/* Copyright 2008-2010 Gephi Authors : Jeremy Subtil <jeremy.subtil@gephi.org> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.preview; import java.util.HashMap; import org.gephi.data.attributes.type.TimeInterval; import org.gephi.dynamic.DynamicUtilities; import org.gephi.dynamic.api.DynamicController; import org.gephi.graph.api.HierarchicalDirectedGraph; import org.gephi.graph.api.HierarchicalGraph; import org.gephi.graph.api.HierarchicalMixedGraph; import org.gephi.graph.api.HierarchicalUndirectedGraph; import org.gephi.preview.api.PreviewModel; import org.openide.util.Lookup; /** * Factory creating preview graphs from workspace graphs. * * @author Jérémy Subtil <jeremy.subtil@gephi.org> */ public class PreviewGraphFactory { private final HashMap<Integer, NodeImpl> nodeMap = new HashMap<Integer, NodeImpl>(); private TimeInterval timeInterval = new TimeInterval(); /** * Creates a preview graph from the given undirected graph. * * @param sourceGraph the undirected graph * @return a generated preview graph */ public GraphImpl createPreviewGraph(PreviewModel model, HierarchicalUndirectedGraph sourceGraph) { // creates graph GraphImpl previewGraph = new GraphImpl(model); // creates nodes for (org.gephi.graph.api.Node sourceNode : sourceGraph.getNodes()) { createPreviewNode(previewGraph, sourceNode); } calculateMinMaxWeight(sourceGraph, previewGraph); // creates edges for (org.gephi.graph.api.Edge sourceEdge : sourceGraph.getEdgesAndMetaEdges()) { if (sourceEdge.isSelfLoop()) { createPreviewSelfLoop(previewGraph, sourceEdge); continue; } createPreviewUndirectedEdge(previewGraph, sourceEdge); } // clears the node map nodeMap.clear(); return previewGraph; } /** * Creates a preview graph from the given directed graph. * * @param sourceGraph the directed graph * @return a generated preview graph */ public GraphImpl createPreviewGraph(PreviewModel model, HierarchicalDirectedGraph sourceGraph) { // creates graph GraphImpl previewGraph = new GraphImpl(model); // creates nodes for (org.gephi.graph.api.Node sourceNode : sourceGraph.getNodes()) { createPreviewNode(previewGraph, sourceNode); } calculateMinMaxWeight(sourceGraph, previewGraph); // creates edges for (org.gephi.graph.api.Edge sourceEdge : sourceGraph.getEdgesAndMetaEdges()) { if (sourceEdge.isSelfLoop()) { createPreviewSelfLoop(previewGraph, sourceEdge); continue; } if (isBidirectional(sourceGraph, sourceEdge)) { createPreviewBidirectionalEdge(previewGraph, sourceEdge); } else { createPreviewUnidirectionalEdge(previewGraph, sourceEdge); } } // clears the node map nodeMap.clear(); return previewGraph; } /** * Creates a preview graph from the given mixed graph. * * @param sourceGraph the mixed graph * @return a generated preview graph */ public GraphImpl createPreviewGraph(PreviewModel model, HierarchicalMixedGraph sourceGraph) { // creates graph GraphImpl previewGraph = new GraphImpl(model); // creates nodes for (org.gephi.graph.api.Node sourceNode : sourceGraph.getNodes()) { createPreviewNode(previewGraph, sourceNode); } calculateMinMaxWeight(sourceGraph, previewGraph); // creates edges for (org.gephi.graph.api.Edge sourceEdge : sourceGraph.getEdgesAndMetaEdges()) { if (sourceEdge.isSelfLoop()) { createPreviewSelfLoop(previewGraph, sourceEdge); continue; } if (sourceEdge.isDirected()) { if (isBidirectional(sourceGraph, sourceEdge)) { createPreviewBidirectionalEdge(previewGraph, sourceEdge); } else { createPreviewUnidirectionalEdge(previewGraph, sourceEdge); } } else { createPreviewUndirectedEdge(previewGraph, sourceEdge); } } // clears the node map nodeMap.clear(); return previewGraph; } private void calculateMinMaxWeight(HierarchicalGraph sourceGraph, GraphImpl previewGraph) { //Set time interval DynamicController dynamicController = Lookup.getDefault().lookup(DynamicController.class); if (dynamicController != null) { timeInterval = DynamicUtilities.getVisibleInterval(dynamicController.getModel(sourceGraph.getGraphModel().getWorkspace())); } if (timeInterval == null) { timeInterval = new TimeInterval(); } //Min/Max weight float minWeight = Float.POSITIVE_INFINITY; float maxWeight = Float.NEGATIVE_INFINITY; float minMetaWeight = Float.POSITIVE_INFINITY; float maxMetaWeight = Float.NEGATIVE_INFINITY; for (org.gephi.graph.api.Edge sourceEdge : sourceGraph.getEdges()) { minWeight = Math.min(minWeight, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh())); maxWeight = Math.max(maxWeight, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh())); } for (org.gephi.graph.api.Edge sourceEdge : sourceGraph.getMetaEdges()) { minMetaWeight = Math.min(minMetaWeight, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh())); maxMetaWeight = Math.max(maxMetaWeight, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh())); } previewGraph.setMinWeight(minWeight); previewGraph.setMaxWeight(maxWeight); previewGraph.setMinMetaWeight(minMetaWeight); previewGraph.setMaxMetaWeight(maxMetaWeight); } /** * Creates a preview node from the given source node. * * @param previewGraph the parent preview graph * @param sourceNode the source node * @return the generated preview node */ private NodeImpl createPreviewNode(GraphImpl previewGraph, org.gephi.graph.api.Node sourceNode) { org.gephi.graph.api.NodeData sourceNodeData = sourceNode.getNodeData(); org.gephi.graph.api.TextData sourceNodeTextData = sourceNodeData.getTextData(); String label = sourceNodeData.getLabel(); if (sourceNodeTextData != null && sourceNodeTextData.getText() != null && !sourceNodeTextData.getText().isEmpty() && sourceNodeTextData.isVisible()) { label = sourceNodeTextData.getText(); } else if (sourceNodeTextData != null && !sourceNodeTextData.isVisible()) { label = null; } float labelSize = 1f; if (sourceNodeTextData != null) { labelSize = sourceNodeTextData.getSize(); } if (previewGraph.getModel().getNodeSupervisor().getProportionalLabelSize()) { labelSize *= sourceNodeData.getRadius() / 10f; } NodeImpl previewNode = new NodeImpl( previewGraph, sourceNodeData.x(), -sourceNodeData.y(), // different referential from the workspace one sourceNodeData.getRadius(), label, labelSize, sourceNodeData.r(), sourceNodeData.g(), sourceNodeData.b()); previewGraph.addNode(previewNode); // adds the preview node to the node map nodeMap.put(sourceNode.getId(), previewNode); return previewNode; } /** * Creates a preview self-loop from the given source edge. * * @param previewGraph the parent preview graph * @param sourceEdge the source edge * @return the generated preview self-loop */ private SelfLoopImpl createPreviewSelfLoop(GraphImpl previewGraph, org.gephi.graph.api.Edge sourceEdge) { org.gephi.graph.api.EdgeData sourceEdgeData = sourceEdge.getEdgeData(); SelfLoopImpl previewSelfLoop = new SelfLoopImpl( previewGraph, sourceEdge, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh()), nodeMap.get(sourceEdge.getSource().getId())); previewGraph.addSelfLoop(previewSelfLoop); return previewSelfLoop; } /** * Creates a preview unidirectional edge from the given source edge. * * @param previewGraph the parent preview graph * @param sourceEdge the source edge * @return the generated preview unidirectional edge */ private UnidirectionalEdgeImpl createPreviewUnidirectionalEdge(GraphImpl previewGraph, org.gephi.graph.api.Edge sourceEdge) { org.gephi.graph.api.EdgeData sourceEdgeData = sourceEdge.getEdgeData(); org.gephi.graph.api.TextData sourceEdgeTextData = sourceEdgeData.getTextData(); String label = sourceEdgeData.getLabel(); if (sourceEdgeTextData != null && sourceEdgeTextData.getText() != null && !sourceEdgeTextData.getText().isEmpty() && sourceEdgeTextData.isVisible()) { label = sourceEdgeTextData.getText(); } else if (sourceEdgeTextData != null && !sourceEdgeTextData.isVisible()) { label = null; } float labelSize = 1f; if (sourceEdgeTextData != null) { labelSize = sourceEdgeTextData.getSize(); } UnidirectionalEdgeImpl previewEdge = new UnidirectionalEdgeImpl( previewGraph, sourceEdge, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh()), nodeMap.get(sourceEdge.getSource().getId()), nodeMap.get(sourceEdge.getTarget().getId()), label, labelSize); previewGraph.addUnidirectionalEdge(previewEdge); return previewEdge; } /** * Creates a preview bidirectional edge from the given source edge. * * @param previewGraph the parent preview graph * @param sourceEdge the source edge * @return the generated preview bidirectional edge */ private BidirectionalEdgeImpl createPreviewBidirectionalEdge(GraphImpl previewGraph, org.gephi.graph.api.Edge sourceEdge) { org.gephi.graph.api.EdgeData sourceEdgeData = sourceEdge.getEdgeData(); org.gephi.graph.api.TextData sourceEdgeTextData = sourceEdgeData.getTextData(); String label = sourceEdgeData.getLabel(); if (sourceEdgeTextData != null && sourceEdgeTextData.getText() != null && !sourceEdgeTextData.getText().isEmpty() && sourceEdgeTextData.isVisible()) { label = sourceEdgeTextData.getText(); } else if (sourceEdgeTextData != null && !sourceEdgeTextData.isVisible()) { label = null; } float labelSize = 1f; if (sourceEdgeTextData != null) { labelSize = sourceEdgeTextData.getSize(); } BidirectionalEdgeImpl previewEdge = new BidirectionalEdgeImpl( previewGraph, sourceEdge, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh()), nodeMap.get(sourceEdge.getSource().getId()), nodeMap.get(sourceEdge.getTarget().getId()), label, labelSize); previewGraph.addBidirectionalEdge(previewEdge); return previewEdge; } /** * Creates a preview undirected edge from the given source edge. * * @param previewGraph the parent preview graph * @param sourceEdge the source edge * @return the generated preview undirected edge */ private UndirectedEdgeImpl createPreviewUndirectedEdge(GraphImpl previewGraph, org.gephi.graph.api.Edge sourceEdge) { org.gephi.graph.api.EdgeData sourceEdgeData = sourceEdge.getEdgeData(); org.gephi.graph.api.TextData sourceEdgeTextData = sourceEdgeData.getTextData(); String label = sourceEdgeData.getLabel(); if (sourceEdgeTextData != null && sourceEdgeTextData.getText() != null && !sourceEdgeTextData.getText().isEmpty() && sourceEdgeTextData.isVisible()) { label = sourceEdgeTextData.getText(); } else if (sourceEdgeTextData != null && !sourceEdgeTextData.isVisible()) { label = null; } float labelSize = 1f; if (sourceEdgeTextData != null) { labelSize = sourceEdgeTextData.getSize(); } UndirectedEdgeImpl previewEdge = new UndirectedEdgeImpl( previewGraph, sourceEdge, sourceEdge.getWeight(timeInterval.getLow(), timeInterval.getHigh()), nodeMap.get(sourceEdge.getSource().getId()), nodeMap.get(sourceEdge.getTarget().getId()), label, labelSize); previewGraph.addUndirectedEdge(previewEdge); return previewEdge; } /** * Returns whether the given source edge is bidirectional or not. * * @param sourceGraph the directed graph * @param sourceEdge the source edge * @return true if the source edge is bidirectional */ private boolean isBidirectional(org.gephi.graph.api.DirectedGraph sourceGraph, org.gephi.graph.api.Edge sourceEdge) { return sourceGraph.getEdge(sourceEdge.getTarget(), sourceEdge.getSource()) != null; } /** * Returns whether the given source edge is bidirectional or not. * * @param sourceGraph the mixed graph * @param sourceEdge the source edge * @return true if the source edge is bidirectional */ private boolean isBidirectional(org.gephi.graph.api.MixedGraph sourceGraph, org.gephi.graph.api.Edge sourceEdge) { return sourceGraph.getEdge(sourceEdge.getTarget(), sourceEdge.getSource()) != null; } }