import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.image.*; import java.util.*; import java.util.Properties; import java.io.*; import java.lang.*; import java.lang.reflect.*; import java.math.*; import javax.swing.*; import javax.swing.event.*; /* import javax.swing.text.*; import javax.swing.JFileChooser.*; import javax.swing.filechooser.FileFilter; */ import ij.*; import ij.plugin.filter.PlugInFilter; import ij.plugin.PlugIn; import ij.gui.*; import ij.process.*; import ij.measure.*; import ij.io.*; /******************************************************************************* ** CubicSpline.java ** ================ Eva Kocsis, September 2000 BEPS/ORS/OD/NIH Straigths filamentous molecules. The user selects a set of nodes by mouse. Non-uniform cubic Spline is fitted to these points, the filament is straigtened along it. The width of the filament can be changed interactively. The position of the nodes can be refined with the option of 'Automatic Refinement'. *******************************************************************************/ public class CubicSplineBBc_ implements PlugInFilter { private ImagePlus imp; public int setup(String arg, ImagePlus imp) { this.imp = imp; if (arg.equals("about")) {showAbout(); return DONE;} return DOES_8G; } public void run(ImageProcessor ip) { boolean first = true; mainProgram mainPr = new mainProgram(ip, first); } void showAbout() { IJ.showMessage("About CubicSpline_...", "This program is used for straightening filamentous particles. \n" + "The user selects a set of nodes by mouse. \n" + "Non-uniform cubic Spline is fitted to these points,\n" + " the filament is straigtened along it. \n" + "The width of the filament can be changed interactively.\n" + "The position of the nodes can be refined with the option of \n" + "'Automatic Refinement'. \n\n"+ "Written by Eva Kocsis, NIH " ); } } //========================================================================================== class mainProgram implements ActionListener { public mainProgram(ImageProcessor ip, boolean first) { String winTitle = "C.Spline: "+ WindowManager.getCurrentImage().getTitle(); SplineImagePlus sIP = new SplineImagePlus(winTitle, ip); sIP.show(); SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); wW = new widthWindow(spIc); if (first) // Create Menu { MenuBar mbar = new MenuBar(); mbar = Menus.getMenuBar(); readInNodes = new MenuItem(" Read in Nodes "); run = new MenuItem(" Run CubicSpline "); straightIt = new MenuItem(" Straight the Curve "); reset = new MenuItem(" Reset "); newCurve = new MenuItem(" New Curve "); autRef = new MenuItem(" Automatic Node Refinement "); filWidth = new MenuItem(" Width of Filament/Wide line "); centerYellow = new MenuItem(" yellow "); centerOrange = new MenuItem(" orange "); centerRed = new MenuItem(" red "); centerPink = new MenuItem(" pink "); centerMagenta = new MenuItem(" magenta"); centerCyan = new MenuItem(" cyan "); centerGreen = new MenuItem(" green "); centerBlue = new MenuItem(" blue "); center1 = new MenuItem(" 1.0 "); center55 = new MenuItem(" 0.55 "); center45 = new MenuItem(" 0.45 "); center35 = new MenuItem(" 0.35 "); center25 = new MenuItem(" 0.25 "); center15 = new MenuItem(" 0.15 "); center0 = new MenuItem(" 0.0 "); wideCyan = new MenuItem(" cyan "); wideGreen = new MenuItem(" green "); wideBlue = new MenuItem(" blue "); wideYellow = new MenuItem(" yellow "); wideOrange = new MenuItem(" orange "); wideRed = new MenuItem(" red "); widePink = new MenuItem(" pink "); wideMagenta = new MenuItem(" magenta"); wide1 = new MenuItem(" 1.0 "); wide55 = new MenuItem(" 0.55 "); wide45 = new MenuItem(" 0.45 "); wide35 = new MenuItem(" 0.35 "); wide25 = new MenuItem(" 0.25 "); wide15 = new MenuItem(" 0.15 "); wide0 = new MenuItem(" 0.0 "); mbar.add(menuMeth.makeMenu(" CubicSpline ", new Object[] { run, null, readInNodes, null, straightIt, reset, newCurve, null, filWidth, null, autRef, null, menuMeth.makeMenu(" Graphics ", new Object[] { menuMeth.makeMenu(" Center Line ", new Object[] { menuMeth.makeMenu(" Color ", new Object[] { centerYellow , centerOrange , centerRed , centerPink , centerMagenta, centerCyan , centerGreen , centerBlue }, this), menuMeth.makeMenu(" Translucent ", new Object[] { center1 , center55, center45, center35, center25, center15, center0 }, this), }, this), menuMeth.makeMenu(" Wide Line ", new Object[] { menuMeth.makeMenu(" Color ", new Object[] { wideYellow , wideOrange , wideRed , widePink , wideMagenta, wideCyan , wideGreen , wideBlue }, this), menuMeth.makeMenu(" Translucent ", new Object[] { wide1 , wide55, wide45, wide35, wide25, wide15, wide0 }, this), }, this), }, this) }, this)); } } public void actionPerformed(ActionEvent evt) { MenuItem item = (MenuItem)evt.getSource(); if (item == run) { ImageProcessor nIp = WindowManager.getCurrentWindow().getImagePlus().getProcessor(); boolean first = false; mainProgram mainPr = new mainProgram(nIp, first); } else if (item == readInNodes) { ; } else if (item == straightIt) { ImageProcessor cIp = WindowManager.getCurrentWindow(). getImagePlus().getProcessor(); SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); if (cIp instanceof ByteProcessor) { byte[] pixels = (byte[])cIp.getPixels(); spIc.doStraight(pixels); } else { spIc.doStraight(null); } } else if (item == reset) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); spIc.reSet(); } else if (item == newCurve) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); spIc.deleteNodes(); } else if (item == filWidth) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); wW.show(spIc); } else if (item == autRef) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); // spIc.autRef(); } else { String arg = evt.getActionCommand(); makeAction(item, arg); } } public void makeAction(MenuItem item, String arg) { if (item == centerYellow || item == centerOrange || item == centerRed || item == centerPink || item == centerMagenta || item == centerCyan || item == centerGreen || item == centerBlue) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); spIc.CsetColor(arg); } else if (item == wideYellow || item == wideOrange || item == wideRed || item == widePink || item == wideMagenta || item == wideCyan || item == wideGreen || item == wideBlue) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); spIc.WsetColor(arg); } else if (item == center1 || item == center55 || item == center45 || item == center35 || item == center25 || item == center15 || item == center0) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); spIc.CsetTransl(arg); } else if (item == wide1 ||item == wide55 || item == wide45 || item == wide35 || item == wide25 || item == wide15 || item == wide0) { SplineImageCanvas spIc = (SplineImageCanvas)WindowManager. getCurrentWindow().getCanvas(); spIc.WsetTransl(arg); } else {;} } private MenuItem run, readInNodes, straightIt; private MenuItem reset, newCurve, autRef, filWidth; private MenuItem centerYellow, centerOrange, centerRed, centerPink, centerMagenta; private MenuItem centerCyan, centerGreen, centerBlue, center1, center25, center15; private MenuItem center35, center45, center55, center0; private MenuItem wideCyan, wideGreen, wideBlue, wideYellow, wideOrange, wideRed; private MenuItem widePink, wideMagenta, wide1, wide25, wide15, wide0; private MenuItem wide35, wide45, wide55; private widthWindow wW; } //========================================================================================== class menuMeth { public static Menu makeMenu(Object parent, Object[] items, Object target) { Menu m = null; if (parent instanceof Menu) m = (Menu)parent; else if (parent instanceof String) m = new Menu((String)parent); else return null; for (int i = 0; i < items.length; i++) { if (items[i] == null) m.addSeparator(); else m.add(makeMenuItem(items[i], target)); } return m; } public static MenuItem makeMenuItem(Object item, Object target) { MenuItem r = null; if (item instanceof String) r = new MenuItem((String)item); else if (item instanceof MenuItem) r = (MenuItem)item; else return null; if (target instanceof ActionListener) r.addActionListener((ActionListener)target); return r; } } //========================================================================================== class SplineImagePlus extends ImagePlus { public SplineImagePlus(String title, ImageProcessor ip) { super(title, ip); ic = new SplineImageCanvas(this, title); } public SplineImagePlus(String title, ImageProcessor ip, double[] strNodes, int nN, SplineImageCanvas parentIc) { super(title, ip); ic = new SplineImageCanvas(this, strNodes, nN, parentIc, title); } public void show(String statusMessage) { if (win!=null) return; img = getImage(); if ((img!=null) && (width>=0) && (height>=0)) { win = new ImageWindow(this, ic); draw(); IJ.showStatus(statusMessage); } else IJ.write(""); } protected SplineImageCanvas ic; } //========================================================================================== class SplineImageCanvas extends ImageCanvas { public SplineImageCanvas(SplineImagePlus imp, String title) { super(imp); this.imp = imp; addMouseListener(this); addMouseMotionListener(this); imJ = IJ.getInstance(); addKeyListener(imJ); // ImageJ handles keyboard shortcuts magnification = 1.0; imageWidth = imp.getWidth(); imageHeight = imp.getHeight(); this.title = title; } public SplineImageCanvas(SplineImagePlus imp, double[] strNodes, int nN, SplineImageCanvas splIc, String title) { super(imp); this.imp = imp; addMouseListener(this); addMouseMotionListener(this); imJ = IJ.getInstance(); addKeyListener(imJ); // ImageJ handles keyboard shortcuts magnification = 1.0; imageWidth = imp.getWidth(); imageHeight = imp.getHeight(); width = imageHeight; double ny = (double)(width/2 + 1); npoints = nN; for (int i = 0; i < npoints; i++) { points[i] = new Point2D.Double(strNodes[i], ny); drawingPoints[i] = new Point2D.Double(strNodes[i], ny); } savePoints(); //for reSet parentIc = new SplineImageCanvas(imp,""); parentIc = splIc; hasParentCanvas = true; this.title = title; } public void mousePressed(MouseEvent event) { if (imJ==null) return; int toolID = Toolbar.getToolId(); ImageWindow win = imp.getWindow(); if (win.running && toolID!=Toolbar.MAGNIFIER) { win.running = false; return; } int x = event.getX(); int y = event.getY(); int flags = event.getModifiers(); if (toolID!=Toolbar.MAGNIFIER && (event.isPopupTrigger() || (flags & event.META_MASK)!=0)) { PopupMenu popup = Menus.getPopupMenu(); if (popup!=null) { add(popup); popup.show(this, x, y); } return; } int ox = offScreenX(x); int oy = offScreenY(y); if (IJ.spaceBarDown()) { // temporarily switch to "hand" tool of space bar down xMouseStart = ox; yMouseStart = oy; xSrcStart = srcRect.x; ySrcStart = srcRect.y; return; } if ((flags&Event.ALT_MASK)!=0 && toolID!=Toolbar.MAGNIFIER && toolID!=Toolbar.DROPPER) { // temporarily switch to color tool alt/option key down setDrawingColor(ox, oy, false); return; } switch (toolID) { case Toolbar.MAGNIFIER: if ((flags & (Event.ALT_MASK|Event.META_MASK|Event.CTRL_MASK))!=0) zoomOut(x, y); else zoomIn(x, y); break; case Toolbar.HAND: xMouseStart = ox; yMouseStart = oy; xSrcStart = srcRect.x; ySrcStart = srcRect.y; break; case Toolbar.DROPPER: setDrawingColor(ox, oy, IJ.altKeyDown()); break; case Toolbar.CROSSHAIR: /* Select node points */ current = find(x, y); if (current < 0) // not inside a point add(x, y); break; case Toolbar.WAND: Roi roi = imp.getRoi(); if (roi!=null && roi.contains(ox, oy)) { Rectangle r = roi.getBoundingRect(); if (r.width==imageWidth && r.height==imageHeight) imp.killRoi(); else { return; } } if (imp.getType()==ImagePlus.GRAY16 || imp.getType()==ImagePlus.GRAY32) { IJ.error("The wand tool does not work with 16 and 32-bit grayscale images."); return; } ImageProcessor ip = imp.getProcessor(); Wand w = new Wand(ip); double t1 = ip.getMinThreshold(); if (t1==ip.NO_THRESHOLD) w.autoOutline(ox, oy); else w.autoOutline(ox, oy, (int)t1, (int)ip.getMaxThreshold()); if (w.npoints>0) { roi = new PolygonRoi(w.xpoints, w.ypoints, w.npoints, imp, Roi.TRACED_ROI); imp.setRoi(roi); } break; default: /* Select node points with CROSSHAIR */ Toolbar.getInstance().setTool(7); //CROSSHAIR current = find(x, y); if (current < 0) // not inside a point add(x, y); } } public void mouseClicked(MouseEvent event) { int x = event.getX(); int y = event.getY(); if (event.getClickCount() >= 2) { remove(current); } } public void mouseDragged(MouseEvent event) { if (current == -1) return; Point p = event.getPoint(); double px = p.getX(); double py = p.getY(); drawingPoints[current].setLocation(px, py); if (magnification != 1.0) { px = px / magnification; py = py / magnification; } points[current].setLocation(px, py); repaint(); } public int find(int x, int y) { for (int i = 0; i < npoints; i ++) if ( drawingPoints[i].getX() - CLICKSIZE / 2 <= x && x <= drawingPoints[i].getX() + CLICKSIZE /2 && drawingPoints[i].getY() - CLICKSIZE /2 <= y && y <= drawingPoints[i].getY() + CLICKSIZE /2 ) return i; return -1; } public void add(int x, int y) { if (npoints < MAXNPOINTS) { double dx = (double)x; double dy = (double)y; drawingPoints[npoints] = new Point2D.Double(dx, dy); if (magnification != 1.0) { dx = dx / magnification; dy = dy / magnification; } points[npoints] = new Point2D.Double(dx, dy); npoints++; current = -1; repaint(); } } public void remove(int n) { if (n < 0 || n >= npoints) return; npoints--; for (int i = n; i < npoints; i++) { points[i].setLocation(points[i+1]); drawingPoints[i].setLocation(drawingPoints[i+1]); } if (current == n) current = -1; repaint(); } public void deleteNodes() { for (int i = 0; i < npoints; i++) { points[i].setLocation(0.0,0.0); drawingPoints[i].setLocation(0.0,0.0); } npoints = 0; current = -1; repaint(); } public void paint(Graphics g) { srcRect = getSrcRect(); Roi roi = imp.getRoi(); //if (roi != null) roi.updatePaste(); double oldMagnification = magnification; magnification = super.getMagnification(); // System.out.println(" Old & Current Mag: "+oldMagnification+", "+magnification); if (oldMagnification != magnification) { for (int i = 0; i < npoints; i++) { double pxM = points[i].getX() * magnification; double pyM = points[i].getY() * magnification; drawingPoints[i].setLocation(pxM, pyM); } markWidthDraw = (int)((double)markWidth * magnification); } try { //imageUpdated = super.getImageUpdated(); if (imageUpdated) { imageUpdated = false; imp.updateImage(); } Image img = imp.getImage(); if (img!=null) g.drawImage(img, 0, 0, (int)(srcRect.width*magnification), (int)(srcRect.height*magnification), srcRect.x, srcRect.y, srcRect.x+srcRect.width, srcRect.y+srcRect.height, null); if (roi != null) roi.draw(g); } catch(OutOfMemoryError e) {IJ.outOfMemory("Paint");} if (notFirstTime) { Graphics2D g2 = (Graphics2D)g; if (npoints == 0) return; if (npoints < 2) { for (int i = 0; i < npoints; i++) { double x = drawingPoints[i].getX() - markWidthDraw / 2; double y = drawingPoints[i].getY() - markWidthDraw / 2; g2.setColor(ColorCode(i)); g2.fill(new Rectangle2D.Double(x, y, markWidthDraw, markWidthDraw)); } return; } g2.setColor(colorW); AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,alphaW); int drawingWidth = (int) (width * magnification); g2.setStroke(new BasicStroke(drawingWidth)); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setComposite(ac); CubicCurveMaker curveMakerDraw = new CubicCurveMaker(npoints, drawingPoints); curveDraw = curveMakerDraw.makeShape(); g2.draw(curveDraw); g2.setColor(colorC); ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,alphaC); g2.setStroke(new BasicStroke(1)); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setComposite(ac); g2.draw(curveDraw); for (int i = 0; i < npoints; i++) { double x = drawingPoints[i].getX() - markWidthDraw / 2; double y = drawingPoints[i].getY() - markWidthDraw / 2; g2.setColor(ColorCode(i)); g2.fill(new Rectangle2D.Double(x, y, markWidthDraw, markWidthDraw)); } } if (!notFirstTime) notFirstTime = true; } public void setWidth(int w) { width = w; repaint(); } public void CsetColor(String source) { if (source == " yellow ") { colorC = Color.yellow; repaint(); } else if (source == " orange ") { colorC = Color.orange; repaint(); } else if (source == " red ") { colorC = Color.red; repaint(); } else if (source == " pink ") { colorC = Color.pink; repaint(); } else if (source == " magenta") { colorC = Color.magenta; repaint(); } else if (source == " cyan ") { colorC = Color.cyan; repaint(); } else if (source == " green ") { colorC = Color.green; repaint(); } else if (source == " blue ") { colorC = Color.blue; repaint(); } } public void WsetColor(String source) { if (source == " yellow ") { colorW = Color.yellow; repaint(); } else if (source == " orange ") { colorW = Color.orange; repaint(); } else if (source == " red ") { colorW = Color.red; repaint(); } else if (source == " pink ") { colorW = Color.pink; repaint(); } else if (source == " magenta") { colorW = Color.magenta; repaint(); } else if (source == " cyan ") { colorW = Color.cyan; repaint(); } else if (source == " green ") { colorW = Color.green; repaint(); } else if (source == " blue ") { colorW = Color.blue; repaint(); } } public void CsetTransl(String source) { if (source == " 1.0 ") { alphaC = 1.0f; repaint(); } else if (source == " 0.55 ") { alphaC = 0.55f; repaint(); } else if (source == " 0.45 ") { alphaC = 0.45f; repaint(); } else if (source == " 0.35 ") { alphaC = 0.35f; repaint(); } else if (source == " 0.25 ") { alphaC = 0.25f; repaint(); } else if (source == " 0.15 ") { alphaC = 0.15f; repaint(); } else if (source == " 0.0 ") { alphaC = 0.0f; repaint(); } } public void WsetTransl(String source) { if (source == " 1.0 ") { alphaW = 1.0f; repaint(); } else if (source == " 0.55 ") { alphaW = 0.55f; repaint(); } else if (source == " 0.45 ") { alphaW = 0.45f; repaint(); } else if (source == " 0.35 ") { alphaW = 0.35f; repaint(); } else if (source == " 0.25 ") { alphaW = 0.25f; repaint(); } else if (source == " 0.15 ") { alphaW = 0.15f; repaint(); } else if (source == " 0.0 ") { alphaW = 0.0f; repaint(); } } public Color ColorCode(int n) { String sN = Integer.toString(n); BigInteger nBI = new BigInteger(sN); BigInteger eBI = new BigInteger("7"); int i = nBI.mod(eBI).intValue(); Color colorN = Color.blue; switch(i) { case 1: colorN = Color.orange; break; case 2: colorN = Color.red; break; case 3: colorN = Color.pink; break; case 4: colorN = Color.magenta; break; case 5: colorN = Color.cyan; break; case 6: colorN = Color.green; break; } return colorN; } public void relocateNodes(Point2D[] shift, int num) { double sdist = 1.0; double theta = Math.PI / 2.0; boolean mu = true; int count = num; savePoints(); //for reSet // Has the number of points changed? if (num > npoints) count = npoints; int hW= W/2 + 1; int i = 0; while ((shift[i].getX() == strNodes[i]) && (shift[i].getY() == hW) && i < count) i++; if (i < count) //there is change in the node positions for (int j = i; j < count; j++) { int xL = (int)shift[j].getX(); double dyL = shift[j].getY() - (double)hW; if (slope[xL] == 0.0) sdist = 1.0; else theta = Math.atan(-1.0 / slope[xL]); if (Math.abs(theta) < 0.1) mu = false; if (mu) { sdist = 1.0; if (slope[xL] < 0.0) sdist = -sdist; if (Spline.get(xL).getX() > Spline.get(i+1).getX()) sdist = -sdist; } double yL = Spline.get(xL).getY() + dyL * sdist * Math.sin(theta); points[j].setLocation(Spline.get(xL).getX(), yL); drawingPoints[j].setLocation(points[j]); } if (count < num) //there are additional nodes for (int j = count; j < num; j++) { points[j] = new Point2D.Double(0.0, 0.0); } npoints = num; for (i = 0; i < npoints; i++) { double px = points[i].getX(); double py = points[i].getY(); if (magnification != 1.0) { px = px * magnification; py = py * magnification; } drawingPoints[i].setLocation(px, py); } repaint(); } public void doStraight(byte[] pixels) { if (hasParentCanvas) //positions of nodes are changed on the straightened image { parentIc.relocateNodes(points, npoints); byte[] parPixels = (byte[])parentIc.getImagePlus().getProcessor().getPixels(); parentIc.doStraight(parPixels); } else { CubicCurveMaker curveMaker = new CubicCurveMaker(npoints, points); curve = curveMaker.makeShape(); Spline = curveMaker.getSpline(); strNodes = new double[npoints]; strNodes = curveMaker.getStrNodes(); int size = curveMaker.getSlopeSize(); slope = new double[size]; slope = curveMaker.getSlope(); length = size+1; W = 2 * (width/2) + 1; strArray = new float[length * W]; StraightArray makeStrArr = new StraightArray(W, Spline, slope); strArray = makeStrArr.calcStraight(pixels, imageWidth, strNodes); dirs = makeStrArr.getDirs(); // for automatic refinement ImageProcessor ipStr = new FloatProcessor(length, W, strArray, null); numOfStr++; String text = "(" + numOfStr +") Straightened Filament "; SplineImagePlus strImp = new SplineImagePlus (text, ipStr, strNodes, npoints, this); strImp.show(); } } public void savePoints() { onp = npoints; for (int i = 0; i < npoints; i++) oldPoints[i] = new Point2D.Double(points[i].getX(), points[i].getY()); } public void reSet() { npoints = onp; for (int i = 0; i < npoints; i++) { points[i].setLocation(oldPoints[i]); double px = points[i].getX(); double py = points[i].getY(); if (magnification != 1.0) { px = px * magnification; py = py * magnification; } drawingPoints[i].setLocation(px, py); } repaint(); } public int getWidth() { return width; } public String getTitle() { return title; } /* public int getNumNodes() { return npoints; } public Point2D[] getNodes() { return points; } public void readNodeNum(int n) { npoints = n; } public void readNodes(Point2D[] p) { for (int i = 0; i < npoints; i++) points[i] = new Point2D.Double(p[i].getX(), p[i].getY()); repaint(); } */ public SplineImagePlus getImagePlus() { return imp; } //ImageJ needs the followings protected SplineImagePlus imp; private SplineImageCanvas parentIc; private ImageJ imJ; private int imageWidth, imageHeight; private Rectangle srcRect = new Rectangle(0, 0, 0, 0); private int xMouseStart = 0; private int yMouseStart = 0; private int xSrcStart = 0; private int ySrcStart = 0; private int xMouse = -1; private int yMouse = -1; private static final String MARK_WIDTH = "mark.width"; public static int markWidth = Prefs.getInt(MARK_WIDTH,3); public int markWidthDraw = markWidth; private double magnification = 1.0; private boolean imageUpdated; // private int current = -1; private int npoints = 0; private int onp = 0; private static final int CLICKSIZE = 10; private static final int MAXNPOINTS = 30; private static final int MAX_ITEMS = 10; private Point2D[] points = new Point2D[MAXNPOINTS]; private Point2D[] drawingPoints = new Point2D[MAXNPOINTS]; private Point2D[] oldPoints = new Point2D[MAXNPOINTS]; private double[] strNodes; private double[] slope; private JButton[] button = new JButton[MAX_ITEMS]; private Point2DVector Spline = new Point2DVector(); private CubicCurveMaker curveMaker, curveMakerDraw; private Shape curve, curveDraw; private int width = 21; private int length, W; private float alphaW = 0.25f; private float alphaC = 1.0f; private Color colorW = Color.yellow; private Color colorC = Color.green; private float[] strArray; private float[][] dirs; private boolean notFirstTime = false; private boolean hasParentCanvas = false; private int numOfStr = 0; private String title; } //========================================================================================== class StraightArray { public StraightArray(int height, Point2DVector sPoints, double[] Slopes) { Len = sPoints.size(); Spline = new Point2D[Len]; sPoints.copyInto(Spline); slope = new double[Len-1]; for (int i = 0; i < Len-1; i++) slope[i] = Slopes[i]; Ht = height; rad = Ht / 2; strArray = new float[Len*Ht]; } public StraightArray() { } public float[] calcStraight(byte[] curvArray, int w, double[] nodes) { double sdist = 1.0; double theta = Math.PI / 2.0; boolean mu = true; float x, y; int np = nodes.length; dirs = new float[np][2]; if (slope[0] < 0.0) sdist = -sdist; if (Spline[0].getX() > Spline[1].getX()) sdist = -sdist; int k = 0; int posNode = 0; for (int i = 0; i < Len-1; i++) { theta = Math.PI / 2.0; if (slope[i] == 0.0) sdist = Math.abs(sdist); else theta = Math.atan(-1.0 / slope[i]); if (Math.abs(theta) < 0.1) mu = false; if (mu) { sdist = Math.abs(sdist); if (slope[i] < 0.0) sdist = -sdist; if (Spline[i].getX() > Spline[i+1].getX()) sdist = -sdist; } for (int j = Ht; j > 0; j--) { x = (float)((j - rad - 1) * sdist * Math.cos(theta)) + (float)Spline[i].getX(); y = (float)((j - rad - 1) * sdist * Math.sin(theta)) + (float)Spline[i].getY(); strArray[(Ht - j )*Len + i] = Bilin(x, y, curvArray, w); } mu = true; if (i == posNode) { dirs[k][0] = (float)(sdist * Math.cos(theta)); dirs[k][1] = (float)(sdist * Math.sin(theta)); // System.out.println(" dirs["+k+"]: "+ dirs[k][0] +", "+ dirs[k][1]); // System.out.println(" k, posNode, np : "+k+", "+posNode+", "+np); k++; if (k < np) posNode = (int)Math.round(nodes[k]); } } //the last point for (int j = Ht; j > 0; j--) { x = (float)((j - rad - 1) * sdist * Math.cos(theta)) + (float)Spline[Len-1].getX(); y = (float)((j - rad - 1) * sdist * Math.sin(theta)) + (float)Spline[Len-1].getY(); strArray[(Ht - j)*Len+(Len-1)] = Bilin(x, y, curvArray, w); } if (k == np-1) { dirs[k][0] = (float)(sdist * Math.cos(theta)); dirs[k][1] = (float)(sdist * Math.sin(theta)); // System.out.println(" dirs["+k+"]: "+ dirs[k][0] +", "+ dirs[k][1]); } return strArray; } public float Bilin(float x, float y, byte[] array, int w) { int ix = (int) x; int iy = (int) y; float delx = x - (float) ix; float dely = y - (float) iy; float r1 = (float)array[iy*w+ix]; //(ix,iy) float r2 = (float)array[(iy+1)*w+ix]; //(ix,iy+1) float r3 = (float)array[iy*w+ix+1]; //(ix+1,iy) float r4 = (float)array[(iy+1)*w+ix+1]; //(ix+1,iy+1) float r12 = r1 + (r2-r1)*dely; float r34 = r3 + (r4-r3)*dely; float interp = r12 + (r34-r12)*delx; return interp; } public float[][] getDirs() { return dirs; } private int Len, Ht, rad; private float[] strArray; private Point2D[] Spline; private double[] slope; private float[][] dirs; } //========================================================================================== class Point2DVector { public Point2DVector(int iC, int cI) { iCap = iC; capI = cI; } public Point2DVector() { } public void set(int n, double x, double y) { v.set(n, new Point2D.Double(x, y)); } public void add(double x, double y) { v.add(new Point2D.Double(x, y)); } public Point2D get(int n) { return ((Point2D)v.get(n)); } public int size() { return v.size(); } public void trimToSize() { v.trimToSize(); } public void copyInto(Point2D[] a) { v.copyInto(a); } private int iCap; private int capI; private Vector v = new Vector(iCap, capI); } class DoubleVector { public DoubleVector(int iC, int cI) { iCap = iC; capI = cI; } public void set(int n, double x) { v.set(n, new Double(x)); } public void add(double x) { v.add(new Double(x)); } public double get(int n) { return ((Double)v.get(n)).doubleValue(); } public int size() { return v.size(); } public void trimToSize() { v.trimToSize(); } public void copyInto(Double[] a) { v.copyInto(a); } private int iCap; private int capI; private Vector v = new Vector(iCap, capI); } class CubicCurveMaker { public CubicCurveMaker(int nps, Point2D[] points) { np = nps; for (int i = 0; i < np; i++) p[i] = new Point2D.Double(points[i].getX(), points[i].getY()); c = new Point2D[np][4]; ts = new double[np]; t = new double[np]; length = new double[np]; } public void calCoeff(double[] tt) { double dt, dtj, dtjp1, dtp; if (np > 2 ) { dtj = tt[1] - tt[0]; Point2D dj = new Point2D.Double(p[1].getX() - p[0].getX(), p[1].getY() - p[0].getY()); Point2D djp1 = new Point2D.Double(0.0,0.0); for (int j = 1; j < np - 1; j++) { dtjp1 = tt[j+1] - tt[j]; dtp = dtj + dtjp1; djp1.setLocation(p[j+1].getX() - p[j].getX(), p[j+1].getY() - p[j].getY()); c[j][1] = new Point2D.Double(dtjp1/dtp, dtjp1/dtp); c[j][2] = new Point2D.Double(1.0 - c[j][1].getX(), 1.0 - c[j][1].getY()); c[j][3] = new Point2D.Double(6.0 * (djp1.getX()/dtjp1 - dj.getX()/dtj) / dtp, 6.0 * (djp1.getY()/dtjp1 - dj.getY()/dtj) / dtp); dtj = dtjp1; dj.setLocation(djp1); } c[0][1] = new Point2D.Double(0.0,0.0); c[0][2] = new Point2D.Double(0.0,0.0); c[0][3] = new Point2D.Double(0.0,0.0); for (int j = 1; j < np - 1; j++) { Point2D pj = new Point2D.Double(c[j][2].getX() * c[j-1][1].getX() + 2.0, c[j][2].getY() * c[j-1][1].getY() + 2.0); c[j][1].setLocation(-c[j][1].getX() / pj.getX(), -c[j][1].getY() / pj.getY()); c[j][2].setLocation((c[j][3].getX() - c[j][2].getX() * c[j-1][2].getX()) / pj.getX(), (c[j][3].getY() - c[j][2].getY() * c[j-1][2].getY()) / pj.getY()); } Point2D ppb = new Point2D.Double(0.0,0.0); Point2D ppa = new Point2D.Double(0.0,0.0); for (int i = 2; i <= np ; i++) { int j = np - i; ppa.setLocation(c[j][1].getX() * ppb.getX() + c[j][2].getX(), c[j][1].getY() * ppb.getY() + c[j][2].getY()); dt = tt[j+1] - tt[j]; c[j][3].setLocation((ppb.getX() - ppa.getX()) / (6.0 * dt), (ppb.getY() - ppa.getY()) / (6.0 * dt)); c[j][2].setLocation(ppa.getX() / 2.0, ppa.getY() / 2.0); c[j][1].setLocation((p[j+1].getX() - p[j].getX()) / dt - (c[j][2].getX() + c[j][3].getX() * dt) * dt, (p[j+1].getY() - p[j].getY()) / dt - (c[j][2].getY() + c[j][3].getY() * dt) * dt); c[j][0] = new Point2D.Double(p[j].getX(), p[j].getY()); ppb.setLocation(ppa); } } else { dt = tt[1] - tt[0]; c[0][0] = new Point2D.Double(p[0].getX(), p[0].getY()); c[0][1] = new Point2D.Double((p[1].getX() - p[0].getX()) / dt, (p[1].getY() - p[0].getY()) / dt); c[0][2] = new Point2D.Double(0.0,0.0); c[0][3] = new Point2D.Double(0.0,0.0); } } public Point2D[][] getCoeff(double[] ts) { calCoeff(ts); return c; } public Shape makeShape() { GeneralPath g = new GeneralPath(); calcSpline(); for (int i = 1; i <= (int)length[np-1]; i++) { g.append(new Line2D.Double(Spline.get(i-1),Spline.get(i)), false); } return g; } public void calcSlope(double pos, int nod) { der = new Point2D.Double(0.0,0.0); dder = new Point2D.Double(0.0,0.0); Point2D spp = new Point2D.Double(0.0,0.0); double d; d = pos - length[nod]; if (d == 0.0) { der.setLocation(c[nod][1]); dder.setLocation(2 * c[nod][2].getX(), 2 * c[nod][2].getY()); } else { spp.setLocation(3.0 * c[nod][3].getX() * d + c[nod][2].getX(), 3.0 * c[nod][3].getY() * d + c[nod][2].getY()); der.setLocation((spp.getX() + c[nod][2].getX()) * d + c[nod][1].getX(), (spp.getY() + c[nod][2].getY()) * d + c[nod][1].getY()); dder.setLocation(2 * spp.getX(), 2 * spp.getY()); } } public void calcSpline() { Function F = new Function(np, p, 0); length = F.calcLength(); // System.out.println(length[np-1]); calCoeff(length); Spline.add(p[0].getX(), p[0].getY()); calcSlope(0.0,0); if (der.getX() == 0.0) { slope.add(1E308); } else { slope.add(der.getY() / der.getX()); } double ln = 1.0; double d; double sx, sy; for (int i = 0; i < np-1; i++) { while (ln < length[i+1]) { calcSlope(ln, i); if (der.getX() == 0.0) { slope.add(1E308); } else { slope.add(der.getY() / der.getX()); } d = ln - length[i]; sx = ((c[i][3].getX() * d + c[i][2].getX()) * d + c[i][1].getX()) * d + c[i][0].getX(); sy = ((c[i][3].getY() * d + c[i][2].getY()) * d + c[i][1].getY()) * d + c[i][0].getY(); Spline.add(sx, sy); ln += 1.0; } } Spline.add(p[np-1].getX(), p[np-1].getY()); } public Point2DVector getSpline() { Spline.trimToSize(); return Spline; } public int getSlopeSize() { slope.trimToSize(); slopeSize = slope.size(); return slopeSize; } public double[] getSlope() { Double[] slopeDarr = new Double[slopeSize]; slope.copyInto(slopeDarr); double[] slopeArr = new double[slopeSize]; for (int i = 0; i < slopeSize; i++) slopeArr[i] = slopeDarr[i].doubleValue(); return slopeArr; } public double[] getStrNodes() { return length; } private int np; private static final int MAXNPOINTS = 30; private Point2D[] p = new Point2D[MAXNPOINTS]; private Point2D[][] c; private double[] ts; private double[] t; private double[] length; private Point2DVector Spline = new Point2DVector(400,200); private DoubleVector slope = new DoubleVector(400,200); private Point2D der; private int slopeSize = 0; private Point2D dder; } class Integration { public Integration(double beg, double end, int nint, int npoints, Point2D[] points) { a = beg; b = end; np = npoints; for (int i = 0; i < np; i++) p[i] = new Point2D.Double(points[i].getX(), points[i].getY()); ii = nint; F = new Function(np, p, ii); } public double Romberg() { double ss; double dss; double[] s = new double[JMAXP]; double[] h = new double[JMAXP + 1]; h[1] = 1.0; for (int j = 1; j <= JMAX; j++) { s[j] = Trapzd(j); if (j >= K) { Interpolation Ip = new Interpolation(h, s, K, j-K+1, 0.0); Ip.PolInt(); ss = Ip.getValue(); dss = Ip.getErrEst(); if (Math.abs(dss) <= EPS * Math.abs(ss)) return ss; } h[j + 1] = 0.25 * h[j]; } System.out.println(" Too many steps in Romberg Integration"); return 0.0; } public double Trapzd(int n) { double x, tnm, sum, del; if (n == 1) { return (sT = 0.5 * (b - a) * (F.getVal(a) + F.getVal(b))); } else { int it = 1; for (int j = 1; j < n-1; j++) it <<= 1; tnm = it; del = (b-a) / tnm; x = a + 0.5 * del; sum = 0.0; for (int j = 1; j <= it; j++, x += del) { sum += F.getVal(x); } sT = 0.5 * (sT + (b - a) * sum / tnm); return sT; } } private static final double EPS = 1.0e-6; private static final int JMAX = 20; private static final int JMAXP = JMAX + 1; private double sT; private static final int K = 5; private double a; private double b; private int np; private int ii; private static final int MAXNPOINTS = 30; private Point2D[] p = new Point2D[MAXNPOINTS]; private Function F; } class Interpolation { public Interpolation(double[] xarray, double[] yarray, int np, int beg, double xx) { n = np; from = beg; System.arraycopy(xarray,from,xa,1,n); System.arraycopy(yarray,from,ya,1,n); x = xx; } public void PolInt() { int i, m, ns = 1; double den, dif, dift, ho, hp, w; dif = Math.abs(x - xa[1]); for (i = 1; i <= n; i++) { if ((dift = Math.abs(x - xa[i])) < dif) { ns = i; dif = dift; } c[i] = ya[i]; d[i] = ya[i]; } y = ya[ns--]; for (m = 1; m < n; m++) { for (i = 1; i <= n - m; i++) { ho = xa[i] - x; hp = xa[i + m] - x; w = c[i+1] - d[i]; if ((den = ho - hp) == 0.0) { System.out.println(" Error in PolInt!"); System.exit(0); } den = w/den; d[i] = hp * den; c[i] = ho * den; } y += (dy = (2 * ns < (n - m) ? c[ns + 1] : d[ns--])); } } public double getValue() { return y; } public double getErrEst() { return dy; } private static final int MAXNINT = 6; //K = 5 in Romberg private double[] xa = new double[MAXNINT]; private double[] ya = new double[MAXNINT]; private double[] c = new double[MAXNINT]; private double[] d = new double[MAXNINT]; private int n; private int from; private double x; private double y; private double dy; } class Function { public Function(int npoints, Point2D[] points, int ii) { np = npoints; for (int i=0; i < np; i++) p[i] = new Point2D.Double(points[i].getX(), points[i].getY()); t = new double[np]; ts = new double[np]; length = new double[np]; c = new Point2D[np][4]; CCM = new CubicCurveMaker(np, p); nInt = ii; ts[0] = 0.0; for (int i = 1; i < np; i++) { t[i] = p[i].distance(p[i-1]); ts[i] = ts[i-1] + t[i]; } c = CCM.getCoeff(ts); } public double[] calcLength() { length[0] = 0.0; for (int i = 1; i < np; i++) { FSnum = i - 1; Integration iFS = new Integration(0.0, t[i], FSnum, np, p); length[i] = length[i-1] + iFS.Romberg(); } return length; } public double getVal(double tt) { double ddx = (3 * c[nInt][3].getX() * tt + 2 * c[nInt][2].getX()) * tt + c[nInt][1].getX(); double ddy = (3 * c[nInt][3].getY() * tt + 2 * c[nInt][2].getY()) * tt + c[nInt][1].getY(); double Val = Math.sqrt(ddx * ddx + ddy * ddy); return Val; } private static final int MAXNPOINTS = 30; private int np; private CubicCurveMaker CCM; private Point2D[] p = new Point2D[MAXNPOINTS]; private double[] t; private double[] ts; private double[] length; private Integration iFS; private int FSnum, nInt; private Point2D[][] c; } //========================================================================================== class widthWindow extends Frame implements DocumentListener { /** Creates a window for interactive setting of width of filament */ public widthWindow(SplineImageCanvas ic) { super(" Width of Filament/Wide Line "); this.ic = ic; setSize(300,100); grid = new GridBagLayout(); gbc = new GridBagConstraints(); gbc.weightx = 0; gbc.weighty = 0; panel.setLayout(grid); /** Sets up the text+numeric field */ gbc.insets = new Insets(10, 0, 0, 0); titleF = new JTextField(" Current Window "); gbc.gridwidth = 1; gbc.gridx = 0; gbc.gridy = y; gbc.anchor = GridBagConstraints.NORTH; panel.add(titleF, gbc); y++; tF = new JTextField(filWidth, 4); tF.getDocument().addDocumentListener(this); gbc.gridwidth = 1; gbc.gridx = 0; gbc.gridy = y; gbc.anchor = GridBagConstraints.EAST; panel.add(tF, gbc); Label theLabel = makeLabel(" pixels "); gbc.gridwidth = 1; gbc.anchor = GridBagConstraints.WEST; gbc.gridx = 1; gbc.gridy = y; panel.add(theLabel, gbc); add(panel, "Center"); } public void show(SplineImageCanvas ic) { this.ic =ic; adjustTitle(" "+ic.getTitle()+" : "); adjustWidth(ic.getWidth()); repaint(); setVisible(true); } private Label makeLabel(String label) { if (IJ.isMacintosh()) label += " "; return new Label(label); } public void adjustTitle(String title) { titleF.setText(title); } public void adjustWidth(int fW) { filWidth = Integer.toString(fW); tF.setText(filWidth); // triggers removeUpdate(DocumentEvent e) } public void insertUpdate(DocumentEvent e) { int w = Integer.parseInt(tF.getText().trim()); ic.setWidth(w); } public void removeUpdate(DocumentEvent e) { if (tF.getText().trim().equals("")) { } else { int w = Integer.parseInt(tF.getText().trim()); ic.setWidth(w); } } public void changedUpdate(DocumentEvent e) { } Panel panel = new Panel(); private GridBagLayout grid; private GridBagConstraints gbc; private int y = 0; private JTextField tF, titleF; private String filWidth = "21"; private SplineImageCanvas ic; }