/* Part of the G4P library for Processing http://www.lagers.org.uk/g4p/index.html http://sourceforge.net/projects/g4p/files/?source=navbar Copyright (c) 2012 Peter Lager This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package automenta.vivisect.gui; import processing.core.PApplet; import processing.core.PImage; /** * Base class for different types of hot spot. * * @author Peter Lager * */ abstract class HotSpot implements GConstants, Comparable<HotSpot> { public final Integer id; public float x, y; abstract public boolean contains(float px, float py); protected HotSpot(int id){ this.id = Math.abs(id); } public void adjust(Object ... arguments){} public int compareTo(HotSpot spoto) { return id.compareTo(spoto.id); } /** * Hit is based on being inside a rectangle. * * @author Peter Lager */ static class HSrect extends HotSpot { public float w, h; public HSrect(int id, float x, float y, float w, float h) { super(id); this.x = x; this.y = y; this.w = w; this.h = h; } @Override public boolean contains(final float px, final float py) { return (px >= x && py >= y && px <= x + w && py <= y + h); } } /** * Hit based on an arc (pie slice) * * @author Peter Lager * */ static class HSarc extends HotSpot { public float sa, ea, r, r2; public HSarc(int id, float x, float y, float r, float sa, float ea) { super(id); this.x = x; this.y = y; this.r = r; this.r2 = r * r; this.sa = sa; this.ea = ea; } @Override public boolean contains(float px, float py) { if((px-x)*(px-x) + (py-y)*(py-y) > r2) return false; // Now check angle float a = (float) Math.toDegrees(Math.atan2(py-y, px-x)); if(a < 0) a += 360; if(a < sa) a += 360; return (a >= sa && a <= ea); } } /** * Hit is based on being inside a rectangle. * * @author Peter Lager */ static class HScircle extends HotSpot { public float r, r2; public HScircle(int id, float x, float y, float r) { super(id); this.x = x; this.y = y; this.r = r; this.r2 = r * r; } @Override public boolean contains(final float px, final float py) { float dx = (px-x); float dy = (py-y); dx*=dx; if (dx <= r2) { dy*=dy; if (dy+dx <= r2) return true; } return false; } /** * If used the parameters must be in the order x, y then r. <br> * */ @SuppressWarnings(value={"fallthrough"}) public void adjust(Object ... arguments){ switch(arguments.length){ case 3: r = Float.valueOf(arguments[2].toString()); r2 = r * r; case 2: y = Float.valueOf(arguments[1].toString()); case 1: x = Float.valueOf(arguments[0].toString()); } } public String toString(){ return "HS circle ["+x+", "+y+"] radius = "+r; } } /** * Hit depends on the mask image. non-transparent areas are black and * transparent areas are white. <br> * * It is better this way because scaling the image can change the * colour white to very nearly white but black is unchanged so is * easier to test. * * @author Peter Lager * */ static class HSmask extends HotSpot { private PImage mask = null; protected HSmask(int id, PImage mask) { super(id); this.mask = mask; } @Override public boolean contains(float px, float py) { if(mask != null){ int pixel = mask.get((int)px, (int)py); float alpha = (pixel >> 24) & 0xff; // A > 0 and RGB = 0 is transparent if(alpha > 0 && (pixel & 0x00ffffff) == 0){ return true; } } return false; } public String toString(){ return "HS mask ["+x+", "+y+"]"; } } /** * Hit is determined by the alpha channel value. * @author Peter * */ static class HSalpha extends HotSpot { private PImage image = null; private int offX, offY; protected HSalpha(int id, float x, float y, PImage image, int imageMode) { super(id); this.image = image; this.x = x; this.y = y; if(imageMode == PApplet.CENTER){ offX = -image.width/2; offY = -image.height/2; } else offX = offY = 0; } /** * If used the parameters must be in the order x, y then image. <br> */ @SuppressWarnings(value={"fallthrough"}) public void adjust(Object ... arguments){ switch(arguments.length){ case 3: image = (PImage) arguments[2]; case 2: y = Float.valueOf(arguments[1].toString()); case 1: x = Float.valueOf(arguments[0].toString()); } } @Override public boolean contains(float px, float py) { if(image != null){ int imgX = Math.round(px - x) - offX; int imgY = Math.round(py - y) - offY; float alpha = (image.get(imgX, imgY) >> 24) & 0xff; if(alpha > ALPHA_PICK) return true; } return false; } public String toString(){ return "HS alpha ["+x+", "+y+"]"; } } }