package vnt;
/**
 * DistanceMap_Outline.java - v1.0
 * Began: July 14, 2005
 * Last Updated: July 28, 2005 
 * 
 * Copyright (C) 2005 - Michael D. Miller - mdm162@truman.edu
 * Truman State University
 * 100 E. Normal
 * Kirksville, MO - 63501
 * 
 * This program 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 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

import ij.*;
import ij.gui.*;
import java.awt.*;
import java.awt.Color.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;
import java.io.*;
import ij.io.*;
import java.lang.String.*;
import java.lang.Math.*;
import ij.plugin.filter.*;

/**
 * <p>Generates an approximate outline of the vessels from
 * a distance map skeleton (a skeleton that is grayscale,
 * retaining distance map information along the skeleton).</p>
 * 
 * @author Michael Miller - Truman State University
 * @version 1.0
 * @since 1.0
 */
public class DistanceMap_Outline extends VascularNetworkToolkit implements PlugInFilter {

    /**
    * Specifies the preconditions for the plug-in.
    * If this method succeeds then run() is called.
    *
    * <p>Pre: ImageJ is running and an 8-bit grayscale image is open. The plug-in was just activated.
    * <br />Post: Either an argument was processed, the image was not saved to a local folder, or the plug-in is cleared to run on the image.
    * @param arg Required by the interface. The argument list passed to the plug-in.
    * @param imp Required by the interface. The ImagePlus datastructure holding (among other things) information to grab path and filename.
    * @return If DONE is returned, ImageJ quits without run()'ing the plug-in. Otherwise, the plug-in signals to ImageJ that this plugin only handles 8-bit (256 grayscale) and will not change the original image.
    * @see #run
    */
    public int setup(String arg, ImagePlus ip) {
        if (arg.equals("about")) { 
            showAbout("Distance Map Outline", "  * Calculates and displays the envelope of maximal discs along the blum medial axis. This is essentially the outline of the segmented object. (Copyright 2005. Michael Miller mdm162@truman.edu)");
            return DONE; // exit without run()
        }

        // will only save if this succeeds
        getFileInformation(ip);
                    
        return DOES_8G+NO_CHANGES; // success, run()
    }

    /**
     * Receives a distance map skeleton and generates 
     * the approximate outline.
     * 
     * 1) Draws black circles at every point of the skeleton. The outline is the envelope of those circles.
     * 2) Draws  white circles with radius-1 at every point of the skeleton. The union of all the pixels drawn is the area inside the outline.
     *  
     * <p>Pre: The image was cleared to run by the setup() method.
     * <br />Post: The image outline is computed and drawn in a new image. 
     * @param bp Required by the interface. The access information to the original image.
     * @see #setup
     * @see #generateOutline
     */
    public void run(ImageProcessor bp){ 
        // get the width and height information
        getDimensions(bp);
        // generate the outline
        ImageProcessor outline = generateOutline(bp, true);
        // save the outline image
        saveFile("outline");
        return;
    }

    /**
     * Computes the envelope of the Blum medial axis maximal discs.
     * 
     * 1) Draws black circles at every point along the skeleton using the radius of the color of the skeleton. This regenerates the approximation of the segmented image.
     * 2) Draws white circles at every point along the skeleton using the radius-1 of the color of the skeleton. This deletes the inside of the outline.
     * 
     * <p>Pre: The dimensions width and height must have been loaded prior to calling this method. The given ImageProcessor must be for the ridge skeleton and must be valid. Relies on the fact that this is an 8-bit grayscale distance map.
     * <br />Post: On success, a new image of the outline is drawn. On failure, no change is made.  
     * @param ip The Image Processor is required for the original image data.
     * @param outline If true, an outline is generated. If false, a solid image (which will resemble the original segmented image) is drawn.
     * @return The ImageProcessor for the newly created image representing the thinned distance map ridge trace. 
     */
    public ImageProcessor generateOutline (ImageProcessor ip, boolean outline) {
        if ((ip == null) || (width < 1) || (height < 1)) {
            return null;
        }
        int x=0, y=0, size=0;

        String title = "Outline from Distance Map"; 
        // load the distance-map skeleton into memory
        pixel = VascularNetworkToolkit.LoadImage(ip);
        ImagePlus imp = NewImage.createByteImage (title, width, height, 1, NewImage.FILL_WHITE);
        ImageProcessor nip = imp.getProcessor();
        
        if (animatedDisplay) {
            imp.show();
            IJ.selectWindow(title);
        }
        
        // draw black circles
        for(y=0; y<height; y++) {
            for(x=0; x<width; x++) {
                if (pixel[x][y] != WHITE) {
                    size = 255 - pixel[x][y];
                    VascularNetworkToolkit.drawCircle(nip,x,y,size,BLACK);
                    if (animatedDisplay)
                        imp.updateAndDraw();
                }
            }
        }
        // draw white circles with reduced radius
        if (outline) {
            for(y=0; y<height; y++) {
                for(x=0; x<width; x++) {
                    if (pixel[x][y] != WHITE) {
                        size = 254 - pixel[x][y];
                        if (size > 0) {
                            VascularNetworkToolkit.drawCircle(nip,x,y,size,WHITE);
                            if (animatedDisplay)
                                imp.updateAndDraw();
                        }
                    }
                }
            }
        }
        
        if (!animatedDisplay) {
            imp.show();
            IJ.selectWindow(title);
        }
        return nip;
    }
}