Revision: 20572
          http://sourceforge.net/p/jmol/code/20572
Author:   hansonr
Date:     2015-06-11 03:27:51 +0000 (Thu, 11 Jun 2015)
Log Message:
-----------
JPG and other non-transparent background images are not shown in latest fix of 
image rendering in JSmol because in JavaScript 

(b & 0xFF000000) != 0xFF000000  when b = 0xFF000000

because the expression on the left forces a signed 32-bit integer result, and 
the expression on the right has no such forcing.  One
must apply signed-integer forcing to both sides:

(b & 0xFF000000) == (0xFF000000 & 0xFF000000)

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/g3d/Graphics3D.java
    trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java
    trunk/Jmol/src/org/jmol/scriptext/MathExt.java
    trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java
    trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java
    trunk/Jmol/src/org/jmol/viewer/Jmol.properties

Modified: trunk/Jmol/src/org/jmol/g3d/Graphics3D.java
===================================================================
--- trunk/Jmol/src/org/jmol/g3d/Graphics3D.java 2015-06-10 11:54:54 UTC (rev 
20571)
+++ trunk/Jmol/src/org/jmol/g3d/Graphics3D.java 2015-06-11 03:27:51 UTC (rev 
20572)
@@ -1193,10 +1193,10 @@
         && (x >= 0 && x + imageWidth <= w && y >= 0 && y + imageHeight <= h)) {
       // unclipped 
       for (int i = 0, offset = 0, pbufOffset = y * w + x; i < imageHeight; 
i++, pbufOffset += (w - imageWidth)) {
-        for (int j = 0; j < imageWidth; j++) {
-          if (z < zb[pbufOffset++]) {
-            int b = buffer[offset++];
-            if ((b & 0xFF000000) == 0xFF000000)
+        for (int j = 0; j < imageWidth; j++,offset++,pbufOffset++) {
+          if (z < zb[pbufOffset]) {
+            int b = buffer[offset];
+            if ((b & 0xFF000000) == (0xFF000000 & 0xFF000000))
               p.addPixel(pbufOffset, z, b);
           }
         }
@@ -1208,7 +1208,7 @@
       for (int i = 0, offset = 0; i < imageHeight; i++)
         for (int j = 0; j < imageWidth; j++) {
           int b = buffer[offset++];
-          if ((b & 0xFF000000) == 0xFF000000)
+          if ((b & 0xFF000000) == (0xFF000000 & 0xFF000000))
             jmolRenderer.plotImagePixel(b, x + j, y + i, z, 8, bg, w,
               h, zb, p, t);
         }

Modified: trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java
===================================================================
--- trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java        
2015-06-10 11:54:54 UTC (rev 20571)
+++ trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java        
2015-06-11 03:27:51 UTC (rev 20572)
@@ -73,24 +73,24 @@
       return false;
     }
     P3[] vertices = p.vertices;
-    byte[] planes;
     if (screens3f == null || screens3f.length < vertices.length) {
       screens3f = new P3[vertices.length];
       for (int i = vertices.length; --i >= 0;)
         screens3f[i] = new P3();
     }
-    planes = p.planes;
+    P3[] sc = this.screens3f;
+    P3i[] planes = p.planes;
     for (int i = vertices.length; --i >= 0;) {
       Atom atom = (vertices[i] instanceof Atom ? (Atom) vertices[i] : null);
       if (atom == null) {
-        tm.transformPtScrT3(vertices[i], screens3f[i]);
+        tm.transformPtScrT3(vertices[i], sc[i]);
       } else if (atom.isVisible(myVisibilityFlag)) {
-        screens3f[i].set(atom.sX, atom.sY, atom.sZ);
+        sc[i].set(atom.sX, atom.sY, atom.sZ);
       } else if (vibs && atom.hasVibration()) {
         scrVib = tm.transformPtVib(atom, ms.vibrations[atom.i]);
-        screens3f[i].set(scrVib.x, scrVib.y, scrVib.z);
+        sc[i].set(scrVib.x, scrVib.y, scrVib.z);
       } else {
-        tm.transformPt3f(atom, screens3f[i]);
+        tm.transformPt3f(atom, sc[i]);
       }
     }
 
@@ -99,16 +99,20 @@
 
     // no edges to new points when not collapsed
     if (!needTranslucent || g3d.setC(colix))
-      for (int i = 0, j = 0; j < planes.length;)
-        fillFace(p.normixes[i++], screens3f[planes[j++]],
-            screens3f[planes[j++]], screens3f[planes[j++]]);
+      for (int i = planes.length; --i >= 0;) {
+        P3i pl = planes[i];
+        fillFace(p.normixes[i], sc[pl.x], sc[pl.y],
+            sc[pl.z]);
+      }
     // edges are not drawn translucently ever
     if (p.colixEdge != C.INHERIT_ALL)
       colix = p.colixEdge;
     if (g3d.setC(C.getColixTranslucent3(colix, false, 0)))
-      for (int i = 0, j = 0; j < planes.length;)
-        drawFace(p.normixes[i++], screens3f[planes[j++]],
-            screens3f[planes[j++]], screens3f[planes[j++]]);
+      for (int i = planes.length; --i >= 0;) {
+        P3i pl = planes[i];
+        drawFace(p.normixes[i], sc[pl.x], sc[pl.y],
+            sc[pl.z]);
+      }
     return needTranslucent;
   }
 

Modified: trunk/Jmol/src/org/jmol/scriptext/MathExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/MathExt.java      2015-06-10 11:54:54 UTC 
(rev 20571)
+++ trunk/Jmol/src/org/jmol/scriptext/MathExt.java      2015-06-11 03:27:51 UTC 
(rev 20572)
@@ -1261,6 +1261,7 @@
     // format("byteArray", x)
     // format("array", x)
     SV x1 = (args.length < 2 ? mp.getX() : null);
+    
     String format = (args.length == 0 ? "%U" : SV.sValue(args[0]));
     if (x1 == null) {
       int pt = (isLabel ? -1 : SV.getFormatType(format));

Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-06-10 11:54:54 UTC 
(rev 20571)
+++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-06-11 03:27:51 UTC 
(rev 20572)
@@ -47,14 +47,21 @@
 public class Polyhedra extends AtomShape {
 
   private final static float DEFAULT_DISTANCE_FACTOR = 1.85f;
+  private final static float DEFAULT_MANY_VERTEX_DISTANCE_FACTOR = 1.5f;
   private final static float DEFAULT_FACECENTEROFFSET = 0.25f;
   private final static int EDGES_NONE = 0;
   public final static int EDGES_ALL = 1;
   public final static int EDGES_FRONT = 2;
-  private final static int MAX_VERTICES = 150;
+  private final static int MAX_VERTICES = 250;
   private final static int FACE_COUNT_MAX = MAX_VERTICES - 3;
   private P3[] otherAtoms = new P3[MAX_VERTICES + 1];
+  private short[] normixesT = new short[MAX_VERTICES];
+  private P3i[] planesT = new P3i[MAX_VERTICES];
+  private final static P3 randomPoint = P3.new3(3141f, 2718f, 1414f);
 
+  private BS bsTemp;
+
+  
   public int polyhedronCount;
   public Polyhedron[] polyhedrons = new Polyhedron[32];
   public int drawEdges;
@@ -63,8 +70,9 @@
   private int nVertices;
 
   float faceCenterOffset;
-  float distanceFactor;
+  float distanceFactor = Float.NaN;
   boolean isCollapsed;
+  
 
   private boolean iHaveCenterBitSet;
   private boolean bondedOnly;
@@ -79,7 +87,7 @@
 
     if ("init" == propertyName) {
       faceCenterOffset = DEFAULT_FACECENTEROFFSET;
-      distanceFactor = DEFAULT_DISTANCE_FACTOR;
+      distanceFactor = Float.NaN;
       radius = 0.0f;
       nVertices = 0;
       bsVertices = null;
@@ -299,8 +307,7 @@
     int bondCount = 0;
     for (int i = bonds.length; --i >= 0;) {
       Bond bond = bonds[i];
-      Atom otherAtom = bond.atom1 == atom ? bond.atom2 : bond
-          .atom1;
+      Atom otherAtom = bond.atom1 == atom ? bond.atom2 : bond.atom1;
       if (bsVertices != null && !bsVertices.get(otherAtom.i))
         continue;
       if (radius > 0f && bond.atom1.distance(bond.atom2) > radius)
@@ -309,9 +316,8 @@
       if (bondCount == MAX_VERTICES)
         break;
     }
-    if (bondCount < 3 || nVertices > 0 && !bsVertexCount.get(bondCount))
-      return null;
-    return validatePolyhedronNew(atom, bondCount, otherAtoms);
+    return (bondCount < 3 || nVertices > 0 && !bsVertexCount.get(bondCount) ? 
null
+        : validatePolyhedronNew(atom, bondCount, otherAtoms));
   }
 
   private Polyhedron constructBitSetPolyhedron(int atomIndex) {
@@ -322,7 +328,8 @@
     return validatePolyhedronNew(atoms[atomIndex], otherAtomCount, otherAtoms);
   }
 
-  private Polyhedron constructRadiusPolyhedron(int atomIndex, 
AtomIndexIterator iter) {
+  private Polyhedron constructRadiusPolyhedron(int atomIndex,
+                                               AtomIndexIterator iter) {
     Atom atom = atoms[atomIndex];
     int otherAtomCount = 0;
     vwr.setIteratorForAtom(iter, atomIndex, radius);
@@ -331,28 +338,19 @@
       if (bsVertices != null && !bsVertices.get(other.i)
           || atom.distance(other) > radius)
         continue;
-      if (other.altloc != atom.altloc
-          && other.altloc != 0
-          && atom.altloc != 0)
+      if (other.altloc != atom.altloc && other.altloc != 0 && atom.altloc != 0)
         continue;
       if (otherAtomCount == MAX_VERTICES)
         break;
       otherAtoms[otherAtomCount++] = other;
     }
-    if (otherAtomCount < 3 || nVertices > 0
-        && !bsVertexCount.get(otherAtomCount))
-      return null;
-    return validatePolyhedronNew(atom, otherAtomCount, otherAtoms);
+    return (otherAtomCount < 3 || nVertices > 0
+        && !bsVertexCount.get(otherAtomCount) ? null : validatePolyhedronNew(
+        atom, otherAtomCount, otherAtoms));
   }
 
-  private short[] normixesT = new short[MAX_VERTICES];
-  private byte[] planesT = new byte[MAX_VERTICES * 3];
-  private final static P3 randomPoint = P3.new3(3141f, 2718f, 1414f);
-
-  private BS bsTemp;
-
   private Polyhedron validatePolyhedronNew(Atom centralAtom, int vertexCount,
-                                   P3[] otherAtoms) {
+                                           P3[] otherAtoms) {
     V3 normal = new V3();
     int planeCount = 0;
     int ipt = 0;
@@ -368,7 +366,13 @@
       dAverage += points[ptCenter].distance(points[i]);
     }
     dAverage = dAverage / ptCenter;
-    float factor = distanceFactor;
+
+    int nother1 = ptCenter - 1;
+    int nother2 = ptCenter - 2;
+    // for many-vertex polygons we reduce the  distance allowed to avoid 
through-polyhedron faces
+    float factor = (!Float.isNaN(distanceFactor) ? distanceFactor
+        : nother1 <= 6 ? DEFAULT_DISTANCE_FACTOR
+            : DEFAULT_MANY_VERTEX_DISTANCE_FACTOR);
     BS bs = BS.newN(ptCenter);
     boolean isOK = (dAverage == 0);
 
@@ -378,8 +382,8 @@
     while (!isOK && factor < 10.0f) {
       distMax = dAverage * factor;
       bs.setBits(0, ptCenter);
-      for (int i = 0; i < ptCenter - 2; i++)
-        for (int j = i + 1; j < ptCenter - 1; j++) {
+      for (int i = 0; i < nother2; i++)
+        for (int j = i + 1; j < nother1; j++) {
           if (points[i].distance(points[j]) > distMax)
             continue;
           for (int k = j + 1; k < ptCenter; k++) {
@@ -405,7 +409,6 @@
         }
     }
 
-
     /*  Start by defining a face to be when all three distances
      *  are < distanceFactor * (longest central) but if a vertex is missed, 
      *  then expand the range. The collapsed trick is to introduce 
@@ -426,12 +429,12 @@
     // produce face-centered catalog and facet-aligned catalog
     String faceCatalog = "";
     String facetCatalog = "";
-    for (int i = 0; i < ptCenter - 2; i++)
-      for (int j = i + 1; j < ptCenter - 1; j++)
+    for (int i = 0; i < nother2; i++)
+      for (int j = i + 1; j < nother1; j++)
         for (int k = j + 1; k < ptCenter; k++)
           if (isPlanar(points[i], points[j], points[k], points[ptCenter]))
             faceCatalog += faceId(i, j, k);
-    for (int j = 0; j < ptCenter - 1; j++)
+    for (int j = 0; j < nother1; j++)
       for (int k = j + 1; k < ptCenter; k++) {
         if (isAligned(points[j], points[k], points[ptCenter]))
           facetCatalog += faceId(j, k, -1);
@@ -440,46 +443,49 @@
     // this next check for distance allows for bond AND distance constraints
     if (bsTemp == null)
       bsTemp = Normix.newVertexBitSet();
-
-    for (int i = 0; i < ptCenter - 2; i++)
-      for (int j = i + 1; j < ptCenter - 1; j++) {
+    P3i[] p = planesT;
+    boolean collapsed = isCollapsed;
+    float offset = faceCenterOffset;
+    int fmax = FACE_COUNT_MAX;
+    int vmax = MAX_VERTICES;
+    P3 rpt = randomPoint;
+    BS bsT = bsTemp;
+    short[] n = normixesT;
+    for (int i = 0; i < nother2; i++)
+      for (int j = i + 1; j < nother1; j++) {
         if (points[i].distance(points[j]) > distMax)
           continue;
         for (int k = j + 1; k < ptCenter; k++) {
           //System.out.println("checking poly " + i + " " + j + " " + k);
           //System.out.println("checking poly " + points[i] + " " + points[j] 
+ " " + points[k]);
-          
+
           if (points[i].distance(points[k]) > distMax
               || points[j].distance(points[k]) > distMax)
             continue;
           //System.out.println("checking poly " + i + " " + j + " " + k + " ok 
");
 
-          if (planeCount >= FACE_COUNT_MAX) {
-            Logger.error("Polyhedron error: maximum face(" + FACE_COUNT_MAX
+          if (planeCount >= fmax) {
+            Logger.error("Polyhedron error: maximum face(" + fmax
                 + ") -- reduce RADIUS or DISTANCEFACTOR");
             return null;
           }
-          if (nPoints >= MAX_VERTICES) {
+          if (nPoints >= vmax) {
             Logger.error("Polyhedron error: maximum vertex count("
-                + MAX_VERTICES + ") -- reduce RADIUS");
+                + vmax + ") -- reduce RADIUS");
             return null;
           }
           boolean isFlat = (faceCatalog.indexOf(faceId(i, j, k)) >= 0);
           // if center is on the face, then we need a different point to 
           // define the normal
           //System.out.println("# polyhedra\n");
-          boolean isWindingOK = 
-            (isFlat ?
-            Measure.getNormalFromCenter(randomPoint, points[i], points[j],
-                points[k], false, normal) :
-            Measure.getNormalFromCenter(points[ptCenter], points[i],
-                points[j], points[k], true, normal)
-                );
-          normal.scale(isCollapsed && !isFlat ? faceCenterOffset
-              : 0.001f);
+          boolean isWindingOK = (isFlat ? Measure.getNormalFromCenter(
+              rpt, points[i], points[j], points[k], false, normal)
+              : Measure.getNormalFromCenter(points[ptCenter], points[i],
+                  points[j], points[k], true, normal));
+          normal.scale(collapsed && !isFlat ? offset : 0.001f);
           int nRef = nPoints;
           ptRef.setT(points[ptCenter]);
-          if (isCollapsed && !isFlat) {
+          if (collapsed && !isFlat) {
             points[nPoints] = P3.newP(points[ptCenter]);
             points[nPoints].add(normal);
             otherAtoms[nPoints] = points[nPoints];
@@ -489,54 +495,49 @@
           }
           String facet;
           facet = faceId(i, j, -1);
-          if (isCollapsed || isFlat && facetCatalog.indexOf(facet) < 0) {
+          if (collapsed || isFlat && facetCatalog.indexOf(facet) < 0) {
             facetCatalog += facet;
-            planesT[ipt++] = (byte) (isWindingOK ? i : j);
-            planesT[ipt++] = (byte) (isWindingOK ? j : i);
-            planesT[ipt++] = (byte) nRef;
-            Measure.getNormalFromCenter(points[k], points[i], points[j],
-                ptRef, false, normal);
-            normixesT[planeCount++] = (isFlat ? Normix
-                .get2SidedNormix(normal, bsTemp) : Normix.getNormixV(normal, 
bsTemp));
+            p[planeCount] = P3i.new3(isWindingOK ? i : j, isWindingOK ? j : i, 
nRef);
+            Measure.getNormalFromCenter(points[k], points[i], points[j], ptRef,
+                false, normal);
+            n[planeCount++] = (isFlat ? Normix.get2SidedNormix(normal,
+                bsT) : Normix.getNormixV(normal, bsT));
           }
           facet = faceId(i, k, -1);
-          if (isCollapsed || isFlat && facetCatalog.indexOf(facet) < 0) {
+          if (collapsed || isFlat && facetCatalog.indexOf(facet) < 0) {
             facetCatalog += facet;
-            planesT[ipt++] = (byte) (isWindingOK ? i : k);
-            planesT[ipt++] = (byte) nRef;
-            planesT[ipt++] = (byte) (isWindingOK ? k : i);
-            Measure.getNormalFromCenter(points[j], points[i], ptRef,
-                points[k], false, normal);
-            normixesT[planeCount++] = (isFlat ? Normix
-                .get2SidedNormix(normal, bsTemp) : Normix.getNormixV(normal, 
bsTemp));
+            p[planeCount] = P3i.new3(isWindingOK ? i : k, nRef,isWindingOK ? k 
: i);
+            Measure.getNormalFromCenter(points[j], points[i], ptRef, points[k],
+                false, normal);
+            n[planeCount++] = (isFlat ? Normix.get2SidedNormix(normal,
+                bsT) : Normix.getNormixV(normal, bsT));
           }
           facet = faceId(j, k, -1);
-          if (isCollapsed || isFlat && facetCatalog.indexOf(facet) < 0) {
+          if (collapsed || isFlat && facetCatalog.indexOf(facet) < 0) {
             facetCatalog += facet;
-            planesT[ipt++] = (byte) nRef;
-            planesT[ipt++] = (byte) (isWindingOK ? j : k);
-            planesT[ipt++] = (byte) (isWindingOK ? k : j);
-            Measure.getNormalFromCenter(points[i], ptRef, points[j],
-                points[k], false, normal);
-            normixesT[planeCount++] = (isFlat ? Normix
-                .get2SidedNormix(normal, bsTemp) : Normix.getNormixV(normal, 
bsTemp));
+            p[planeCount] = P3i.new3(nRef, isWindingOK ? j : k, isWindingOK ? 
k : j);
+            Measure.getNormalFromCenter(points[i], ptRef, points[j], points[k],
+                false, normal);
+            n[planeCount++] = (isFlat ? Normix.get2SidedNormix(normal,
+                bsT) : Normix.getNormixV(normal, bsT));
           }
           if (!isFlat) {
-            if (isCollapsed) {
+            if (collapsed) {
               nPoints++;
             } else {
               // finally, the standard face:
-              planesT[ipt++] = (byte) (isWindingOK ? i : j);
-              planesT[ipt++] = (byte) (isWindingOK ? j : i);
-              planesT[ipt++] = (byte) k;
-              normixesT[planeCount++] = Normix.getNormixV(normal, bsTemp);
+              p[planeCount] = P3i.new3(isWindingOK ? i : j, isWindingOK ? j : 
i, k);
+              n[planeCount++] = Normix.getNormixV(normal, bsT);
             }
           }
         }
       }
-    //Logger.debug("planeCount="+planeCount + " nPoints="+nPoints);
+    
+    
+    if (Logger.debugging)
+      Logger.info("planeCount=" + planeCount + " nPoints=" + nPoints);
     return new Polyhedron(centralAtom, ptCenter, nPoints, planeCount,
-        otherAtoms, normixesT, planesT, isCollapsed, faceCenterOffset, 
distanceFactor);
+        otherAtoms, n, p, collapsed, offset, factor);
   }
 
   private String faceId(int i, int j, int k) {

Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java        2015-06-10 
11:54:54 UTC (rev 20571)
+++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java        2015-06-11 
03:27:51 UTC (rev 20572)
@@ -1,6 +1,7 @@
 package org.jmol.shapespecial;
 
 import javajs.util.P3;
+import javajs.util.P3i;
 
 import org.jmol.java.BS;
 import org.jmol.modelset.Atom;
@@ -18,7 +19,7 @@
   int ptCenter;
   boolean visible;
   public final short[] normixes;
-  public byte[] planes;
+  public P3i[] planes;
   //int planeCount;
   public int visibilityFlags = 0;
   boolean collapsed = false;
@@ -28,7 +29,7 @@
   public short colixEdge = C.INHERIT_ALL;
 
   Polyhedron(Atom centralAtom, int ptCenter, int nPoints, int planeCount,
-      P3[] otherAtoms, short[] normixes, byte[] planes, boolean collapsed, 
float faceCenterOffset, float distanceFactor) {
+      P3[] otherAtoms, short[] normixes, P3i[] planes, boolean collapsed, 
float faceCenterOffset, float distanceFactor) {
     this.centralAtom = centralAtom;
     modelIndex = centralAtom.mi;
     this.ptCenter = ptCenter;
@@ -36,13 +37,15 @@
     this.visible = true;
     this.normixes = new short[planeCount];
     //this.planeCount = planeCount;
-    this.planes = new byte[planeCount * 3];
+    this.planes = new P3i[planeCount];
     for (int i = nPoints; --i >= 0;)
       vertices[i] = otherAtoms[i];
     for (int i = planeCount; --i >= 0;)
       this.normixes[i] = normixes[i];
-    for (int i = planeCount * 3; --i >= 0;)
-      this.planes[i] = planes[i];
+    for (int i = planeCount; --i >= 0;) {
+      P3i p = planes[i];
+      this.planes[i] = P3i.new3(p.x, p.y, p.z);
+    }
     this.collapsed = collapsed;
     this.faceCenterOffset = faceCenterOffset;
     this.distanceFactor = distanceFactor;

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2015-06-10 11:54:54 UTC 
(rev 20571)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2015-06-11 03:27:51 UTC 
(rev 20572)
@@ -14,8 +14,16 @@
 
 TODO: remove HTML5 dependency on synchronous file loading (check SCRIPT 
command for problems)
 
-Jmol.___JmolVersion="14.3.14_2015.06.10c"
+Jmol.___JmolVersion="14.3.15_2015.06.11"
 
+bug fix: polyhedra broken for number of vertices > 6.
+ -- needed smaller default distanceFactor (set to 1.5; formerly 1.85)
+ -- this setting is for any 
+  
+code: to be released 6/11/15
+
+JmolVersion="14.3.14_2015.06.10c"
+
 bug fix: "transparent" PNG images as echos in front still hide pixels
 
 code : PNG images with partial transparency are not supported. 

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
_______________________________________________
Jmol-commits mailing list
Jmol-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jmol-commits

Reply via email to