/* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */ package edu.stanford.rsl.conrad.utils; import java.awt.Point; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import ij.IJ; import ij.ImageJ; import edu.stanford.rsl.apps.gui.RawDataOpener; public abstract class CONRAD { public static final String VersionString = "Version 1.0.6"; public static final String CONRADBibtex = "@article{Maier13-CSF," + " author = {A. Maier, H. G. Hofmann, M. Berger, P. Fischer, C. Schwemmer, H. Wu, K. Müller, J. Hornegger, J. H. Choi, C. Riess, A. Keil, and R. Fahrig},\n" + " title={{CONRAD - A software framework for cone-beam imaging in radiology}},\n" + " journal={Medical Physics},\n" + " volume={40},\n" + " number={11},\n" + " pages={111914-1-8},\n" + " year={2013}\n" + "}"; public static final String CONRADMedline = "A. Maier, H. G. Hofmann, M. Berger, P. Fischer, C. Schwemmer, H. Wu, K. Müller, J. Hornegger, J. H. Choi, C. Riess, A. Keil, and R. Fahrig. CONRAD—A software framework for cone-beam imaging in radiology. Medical Physics 40(11):111914-1-8. 2013"; public static final String CONRADDefinition = "CONe-beam framework for RADiology (CONRAD)"; public static final double SMALL_VALUE = 1.0e-12; public static final double BIG_VALUE = 1.0e12; public static final double DOUBLE_EPSILON; public static final double FLOAT_EPSILON; public static final int INVERSE_SPEEDUP = 0; public static boolean useGarbageCollection; public static final String EOL = System.getProperty("line.separator"); public static final long INPUT_QUEUE_DELAY = 0; /** * This flag can be used to control debug outputs. * 0: No Debug output * 1: Some Debug output * 2: More debug output * 3: All debug output */ public static int DEBUGLEVEL = 0; static { double doubleEps = 1.0d; do doubleEps /= 2.0d; while ((1.0d + (doubleEps/2.0)) != 1.0); DOUBLE_EPSILON = doubleEps; // System.out.println( "Calculated double epsilon to " + DOUBLE_EPSILON + "."); float floatEps = 1.0f; do floatEps /= 2.0f; while ((1.0f + (floatEps/2.0f)) != 1.0f); FLOAT_EPSILON = floatEps; // System.out.println( "Calculated float epsilon to " + FLOAT_EPSILON + "."); } public static void setup(){ new ImageJ(); Configuration.loadConfiguration(); RawDataOpener opener = RawDataOpener.getRawDataOpener(); opener.setVisible(true); opener.getjButtonLittle().doClick(); opener.getjButtonFloat().doClick(); opener.setLocation(0, 500); } public static Point getWindowTopCorner(){ String string = Configuration.getGlobalConfiguration().getRegistryEntry(RegKeys.CONRAD_WINDOW_DEFAULT_LOCATION); string = string.replace("[","").replace("]", "").replace(" ", "").replace(";", ""); String [] strings = string.split(","); Point location = new Point(Integer.parseInt(strings[0]), Integer.parseInt(strings[1])); return location; } public static void gc(){ if (useGarbageCollection) { Runtime.getRuntime().gc(); } } public static boolean isUseGarbageCollection() { return useGarbageCollection; } public static void setUseGarbageCollection(boolean useGarbageCollection) { CONRAD.useGarbageCollection = useGarbageCollection; } /** * Returns the number of processors which should be used by CONRAD. Equals Runtime.getRuntime().availableProcessors() if "MAX_THREADS" is not set in CONRAD registry. * Otherwise "MAX_THREADS" is the upper bound for availableProcessors(). * @return the maximal number of threads */ public static int getNumberOfThreads(){ int numThreads = Runtime.getRuntime().availableProcessors(); try { String regKey = Configuration.getGlobalConfiguration().getRegistryEntry(RegKeys.MAX_THREADS); int threadLimit = numThreads; if (regKey != null) { threadLimit = Integer.parseInt(regKey); } if (threadLimit < numThreads) numThreads = threadLimit; } catch (Exception e){ System.out.println("Key '"+RegKeys.MAX_THREADS+"' was not found in registry."); } return numThreads; } /** * CONRAD checks the environment variables for a variable called "CONRAD_HOME". If this is set, the variable will be useed. Otherwise the user home will be set up as CONRAD home. * @return the path to the CONRAD home. */ public static String getUserHome(){ Map<String,String> env = System.getenv(); if (env.containsKey("CONRAD_HOME")){ return env.get("CONRAD_HOME"); } return System.getProperty("user.home"); } /** * Returns the total free memory as double between 1.0 and 0.0. * 0.0 means that there is no free memory available. * 1.0 means that the memory is completely free. * Note that this function also takes the memory into account that the VM will allocate, if more memory is required. * @return the free memory */ public static double getFreeMemoryAsDouble(){ long t = Runtime.getRuntime().totalMemory(); long m = Runtime.getRuntime().maxMemory(); long f = Runtime.getRuntime().freeMemory(); return (m-t+f)/(double)m; } private static HashMap<Class<? extends Object>, ArrayList<Object>> classLookupTable = new HashMap<Class<? extends Object>, ArrayList<Object>>(); /** * The method will parse the whole current directories currently available to the ClassLoader to find all * classes that are subclasses of cl. The method returns an ArrayList with all objects that could be instantiated using the default constructor. * Introspection is quite useful... * <br><br> * Parsing of the class path will only happen once. Further class will be redirected to an internal HashMap. * <br> We now return clones of the original list as the instances might be changes by the user and we * want default instances here that are suited for user selection. * @param cl the class to find the subclasses for * @return the list of found instances. * @throws ClassNotFoundException * @throws IOException */ public static ArrayList<Object> getInstancesFromConrad(Class<? extends Object> cl) throws ClassNotFoundException, IOException{ ArrayList<Object> found = classLookupTable.get(cl); if (found == null){ found = getInstancesFromConradFromClasspath(cl); } // Create a clone of the found array list as instance might be altered by the user... ArrayList<Object> cloneArrayList = new ArrayList<Object>(); for (int i=0; i < found.size(); i++){ try { // uncomment this line to figure out which instantiation takes so long... //long time = System.currentTimeMillis(); cloneArrayList.add(found.get(i).getClass().newInstance()); //System.out.println("Copied " + found.get(i) + " in " + (-time+System.currentTimeMillis()) + " ms"); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return cloneArrayList; } /** * Searches the class path for classes that can be cast onto the class cl. * Method will register the found classes in an internal lookup table. * * @param cl the class to search for * @return the list of matching classes * @throws ClassNotFoundException might happen * @throws IOException may also occur. */ private synchronized static ArrayList<Object> getInstancesFromConradFromClasspath(Class<? extends Object> cl) throws ClassNotFoundException, IOException{ ArrayList<Object> found = new ArrayList<Object>(); ArrayList<Class<? extends Object>> classes = getClasses("edu.stanford.rsl"); for (Class<? extends Object> match: classes){ if (cl.isAssignableFrom(match)){ try { found.add(match.newInstance()); } catch (InstantiationException e) { /** * skip over abstract classes. Only the ones which implement the default constructor will be * returned. */ } catch (IllegalAccessException e) { e.printStackTrace(); } } } classLookupTable.put(cl, found); return found; } /** * Scans all classes accessible from the context class loader which belong to the given package and subpackages. * * @param packageName The base package * @return The classes * @throws ClassNotFoundException * @throws IOException */ private static ArrayList<Class<? extends Object>> getClasses(String packageName) throws ClassNotFoundException, IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); assert classLoader != null; String path = packageName.replace('.', '/'); Enumeration<URL> resources = classLoader.getResources(path); List<File> dirs = new ArrayList<File>(); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); String filename = resource.getFile(); if (filename.contains("%20")) filename = filename.replace("%20", " "); dirs.add(new File(filename)); } ArrayList<Class<? extends Object>> classes = new ArrayList<Class<? extends Object>>(); for (File directory : dirs) { classes.addAll(findClasses(directory, packageName)); } return classes; } /** * Recursive method used to find all classes in a given directory and subdirs. * * @param directory The base directory * @param packageName The package name for classes found inside the base directory * @return The classes * @throws ClassNotFoundException */ private static List<Class<? extends Object>> findClasses(File directory, String packageName) throws ClassNotFoundException { List<Class<? extends Object>> classes = new ArrayList<Class<? extends Object>>(); if (!directory.exists()) { return classes; } File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory()) { assert !file.getName().contains("."); classes.addAll(findClasses(file, packageName + "." + file.getName())); } else if (file.getName().endsWith(".class")) { try{ classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); } catch (UnsatisfiedLinkError e){ /** * We skip over classes that cannot be loaded (compilation errors, etc.). */ //System.out.println("skipping " + file); } catch (NoClassDefFoundError e2){ /** * We skip over classes that cannot be loaded (compilation errors, etc.). */ //System.out.println("skipping " + file); } } } return classes; } /** * Method to log something in a log file. * Currently it just redirects to IJ.log method. * @param string */ public static void log(String string) { IJ.log(string); } }