/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: CurveListener.java * * Copyright (c) 2005 Sun Microsystems and Static Free Software * * Electric(tm) 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. * * Electric(tm) 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. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.user.ui; import com.sun.electric.database.ImmutableArcInst; import com.sun.electric.database.geometry.DBMath; import com.sun.electric.database.geometry.GenMath; import com.sun.electric.database.geometry.Poly; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.Geometric; import com.sun.electric.tool.Job; import com.sun.electric.tool.JobException; import com.sun.electric.tool.user.CircuitChangeJobs; import com.sun.electric.tool.user.Highlighter; import com.sun.electric.tool.user.User; import java.awt.Cursor; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.geom.Point2D; import java.util.EventListener; import java.util.List; /** * Class to handle changes to arc curvature. */ public class CurveListener implements MouseMotionListener, MouseListener, MouseWheelListener, KeyListener { private ArcInst curveAI; private EventListener oldListener; private boolean through; private CurveListener() {} /** * This method sets curvature on the highlighted arc. * @param through true to have arc curve through cursor, * false to have arc curve about cursor. */ public static void setCurvature(boolean through) { EditWindow wnd = EditWindow.needCurrent(); if (wnd == null) return; Highlighter highlighter = wnd.getHighlighter(); List<Geometric> geomList = highlighter.getHighlightedEObjs(true, true); if (geomList == null) return; if (geomList.size() != 1) { System.out.println("Select just one arc to setting curvature"); return; } Geometric geom = geomList.get(0); if (!(geom instanceof ArcInst)) { System.out.println("Select an arc before setting curvature"); return; } EventListener newListener = null; // remember the listener that was there before EventListener oldListener = WindowFrame.getListener(); System.out.println("Click to adjust curvature"); newListener = oldListener; if (newListener == null || !(newListener instanceof CurveListener)) { newListener = new CurveListener(); WindowFrame.setListener(newListener); } ((CurveListener)newListener).curveAI = (ArcInst)geom; ((CurveListener)newListener).oldListener = oldListener; ((CurveListener)newListener).through = through; } /** * This method removes curvature on the currently selected arc. */ public static void removeCurvature() { EditWindow wnd = EditWindow.needCurrent(); if (wnd == null) return; Highlighter highlighter = wnd.getHighlighter(); List<Geometric> geomList = highlighter.getHighlightedEObjs(true, true); if (geomList == null) return; if (geomList.size() != 1) { System.out.println("Select just one arc to remove curvature"); return; } Geometric geom = geomList.get(0); if (!(geom instanceof ArcInst)) { System.out.println("Select an arc before removing curvature"); return; } new SetArcCurvature((ArcInst)geom, 0); } public void mousePressed(MouseEvent evt) { showHighlight(evt, (EditWindow)evt.getSource()); } public void mouseMoved(MouseEvent evt) { showHighlight(evt, (EditWindow)evt.getSource()); } public void mouseDragged(MouseEvent evt) { showHighlight(evt, (EditWindow)evt.getSource()); } public void mouseReleased(MouseEvent evt) { // restore the listener to the former state WindowFrame.setListener(oldListener); EditWindow wnd = (EditWindow)evt.getSource(); showHighlight(null, wnd); // handle scaling the selected objects Point2D dbPt = wnd.screenToDatabase(evt.getX(), evt.getY()); double lambdaCurvature; if (through) { lambdaCurvature = curveArcThroughPoint(curveAI, dbPt.getX(), dbPt.getY()); } else { lambdaCurvature = curveArcAboutPoint(curveAI, dbPt.getX(), dbPt.getY()); } new SetArcCurvature(curveAI, DBMath.lambdaToGrid(lambdaCurvature)); } public void keyPressed(KeyEvent evt) { int chr = evt.getKeyCode(); EditWindow wnd = (EditWindow)evt.getSource(); Cell cell = wnd.getCell(); if (cell == null) return; // ESCAPE for abort if (chr == KeyEvent.VK_ESCAPE) { // restore the listener to the former state WindowFrame.setListener(oldListener); showHighlight(null, wnd); System.out.println("Aborted"); } } public void mouseClicked(MouseEvent evt) {} public void mouseEntered(MouseEvent evt) {} public void mouseExited(MouseEvent evt) {} public void mouseWheelMoved(MouseWheelEvent evt) {} public void keyReleased(KeyEvent evt) {} public void keyTyped(KeyEvent evt) {} private void showHighlight(MouseEvent evt, EditWindow wnd) { Highlighter highlighter = wnd.getHighlighter(); highlighter.clear(); if (evt != null) { Point2D dbPt = wnd.screenToDatabase(evt.getX(), evt.getY()); double lambdaCurvature; if (through) { lambdaCurvature = curveArcThroughPoint(curveAI, dbPt.getX(), dbPt.getY()); } else { lambdaCurvature = curveArcAboutPoint(curveAI, dbPt.getX(), dbPt.getY()); } Poly curvedPoly = curveAI.curvedArcLambdaOutline(Poly.Type.CLOSED, curveAI.getGridBaseWidth(), DBMath.lambdaToGrid(lambdaCurvature)); if (curvedPoly != null) highlighter.addPoly(curvedPoly, curveAI.getParent(), null); } highlighter.finished(); wnd.repaint(); } /** * Method to return the curvature for arc "ai" that will allow it to * curve about (xcur, ycur), a center point. */ private double curveArcAboutPoint(ArcInst ai, double xcur, double ycur) { // get true center of arc through cursor Point2D r0 = ai.getHeadLocation(); Point2D r1 = ai.getTailLocation(); int ang = ai.getAngle(); double acx = (r0.getX() + r1.getX()) / 2; double acy = (r0.getY() + r1.getY()) / 2; Point2D ip = GenMath.intersect(new Point2D.Double(xcur, ycur), ang, new Point2D.Double(acx, acy), (ang+900)%3600); double r = r0.distance(ip); // now see if this point will be re-created Point2D [] pts = DBMath.findCenters(r, r0, r1); if (pts != null) { if (Math.abs(pts[0].getX()-ip.getX())+Math.abs(pts[0].getY()-ip.getY()) < Math.abs(pts[1].getX()-ip.getX())+Math.abs(pts[1].getY()-ip.getY())) r = -r; } return r; } /** * Method to return the curvature for arc "ai" that will allow it to * curve through (xcur, ycur), an edge point. */ private double curveArcThroughPoint(ArcInst ai, double xcur, double ycur) { Point2D r0 = ai.getHeadLocation(); Point2D r1 = ai.getTailLocation(); double r0x = r0.getX(); double r0y = r0.getY(); double r1x = r1.getX(); double r1y = r1.getY(); double r2x = xcur; double r2y = ycur; double r02x = r2x-r0x; double r02y = r2y-r0y; double rpx = r0y-r1y; double rpy = r1x-r0x; double u = r02x; u *= (r2x-r1x); double v = r02y; v *= (r2y-r1y); double t = u + v; u = r02x; u *= rpx; v = r02y; v *= rpy; t /= (u + v) * 2.0f; double rcx = r0x + (r1x-r0x)/2 + t*rpx; double rcy = r0y + (r1y-r0y)/2 + t*rpy; Point2D rc = new Point2D.Double(rcx, rcy); //now see if this point will be re-created double r = r0.distance(rc); Point2D [] pts = DBMath.findCenters(r, r0, r1); if (pts != null) { if (Math.abs(pts[0].getX()-rcx) + Math.abs(pts[0].getY()-rcy) < Math.abs(pts[1].getX()-rcx) + Math.abs(pts[1].getY()-rcy)) r = -r; } else { rcx = r0x + (r1x-r0x)/2; rcy = r0y + (r1y-r0y)/2; r = r0.distance(rc) + 1; } return r; } private static class SetArcCurvature extends Job { private ArcInst curveAI; private long gridCurvature; protected SetArcCurvature(ArcInst curveAI, long gridCurvature) { super("Set arc curvature", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.curveAI = curveAI; this.gridCurvature = gridCurvature; startJob(); } public boolean doIt() throws JobException { // make sure changing the arc is allowed if (CircuitChangeJobs.cantEdit(curveAI.getParent(), null, true, false, true) != 0) return false; if (gridCurvature == 0) { if (curveAI.getVar(ImmutableArcInst.ARC_RADIUS) != null) curveAI.delVar(ImmutableArcInst.ARC_RADIUS); } else { curveAI.newVar(ImmutableArcInst.ARC_RADIUS, new Double(DBMath.gridToLambda(gridCurvature))); } curveAI.modify(0, 0, 0, 0); return true; } } }