/* * Copyright 2004-2010 Information & Software Engineering Group (188/1) * Institute of Software Technology and Interactive Systems * Vienna University of Technology, Austria * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.tuwien.ifs.somtoolbox.visualization.thematicmap; import java.awt.Color; import java.awt.Graphics2D; import java.util.ArrayList; import java.util.Iterator; import org.jfree.util.PaintList; import edu.cornell.cs.voronoi.DelaunayTriangulation; import edu.cornell.cs.voronoi.Pnt; import edu.cornell.cs.voronoi.Simplex; import at.tuwien.ifs.somtoolbox.data.SOMLibClassInformation; import at.tuwien.ifs.somtoolbox.layers.Unit; import at.tuwien.ifs.somtoolbox.util.ProgressListener; import at.tuwien.ifs.somtoolbox.util.ProgressListenerFactory; /** * @author Taha Abdel Aziz * @version $Id: RegionManager.java 3888 2010-11-02 17:42:53Z frank $ */ public class RegionManager { public static final int BORDER = 5; public static final int DEFAULT_ZOOM_FACTOR = 10; private int zoom = DEFAULT_ZOOM_FACTOR; int initialSize = 10000; int width; int height; ArrayList<SOMRegion> regions = new ArrayList<SOMRegion>(); Simplex initialTriangle = new Simplex(new Pnt[] { new Pnt(-initialSize, -initialSize), new Pnt(initialSize, -initialSize), new Pnt(0, initialSize) }); DelaunayTriangulation mainDt = new DelaunayTriangulation(initialTriangle); DelaunayTriangulation resolvedDt = new DelaunayTriangulation(initialTriangle); SOMLibClassInformation classInfo; double min_visible_class = 0; private PaintList paintList; public RegionManager(SOMLibClassInformation classInfo, PaintList paintList, int width, int height, double min_visible_class) { this(classInfo, paintList, width, height, min_visible_class, DEFAULT_ZOOM_FACTOR); } /** Creates a new instance of SOMegions */ public RegionManager(SOMLibClassInformation classInfo, PaintList paintList, int width, int height, double min_visible_class, int zoom) { this.classInfo = classInfo; this.paintList = paintList; this.width = width; this.height = height; this.min_visible_class = min_visible_class; this.zoom = zoom; } public SOMRegion getRegion(ArrayList<SOMRegion> candidates, double x, double y) { for (int i = 0; i < candidates.size(); i++) { SOMRegion r = candidates.get(i); if (r.equals(new Pnt(x, y))) { return r; } } return null; } public SOMRegion getRegion(ArrayList<SOMRegion> candidates, Pnt center) { for (int i = 0; i < candidates.size(); i++) { SOMRegion r = candidates.get(i); if (r.equals(center)) { return r; } } return null; } public SOMRegion addNewRegion(Unit unit) { SOMRegion r = new SOMRegion(unit, classInfo, paintList, zoom); regions.add(r); double x = (double) unit.getXPos() * zoom + BORDER; double y = (double) unit.getYPos() * zoom + BORDER; Pnt point = new Pnt(x, y); mainDt.delaunayPlace(point); return r; } public void removeRegion(SOMRegion r) { regions.remove(r); } public void drawRegions(Graphics2D g) { if (regions.isEmpty()) { return; } for (int i = 0; i < regions.size(); i++) { SOMRegion r = regions.get(i); r.drawRegion(g); } } @SuppressWarnings({ "rawtypes", "unchecked" }) public void drawDelaunayTrangulation(Graphics2D g) { for (Iterator it = mainDt.iterator(); it.hasNext();) { Simplex triangle = (Simplex) it.next(); Pnt[] t_points = (Pnt[]) triangle.toArray(new Pnt[0]); for (int i = 0; i < t_points.length; i++) { int x1 = (int) t_points[i].coord(0); int y1 = (int) t_points[i].coord(1); int x2 = 0; int y2 = 0; if (i + 1 < t_points.length) { x2 = (int) t_points[i + 1].coord(0); y2 = (int) t_points[i + 1].coord(1); } else { x2 = (int) t_points[0].coord(0); y2 = (int) t_points[0].coord(1); } g.setColor(Color.CYAN); g.drawLine(x1, y1, x2, y2); } } } public void fillRegions(Graphics2D g, boolean chessboard) { if (!regions.isEmpty()) { for (int i = 0; i < regions.size(); i++) { regions.get(i).fillRegion(g, chessboard); } for (int i = 0; i < regions.size(); i++) { regions.get(i).resolve(min_visible_class); } for (int i = 0; i < regions.size(); i++) { regions.get(i).fillRegion(g, chessboard); } } } /** * Fills SOMRegions according to the specified ClassID. Note that SOMRegions where the ClassID is not the Main class * are colored lighter. */ public void fillSingleRegion(Graphics2D g, boolean chessboard, int ClassID) { for (int i = 0; i < regions.size(); i++) { SOMRegion r = regions.get(i); int resolve = r.resolveMainClassIndex(ClassID); Color c = classInfo.getClassColor(ClassID); if (resolve != ClassID && resolve > -1) { /* * double p = r.getClassWithIndex(ClassID).hits / r.mainClass.hits ; if(p >= 1.0) p=p-1.0; int red = * Math.min((int)Math.round(c.getRed()*(1+p)), 255); int green = Math.min((int)Math.round(c.getGreen()*(1+p)), 255); int blue = * Math.min((int)Math.round(c.getBlue()*(1+p)), 255); Color d = new Color(red,green,blue); */ g.setColor(c); g.fillPolygon(r); } if (r.mainClass.classIndex == ClassID) { g.setColor(c); g.fillPolygon(r); } } } public void build() { ProgressListener progressWriter = ProgressListenerFactory.getInstance().createProgressListener(regions.size(), "Processing region ", 10); build(regions, mainDt); for (int i = 0; i < regions.size(); i++) { SOMRegion r = regions.get(i); r.makeUniqe(); cut(); r.sortSegments(); r.calcRelations(); progressWriter.progress(); } } public void cut() { for (int i = 0; i < regions.size(); i++) { SOMRegion r = regions.get(i); r.cut(width, height); } } @SuppressWarnings({ "rawtypes", "unchecked" }) public void build(ArrayList<SOMRegion> regions, DelaunayTriangulation dt) { Color[] c = new Color[8]; c[0] = Color.BLACK; c[1] = Color.BLUE; c[2] = Color.CYAN; c[3] = Color.DARK_GRAY; c[4] = Color.GREEN; c[5] = Color.RED; c[6] = Color.YELLOW; c[7] = Color.MAGENTA; // int n=0; // Loop through all the edges of the DT (each is done twice) for (Iterator it = dt.iterator(); it.hasNext();) { Simplex triangle = (Simplex) it.next(); Pnt[] t_points = (Pnt[]) triangle.toArray(new Pnt[0]); Pnt p = Pnt.circumcenter(t_points); for (Iterator otherIt = dt.neighbors(triangle).iterator(); otherIt.hasNext();) { Simplex other = (Simplex) otherIt.next(); Pnt[] n_points = (Pnt[]) other.toArray(new Pnt[0]); Pnt q = Pnt.circumcenter(n_points); ArrayList<Pnt> common = new ArrayList<Pnt>(); for (Pnt t_point : t_points) { for (Pnt n_point : n_points) { if (t_point.equals(n_point)) { common.add(t_point); } } } Pnt node1 = common.get(0); Pnt node2 = common.get(1); SOMRegion r1 = getRegion(regions, node1); SOMRegion r2 = getRegion(regions, node2); if (r1 != null) { Segment s = new Segment(p, q); s.neighborRegion = r2; r1.addSegment(s); } if (r2 != null) { Segment s = new Segment(p, q); s.neighborRegion = r1; r2.addSegment(s); } } } } public void resolve() { for (int i = 0; i < regions.size(); i++) { SOMRegion r = regions.get(i); r.resolve(min_visible_class); } // for (int i = 0; i < resolvedRegions.size(); i++) { // Pnt pnt = (Pnt)resolvedRegions.get(i); // resolvedDt.delaunayPlace(pnt); // } // build(resolvedRegions, resolvedDt); } /** Allows to reset the resolved state, for reusing the diagram. */ public void resetResolvingState() { for (int i = 0; i < regions.size(); i++) { SOMRegion r = regions.get(i); r.resolved = false; } } /** * Goes through all the Regions and returns the Region with smallest Entropy Error. This is used in the End to * spread the Value among the whole Palette Interval (used for Visualization) * * @return smallest Entropy */ public SOMRegion getMaximumEntropyRegion() { SOMRegion reg; int counter = 0; double max = Double.MIN_VALUE; for (int i = 0; i < this.regions.size(); i++) { SOMRegion r = this.regions.get(i); double c1 = r.calculateEntropy(); // System.out.println("Region Entropy :"+c1); if (c1 > max) { max = c1; counter = i; } } // System.out.println("Max Region Entropy :"+max); return this.regions.get(counter); } /** * Goes through all the Regions and returns the Region with biggest Entropy Error. This is used in the End to spread * the Value among the whole Palette Interval (used for Visualization) * * @return biggest Entropy */ public SOMRegion getMinimumEntropyRegion() { // SOMRegion reg; int counter = 0; double min = Double.MAX_VALUE; for (int i = 0; i < this.regions.size(); i++) { SOMRegion r = this.regions.get(i); double c1 = r.calculateEntropy(); if (c1 < min) { min = c1; counter = i; } } return this.regions.get(counter); } public ArrayList<SOMRegion> getRegions() { return regions; } }