From: <ha...@us...> - 2011-01-31 04:18:50
|
Revision: 15079 http://jmol.svn.sourceforge.net/jmol/?rev=15079&view=rev Author: hansonr Date: 2011-01-31 04:18:42 +0000 (Mon, 31 Jan 2011) Log Message: ----------- version=12.1.33 # new feature: write xxx.OBJ -- WaveFront OBJ file writing # new feature: isosurface MRC keyword indicates file is MRC type (for nonstandard MRC files) # bug fix: scriptLevelMax 20 too small -- changed to 100 # bug fix: for/while local variables improperly localized in iterative functions # bug fix: 12.1.32 should not have changed <string> + <array> to be <array> Modified Paths: -------------- trunk/Jmol/src/org/jmol/adapter/readers/quantum/BasisFunctionReader.java trunk/Jmol/src/org/jmol/adapter/readers/quantum/NWChemReader.java trunk/Jmol/src/org/jmol/export/_ObjExporter.java trunk/Jmol/src/org/jmol/jvxl/readers/MapFileReader.java trunk/Jmol/src/org/jmol/jvxl/readers/MrcBinaryReader.java trunk/Jmol/src/org/jmol/jvxl/readers/SurfaceGenerator.java trunk/Jmol/src/org/jmol/quantum/MOCalculation.java trunk/Jmol/src/org/jmol/quantum/QuantumCalculation.java trunk/Jmol/src/org/jmol/script/ScriptEvaluator.java trunk/Jmol/src/org/jmol/script/Token.java trunk/Jmol/src/org/jmol/viewer/Jmol.properties Modified: trunk/Jmol/src/org/jmol/adapter/readers/quantum/BasisFunctionReader.java =================================================================== --- trunk/Jmol/src/org/jmol/adapter/readers/quantum/BasisFunctionReader.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/adapter/readers/quantum/BasisFunctionReader.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -152,7 +152,7 @@ // [4 0 0 0 -4] // meaning add that number to the pointer for this coef. if (dfCoefMaps == null) { - dfCoefMaps = new int[][] {null, new int[3], new int[4], + dfCoefMaps = new int[][] {new int[1], new int[3], new int[4], new int[5], new int[6], new int[7], new int[10]}; } String[] tokens = getTokens(fileList); Modified: trunk/Jmol/src/org/jmol/adapter/readers/quantum/NWChemReader.java =================================================================== --- trunk/Jmol/src/org/jmol/adapter/readers/quantum/NWChemReader.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/adapter/readers/quantum/NWChemReader.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -87,6 +87,7 @@ @Override protected void initializeReader() { readROHFonly = (filter != null && filter.indexOf("ROHF") >= 0); + calculationType = "(NWCHEM)"; // normalization is different for NWCHEM } /** @@ -105,7 +106,7 @@ return true; } if (line.indexOf(" wavefunction = ") >= 0) { - calculationType = line.substring(line.indexOf("=") + 1).trim(); + calculationType = line.substring(line.indexOf("=") + 1).trim() + "(NWCHEM)"; moData.put("calculationType", calculationType); return true; } @@ -154,7 +155,7 @@ readBasis(); return true; } - if (line.contains("ROHF Final Molecular Orbital Analysis")) { + if (readROHFonly && line.contains("ROHF Final Molecular Orbital Analysis")) { return readMolecularOrbitals(); } Modified: trunk/Jmol/src/org/jmol/export/_ObjExporter.java =================================================================== --- trunk/Jmol/src/org/jmol/export/_ObjExporter.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/export/_ObjExporter.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -1,17 +1,21 @@ package org.jmol.export; +import java.awt.Point; +import java.awt.image.BufferedImage; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.util.ArrayList; import java.util.BitSet; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import javax.imageio.ImageIO; import javax.vecmath.AxisAngle4f; import javax.vecmath.Matrix4f; import javax.vecmath.Point3f; @@ -26,38 +30,60 @@ import org.jmol.viewer.Viewer; /** - * Class to export Wavefront OBJ files. The format is described at<br><br> + * Class to export Wavefront OBJ files. The format is described at<br> + * <br> * <a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file"> * http://en.wikipedia.org/wiki/Wavefront_.obj_file</a><br> * and<br> * <a href="http://www.martinreddy.net/gfx/3d/OBJ.spec"> - * http://www.martinreddy.net/gfx/3d/OBJ.spec</a><br><br> - * Two files are produced: the object in the .obj file and the materials in the - * .mtl file. Both should be kept in the same directory.<br><br> + * http://www.martinreddy.net/gfx/3d/OBJ.spec</a><br> + * <br> + * At least two files are produced: the object in the .obj file and the + * materials in the .mtl file. An additional image file is produced for each + * surface. All should be kept in the same directory.<br> + * <br> * The exporter has been tested for ball and stick models, but not for: * <ul> - * <li>outputFace (not implemented)</li> + * <li>outputFace (not used)</li> * <li>outputCone</li> * <li>outputTextPixel</li> * <li>outputTriangle</li> - * <li>outputSurface (not implemented)</li> + * <li>outputSurface (only some possibilities tested)</li> * </ul> * * @author ke...@ke... * */ public class _ObjExporter extends __CartesianExporter { + /** Flag to cause debugging output to stdout. */ private static final boolean debug = false; + /** Flag to cause only surfaces to be output. */ + private boolean surfacesOnly = false; + /** + * Whether to normalize UV texture coordinates. (Many applications expect them + * to be normalized.) + */ + private boolean normalizeUV = true; /** BufferedWriter for the .mtl file. */ + /** + * Specify the texture type. You can find the available formats by using + * ImageIO.getWriterFormatNames(). + */ + private String textureType = "png"; + private BufferedWriter mtlbw; /** FileOutputStream for the .mtl file. */ private FileOutputStream mtlos; + /** Path of the OBJ file without the extension. */ + String objFileRootName; /** File for the .mtl file. */ File mtlFile; /** Bytes written to the .mtl file. */ private int nMtlBytes; /** HashSet for textures. */ Set<Short> textures = new HashSet<Short>(); + /** List of texture files created. */ + List<String> textureFiles; /** Number for the next mesh of this type. */ private int sphereNum = 1; @@ -73,13 +99,24 @@ private int coneNum = 1; /** Number for the next mesh of this type. */ private int triangleNum = 1; + /** Number for the next mesh of this type. */ + private int surfaceNum = 1; - /** Wavefront OBJ refers to vertices and normals by their location in the - * file. This keeps track of where the latest set starts. */ + /** + * Wavefront OBJ refers to vertices and normals and textures by their location + * in the file. This keeps track of where the latest vertex set starts. + */ private int currentVertexOrigin = 1; - /** Wavefront OBJ refers to vertices and normals by their location in the - * file. This keeps track of where the latest set starts. */ + /** + * Wavefront OBJ refers to vertices and normals and textures by their location + * in the file. This keeps track of where the latest normal set starts. + */ private int currentNormalOrigin = 1; + /** + * Wavefront OBJ refers to vertices and normals and textures by their location + * in the file. This keeps track of where the latest texture set starts. + */ + private int currentTextureOrigin = 1; public _ObjExporter() { debugPrint("_WavefrontObjExporter CTOR"); @@ -87,7 +124,8 @@ } /** - * Debug print utility. Only prints if debug is true. + * Debug print utility. Only prints if debug is true. + * * @param string */ protected void debugPrint(final String string) { @@ -105,16 +143,19 @@ */ @Override protected void outputFace(int[] face, int[] map, int faceVertexMax) { - // hundreds of thousands of these... debugPrint("outputFace"); + // Currently this is not used + // If it becomes used, omit the debugPrint as there will be many calls + debugPrint("outputFace"); iface[0] = map[face[0]]; iface[1] = map[face[1]]; iface[2] = map[face[2]]; - outputFace(iface); - if (faceVertexMax == 3 || face.length != 4) + outputFace1(iface); + if (faceVertexMax == 3 || face.length != 4) { return; + } iface[1] = map[face[2]]; iface[2] = map[face[3]]; - outputFace(iface); + outputFace1(iface); } /* (non-Javadoc) @@ -124,10 +165,12 @@ protected void outputCircle(Point3f pt1, Point3f pt2, float radius, short colix, boolean doFill) { debugPrint("outputCircle"); - + if (surfacesOnly) { + debugPrint(" Not done owing to surfacesOnly"); + return; + } if (doFill) { outputCircle1(pt1, pt2, colix, radius); - return; } } @@ -138,6 +181,10 @@ protected void outputCone(Point3f ptBase, Point3f ptTip, float radius, short colix) { debugPrint("outputCone"); + if (surfacesOnly) { + debugPrint(" Not done owing to surfacesOnly"); + return; + } outputCone1(ptBase, ptTip, radius, colix); } @@ -163,6 +210,10 @@ debugPrint(" ptX=" + ptX); debugPrint(" ptY=" + ptY); } + if (surfacesOnly) { + debugPrint(" Not done owing to surfacesOnly"); + return true; + } if (ptX != null) { if (endcaps == Graphics3D.ENDCAPS_FLAT) { @@ -198,6 +249,11 @@ debugPrint(" points[1]=" + points[1]); debugPrint(" points[2]=" + points[2]); } + if (surfacesOnly) { + debugPrint(" Not done owing to surfacesOnly"); + return; + } + AxisAngle4f a = Quaternion.getQuaternionFrame(center, points[1], points[3]) .toAxisAngle4f(); float sx = points[1].distance(center); @@ -224,6 +280,11 @@ debugPrint(" center.z=" + center.z); debugPrint(" radius=" + radius); } + if (surfacesOnly) { + debugPrint(" Not done owing to surfacesOnly"); + return; + } + // Treat as a special case of ellipsoid outputEllipsoid1(center, radius, radius, radius, null, colix); } @@ -234,6 +295,10 @@ @Override protected void outputTextPixel(Point3f pt, int argb) { debugPrint("outputTextPixel"); + if (surfacesOnly) { + debugPrint(" Not done owing to surfacesOnly"); + return; + } short colix = Graphics3D.getColix(argb); outputSphere(pt, 0.02f, colix); @@ -246,6 +311,10 @@ protected void outputTriangle(Point3f pt1, Point3f pt2, Point3f pt3, short colix) { debugPrint("outputTriangle"); + if (surfacesOnly) { + debugPrint(" Not done owing to surfacesOnly"); + return; + } outputTriangle1(pt1, pt2, pt3, colix); } @@ -267,6 +336,206 @@ debugPrint("output"); } + /* (non-Javadoc) + * @see org.jmol.export.___Exporter#outputSurface(javax.vecmath.Point3f[], javax.vecmath.Vector3f[], short[], int[][], short[], int, int, int, java.util.BitSet, int, short, java.util.List, java.util.Map, javax.vecmath.Point3f) + */ + @Override + protected void outputSurface(Point3f[] vertices, Vector3f[] normals, + short[] colixes, int[][] indices, + short[] polygonColixes, int nVertices, + int nPolygons, int nFaces, BitSet bsFaces, + int faceVertexMax, short colix, + List<Short> colorList, + Map<String, String> htColixes, Point3f offset) { + debugPrint("outputSurface"); + if (vertices == null) { + debugPrint(" nVertices=" + "null"); + } else { + debugPrint(" nVertices=" + vertices.length); + if (debug) { + int nNonNull = 0; + for (Tuple3f vertex : vertices) { + if (vertex != null) { + nNonNull++; + } + } + debugPrint(" nNonNull=" + nNonNull); + } + } + if (normals == null) { + debugPrint(" nNormals=" + "null"); + } else { + debugPrint(" nNormals=" + normals.length); + } + if (colixes == null) { + debugPrint(" nColixes=" + "null"); + } else { + debugPrint(" nColixes=" + colixes.length); + } + if (indices == null) { + debugPrint(" nIndices=" + "null"); + } else { + debugPrint(" nIndices=" + indices.length); + } + if (polygonColixes == null) { + debugPrint(" nPolygonColixes=" + "null"); + } else { + debugPrint(" nPolygonColixes=" + polygonColixes.length); + } + debugPrint(" nPolygons=" + nPolygons + " nFaces=" + nFaces + + " faceVertexMax=" + faceVertexMax); + if (bsFaces == null) { + debugPrint(" nBsFaces=" + "null"); + } else { + debugPrint(" nBsFaces=" + bsFaces.size()); + } + debugPrint(" colix=" + colix); + if (colorList == null) { + debugPrint(" ncolorList=" + "null"); + } else { + debugPrint(" ncolorList=" + colorList.size()); + } + + boolean haveFaceColors = (polygonColixes != null); + if (haveFaceColors) { + // TODO + // This is not handled in the _IdtfExporter + // If we have polygonColixes, we are going to have to write individual + // vertex/vertex normal face sets if polygonColixes[] is not null. + // this will be individual + debugPrint("outputSurface: polygonColixes != null is not implemented"); + return; + } + + // Find non-null vertices + // FIXME Don't need the first loop if it is guaranteed + // only the first nVertices elements are used. Then nNonNull = nVertices. + int nUsed = 0; + for (Tuple3f vertex : vertices) { + if (vertex != null) { + nUsed++; + } + } + Tuple3f[] vertices1 = new Tuple3f[nUsed]; + nUsed = 0; + for (Tuple3f vertex : vertices) { + if (vertex != null) { + vertices1[nUsed++] = vertex; + } + } + + // Find non-null normals + // Apparently the number of normals is expected to be the same as the number + // of vertices + // FIXME Don't need the first loop if it is guaranteed + // only the first nVertices elements are used. Then nNonNull = nVertices. + nUsed = 0; + for (Vector3f normal : normals) { + if (normal != null) { + nUsed++; + } + } + Vector3f[] normals1 = new Vector3f[nUsed]; + nUsed = 0; + for (Vector3f normal : normals) { + if (normal != null) { + normals1[nUsed++] = normal; + } + } + + // Find used faces + boolean isAll = (bsFaces == null); + // If bsFaces is null, loop over nPolygons, else use flags in bsFaces + int[] face; + nUsed = 0; + for (int i = isAll ? 0 : bsFaces.nextSetBit(0); i >= 0; i = isAll ? nPolygons - 1 + : bsFaces.nextSetBit(i + 1)) { + face = indices[i]; + nUsed++; + // Apparently there may be a second face + // TODO Check this logic + if (faceVertexMax == 3 || face.length != 4) { + continue; + } + nUsed++; + } + int[][] faces1 = new int[nUsed][3]; + nUsed = 0; + for (int i = isAll ? 0 : bsFaces.nextSetBit(0); i >= 0; i = isAll ? nPolygons - 1 + : bsFaces.nextSetBit(i + 1)) { + face = indices[i]; + // Don't use, there are hundreds of thousands of these + // debugPrint("outputFace"); + faces1[nUsed][0] = face[0]; + faces1[nUsed][1] = face[1]; + faces1[nUsed][2] = face[2]; + nUsed++; + // Apparently there may be a second face + // TODO Check this logic + if (faceVertexMax == 3 || face.length != 4) { + continue; + } + faces1[nUsed][0] = face[0]; + faces1[nUsed][1] = face[2]; + faces1[nUsed][2] = face[3]; + nUsed++; + } + Data data = new Data(faces1, vertices1, normals1); + debugPrint(" Used " + vertices1.length + " vertices"); + debugPrint(" Used " + normals1.length + " normals"); + debugPrint(" Used " + faces1.length + " faces"); + + // Assume there is no transformation + Matrix4f matrix = new Matrix4f(); + matrix.setIdentity(); + + // Do the texture + String name = "Surface" + surfaceNum++; + addTexture(colix); + + // Create a Point with the image file dimensions + // If it remains null, then it is a flag that a texture file and + // texture coordinates are not used + Point dim = null; + + // Make a texture file if colixes is defined + if (colixes == null) { + debugPrint("outputSurface: colixes = null"); + debugPrint(" Omitting texture map"); + } else { + // Determine the height and width of an image file that is as close to + // square as possible + int width = (int) Math.ceil(Math.sqrt(nUsed)); + int height = nUsed / width; + if (nUsed % width != 0) { + height++; + } + dim = new Point(width, height); + debugPrint(" width=" + width + " height=" + height + " size = " + + (width * height)); + File file = createTextureFile(name, data, colixes, dim); + if (file == null) { + System.out.println("Error creating texture file: " + name); + textureFiles.add("Error creating texture file: " + name); + return; + } + String error = ""; + if (!file.exists()) { + error = " [Does not exist]"; + } else if (file.length() == 0) { + error = " [Empty]"; + } + textureFiles.add(file.length() + " (" + width + "x" + height + ") " + + file.getPath() + error); + // Add the texture file to the material + outputMtl(" map_Kd " + file.getName() + "\n"); + // TODO Check this is wise + outputMtl(" map_Ka " + file.getName() + "\n"); + } + + addMesh(name, data, matrix, colix, dim); + } + // Non-abstract overrides from _Exporter /* (non-Javadoc) @@ -282,14 +551,17 @@ return false; } + // Get the root path + int dot = fileName.lastIndexOf("."); + if (dot < 0) { + debugPrint("End initializeOutput (Error creating .mtl file):"); + return false; + } + objFileRootName = fileName.substring(0, dot); + // Open stream and writer for the .mtl file try { - int dot = fileName.lastIndexOf("."); - if (dot < 0) { - debugPrint("End initializeOutput (Error creating .mtl file):"); - return false; - } - String mtlFileName = fileName.substring(0, dot) + ".mtl"; + String mtlFileName = objFileRootName + ".mtl"; mtlFile = new File(mtlFileName); System.out.println("_WavefrontObjExporter writing to " + mtlFile.getAbsolutePath()); @@ -301,6 +573,9 @@ } outputMtl("# Created by Jmol " + Viewer.getJmolVersion() + "\n"); output("\nmtllib " + mtlFile.getName() + "\n"); + + // Keep a list of texture files created + textureFiles = new ArrayList<String>(); debugPrint("End initializeOutput:"); return true; } @@ -328,6 +603,9 @@ } retVal += ", " + nMtlBytes + " " + mtlFile.getPath(); + for (String string : textureFiles) { + retVal += ", " + string; + } debugPrint(retVal); debugPrint("End finalizeOutput:"); return retVal; @@ -351,10 +629,11 @@ /** * Returns the name to be used for the texture associated with the given - * colix. Jmol reading of the file without additional resources requires a color name here - * in the form: kRRGGBB + * colix. Jmol reading of the file without additional resources requires a + * color name here in the form: kRRGGBB * - * @param colix The value of colix. + * @param colix + * The value of colix. * @return The name for the structure. */ private String getTextureName(short colix) { @@ -380,7 +659,7 @@ matrix.m13 = ptCenter.y; matrix.m23 = ptCenter.z; matrix.m33 = 1; - addMesh(name, data, matrix, colix); + addMesh(name, data, matrix, colix, null); } /** @@ -402,7 +681,7 @@ matrix.m13 = ptBase.y; matrix.m23 = ptBase.z; matrix.m33 = 1; - addMesh(name, data, matrix, colix); + addMesh(name, data, matrix, colix, null); } /** @@ -426,11 +705,133 @@ matrix.m13 = ptZ.y; matrix.m23 = ptZ.z; matrix.m33 = 1; - addMesh(name, data, matrix, colix); + addMesh(name, data, matrix, colix, null); return true; } /** + * Writes a texture file with the colors in the colixes array in a way that it + * can be mapped by the texture coordinates vt. + * + * @param name + * The name of the file without the path or ext. This will be added + * to the root name of the OBJ file along with the image suffix. The + * value should be the name given to the surface. + * @param data + * @param colixes + * @param dim + * A Point representing the width, height of the image. + * @return The File created or null on failure. + */ + public File createTextureFile(String name, Data data, short[] colixes, + Point dim) { + // This needs to be kept correlated with what doUV in addMesh does + debugPrint("createTextureFile: " + name); + // Do nothing unless all the arrays exist and have the same size + // if (debug) { + // debugPrint(" ImageIO Avaliable Formats:"); + // String[] formats = ImageIO.getWriterFormatNames(); + // for (String format : formats) { + // debugPrint(" " + format); + // } + // } + + // Create the File before checking the input, deleting any existing file + // of the same name (silently) so we will not have an inconsistent set of + // files. Create the file even if it will be empty so we can denote that + // in the console output. + File imageFile = null; + try { + imageFile = new File(objFileRootName + "_" + name + "." + textureType); + if (imageFile.exists()) { + imageFile.delete(); + } + imageFile.createNewFile(); + System.out.println("_WavefrontObjExporter writing to " + + imageFile.getAbsolutePath()); + } catch (Exception ex) { + debugPrint("End createTextureFile (" + ex.getMessage() + "):"); + return imageFile; + } + + // Check input + if (colixes == null || data == null || colixes.length == 0) { + debugPrint("createTextureFile: Array problem"); + debugPrint(" colixes=" + colixes + " data=" + data); + if (colixes != null) { + debugPrint(" colixes.length=" + colixes.length); + } + return imageFile; + } + + int nColors = colixes.length; + Tuple3f[] vertices = data.getVertexes(); + Tuple3f[] normals = data.getNormals(); + if (vertices == null || normals == null || vertices.length != nColors + || normals.length != nColors) { + debugPrint("createTextureFile: Vertices / normals problem"); + debugPrint(" vertices=" + vertices + " normals=" + normals); + if (vertices != null) { + debugPrint(" vertices.length=" + vertices.length); + } + if (normals != null) { + debugPrint(" normals=" + normals.length); + } + return imageFile; + } + // FIXME Fix it to draw a triangle rather than a point + // FIXME Find the number of unique colors + int nUsed = data.getFaces().length; + if (nUsed <= 0) { + debugPrint("createTextureFile: nFaces = 0"); + return imageFile; + } + // Make a BufferedImage and set the pixels in it + int width = dim.x; + int height = dim.y; + BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + int rgb, nVertices, color; + Point3f colors; + Point3f sum = new Point3f(); + int iFace = 0; + int[] face = null; + // Write it bottom to top to match direction of UV coordinate v + for (int row = height - 1; row >= 0; row--) { + for (int col = 0; col < width; col++) { + face = data.getFaces()[iFace++]; + nVertices = face.length; + // Get the vertex colors and average them + sum.set(0, 0, 0); + for (int iVertex : face) { + color = g3d.getColorArgbOrGray(colixes[iVertex]); + colors = Graphics3D.colorPointFromInt2(color); + sum.add(colors); + } + sum.scale(1.0f / nVertices); + rgb = Graphics3D.colorPtToInt(sum); + image.setRGB(col, row, rgb); + // Stop if all faces are done + if (iFace >= nUsed) { + break; + } + } + } + + // Write the file + // TODO Fix this to set compression for JPEGs + try { + ImageIO.write(image, textureType, imageFile); + } catch (IOException ex) { + debugPrint("End createTextureFile (" + ex.getMessage() + "):"); + return null; + } + + debugPrint("End createTextureFile: " + name); + return imageFile; + } + + /** * Local implementation of outputEllipsoid. * * @param center @@ -455,7 +856,7 @@ name = "Ellipsoid" + ellipsoidNum++; } setSphereMatrix(center, rx, ry, rz, a, sphereMatrix); - addMesh(name, data, sphereMatrix, colix); + addMesh(name, data, sphereMatrix, colix, null); } /** @@ -488,16 +889,20 @@ matrix.m23 = pt1.z; matrix.m33 = 1; } - addMesh(name, data, matrix, colix); + addMesh(name, data, matrix, colix, null); } /** * Local implementation of outputCylinder. * - * @param pt1 Vertex 1. - * @param pt2 Vertex 2. - * @param pt3 Vertex 3. - * @param colix The colix. + * @param pt1 + * Vertex 1. + * @param pt2 + * Vertex 2. + * @param pt3 + * Vertex 3. + * @param colix + * The colix. */ private void outputTriangle1(Point3f pt1, Point3f pt2, Point3f pt3, short colix) { @@ -506,12 +911,12 @@ addTexture(colix); String name = "Triangle" + triangleNum++; matrix.setIdentity(); - addMesh(name, data, matrix, colix); + addMesh(name, data, matrix, colix, null); } /** - * Adds a texture to the .mtl file if it is a new texture. Some of the - * parameter choices are arbitrarily chosen. The .mtl file can be easily + * Adds a texture to the .mtl file if it is a new texture. Some of the + * parameter choices are arbitrarily chosen. The .mtl file can be easily * edited if it is desired to change things. * * @param colix @@ -549,11 +954,25 @@ * colix after transforming it via the given affine transform matrix. * * @param name + * The name to be used for the mesh. * @param data + * Where the data are located. * @param matrix + * Transformation to transform the base mesh. * @param colix + * Colix associated with the mesh. + * @param dim + * The width, height of the associated image for UV texture + * coordinates. If null no UV coordinates are used. */ - private void addMesh(String name, Data data, Matrix4f matrix, short colix) { + private void addMesh(String name, Data data, Matrix4f matrix, short colix, + Point dim) { + // Use to only get surfaces in the output + if (surfacesOnly) { + if (name == null || !name.startsWith("Surface")) { + return; + } + } // Note: No texture coordinates (vt) are used // The group (g) is probably not needed, but makes the file easier to read // Vertices and normals are numbered sequentially throughout the OBJ file @@ -581,14 +1000,65 @@ matrix.transform(v0); output("vn " + v0.x + " " + v0.y + " " + v0.z + "\n"); } - output("# Number of faces: " + nFaces + "\n"); - for (int[] face : data.getFaces()) - outputFace(face); + int iFace = 0; + if (dim != null) { + // This needs to be kept correlated with what createTextureFile does + output("# Number of texture coordinates: " + nFaces + "\n"); + int width = dim.x; + int height = dim.y; + int[] face = null; + float u, v; + for (int row = 0; row < height; row++) { + v = row + .5f; + if (normalizeUV) { + v /= height; + } + for (int col = 0; col < width; col++) { + face = data.getFaces()[iFace++]; + nVertices = face.length; + u = col + .5f; + if (normalizeUV) { + u /= width; + } + output("vt " + u + " " + v + "\n"); + // Stop if all faces are done + if (iFace >= nFaces) { + break; + } + } + } + if (!normalizeUV) { + // Be sure there are values to denote the limits of the UV mesh + output("vt 0.0 0.0\n"); + output("vt " + (float) width + " " + (float) height + "\n"); + iFace += 2; + } + } + output("# Number of faces: " + iFace + "\n"); + int[][] faces = data.getFaces(); + for (int i = 0; i < nFaces; i++) { + if (dim != null) { + outputFace2(faces[i], i); + } else { + outputFace1(faces[i]); + } + } + + // Increase the the current numbering start points for the vertices, + // textures, and normals + if (dim != null) { + currentTextureOrigin += iFace; + } currentVertexOrigin += nVertices; currentNormalOrigin += nNormals; } - private void outputFace(int[] face) { + /** + * Local implementation of outputFace used for no texture coordinates. + * + * @param face + */ + private void outputFace1(int[] face) { output("f"); for (int i = 0; i < face.length; i++) { output(" " + (face[i] + currentVertexOrigin) + "//" @@ -597,76 +1067,22 @@ output("\n"); } - /* (non-Javadoc) - * @see org.jmol.export.___Exporter#outputSurface(javax.vecmath.Point3f[], javax.vecmath.Vector3f[], short[], int[][], short[], int, int, int, java.util.BitSet, int, short, java.util.List, java.util.Map, javax.vecmath.Point3f) + /** + * Local implementation of outputFace used with texture coordinates. + * + * @param face + * Array of vertices for the face. + * @param vt + * Number of the vt texture coordinate. */ - @Override - protected void outputSurface(Point3f[] vertices, Vector3f[] normals, - short[] colixes, int[][] indices, - short[] polygonColixes, int nVertices, - int nPolygons, int nFaces, BitSet bsFaces, - int faceVertexMax, short colix, - List<Short> colorList, - Map<String, String> htColixes, Point3f offset) { - - debugPrint("outputSurface"); - - boolean haveFaceColors = (polygonColixes != null); - - // OBJ will use vt# in face for individual colors when colixes[] is not null - - // bsFaces indicates WHICH faces are actually to be used -- sometimes a - // mesh fragment is being displayed, so we need to select only the "active" faces - - // 1) set overall colix -- may be over-ruled by individual vertex colixes. - - // coordinates -- write v list - //outputIndices(indices, map, nPolygons, bsFaces, faceVertexMax); - - if (normals != null) { - // write vn list + private void outputFace2(int[] face, int vt) { + output("f"); + for (int i = 0; i < face.length; i++) { + output(" " + (face[i] + currentVertexOrigin) + "/" + + (currentTextureOrigin + vt) + "/" + (face[i] + currentNormalOrigin)); } - - - // colors, part 1 - - if (colorList != null) { - // write vt list - - /* - boolean isAll = (bsFaces == null); - int i0 = (isAll ? nPolygons - 1 : bsFaces.nextSetBit(0)); - for (int i = i0; i >= 0; i = (isAll ? i - 1 : bsFaces.nextSetBit(i + 1))) { - if (polygonColixes == null) { - sbColorIndexes.append(" " - + htColixes.get("" + colixes[indices[i][0]]) + " " - + htColixes.get("" + colixes[indices[i][1]]) + " " - + htColixes.get("" + colixes[indices[i][2]])); - if (faceVertexMax == 4 && indices[i].length == 4) - sbColorIndexes.append(" " - + htColixes.get("" + colixes[indices[i][0]]) + " " - + htColixes.get("" + colixes[indices[i][2]]) + " " - + htColixes.get("" + colixes[indices[i][3]])); - } else { - // TODO polygon colixes - // output(htColixes.get("" + polygonColixes[i]) + "\n"); - } - } - */ - } - - if (haveFaceColors) { - - // If we have polygonColixes, we are going to have to write individual - // vertex/vertex normal face sets if polygonColixes[] is not null. - // this will be individual - - return; - } - - - // write f list + output("\n"); } - } + \ No newline at end of file Modified: trunk/Jmol/src/org/jmol/jvxl/readers/MapFileReader.java =================================================================== --- trunk/Jmol/src/org/jmol/jvxl/readers/MapFileReader.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/jvxl/readers/MapFileReader.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -131,7 +131,7 @@ This is because our x is the slowest running variable. */ - vectors[0] = new Point3f(1, 0, 0); + vectors[0] = new Point3f(1, 0, 0); vectors[1] = new Point3f(0, 1, 0); vectors[2] = new Point3f(0, 0, 1); unitCell.toCartesian(vectors[0], false); Modified: trunk/Jmol/src/org/jmol/jvxl/readers/MrcBinaryReader.java =================================================================== --- trunk/Jmol/src/org/jmol/jvxl/readers/MrcBinaryReader.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/jvxl/readers/MrcBinaryReader.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -23,9 +23,6 @@ */ package org.jmol.jvxl.readers; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; - import org.jmol.util.BinaryDocument; import org.jmol.util.Logger; @@ -37,17 +34,17 @@ * examples include the emd_1xxx..map electron microscopy files * and xxxx.ccp4 files * + * Jmol 12.1.33: adjusted to allow for nonstandard "MRC" files + * that are little-endian, have no labels, have no "MAP" file type marker + * and are not inside-out. * */ - MrcBinaryReader(SurfaceGenerator sg, String fileName, String data) { + MrcBinaryReader(SurfaceGenerator sg, String fileName) { super(sg, null); binarydoc = new BinaryDocument(); - if (data == null) - binarydoc.setStream(sg.getAtomDataServer().getBufferedInputStream(fileName), true); - else - binarydoc.setStream(new DataInputStream(new ByteArrayInputStream(data.getBytes()))); + binarydoc.setStream(sg.getAtomDataServer().getBufferedInputStream(fileName), true); // data are HIGH on the inside and LOW on the outside nSurfaces = 1; if (params.thePlane == null) @@ -110,6 +107,17 @@ int nlabel; nx = binarydoc.readInt(); // CCP4 "extent[0-2]" + if (nx < 0 || nx > 1<<8) { + binarydoc.setIsBigEndian(false); + nx = BinaryDocument.swapBytes(nx); + if (params.thePlane == null) + params.insideOut = !params.insideOut; + if (nx < 0 || nx > 1000) { + Logger.info("nx=" + nx + " not displayable as MRC file"); + throw new Exception("MRC file type not readable"); + } + Logger.info("reading nonstandard little-endian MRC file"); + } ny = binarydoc.readInt(); nz = binarydoc.readInt(); @@ -184,7 +192,8 @@ Logger.info("MRC header: labels: " + nlabel); labels = new String[nlabel]; - labels[0] = "Jmol MrcBinaryReader"; + if (nlabel > 0) + labels[0] = "Jmol MrcBinaryReader"; for (int i = 0; i < 10; i++) { String s = binarydoc.readString(80).trim(); @@ -221,7 +230,7 @@ } jvxlFileHeaderBuffer = new StringBuffer(); - jvxlFileHeaderBuffer.append("MRC DATA ").append(labels[0]).append("\n"); + jvxlFileHeaderBuffer.append("MRC DATA ").append(nlabel > 0 ? labels[0]: "").append("\n"); jvxlFileHeaderBuffer.append("see http://ami.scripps.edu/software/mrctools/mrc_specification.php\n"); } Modified: trunk/Jmol/src/org/jmol/jvxl/readers/SurfaceGenerator.java =================================================================== --- trunk/Jmol/src/org/jmol/jvxl/readers/SurfaceGenerator.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/jvxl/readers/SurfaceGenerator.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -1183,7 +1183,7 @@ // ignore } br = null; - return new MrcBinaryReader(this, params.fileName, data); + return new MrcBinaryReader(this, params.fileName); } if (fileType.equals("DSN6")) { try { Modified: trunk/Jmol/src/org/jmol/quantum/MOCalculation.java =================================================================== --- trunk/Jmol/src/org/jmol/quantum/MOCalculation.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/quantum/MOCalculation.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -25,7 +25,6 @@ import org.jmol.api.MOCalculationInterface; import org.jmol.api.VolumeDataInterface; -import org.jmol.jvxl.readers.Parameters; import org.jmol.util.Logger; import org.jmol.viewer.JmolConstants; @@ -94,22 +93,13 @@ private final static double CUT = -50; - private final static int MAX_GRID = Parameters.MO_MAX_GRID; // slater coefficients in Bohr - final float[] CX = new float[MAX_GRID]; - final float[] CY = new float[MAX_GRID]; - final float[] CZ = new float[MAX_GRID]; - + private float[] CX, CY, CZ; // d-orbital partial coefficients in Bohr - final float[] DXY = new float[MAX_GRID]; - final float[] DXZ = new float[MAX_GRID]; - final float[] DYZ = new float[MAX_GRID]; - - // exp(-alpha x^2...) - final float[] EX = new float[MAX_GRID]; - final float[] EY = new float[MAX_GRID]; - final float[] EZ = new float[MAX_GRID]; - + private float[] DXY, DXZ, DYZ; + // exp(-alpha x^2...) + private float[] EX, EY, EZ; + private String calculationType; private List<int[]> shells; private float[][] gaussians; @@ -123,8 +113,9 @@ private float occupancy = 2f; //for now -- RHF only //private float coefMax = Integer.MAX_VALUE; private boolean doNormalize = true; + private boolean nwChemMode = false; // S SP DS DC FS FC - private int[][] dfCoefMaps = new int[][] {null, new int[3], new int[4], new int[5], new int[6], new int[7], new int[10]}; + private int[][] dfCoefMaps = new int[][] {new int[1], new int[3], new int[4], new int[5], new int[6], new int[7], new int[10]}; // private float[] nuclearCharges; @@ -168,7 +159,24 @@ if (doDebug || testing || isElectronDensity) calculateElectronDensity(nuclearCharges); } + + @Override + protected void initialize(int nX, int nY, int nZ) { + super.initialize(nX, nY, nZ); + + CX = new float[nX]; + CY = new float[nY]; + CZ = new float[nZ]; + DXY = new float[nX]; + DXZ = new float[nX]; + DYZ = new float[nY]; + + EX = new float[nX]; + EY = new float[nY]; + EZ = new float[nZ]; + } + public void calculateElectronDensity(float[] nuclearCharges) { //TODO float t = 0; @@ -200,12 +208,8 @@ int nShells = shells.size(); // each STO shell is the combination of one or more gaussians moCoeff = 0; - for (int i = 0; i < nShells; i++) { + for (int i = 0; i < nShells; i++) processShell(i); - if (doDebug) - Logger.debug("createGaussianCube shell=" + i + " moCoeff=" + moCoeff - + "/" + moCoefficients.length); - } } boolean as5D = false; @@ -239,6 +243,7 @@ Logger.warn("calculation type not identified -- continuing"); return true; } + nwChemMode = (calculationType.indexOf("NWCHEM") >= 0); /*if (calculationType.indexOf("5D") >= 0) { Logger .error("QuantumCalculation.checkCalculationType: can't read 5D basis sets yet: " @@ -270,7 +275,7 @@ nGaussians = shell[3]; if (doDebug) - Logger.debug("processShell: " + iShell + " type=" + Logger.debug("\t\t\tprocessShell: " + iShell + " type=" + JmolConstants.getQuantumShellTag(basisType) + " nGaussians=" + nGaussians + " atom=" + atomIndex); if (atomIndex != lastAtom && (thisAtom = qmAtoms[atomIndex]) != null) @@ -331,18 +336,29 @@ return; } if (doDebug) - dumpInfo("S "); + dumpInfo(JmolConstants.SHELL_S, dfCoefMaps[0]); + float norm; + if (doNormalize) { + // (8 alpha^3/pi^3)^0.25 exp(-alpha r^2) + norm = 0.712705470f; // (8/pi^3)^0.25 + if (nwChemMode) { + //norm; + } else { + // + } + } else { + norm = 1; + } + float m1 = moCoefficients[moCoeff++]; for (int ig = 0; ig < nGaussians; ig++) { float alpha = gaussians[gaussianPtr + ig][0]; float c1 = gaussians[gaussianPtr + ig][1]; - // (2 alpha^3/pi^3)^0.25 exp(-alpha r^2) - float a = m1 * c1; + float a = norm * m1 * c1; if (doNormalize) - a *= (float) Math.pow(alpha, 0.75) * 0.712705470f; + a *= (float) Math.pow(alpha, 0.75); // the coefficients are all included with the X factor here - for (int i = xMax; --i >= xMin;) { EX[i] = a * (float) Math.exp(-X2[i] * alpha); } @@ -438,7 +454,7 @@ float ms, mx, my, mz; if (c1 == 0) { if (doDebug) - dumpInfo("X Y Z "); + dumpInfo(JmolConstants.SHELL_P, map); ms = 0; } else { if (doDebug) @@ -558,6 +574,19 @@ float mxy = moCoefficients[map[3] + moCoeff++]; float mxz = moCoefficients[map[4] + moCoeff++]; float myz = moCoefficients[map[5] + moCoeff++]; + float norm1, norm2; + if (doNormalize) { + norm1 = 2.8508219178923f; + if (nwChemMode) { + norm2 = norm1;// / ROOT3;//norm1 * ROOT3 * ROOT3; + norm1 /= ROOT3; + } else { + norm2 = norm1 / ROOT3; + } + } else { + norm2 = 1 / ROOT3; + norm1 = 1; + } for (int ig = 0; ig < nGaussians; ig++) { float alpha = gaussians[gaussianPtr + ig][0]; float c1 = gaussians[gaussianPtr + ig][1]; @@ -565,13 +594,13 @@ // xy|xz|yz: (2048 alpha^7/pi^3)^0.25 [xy|xz|yz]exp(-alpha r^2) float a = c1; if (doNormalize) - a *= (float) Math.pow(alpha, 1.75) * 2.8508219178923f; - float axx = a / ROOT3 * mxx; - float ayy = a / ROOT3 * myy; - float azz = a / ROOT3 * mzz; - float axy = a * mxy; - float axz = a * mxz; - float ayz = a * myz; + a *= (float) Math.pow(alpha, 1.75); + float axy = a * norm1 * mxy; + float axz = a * norm1 * mxz; + float ayz = a * norm1 * myz; + float axx = a * norm2 * mxx; + float ayy = a * norm2 * myy; + float azz = a * norm2 * mzz; setCE(CX, EX, alpha, 0, axx, ayy, azz); for (int i = xMax; --i >= xMin;) { @@ -1105,35 +1134,19 @@ return true; } - private void dumpInfo(String info) { - for (int ig = 0; ig < nGaussians; ig++) { - float alpha = gaussians[gaussianPtr + ig][0]; - float c1 = gaussians[gaussianPtr + ig][1]; - if (Logger.debugging) { - Logger.debug("Gaussian " + (ig + 1) + " alpha=" + alpha + " c=" + c1); + private void dumpInfo(int shell, int[] map) { + if (Logger.isActiveLevel(Logger.LEVEL_DEBUGHIGH)) + for (int ig = 0; ig < nGaussians; ig++) { + float alpha = gaussians[gaussianPtr + ig][0]; + float c1 = gaussians[gaussianPtr + ig][1]; + Logger.debug("\t\t\tGaussian " + (ig + 1) + " alpha=" + alpha + " c=" + + c1); } - } - int n = info.length() / 2; - if (Logger.debugging) { - for (int i = 0; i < n; i++) - Logger.debug("MO coeff " + info.substring(2 * i, 2 * i + 2) + " " - + (moCoeff + i + 1) + " " + moCoefficients[moCoeff + i]); - } - return; + String[] so = JmolConstants.getShellOrder(shell); + for (int i = 0; i < so.length; i++) + Logger.debug("MO coeff " + (so == null ? "?" + i : so[i]) + " " + + (map[i] + moCoeff + i + 1) + "\t" + + moCoefficients[map[i] + moCoeff + i] + "\t" + thisAtom.atom); } - private void dumpInfo(int shell, int[] map) { - for (int ig = 0; ig < nGaussians; ig++) { - float alpha = gaussians[gaussianPtr + ig][0]; - float c1 = gaussians[gaussianPtr + ig][1]; - Logger.debug("Gaussian " + (ig + 1) + " alpha=" + alpha + " c=" + c1); - } - if (shell >= 0 && Logger.debugging) { - String[] so = JmolConstants.getShellOrder(shell); - for (int i = 0; i < so.length; i++) - Logger.debug(thisAtom + " MO coeff " + (so == null ? "?" + i : so[i]) + " " + (map[i] + moCoeff + i + 1) + " " - + moCoefficients[map[i] + moCoeff + i]); - } - } - } Modified: trunk/Jmol/src/org/jmol/quantum/QuantumCalculation.java =================================================================== --- trunk/Jmol/src/org/jmol/quantum/QuantumCalculation.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/quantum/QuantumCalculation.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -25,6 +25,7 @@ import javax.vecmath.Point3f; +import org.jmol.modelset.Atom; import org.jmol.util.Logger; import java.util.BitSet; @@ -108,7 +109,7 @@ boolean isAll = (bsSelected == null); int i0 = (isAll ? qmAtoms.length - 1 : bsSelected.nextSetBit(0)); for (int i = i0; i >= 0; i = (isAll ? i - 1 : bsSelected.nextSetBit(i + 1))) - qmAtoms[i] = new QMAtom(atomCoordAngstroms[i], X, Y, Z, X2, Y2, Z2); + qmAtoms[i] = new QMAtom((Atom) atomCoordAngstroms[i], X, Y, Z, X2, Y2, Z2); if (doDebug) Logger.debug("QuantumCalculation:\n origin(Bohr)= " + originBohr[0] + " " + originBohr[1] + " " + originBohr[2] + "\n steps(Bohr)= " @@ -131,8 +132,9 @@ // grid coordinate squares relative to orbital center in Bohr private float[] myX2, myY2, myZ2; + Atom atom; - QMAtom(Point3f coordAngstroms, float[] X, float[] Y, float[] Z, + QMAtom(Atom atom, float[] X, float[] Y, float[] Z, float[] X2, float[] Y2, float[] Z2) { myX = X; myY = Y; @@ -141,7 +143,7 @@ myY2 = Y2; myZ2 = Z2; - set(coordAngstroms); + set(this.atom = atom); scale(unitFactor); } Modified: trunk/Jmol/src/org/jmol/script/ScriptEvaluator.java =================================================================== --- trunk/Jmol/src/org/jmol/script/ScriptEvaluator.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/script/ScriptEvaluator.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -16205,6 +16205,10 @@ i++; } break; + case Token.mrc: + addShapeProperty(propertyList, "fileType", "MRC"); + sbCommand.append(" mrc"); + continue; case Token.object: case Token.obj: addShapeProperty(propertyList, "fileType", "Obj"); Modified: trunk/Jmol/src/org/jmol/script/Token.java =================================================================== --- trunk/Jmol/src/org/jmol/script/Token.java 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/script/Token.java 2011-01-31 04:18:42 UTC (rev 15079) @@ -1124,8 +1124,9 @@ final static int modelbased = misc | 204;// new final static int molecular = misc | 206;// new final static int monomer = misc | 208; - final static int msms = misc | 209;// new - public final static int next = misc | 210; + final static int mrc = misc | 209;// new + final static int msms = misc | 210;// new + public final static int next = misc | 211; public final static int nocontourlines = misc | 212; final static int nocross = misc | 214;// new final static int nodebug = misc | 216;// new @@ -1951,6 +1952,7 @@ "minSet", new Token(minset), "modelBased", new Token(modelbased), "molecular", new Token(molecular), + "mrc", new Token(mrc), "msms", new Token(msms), "noCross", new Token(nocross), "noDebug", new Token(nodebug), Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties =================================================================== --- trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2011-01-30 22:04:42 UTC (rev 15078) +++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2011-01-31 04:18:42 UTC (rev 15079) @@ -3,6 +3,8 @@ version=12.1.33 +# new feature: write xxx.OBJ -- WaveFront OBJ file writing +# new feature: isosurface MRC keyword indicates file is MRC type (for nonstandard MRC files) # bug fix: scriptLevelMax 20 too small -- changed to 100 # bug fix: for/while local variables improperly localized in iterative functions # bug fix: 12.1.32 should not have changed <string> + <array> to be <array> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |