/* * Copyright (c) 2011-2013, Peter Abeles. All Rights Reserved. * * This file is part of BoofCV (http://boofcv.org). * * 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.apache.org/licenses/LICENSE-2.0 * * 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 boofcv.gui.feature; import georegression.geometry.UtilPoint2D_I32; import georegression.struct.point.Point2D_I32; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; /** * Allows the user to select a point, its size, and orientation. First the user clicks on a point * then drags the mouse out. The distance away from the first point is the size and the vector * is its orientation. * * @author Peter Abeles */ public class SelectRegionDescriptionPanel extends JPanel implements MouseListener , MouseMotionListener { double clickTolerance = 10; BufferedImage background; Point2D_I32 target; Point2D_I32 current; // scale of background to view double imageScale; Listener listener; // is the region being dragged around? // In normal mode the current mouse position sets the size and orientation. // In drag mode it sets the region's center. boolean dragMode = false; public SelectRegionDescriptionPanel() { super(new BorderLayout()); addMouseListener(this); addMouseMotionListener(this); } public void setListener(Listener listener) { this.listener = listener; } public void setBackground( BufferedImage image ) { this.background = image; setPreferredSize(new Dimension(image.getWidth(),image.getHeight())); } public void reset() { target = null; current = null; } public boolean hasTarget() { return target != null; } public Point2D_I32 getTarget() { return target.copy(); } public double getFeatureRadius() { double r = UtilPoint2D_I32.distance(target,current); if( r < 1 ) return 1; return r; } public double getFeatureOrientation() { double dy = current.y-target.y; double dx = current.x-target.x; return Math.atan2(dy,dx); } @Override public synchronized void paintComponent(Graphics g) { super.paintComponent(g); if( background == null ) return; computeScale(); Graphics2D g2 = (Graphics2D)g; int dstWidth = (int)(imageScale*background.getWidth()); int dstHeight = (int)(imageScale*background.getHeight()); g2.drawImage(background,0,0,dstWidth,dstHeight,0,0,background.getWidth(),background.getHeight(),null); if( target != null ) { int x1 = (int)(imageScale*target.x); int y1 = (int)(imageScale*target.y); int x2 = (int)(imageScale*current.x); int y2 = (int)(imageScale*current.y); int r,w; // draw feature orientation g2.setStroke(new BasicStroke(2)); g2.setColor(Color.BLUE); g2.drawLine(x1,y1,x2,y2); // draw feature size r = (int)(imageScale*UtilPoint2D_I32.distance(target,current)); w = r*2+1; g2.setColor(Color.PINK); g2.drawOval(x1-r,y1-r,w,w); // draw the feature location r = 5; w = r*2+1; g2.setColor(Color.black); g2.fillOval(x1-r,y1-r,w,w); r = 3; w = r*2+1; g2.setColor(Color.red); g2.fillOval(x1-r,y1-r,w,w); } } private void computeScale() { double scaleX = getWidth() / (double)background.getWidth(); double scaleY = getHeight() / (double)background.getHeight(); imageScale = Math.min(scaleX,scaleY); } @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) { int x = (int)(e.getX()/imageScale); int y = (int)(e.getY()/imageScale); // see if the mouse click was on the image if( x < 0 || x >= background.getWidth() || y < 0 || y >= background.getHeight()) { if( target != null ) { repaint(); if( listener != null ) { listener.descriptionChanged(null,0,0); } } target = null; current = null; } else { boolean adjusted = false; if( target != null ) { // if the user clicked on the center point enter drag mode int targetX = (int)(target.x*imageScale); int targetY = (int)(target.y*imageScale); double distance = UtilPoint2D_I32.distance(e.getX(),e.getY(),targetX,targetY); if( distance < clickTolerance ) { // adjust the target to be at the cursor dragMode = true; current.x += x-target.x; current.y += y-target.y; target.set(x,y); adjusted = true; } else { // see if the user clicked on the circle, if so go into adjustment mode double radiusCircle = imageScale*UtilPoint2D_I32.distance(target,current); distance = Math.abs( distance - radiusCircle); if( distance < clickTolerance ) { current.set(x,y); adjusted = true; } } } if( adjusted ) { repaint(); if( listener != null ) { listener.descriptionChanged(target,getFeatureRadius(),getFeatureOrientation()); } } else { dragMode = false; target = new Point2D_I32(x,y); current = target.copy(); repaint(); } } } @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mouseDragged(MouseEvent e) { if( current == null ) { return; } int x = (int)(e.getX()/imageScale); int y = (int)(e.getY()/imageScale); if( dragMode ) { current.x += x-target.x; current.y += y-target.y; target.set(x,y); } else { current.set(x,y); } repaint(); if( listener != null ) { listener.descriptionChanged(target,getFeatureRadius(),getFeatureOrientation()); } } @Override public void mouseMoved(MouseEvent e) {} public static interface Listener { public void descriptionChanged( Point2D_I32 pt , double radius , double orientation ); } }