/* * Copyright (C) 2016 Naman Dwivedi * * Licensed under the GNU General Public License v3 * * This 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. * * This software 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. */ package com.naman14.algovisualizer.visualizer.graph; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; import com.naman14.algovisualizer.algorithm.graph.Digraph; import com.naman14.algovisualizer.visualizer.AlgorithmVisualizer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class DirectedGraphVisualizer extends AlgorithmVisualizer { private Paint circlePaint; private Paint textPaint; private Paint linePaint; private Paint circleHighlightPaint; private Paint lineHighlightPaint; private Rect bounds; private List<Integer> highlightNode = new ArrayList<>(); private Map<Integer, List<Integer>> highlightLine = new HashMap<>(); private Map<Integer, Point> pointMap = new HashMap<>(); private Digraph graph; private List<Integer> array = new ArrayList<>(); public DirectedGraphVisualizer(Context context) { super(context); initialise(); } public DirectedGraphVisualizer(Context context, AttributeSet attrs) { super(context, attrs); initialise(); } private void initialise() { circlePaint = new Paint(); textPaint = new Paint(); textPaint.setColor(Color.WHITE); textPaint.setTextSize(getDimensionInPixelFromSP(15)); textPaint.setAntiAlias(true); textPaint.setTextAlign(Paint.Align.CENTER); bounds = new Rect(); textPaint.getTextBounds("0", 0, 1, bounds); circlePaint.setColor(Color.RED); circlePaint.setAntiAlias(true); linePaint = new Paint(); linePaint.setStrokeWidth(5); linePaint.setColor(Color.BLACK); circleHighlightPaint = new Paint(circlePaint); circleHighlightPaint.setColor(Color.BLUE); lineHighlightPaint = new Paint(linePaint); lineHighlightPaint.setColor(Color.BLUE); lineHighlightPaint.setStrokeWidth(10); } public void setData(Digraph graph) { this.graph = graph; this.array = graph.topSort(); invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (array != null && array.size() != 0) drawGraph(canvas); } private void drawGraph(Canvas canvas) { pointMap.clear(); double[][] graphArray = graph.directed_array; int root = 0; for (int i = 0; i < array.size(); i++) { double parentnode = graphArray[0][i]; double numhorizontalnode = graphArray[3][i]; double numverticalnode = graphArray[4][i]; double toLeftOfRoot = graphArray[5][i]; Point p = new Point(); Point p0 = new Point(); p0.x = getWidth() / 2 + getDimensionInPixel(25); p0.y = getDimensionInPixel(40); if (parentnode == root) { p.x = getWidth() / 2 + getDimensionInPixel(25); p.y = getDimensionInPixel(40); } else if (toLeftOfRoot == 1) { p.x = (int) (p0.x - numhorizontalnode * getDimensionInPixel(60)); p.y = (int) (p0.y + numverticalnode * getDimensionInPixel(70)); } else if (toLeftOfRoot == 0) { p.x = (int) (p0.x + numhorizontalnode * getDimensionInPixel(60)); p.y = (int) (p0.y + numverticalnode * getDimensionInPixel(70)); } addNode(p, (int) parentnode); } drawNodes(canvas); } private void addNode(Point point, int i) { pointMap.put(i, point); } private void drawNodes(Canvas canvas) { for (Map.Entry<Integer, Point> entry : pointMap.entrySet()) { Integer key = entry.getKey(); if (graph.exists(key)) { List<Integer> edges = graph.getNeighbours(key); for (Integer i : edges) { if (pointMap.get(i) != null) { drawNodeLine(canvas, key, i); } } } } for (Map.Entry<Integer, Point> entry : pointMap.entrySet()) { Integer key = entry.getKey(); Point value = entry.getValue(); drawCircleTextNode(canvas, value, key); } } private void drawCircleTextNode(Canvas canvas, Point p, int number) { String text = String.valueOf(number); if (highlightNode.contains(number)) { canvas.drawCircle(p.x, p.y, getDimensionInPixel(15), circleHighlightPaint); } else { canvas.drawCircle(p.x, p.y, getDimensionInPixel(15), circlePaint); } int yOffset = bounds.height() / 2; canvas.drawText(text, p.x, p.y + yOffset, textPaint); } private void drawNodeLine(Canvas canvas, int s, int e) { Point start = pointMap.get(s); Point end = pointMap.get(e); int midx = (start.x + end.x) / 2; int midy = (start.y + end.y) / 2; boolean highlight = (highlightLine.containsKey(s) && highlightLine.get(s).contains(e)); if (highlight) { canvas.drawLine(start.x, start.y, end.x, end.y, lineHighlightPaint); canvas.drawLine(midx, midy, midx + getDimensionInPixel(5), midy - getDimensionInPixel(2), lineHighlightPaint); canvas.drawLine(midx, midy, midx - getDimensionInPixel(5), midy - getDimensionInPixel(2), lineHighlightPaint); } else { canvas.drawLine(start.x, start.y, end.x, end.y, linePaint); canvas.drawLine(midx, midy, midx + getDimensionInPixel(5), midy - getDimensionInPixel(2), linePaint); canvas.drawLine(midx, midy, midx - getDimensionInPixel(5), midy - getDimensionInPixel(2), linePaint); } } public void highlightNode(int node) { this.highlightNode.add(node); invalidate(); } public void highlightLine(int start, int end) { List<Integer> edges = highlightLine.get(start); if (edges ==null) { edges = new ArrayList<>(); } edges.add(end); this.highlightLine.put(start,edges); invalidate(); } @Override public void onCompleted() { highlightLine.clear(); highlightNode.clear(); } }