/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@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.filters; import java.util.ArrayList; import java.util.List; import org.gephi.filters.spi.ComplexFilter; import org.gephi.filters.spi.EdgeFilter; import org.gephi.filters.spi.Filter; import org.gephi.filters.spi.NodeFilter; import org.gephi.filters.spi.Operator; import org.gephi.graph.api.Edge; import org.gephi.graph.api.Graph; import org.gephi.graph.api.GraphModel; import org.gephi.graph.api.GraphView; import org.gephi.graph.api.HierarchicalGraph; import org.gephi.graph.api.Node; /** * * @author Mathieu Bastian */ public class FilterProcessor { public Graph process(AbstractQueryImpl query, GraphModel graphModel) { List<GraphView> views = new ArrayList<GraphView>(); query = simplifyQuery(query); AbstractQueryImpl[] tree = getTree(query, true); for (int i = 0; i < tree.length; i++) { AbstractQueryImpl q = tree[tree.length - i - 1]; Graph[] input = new Graph[0]; if (q.getChildrenCount() > 0) { input = new Graph[q.getChildrenCount()]; for (int j = 0; j < input.length; j++) { input[j] = q.getChildAt(j).getResult(); } } else { //Leaves GraphView newView = graphModel.newView(); views.add(newView); input = new Graph[]{graphModel.getGraph(newView)}; //duplicate root } //PROCESS if (q instanceof OperatorQueryImpl && !((OperatorQueryImpl) q).isSimple()) { OperatorQueryImpl operatorQuery = (OperatorQueryImpl) q; Operator op = (Operator) operatorQuery.getFilter(); q.setResult(op.filter(input)); } else if (q instanceof OperatorQueryImpl && ((OperatorQueryImpl) q).isSimple()) { OperatorQueryImpl operatorQuery = (OperatorQueryImpl) q; Operator op = (Operator) operatorQuery.getFilter(); Filter[] filters = new Filter[operatorQuery.getChildrenCount()]; for (int k = 0; k < filters.length; k++) { filters[k] = operatorQuery.getChildAt(k).getFilter(); } GraphView newView = graphModel.newView(); views.add(newView); q.setResult(op.filter(graphModel.getGraph(newView), filters)); } else { FilterQueryImpl filterQuery = (FilterQueryImpl) q; Filter filter = filterQuery.getFilter(); if (filter instanceof NodeFilter && filter instanceof EdgeFilter) { processNodeFilter((NodeFilter) filter, input[0]); processEdgeFilter((EdgeFilter) filter, input[0]); q.setResult(input[0]); } else if (filter instanceof NodeFilter) { processNodeFilter((NodeFilter) filter, input[0]); q.setResult(input[0]); } else if (filter instanceof EdgeFilter) { processEdgeFilter((EdgeFilter) filter, input[0]); q.setResult(input[0]); } else if (filter instanceof ComplexFilter) { ComplexFilter cf = (ComplexFilter) filter; q.setResult(cf.filter(input[0])); } else { q.setResult(input[0]); //Put input as result, the filter don't do anything } } } Graph finalResult = tree[0].result; //Destroy intermediate views GraphView finalView = finalResult.getView(); for (GraphView v : views) { if (v != finalView) { graphModel.destroyView(v); } } return finalResult; } private void processNodeFilter(NodeFilter nodeFilter, Graph graph) { if (nodeFilter.init(graph)) { List<Node> nodesToRemove = new ArrayList<Node>(); for (Node n : graph.getNodes()) { if (!nodeFilter.evaluate(graph, n)) { nodesToRemove.add(n); } } for (Node n : nodesToRemove) { graph.removeNode(n); } nodeFilter.finish(); } } private void processEdgeFilter(EdgeFilter edgeFilter, Graph graph) { HierarchicalGraph hgraph = (HierarchicalGraph) graph; if (edgeFilter.init(hgraph)) { List<Edge> edgesToRemove = new ArrayList<Edge>(); for (Edge e : hgraph.getEdges()) { if (!edgeFilter.evaluate(hgraph, e)) { edgesToRemove.add(e); } } for (Edge e : edgesToRemove) { hgraph.removeEdge(e); } edgesToRemove.clear(); for (Edge e : hgraph.getMetaEdges()) { if (!edgeFilter.evaluate(hgraph, e)) { edgesToRemove.add(e); } } for (Edge e : edgesToRemove) { hgraph.removeMetaEdge(e); } edgeFilter.finish(); } } private AbstractQueryImpl simplifyQuery(AbstractQueryImpl query) { AbstractQueryImpl copy = query.copy(); for (AbstractQueryImpl q : getTree(copy, false)) { if (q instanceof OperatorQueryImpl && q.getChildrenCount() > 0) { boolean canSimplify = true; for (AbstractQueryImpl child : q.children) { if (child.getChildrenCount() > 0 || !(child.getFilter() instanceof NodeFilter || child.getFilter() instanceof EdgeFilter)) { canSimplify = false; } } if (canSimplify) { ((OperatorQueryImpl) q).setSimple(true); } } } return copy; } private AbstractQueryImpl[] getTree(AbstractQueryImpl query, boolean ignoreSimple) { ArrayList<AbstractQueryImpl> tree = new ArrayList<AbstractQueryImpl>(); int pointer = 0; tree.add(query); while (pointer < tree.size()) { AbstractQueryImpl q = tree.get(pointer++); if (q.children.size() > 0) { if (!(q instanceof OperatorQueryImpl && ((OperatorQueryImpl) q).isSimple())) { tree.addAll(q.children); } } } return tree.toArray(new AbstractQueryImpl[0]); } }