/* $RCSfile$ * $Author: nicove $ * $Date: 2007-03-25 06:09:49 -0500 (Sun, 25 Mar 2007) $ * $Revision: 7221 $ * * Copyright (C) 2000-2005 The Jmol Development Team * * Contact: jmol-developers@lists.sf.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.openscience.jvxl; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import javax.vecmath.Point4f; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.PosixParser; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.HelpFormatter; import org.jmol.jvxl.readers.*; import org.jmol.util.*; public class Jvxl { private final static String VERSION = "JVXL.java Version 1.0"; public static void main(String[] args) { boolean blockData = false; int fileIndex = Integer.MAX_VALUE; String inputFile = null; String mapFile = null; String outputFile = null; float cutoff = Float.NaN; boolean isPositiveOnly = false; String phase = null; Point4f plane = null; String colorScheme = null; boolean bicolor = false; boolean reverseColor = false; float min = Float.NaN; float max = Float.NaN; Options options = new Options(); options.addOption("h", "help", false, "give this help page"); /* * examples: * * jvxl ch3cl-density.cub --min=0.0 --max=0.2 --map ch3cl-esp.cub * jvxl ethene-HOMO.cub --bicolor --output ethene.jvxl * jvxl d_orbitals.jvxl --index 2 --phase yz * jvxl d_orbitals.jvxl --map sets * jvxl --plane xy --min=0.0 --max=0.2 --map data/ch3cl-density.cub */ // file options options.addOption("B", "blockdata", false, "multiple cube data are in blocks, not interspersed"); options.addOption("P", "progressive", false, "create JVXL+ progressive X low-to-high format"); OptionBuilder.withLongOpt("file"); OptionBuilder.withDescription("file containing surface data"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("f")); OptionBuilder.withLongOpt("index"); OptionBuilder.withDescription("index of surface in file (starting with 1)"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("i")); OptionBuilder.withLongOpt("plane"); OptionBuilder .withDescription("plane: x, y, z, xy, xz, yz, z2, x2-y2, or {a,b,c,d}"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("p")); OptionBuilder.withLongOpt("map"); OptionBuilder .withDescription("file containing data to map onto the surface or \"sets\""); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("m")); OptionBuilder.withLongOpt("output"); OptionBuilder.withDescription("JVXL output file"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("o")); // surface options OptionBuilder.withLongOpt("cutoff"); OptionBuilder.withDescription("isosurface cutoff value"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("c")); // color mapping options options.addOption("b", "bicolor", false, "bicolor map (orbital)"); options.addOption("r", "reversecolor", false, "reverse color"); OptionBuilder.withLongOpt("colorScheme"); OptionBuilder .withDescription("VRML color scheme: bw, wb, roygb, bgyor, rwb, bwr, low, high"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("s")); OptionBuilder.withLongOpt("phase"); OptionBuilder .withDescription("color by phase: x, y, z, xy, xz, yz, z2, x2-y2"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("F")); OptionBuilder.withLongOpt("min"); OptionBuilder.withDescription("color absolute minimum value"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("n")); OptionBuilder.withLongOpt("max"); OptionBuilder.withDescription("color absolute maximum value"); OptionBuilder.withValueSeparator('='); OptionBuilder.hasArg(); options.addOption(OptionBuilder.create("x")); CommandLine line = null; try { CommandLineParser parser = new PosixParser(); line = parser.parse(options, args); } catch (ParseException exception) { Logger.error("Unexpected exception: " + exception.toString()); } if (line.hasOption("h")) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("Jvxl", options); return; } args = line.getArgs(); if (args.length > 0) { inputFile = args[0]; } // files blockData = (line.hasOption("B")); if (line.hasOption("i")) { fileIndex = Parser.parseInt(line.getOptionValue("i")); } if (line.hasOption("f")) { inputFile = line.getOptionValue("f"); } if (line.hasOption("m")) { mapFile = line.getOptionValue("m"); } if (line.hasOption("p")) { plane = getPlane(line.getOptionValue("p")); if (plane == null) { Logger.error("invalid plane"); return; } Logger.info("using plane " + plane); if (mapFile == null) mapFile = inputFile; if (inputFile == null) inputFile = mapFile; } if (line.hasOption("o")) { outputFile = line.getOptionValue("o"); } else { outputFile = inputFile; if (outputFile.indexOf(".") < 0) outputFile += "."; String sIndex = (fileIndex == Integer.MAX_VALUE ? "" : "_" + fileIndex); if (sIndex.length() == 0 && outputFile.indexOf(".jvxl") >= 0) sIndex += "_new"; outputFile = outputFile.substring(0, outputFile.lastIndexOf(".")) + sIndex + ".jvxl"; } // Process more command line arguments // these are also passed to viewer bicolor = (line.hasOption("b")); reverseColor = (line.hasOption("r")); if (bicolor && mapFile != null) { Logger.warn("--map option ignored; incompatible with --bicolor"); mapFile = null; } if (line.hasOption("c")) { String s = line.getOptionValue("c"); if (s.indexOf("+") == 0) { isPositiveOnly = true; s = s.substring(1); } cutoff = Parser.parseFloat(s); } if (line.hasOption("n")) { if (bicolor) Logger.warn("--min option ignored; incompatible with --bicolor"); else min = Parser.parseFloat(line.getOptionValue("n")); } if (line.hasOption("x")) { if (bicolor) Logger.warn("--max option ignored; incompatible with --bicolor"); else max = Parser.parseFloat(line.getOptionValue("x")); } // if (line.hasOption("P")) { // phase = line.getOptionValue("P"); // } boolean progressive = line.hasOption("P"); // compose the surface SurfaceGenerator sg = new SurfaceGenerator(); // input file sg.setVersion(VERSION); if (blockData) sg.setParameter("blockData", Boolean.TRUE); if (!Float.isNaN(cutoff)) sg.setParameter(isPositiveOnly ? "cutoffPositive" : "cutoff", new Float( cutoff)); if (bicolor) sg.setParameter("sign", null); if (reverseColor) sg.setParameter("reverseColor", null); if (phase != null) sg.setParameter("phase", phase); if (progressive) sg.setParameter("progressive", null); if (plane != null) sg.setParameter("plane", plane); else { if (fileIndex != Integer.MAX_VALUE) sg.setParameter("fileIndex", Integer.valueOf(fileIndex)); Object t = FileReader .getBufferedReaderOrErrorMessageFromName(inputFile); if (t instanceof String) { Logger.error((String) t); return; } BufferedReader br = (BufferedReader) t; sg.setParameter("readFile", br); try { br.close(); } catch (Exception e) { // } } sg.setParameter("title", line.toString()); //color scheme is only for VMRL if (colorScheme != null) { ColorEncoder ce = new ColorEncoder(null); ce.setColorScheme(colorScheme, false); sg.setParameter("colorScheme", ce); } if (!Float.isNaN(min)) sg.setParameter("red", new Float(min)); if (!Float.isNaN(max)) sg.setParameter("blue", new Float(max)); if (mapFile != null) { Object t = FileReader .getBufferedReaderOrErrorMessageFromName(mapFile); if (t instanceof String) { Logger.error((String) t); return; } BufferedReader br2 = (BufferedReader) t; sg.setParameter("mapColor", br2); try { br2.close(); } catch (Exception e) { // } } writeFile(outputFile, (String) sg.getProperty("jvxlFileData", 0)); Logger.info((String) sg.getProperty("jvxlFileInfo", 0)); Logger.info("\ncreated " + outputFile); } static void writeFile(String fileName, String text) { try { FileOutputStream os = new FileOutputStream(fileName); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os), 8192); bw.write(text); bw.close(); os = null; } catch (IOException e) { Logger.error("IO Exception: " + e.toString()); } } static Point4f getPlane(String str) { if (str.equalsIgnoreCase("xy")) return new Point4f(0, 0, 1, 0); if (str.equalsIgnoreCase("xz")) return new Point4f(0, 1, 0, 0); if (str.equalsIgnoreCase("yz")) return new Point4f(1, 0, 0, 0); if (str.indexOf("x=") == 0) { return new Point4f(1, 0, 0, -Parser.parseFloat(str.substring(2))); } if (str.indexOf("y=") == 0) { return new Point4f(0, 1, 0, -Parser.parseFloat(str.substring(2))); } if (str.indexOf("z=") == 0) { return new Point4f(0, 0, 1, -Parser.parseFloat(str.substring(2))); } if (str.indexOf("{") == 0) { str = str.replace(',', ' '); int[] next = new int[1]; return new Point4f(Parser.parseFloat(str, next), Parser.parseFloat(str, next), Parser.parseFloat(str, next), Parser.parseFloat(str, next)); } return null; } } class FileReader { FileReader() { } static Object getBufferedReaderOrErrorMessageFromName(String name) { Object t = getInputStreamOrErrorMessageFromName(name); if (t instanceof String) return t; try { BufferedInputStream bis = new BufferedInputStream((InputStream)t, 8192); InputStream is = bis; return new BufferedReader(new InputStreamReader(is)); } catch (Exception ioe) { return ioe.getMessage(); } } private static Object getInputStreamOrErrorMessageFromName(String name) { String errorMessage = null; try { Logger.info("opening " + name); File file = new File(name); int length = (int) file.length(); InputStream in = new FileInputStream(file); return new MonitorInputStream(in, length); } catch (Exception e) { errorMessage = "" + e; } return errorMessage; } } class MonitorInputStream extends FilterInputStream { int length; int position; int markPosition; int readEventCount; long timeBegin; MonitorInputStream(InputStream in, int length) { super(in); this.length = length; this.position = 0; timeBegin = System.currentTimeMillis(); } @Override public int read() throws IOException{ ++readEventCount; int nextByte = super.read(); if (nextByte >= 0) ++position; return nextByte; } @Override public int read(byte[] b) throws IOException { ++readEventCount; int cb = super.read(b); if (cb > 0) position += cb; return cb; } @Override public int read(byte[] b, int off, int len) throws IOException { ++readEventCount; int cb = super.read(b, off, len); if (cb > 0) position += cb; return cb; } @Override public long skip(long n) throws IOException { long cb = super.skip(n); // this will only work in relatively small files ... 2Gb position = (int)(position + cb); return cb; } @Override public synchronized void mark(int readlimit) { super.mark(readlimit); markPosition = position; } @Override public synchronized void reset() throws IOException { position = markPosition; super.reset(); } int getPosition() { return position; } int getLength() { return length; } int getPercentageRead() { return position * 100 / length; } int getReadingTimeMillis() { return (int)(System.currentTimeMillis() - timeBegin); } }