package graphtea.extensions.actions.art; import graphtea.graph.graph.*; import graphtea.graph.old.GStroke; import graphtea.plugins.main.GraphData; import graphtea.plugins.main.core.AlgorithmUtils; import graphtea.plugins.main.extension.GraphActionExtension; import java.awt.*; import java.awt.geom.GeneralPath; import java.awt.geom.QuadCurve2D; /** * @author M. Ali Rostami */ public class GraphArt implements GraphActionExtension { public static final String CURVE_WIDTH = "Curve Width"; @Override public String getName() { return "GraphTea Art"; } @Override public String getDescription() { return "GraphTea Art"; } @Override public void action(GraphData graphData) { Vertex.addGlobalUserDefinedAttribute(CURVE_WIDTH,1); GraphModel g1 = graphData.getGraph(); GraphModel g2 = g1.getCopy(); g2.setFont(new Font(g2.getFont().getName(),g2.getFont().getStyle(), 0)); g2.setLabel("TreeG0"); for(Vertex v : g2) v.setSize(new GPoint(15,15)); for(Edge e : g2.getEdges()) { e.setStroke(GStroke.dashed_dotted); e.setColor(8); } graphData.core.showGraph(g2); AbstractGraphRenderer gr = AbstractGraphRenderer.getCurrentGraphRenderer(graphData.getBlackboard()); gr.addPostPaintHandler(new Painter(graphData)); gr.repaint(); } @Override public String getCategory() { return "Graph-based Visualization"; } } class Painter implements PaintHandler { GraphData gd; GraphModel G; public Painter(GraphData gd) { this.gd = gd; this.G = gd.getGraph(); } public void paint(Graphics gr1d, Object destinationComponent, Boolean b) { final Graphics2D gr = (Graphics2D) gr1d; gr.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); final int n = G.getVerticesCount(); if (n == 0) return; AbstractGraphRenderer.getCurrentGraphRenderer(gd.getBlackboard()).ignoreRepaints(() -> { Vertex V[] = G.getVertexArray(); final Vertex parent[] = new Vertex[n]; //consider the hole structure as a tree AlgorithmUtils.BFSrun(G, V[0], (v, p) -> parent[v.getId()] = p); final int numChild[] = new int[n]; for(int nc = 0;nc < numChild.length;nc++) numChild[nc]=0; for(Vertex v:G) { if(G.getDegree(v) != 1) continue; Vertex par = v; do { int numN=G.getDegree(par)-1; par = parent[par.getId()]; if(par == null) break; numChild[par.getId()] += numN + G.getDegree(par); } while(true); } for (Vertex v : G) { if (v.getId() == 0) continue; if (v.getColor() == 0) { Vertex v1 = parent[v.getId()]; if (v1 == null || v1.getColor() != 0) continue; Vertex v2 = parent[v1.getId()]; if (v2 == null || v2.getColor() != 0) continue; //generate the curve between v1, v2 and v3 GPoint p1 = v.getLocation(); GPoint p2 = v1.getLocation(); GPoint p3 = v2.getLocation(); GPoint m1 = AlgorithmUtils.getMiddlePoint(p1, p2); GPoint m2 = AlgorithmUtils.getMiddlePoint(p2, p3); GPoint cp = p2; // Integer w1 = numChild[v.getId()]/2; Integer w1 = v.getUserDefinedAttribute(GraphArt.CURVE_WIDTH); // Integer w2 = numChild[v1.getId()]/2; Integer w2 = v1.getUserDefinedAttribute(GraphArt.CURVE_WIDTH); // Integer w3 = numChild[v2.getId()]/2; Integer w3 = v2.getUserDefinedAttribute(GraphArt.CURVE_WIDTH); int startWidth = (w1 + w2) / 2; int endWidth = (w3 + w2) / 2; int middleWidth = w2; double teta1 = AlgorithmUtils.getAngle(p1, p2); double teta2 = AlgorithmUtils.getAngle(p1, p3); double teta3 = AlgorithmUtils.getAngle(p2, p3); //generate boundary curves QuadCurve2D c1 = new QuadCurve2D.Double( m1.x - startWidth * Math.sin(teta1), m1.y + startWidth * Math.cos(teta1), cp.x - middleWidth * Math.sin(teta2), cp.y + middleWidth * Math.cos(teta2), m2.x - endWidth * Math.sin(teta3), m2.y + endWidth * Math.cos(teta3)); QuadCurve2D c2 = new QuadCurve2D.Double( m2.x + endWidth * Math.sin(teta3), m2.y - endWidth * Math.cos(teta3), cp.x + middleWidth * Math.sin(teta2), cp.y - middleWidth * Math.cos(teta2), m1.x + startWidth * Math.sin(teta1), m1.y - startWidth * Math.cos(teta1)); //mix them GeneralPath gp = new GeneralPath(c1); gp.append(c2, true); gp.closePath(); gr.setColor(new Color(0,0,0)); //fill the curve gr.fill(gp); // double c11 = m1.x - startWidth * Math.sin(teta1); // double c22 = m1.y + startWidth * Math.cos(teta1); // if(G.getInDegree(v) + G.getOutDegree(v) == 2) { // gr.setColor(Color.gray); // gr.fillOval((int)c11-15,(int)c22-15,30,30); // } } } }, false /* dont repaint after*/); } }