Revision: 20837
          http://sourceforge.net/p/jmol/code/20837
Author:   hansonr
Date:     2015-10-19 06:22:30 +0000 (Mon, 19 Oct 2015)
Log Message:
-----------
Jmol.___JmolVersion="14.4.0_2015.10.18"

bug fix: Polyhedra can have missing triangle for hexagonal faces
bug fix: calculate symmetry can break Jmol if unit cell has been changed
bug fix: DRAW POLYGON front/back nature of winding was reversed.

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java
    trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
    trunk/Jmol/src/org/jmol/scriptext/MathExt.java
    trunk/Jmol/src/org/jmol/shape/Echo.java
    trunk/Jmol/src/org/jmol/shape/Mesh.java
    trunk/Jmol/src/org/jmol/shape/MeshCollection.java
    trunk/Jmol/src/org/jmol/shape/Shape.java
    trunk/Jmol/src/org/jmol/shapecgo/CGO.java
    trunk/Jmol/src/org/jmol/shapespecial/Dipoles.java
    trunk/Jmol/src/org/jmol/shapespecial/Draw.java
    trunk/Jmol/src/org/jmol/shapespecial/Ellipsoids.java
    trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java
    trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java
    trunk/Jmol/src/org/jmol/shapesurface/Isosurface.java
    trunk/Jmol/src/org/jmol/shapesurface/IsosurfaceMesh.java
    trunk/Jmol/src/org/jmol/shapesurface/MolecularOrbital.java
    trunk/Jmol/src/org/jmol/shapesurface/Pmesh.java
    trunk/Jmol/src/org/jmol/symmetry/Symmetry.java
    trunk/Jmol/src/org/jmol/util/MeshCapper.java
    trunk/Jmol/src/org/jmol/viewer/Jmol.properties
    trunk/Jmol/src/org/jmol/viewer/PropertyManager.java

Modified: trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java
===================================================================
--- trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java        
2015-10-17 23:45:49 UTC (rev 20836)
+++ trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java        
2015-10-19 06:22:30 UTC (rev 20837)
@@ -67,10 +67,11 @@
     if (p.visibilityFlags == 0)
       return false;
     short[] colixes = ((Polyhedra) shape).colixes;
-    int iAtom = p.centralAtom.i;
-    short colix = (colixes == null || iAtom >= colixes.length ? C.INHERIT_ALL
+    int iAtom = (p.id == null ? p.centralAtom.i : -1);
+    short colix = (p.id != null ? p.colix : colixes == null || iAtom >= 
colixes.length ? C.INHERIT_ALL
         : colixes[iAtom]);
-    colix = C.getColixInherited(colix, p.centralAtom.colixAtom);
+    if (p.centralAtom != null)
+      colix =  C.getColixInherited(colix, p.centralAtom.colixAtom);
     boolean needTranslucent = false;
     if (C.renderPass2(colix)) {
       needTranslucent = true;

Modified: trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -3197,6 +3197,7 @@
     setShapeProperty(JC.SHAPE_POLYHEDRA, "init", Boolean.TRUE);
     float translucentLevel = Float.MAX_VALUE;
     int[] colorArgb = new int[] { Integer.MIN_VALUE };
+    String id = null;
     for (int i = 1; i < slen; ++i) {
       String propertyName = null;
       Object propertyValue = null;
@@ -3266,6 +3267,15 @@
         }
         propertyValue = Float.valueOf(floatParameter(++i));
         break;
+      case T.id:
+        if (i != 1)
+          invPO();
+        setShapeProperty(JC.SHAPE_POLYHEDRA, "id", stringParameter(++i));
+        setShapeProperty(JC.SHAPE_POLYHEDRA, "center", centerParameter(++i));
+        i = eval.iToken;
+        if (tokAt(++i) != T.to)
+          invPO();
+        //$FALL-THROUGH$
       case T.to:
         if (nAtomSets > 1)
           invPO();

Modified: trunk/Jmol/src/org/jmol/scriptext/MathExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/MathExt.java      2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/scriptext/MathExt.java      2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -1435,7 +1435,7 @@
    * 
    * @param mp
    * @param args
-   * @param tok0 
+   * @param tok0
    * @param isAtomProperty
    * @return true if no syntax problems
    * @throws ScriptException
@@ -1452,7 +1452,9 @@
       return mp.addXObj(vwr.extractProperty(args[0].value,
           args[1].value.toString(), -1));
     }
-    String propertyName = (args.length > 0 ? SV.sValue(args[pt++]) : "");
+    BS bsSelect = (isAtomProperty && args.length == 1 && args[0].tok == 
T.bitset ? SV.bsSelectVar(args[0]) : null);
+    String pname = (bsSelect == null && args.length > 0 ? 
SV.sValue(args[pt++]) : "");
+    String propertyName = pname;
     String lc = propertyName.toLowerCase();
     if (!isSelect && lc.indexOf("[select ") < 0)
       propertyName = lc;
@@ -1464,9 +1466,48 @@
     SV x = null;
     if (isAtomProperty) {
       x = mp.getX();
-      if (x.tok != T.bitset) {
+      switch (x.tok) {
+      case T.bitset:
+        break;
+      case T.string:
+        String name = (String) x.value;
+        Object[] data = new Object[3];
+        int shapeID;
+        if (name.startsWith("$")) {
+          // "P4".getProperty....
+          name = name.substring(1);
+          shapeID = vwr.shm.getShapeIdFromObjectName(name);
+          if (shapeID >= 0) {
+            data[0] = name;
+            vwr.shm.getShapePropertyData(shapeID, "index", data);
+            if (data[1] != null && !pname.equals("index")) {
+              int index = ((Integer) data[1]).intValue();
+                data[1] = vwr.shm.getShapePropertyIndex(shapeID,
+                    pname.intern(), index);
+            }
+          }
+        } else {
+          shapeID = JC.shapeTokenIndex(T.getTokFromName(name));
+          if (shapeID >= 0) {
+            // "isosurface".getProperty...
+            data[0] = pname;
+            data[1] = Integer.valueOf(-1);
+            vwr.shm.getShapePropertyData(shapeID, pname.intern(), data);
+          }
+        }
+        return (data[1] == null ? mp.addXStr("") : mp.addXObj(data[1]));
+      case T.varray:
+        if (bsSelect != null) {
+          Lst<SV> l0 = x.getList();
+          Lst<SV> lst = new Lst<SV>();
+          for (int i = bsSelect.nextSetBit(0); i >= 0; i = 
bsSelect.nextSetBit(i + 1))
+            lst.addLast(l0.get(i));
+          return mp.addXList(lst);
+        }
+        //$FALL-THROUGH$
+      default:
         if (isSelect)
-          propertyName = "[SELECT " + propertyName + "]"; 
+          propertyName = "[SELECT " + propertyName + "]";
         return mp.addXObj(vwr.extractProperty(x, propertyName, -1));
       }
     }
@@ -3121,9 +3162,9 @@
         plane = e.getHklPlane(pt);
       break;
     case T.varray:
-      if (last != 2)
+      pt = (last == 2 ? SV.ptValue(args[1]) : last == 1 ? P3.new3(Float.NaN, 
0, 0) : null);
+      if (pt == null)
         return false;
-      pt = SV.ptValue(args[1]);
       break;
     }
     if (last > 0 && plane == null && pt == null
@@ -3142,13 +3183,42 @@
     if (pt != null) {
       if (args[last].tok == T.varray) {
         // within(dist, pt, [pt1, pt2, pt3...])
-        Lst<SV> sv = args[2].getList();
+        Lst<SV> sv = args[last].getList();
         Lst<T3> pts = new Lst<T3>();
         Bspt bspt = new Bspt(3, 0);
-        for (int i = sv.size(); --i >= 0;) {
+        CubeIterator iter;
+        if (Float.isNaN(pt.x)) {
+          // internal comparison
+          Point3fi  p;
+          Point3fi[] pt3 = new Point3fi[sv.size()]; 
+          for (int i = pt3.length; --i >= 0;) {
+            p = new Point3fi();
+            p.setT(SV.ptValue(sv.get(i)));
+            p.i = i;
+            pt3[i] = p;
+            bspt.addTuple(p);
+          }
+          iter = bspt.allocateCubeIterator();
+          BS bsp = BSUtil.newBitSet2(0, sv.size());
+          for (int i = pt3.length; --i >= 0;) {
+            iter.initialize(p = pt3[i], distance, false);
+            float d2 = distance * distance;
+            int n = 0;
+            while (iter.hasMoreElements()) {
+              Point3fi pt2 = (Point3fi) iter.nextElement();
+              if (bsp.get(pt2.i) && pt2.distanceSquared(p) <= d2
+                  && (++n > 1))
+                bsp.clear(pt2.i);
+            }
+          }
+          for (int i = bsp.nextSetBit(0); i >= 0; i = bsp.nextSetBit(i + 1))  
+            pts.addLast(P3.newP(pt3[i]));
+          return mp.addXList(pts);
+        
+        }
+        for (int i = sv.size(); --i >= 0;)
           bspt.addTuple(SV.ptValue(sv.get(i)));
-        }
-        CubeIterator iter = bspt.allocateCubeIterator();
+        iter = bspt.allocateCubeIterator();
         iter.initialize(pt, distance, false);
         float d2 = distance * distance;
         while (iter.hasMoreElements()) {

Modified: trunk/Jmol/src/org/jmol/shape/Echo.java
===================================================================
--- trunk/Jmol/src/org/jmol/shape/Echo.java     2015-10-17 23:45:49 UTC (rev 
20836)
+++ trunk/Jmol/src/org/jmol/shape/Echo.java     2015-10-19 06:22:30 UTC (rev 
20837)
@@ -190,7 +190,7 @@
       }
       return false;
     }
-    return false;
+    return getPropShape(property, data);
   }
 
   @Override

Modified: trunk/Jmol/src/org/jmol/shape/Mesh.java
===================================================================
--- trunk/Jmol/src/org/jmol/shape/Mesh.java     2015-10-17 23:45:49 UTC (rev 
20836)
+++ trunk/Jmol/src/org/jmol/shape/Mesh.java     2015-10-19 06:22:30 UTC (rev 
20837)
@@ -503,12 +503,20 @@
     info.put("polygonCount", Integer.valueOf(pc));
     info.put("haveQuads", Boolean.valueOf(haveQuads));
     info.put("haveValues", Boolean.valueOf(vvs != null));
-    if (vc > 0 && isAll)
-      info.put("vertices", AU.arrayCopyPt(vs, vc));
-    if (vvs != null && isAll)
-      info.put("vertexValues", AU.arrayCopyF(vvs, vc));
-    if (pc > 0 && isAll)
-      info.put("polygons", AU.arrayCopyII(pis, pc));
+    if (isAll) {
+      if (vc > 0) {
+        info.put("vertices", AU.arrayCopyPt(vs, vc));
+        if (bsSlabDisplay != null)
+          info.put("bsVertices", getVisibleVBS());
+      }
+      if (vvs != null)
+        info.put("vertexValues", AU.arrayCopyF(vvs, vc));
+      if (pc > 0) {
+        info.put("polygons", AU.arrayCopyII(pis, pc));
+        if (bsSlabDisplay != null)
+          info.put("bsPolygons", bsSlabDisplay);
+      }
+    }
     return info;
   }
 

Modified: trunk/Jmol/src/org/jmol/shape/MeshCollection.java
===================================================================
--- trunk/Jmol/src/org/jmol/shape/MeshCollection.java   2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/shape/MeshCollection.java   2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -379,6 +379,13 @@
 
   @SuppressWarnings("unchecked")
   protected boolean getPropDataMC(String property, Object[] data) {
+    if (property == "keys") {
+      Lst<String> keys = (data[1] instanceof Lst<?> ? (Lst<String>) data[1] : 
new Lst<String>());
+      data[1] = keys;
+      keys.addLast("count");
+      keys.addLast("getCenter");
+      // will continue on to getPropertyIndex
+    }
     if (property == "getNames") {
       Map<String, T> map = (Map<String, T>) data[0];
       boolean withDollar = ((Boolean) data[1]).booleanValue();
@@ -404,6 +411,11 @@
       data[1] = list.get(0).thisID;
       return true;
     }
+    if (property == "index") {
+      Mesh m = getMesh((String) data[0]);
+      data[1] = Integer.valueOf(m == null ? -1 : m.index);
+      return true;
+    }    
     if (property == "getCenter") {
       String id = (String) data[0];
       int index = ((Integer) data[1]).intValue();
@@ -416,7 +428,7 @@
         data[2] = m.vs[m.getVertexIndexFromNumber(index)];
       return true;
     }
-    return false;
+    return getPropShape(property, data);
   }
 
   /**
@@ -445,8 +457,11 @@
     return list;
   }
 
-  protected Object getPropMC(String property) {
-    Mesh m;
+  protected Object getPropMC(String property, int index) {
+    Mesh m = currentMesh;
+    if (index >= 0
+        && (index >= meshCount || (m = meshes[index]) == null))
+      return null;
     if (property == "count") {
       int n = 0;
       for (int i = 0; i < meshCount; i++)
@@ -454,26 +469,34 @@
           n++;
       return Integer.valueOf(n);
     }
+    if (property == "bsVertices") {
+      if (m == null)
+        return null;
+      Lst<Object> lst = new Lst<Object>();
+      lst.addLast(m.vs);
+      lst.addLast(m.getVisibleVBS());
+      return lst;
+    }
     if (property == "ID")
-      return (currentMesh == null ? null : currentMesh.thisID);
+      return (m == null ? null : m.thisID);
     if (property.startsWith("list")) {
-          clean();
-          SB sb = new SB();
+      clean();
+      SB sb = new SB();
       int k = 0;
       boolean isNamed = property.length() > 5;
-      String id = (property.equals("list") ? null : isNamed ? 
property.substring(5) : currentMesh == null ? null : currentMesh.thisID);
+      String id = (property.equals("list") ? null : isNamed ? property
+          .substring(5) : m == null ? null : m.thisID);
       for (int i = 0; i < meshCount; i++) {
         m = meshes[i];
         if (id != null && !id.equalsIgnoreCase(m.thisID))
           continue;
-        sb.appendI((++k)).append(" id:" + m.thisID).append(
-            "; model:" + vwr.getModelNumberDotted(m.modelIndex)).append(
-            "; vertices:" + m.vc).append(
-            "; polygons:" + m.pc)
+        sb.appendI((++k)).append(" id:" + m.thisID)
+            .append("; model:" + vwr.getModelNumberDotted(m.modelIndex))
+            .append("; vertices:" + m.vc).append("; polygons:" + m.pc)
             .append("; visible:" + m.visible);
         float[] range = (float[]) getProperty("dataRange", 0);
         if (range != null)
-            sb.append("; dataRange:").append(Escape.eAF(range));
+          sb.append("; dataRange:").append(Escape.eAF(range));
         if (m.title != null) {
           String s = "";
           for (int j = 0; j < m.title.length; j++)
@@ -492,11 +515,11 @@
       return sb.toString();
     }
     if (property == "vertices")
-      return getVertices(currentMesh);
-    if (property == "getInfo")
-      return (currentMesh == null ? null : currentMesh.getInfo(false));
-    if (property == "getData")
-      return (currentMesh == null ? null : currentMesh.getInfo(true));
+      return getVertices(m);
+    if (property == "info")
+      return (m == null ? null : m.getInfo(false));
+    if (property == "data")
+      return (m == null ? null : m.getInfo(true));
 
     return null;
   }

Modified: trunk/Jmol/src/org/jmol/shape/Shape.java
===================================================================
--- trunk/Jmol/src/org/jmol/shape/Shape.java    2015-10-17 23:45:49 UTC (rev 
20836)
+++ trunk/Jmol/src/org/jmol/shape/Shape.java    2015-10-19 06:22:30 UTC (rev 
20837)
@@ -212,17 +212,6 @@
     // balls, dots, other atomshapes
   }
 
-  /**
-   * 
-   * @param property
-   * @param data
-   * @return true if serviced
-   */
-  public boolean getPropertyData(String property, Object[] data) {
-    return false;
-  }
-
-
   @SuppressWarnings("unchecked")
   protected void setPropS(String propertyName, Object value, BS bsSelected) {
     if (propertyName == "setProperties") {
@@ -250,6 +239,25 @@
   /**
    * 
    * @param property
+   * @param data
+   * @return true if serviced
+   */
+  public boolean getPropertyData(String property, Object[] data) {
+    return getPropShape(property, data);
+  }
+
+  protected boolean getPropShape(String property, Object[] data) {
+    if (data[1] instanceof Integer) {
+       int index = ((Integer) data[1]).intValue();
+       data[1] = getProperty(property, index);
+       return (data[1] != null);
+     }
+    return false;
+   }
+
+  /**
+   * 
+   * @param property
    * @param index
    * @return true if serviced
    */

Modified: trunk/Jmol/src/org/jmol/shapecgo/CGO.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapecgo/CGO.java   2015-10-17 23:45:49 UTC (rev 
20836)
+++ trunk/Jmol/src/org/jmol/shapecgo/CGO.java   2015-10-19 06:22:30 UTC (rev 
20837)
@@ -108,7 +108,14 @@
   }
   
   @Override
+  @SuppressWarnings("unchecked")
   public boolean getPropertyData(String property, Object[] data) {
+    if (property == "keys") {
+      Lst<String> keys = (data[1] instanceof Lst<?> ? (Lst<String>) data[1] : 
new Lst<String>());
+      data[1] = keys;
+      keys.addLast("data");
+      // will continue on to getPropertyIndex
+    }
     if (property == "data")
       return CGOMesh.getData(data);
     return getPropDataMC(property, data);

Modified: trunk/Jmol/src/org/jmol/shapespecial/Dipoles.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Dipoles.java   2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/shapespecial/Dipoles.java   2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -423,7 +423,7 @@
       }
       return false;
     }
-    return false;
+    return getPropShape(property, data);
   }
   
   @Override

Modified: trunk/Jmol/src/org/jmol/shapespecial/Draw.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Draw.java      2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/shapespecial/Draw.java      2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -478,8 +478,15 @@
     }    
   }
 
+  @SuppressWarnings("unchecked")
   @Override
   public boolean getPropertyData(String property, Object[] data) {
+    if (property == "keys") {
+      Lst<String> keys = (data[1] instanceof Lst<?> ? (Lst<String>) data[1] : 
new Lst<String>());
+      data[1] = keys;
+      keys.addLast("getSpinAxis");
+      // will continue on to super
+    }
     if (property == "getCenter") {
       String id = (String) data[0];
       int index = ((Integer) data[1]).intValue();
@@ -498,11 +505,14 @@
 
   @Override
   public Object getProperty(String property, int index) {
+    DrawMesh m = this.thisMesh;
+    if (index >= 0 && (index >= meshCount || (m = (DrawMesh) meshes[index]) == 
null))
+      return null;
     if (property == "command")
-      return getCommand(thisMesh);
+      return getCommand(m);
     if (property == "type")
-      return Integer.valueOf(thisMesh == null ? EnumDrawType.NONE.id : 
thisMesh.drawType.id);
-    return getPropMC(property);
+      return Integer.valueOf(m == null ? EnumDrawType.NONE.id : m.drawType.id);
+    return getPropMC(property, index);
   }
 
   private T3 getSpinCenter(String axisID, int vertexIndex, int modelIndex) {

Modified: trunk/Jmol/src/org/jmol/shapespecial/Ellipsoids.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Ellipsoids.java        2015-10-17 
23:45:49 UTC (rev 20836)
+++ trunk/Jmol/src/org/jmol/shapespecial/Ellipsoids.java        2015-10-19 
06:22:30 UTC (rev 20837)
@@ -117,7 +117,7 @@
     if (property == "checkID") {
       return (checkID((String) data[0]));
     }
-    return false;
+    return getPropShape(property, data);
   }
 
 

Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -95,6 +95,8 @@
   private boolean haveBitSetVertices;
 
   private BS centers;
+  private String thisID;
+  private P3 center;
   private BS bsVertices;
   private BS bsVertexCount;
 
@@ -116,6 +118,8 @@
       nVertices = 0;
       nPoints = 0;
       bsVertices = null;
+      thisID = null;
+      center = null;
       useUnitCell = false;
       centers = null;
       info = null;
@@ -137,6 +141,16 @@
       return;
     }
 
+    if ("center" == propertyName) {
+      center = (P3) value;
+      return;
+    }
+
+    if ("id" == propertyName) {
+      thisID = (String) value;
+      return;
+    }
+
     if ("collapsed" == propertyName) {
       isCollapsed = ((Boolean) value).booleanValue();
       return;
@@ -250,14 +264,28 @@
       // but from Color we need to identify the centers.
       bs = ("colorThis" == propertyName && iHaveCenterBitSet ? centers
           : andBitSet(bs));
+      Object cvalue = ("colorPhase" == propertyName ? ((Object[]) value)[1]
+          : value);
       short colixEdge = ("colorPhase" == propertyName ? C
           .getColix(((Integer) ((Object[]) value)[0]).intValue())
           : C.INHERIT_ALL);
-      for (int i = polyhedronCount; --i >= 0;)
-        if (bs.get(polyhedrons[i].centralAtom.i))
-          polyhedrons[i].colixEdge = colixEdge;
-      if ("colorPhase" == propertyName)
-        value = ((Object[]) value)[1];
+      for (int i = polyhedronCount; --i >= 0;) {
+        Polyhedron p = polyhedrons[i];
+        if (thisID != null) {
+          if (thisID == p.id) {
+            p.colixEdge = colixEdge;
+            isActive = true;
+            p.colix = C.getColixO(value);
+            return;
+          }
+        } else {
+          if (bs.get(p.centralAtom.i))
+            p.colixEdge = colixEdge;
+        }
+      }
+      if (thisID != null)
+        return;
+      value = cvalue;
       propertyName = "color";
       //allow super
     }
@@ -272,15 +300,15 @@
       //allow super
     }
 
-//    if ("token" == propertyName) {
-//      int tok = ((Integer) value).intValue();
-//      Swit
-//      if (tok == T.triangles && tok == T.notriangles) {
-//      } else {
-//        setLighting(tok == T.fullylit, bs);
-//      }
-//      return;
-//    }
+    //    if ("token" == propertyName) {
+    //      int tok = ((Integer) value).intValue();
+    //      Swit
+    //      if (tok == T.triangles && tok == T.notriangles) {
+    //      } else {
+    //        setLighting(tok == T.fullylit, bs);
+    //      }
+    //      return;
+    //    }
 
     if ("radius" == propertyName) {
       radius = ((Float) value).floatValue();
@@ -390,7 +418,7 @@
       }
       return false;
     }
-    return false;
+    return getPropShape(property, data);
   }
 
   @Override
@@ -445,51 +473,59 @@
     }
   }
 
-  private int buildMode;
-
   private void buildPolyhedra() {
-    boolean useBondAlgorithm = radius == 0 || bondedOnly;
-    buildMode = (info != null ? MODE_INFO : nPoints > 0 ? MODE_POINTS
-        : haveBitSetVertices ? MODE_BITSET : useUnitCell ? MODE_UNITCELL
-            : useBondAlgorithm ? MODE_BONDING : MODE_RADIUS);
-    AtomIndexIterator iter = (buildMode == MODE_RADIUS ? ms
-        .getSelectedAtomIterator(null, false, false, false, false) : null);
-    for (int i = centers.nextSetBit(0); i >= 0; i = centers.nextSetBit(i + 1)) 
{
-      Atom atom = atoms[i];
-      Polyhedron p = null;
-      switch (buildMode) {
-      case MODE_BITSET:
-        p = constructBitSetPolyhedron(atom);
-        break;
-      case MODE_UNITCELL:
-        p = constructUnitCellPolygon(atom, useBondAlgorithm);
-        break;
-      case MODE_BONDING:
-        p = constructBondsPolyhedron(atom, 0);
-        break;
-      case MODE_RADIUS:
-        vwr.setIteratorForAtom(iter, i, radius);
-        p = constructRadiusPolyhedron(atom, iter);
-        break;
-      case MODE_INFO:
-        p = new Polyhedron().setInfo(info, vwr.ms.at);
-        break;
-      case MODE_POINTS:
-        p = validatePolyhedron(atom, nPoints);
-        break;
+    Polyhedron p = null;
+    if (center != null) {
+      p = validatePolyhedron(center, nPoints);
+      if (p != null)
+        addPolyhedron(p);
+    } else {
+      boolean useBondAlgorithm = radius == 0 || bondedOnly;
+      int buildMode = (info != null ? MODE_INFO : nPoints > 0 ? MODE_POINTS
+          : haveBitSetVertices ? MODE_BITSET : useUnitCell ? MODE_UNITCELL
+              : useBondAlgorithm ? MODE_BONDING : MODE_RADIUS);
+      AtomIndexIterator iter = (buildMode == MODE_RADIUS ? ms
+          .getSelectedAtomIterator(null, false, false, false, false) : null);
+      for (int i = centers.nextSetBit(0); i >= 0; i = centers.nextSetBit(i + 
1)) {
+        Atom atom = atoms[i];
+        p = null;
+        switch (buildMode) {
+        case MODE_BITSET:
+          p = constructBitSetPolyhedron(atom);
+          break;
+        case MODE_UNITCELL:
+          p = constructUnitCellPolygon(atom, useBondAlgorithm);
+          break;
+        case MODE_BONDING:
+          p = constructBondsPolyhedron(atom, 0);
+          break;
+        case MODE_RADIUS:
+          vwr.setIteratorForAtom(iter, i, radius);
+          p = constructRadiusPolyhedron(atom, iter);
+          break;
+        case MODE_INFO:
+          p = new Polyhedron().setInfo(info, vwr.ms.at);
+          break;
+        case MODE_POINTS:
+          p = validatePolyhedron(atom, nPoints);
+          break;
+        }
+        if (p != null)
+          addPolyhedron(p);
+        if (haveBitSetVertices)
+          break;
       }
-      if (p != null) {
-        if (polyhedronCount == polyhedrons.length)
-          polyhedrons = (Polyhedron[]) AU.doubleLength(polyhedrons);
-        polyhedrons[polyhedronCount++] = p;
-      }
-      if (haveBitSetVertices)
-        break;
+      if (iter != null)
+        iter.release();
     }
-    if (iter != null)
-      iter.release();
   }
 
+  private void addPolyhedron(Polyhedron p) {
+    if (polyhedronCount == polyhedrons.length)
+      polyhedrons = (Polyhedron[]) AU.doubleLength(polyhedrons);
+    polyhedrons[polyhedronCount++] = p;
+  }
+
   private Polyhedron constructBondsPolyhedron(Atom atom, int otherAtomCount) {
     if (otherAtomCount == 0) {
       Bond[] bonds = atom.bonds;
@@ -593,7 +629,7 @@
         otherAtomCount));
   }
 
-  private Polyhedron validatePolyhedron(Atom centralAtom, int vertexCount) {
+  private Polyhedron validatePolyhedron(P3 atomOrPt, int vertexCount) {
     P3[] points = otherAtoms;
     boolean collapsed = isCollapsed;
     int triangleCount = 0;
@@ -603,8 +639,8 @@
     float planarParam = (Float.isNaN(this.planarParam) ? DEFAULT_PLANAR_PARAM
         : this.planarParam);
 
-    points[vertexCount] = centralAtom;
-    P3 ptAve = P3.newP(centralAtom);
+    points[vertexCount] = atomOrPt;
+    P3 ptAve = P3.newP(atomOrPt);
     for (int i = 0; i < vertexCount; i++)
       ptAve.add(points[i]);
     ptAve.scale(1f / (vertexCount + 1));
@@ -674,7 +710,7 @@
             bsCenterPlanes.set(triangleCount++);
           } else if (collapsed) {
             ptRef.setT(points[nPoints] = new P3());
-            points[nPoints].scaleAdd2(offset, normal, centralAtom);
+            points[nPoints].scaleAdd2(offset, normal, atomOrPt);
             addFacet(i, j, k, ptRef, points, normals, triangles, 
triangleCount++, nPoints,
                 isWindingOK, vAC);
             addFacet(k, i, j, ptRef, points, normals, triangles, 
triangleCount++, nPoints,
@@ -695,7 +731,7 @@
         Logger.info("Polyhedron " + PT.toJSON("face[" +i + "]", triangles[i]));
     }
     //System.out.println(PT.toJSON(null, htEdgeMap));
-    return new Polyhedron().set(centralAtom, points, nPoints, vertexCount,
+    return new Polyhedron().set(thisID, atomOrPt, points, nPoints, vertexCount,
         triangles, triangleCount, getFaces(triangles, triangleCount, 
htNormMap), normals, bsCenterPlanes, collapsed, distanceRef);
   }
   
@@ -777,6 +813,8 @@
     }
     V3 norm = normals[index];
     Integer normix = Integer.valueOf(Normix.getNormixV(norm, bsTemp));
+    //if (normix != 629)
+      //return  false;
     Object[] o = htNormMap.get(normix);
     //System.out.println(PT.toJSON(null, p1) + " " + normix);
     if (o == null) {
@@ -837,6 +875,7 @@
     String edge = normix + s + s1;
     if (htEdgeMap.containsKey(edge))
       return false;
+    //    System.out.println(edge);
     //reverse maps are in
     String edge0 = normix + s1 + s;
     Object o = htEdgeMap.get(edge0);
@@ -867,6 +906,8 @@
     } else {
       // set mask to exclude both of these.
       int[] p10 = (int[]) ((Object[]) o)[0];
+      if (p10 == null)
+        return false; // already seen
       int i0 = ((Integer) ((Object[]) o)[1]).intValue();
       p10[3] = -((-p10[3]) ^ (1 << i0));
       p1[3] = -((-p1[3]) ^ (1 << i));
@@ -879,6 +920,8 @@
         }
       }
       // not supported for JavaScript faceList.removeObj(b);
+      htEdgeMap.put(edge, new Object[] {null});
+      htEdgeMap.put(edge0, new Object[] {null});
     }
     return true;
   }
@@ -952,13 +995,17 @@
     */
     for (int i = polyhedronCount; --i >= 0;) {
       Polyhedron p = polyhedrons[i];
-      if (ms.at[p.centralAtom.i].isDeleted())
-        p.isValid = false;
-      p.visibilityFlags = (p.visible && bsModels.get(p.centralAtom.mi)
-          && !ms.isAtomHidden(p.centralAtom.i)
-          && !ms.at[p.centralAtom.i].isDeleted() ? vf : 0);
-      if (p.visibilityFlags != 0)
-        setShapeVisibility(atoms[p.centralAtom.i], true);
+      if (p.id != null) {
+        p.visibilityFlags = (p.visible ? vf : 0);
+      } else {
+        if (ms.at[p.centralAtom.i].isDeleted())
+          p.isValid = false;
+        p.visibilityFlags = (p.visible && bsModels.get(p.centralAtom.mi)
+            && !ms.isAtomHidden(p.centralAtom.i)
+            && !ms.at[p.centralAtom.i].isDeleted() ? vf : 0);
+        if (p.visibilityFlags != 0)
+          setShapeVisibility(atoms[p.centralAtom.i], true);
+      }
     }
   }
 
@@ -977,7 +1024,7 @@
     s.append(vwr.getAtomShapeState(this));
     for (int i = 0; i < polyhedronCount; i++) {
       Polyhedron p = polyhedrons[i];
-      if (p.isValid && p.colixEdge != C.INHERIT_ALL
+      if (p.isValid && p.id == null && p.colixEdge != C.INHERIT_ALL
           && bsColixSet.get(p.centralAtom.i))
         appendCmd(
             s,

Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java        2015-10-17 
23:45:49 UTC (rev 20836)
+++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java        2015-10-19 
06:22:30 UTC (rev 20837)
@@ -48,14 +48,19 @@
   public boolean isValid = true;
   public short colixEdge = C.INHERIT_ALL;
   public int visibilityFlags = 0;
+  P3 center;
+  public String id;
 
   Polyhedron() {  
   }
   
-  Polyhedron set(Atom centralAtom, P3[] points, int nPoints, int vertexCount,
+  Polyhedron set(String id, P3 atomOrPt, P3[] points, int nPoints, int 
vertexCount,
       int[][] triangles, int triangleCount, int[][] faces, V3[] normals, BS 
bsFlat, boolean collapsed, float distanceRef) {
+    
     this.distanceRef = distanceRef;
-    this.centralAtom = centralAtom;
+    centralAtom = (id == null  ? (Atom) atomOrPt : null);
+    center = (centralAtom == null ? (P3) atomOrPt : null);
+    this.id = id;
     this.nVertices = vertexCount;
     this.vertices = new P3[nPoints + 1];
     this.normals = new V3[triangleCount];
@@ -76,7 +81,11 @@
   Polyhedron setInfo(Map<String, SV> info, Atom[] at) {
     try {
       collapsed = info.containsKey("collapsed");
-      centralAtom = at[info.get("atomIndex").intValue];
+      center = (info.containsKey("center") ? P3.newP(SV.ptValue(info
+          .get("center"))) : null);
+      if (center == null) {
+        centralAtom = at[info.get("atomIndex").intValue];
+      }
       Lst<SV> lst = info.get("vertices").getList();
       SV vc = info.get("vertexCount");
       if (vc == null) {
@@ -141,6 +150,7 @@
   }
 
   Map<String, Object> info;
+  public short colix;
   
   Map<String, Object> getInfo(Viewer vwr, boolean isAll) {
     if (isAll && this.info != null && !Logger.debugging)
@@ -151,8 +161,10 @@
       info.put("modelIndex", Integer.valueOf(centralAtom.mi));
       info.put("modelNumber", Integer.valueOf(centralAtom.getModelNumber()));
       info.put("center", P3.newP(centralAtom));
-      info.put("atomNumber", Integer.valueOf(centralAtom.getAtomNumber()));
-      info.put("atomName", centralAtom.getInfo());
+      if (center == null) {
+        info.put("atomNumber", Integer.valueOf(centralAtom.getAtomNumber()));
+        info.put("atomName", centralAtom.getInfo());
+      }
       info.put("element", centralAtom.getElementSymbol());
       info.put("triangleCount", Integer.valueOf(triangles.length));
       info.put("volume", getVolume());
@@ -193,7 +205,12 @@
       info.put("triangles", AU.arrayCopyII(triangles, triangles.length));
     }
     info.put("vertexCount", Integer.valueOf(nVertices));
-    info.put("atomIndex", Integer.valueOf(centralAtom.i));
+    if (center == null) {
+      info.put("atomIndex", Integer.valueOf(centralAtom.i));
+    } else {
+      info.put("id", id);
+      info.put("center", P3.newP(center));
+    }
     info.put("vertices",
         AU.arrayCopyPt(vertices, (isAll ? nVertices : vertices.length)));
     int[] elemNos = new int[nVertices];
@@ -207,6 +224,8 @@
   }
 
   String getSymmetry(Viewer vwr, boolean withPointGroup) {
+    if (id != null)
+      return "";
     info = null;
     SmilesMatcherInterface sm = vwr.getSmilesMatcher();
     try {
@@ -261,9 +280,10 @@
   }
 
   String getState(Viewer vwr) {
+    String ident = (id == null ? "({"+centralAtom.i+"})" : "ID " + 
Escape.e(id));
     return "  polyhedron @{" + Escape.e(getInfo(vwr, false)) + "} " 
         + (isFullyLit ? " fullyLit" : "") + ";"
-        + (visible ? "" : "polyhedra ({"+centralAtom.i+"}) off;") + "\n";
+        + (visible ? "" : "polyhedra " + ident + " off;") + "\n";
   }
 
   public void move(M4 mat) {
@@ -289,4 +309,5 @@
     }
     return normixes;
   }
+
 }

Modified: trunk/Jmol/src/org/jmol/shapesurface/Isosurface.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapesurface/Isosurface.java        2015-10-17 
23:45:49 UTC (rev 20836)
+++ trunk/Jmol/src/org/jmol/shapesurface/Isosurface.java        2015-10-19 
06:22:30 UTC (rev 20837)
@@ -222,7 +222,7 @@
         return;
       String id = currentMesh.thisID;
       int imodel = currentMesh.modelIndex;
-      vwr.cachePut("cache://isosurface_" + id, getPropI("jvxlDataXml"));
+      vwr.cachePut("cache://isosurface_" + id, getPropI("jvxlDataXml", -1));
       deleteMeshI(currentMesh.index);
       setPropI("init", null, null);
       setPropI("thisID", id, null);
@@ -782,18 +782,24 @@
       sg.setJvxlData(jvxlData);
   }
 
+  
   @SuppressWarnings("unchecked")
   @Override
   public boolean getPropertyData(String property, Object[] data) {
+    if (property == "keys") {
+      Lst<String> keys = (data[1] instanceof Lst<?> ? (Lst<String>) data[1] : 
new Lst<String>());
+      data[1] = keys;
+      keys.addLast("info");
+      keys.addLast("data");
+      // will continue on to super
+    }
     if (property == "colorEncoder") {
       IsosurfaceMesh mesh = (IsosurfaceMesh) getMesh((String) data[0]);
-      if (mesh == null || (data[1] = mesh.colorEncoder) == null)
-        return false;
-      return true;
+      return (mesh != null && (data[1] = mesh.colorEncoder) != null);
     }
     if (property == "intersectPlane") {
       IsosurfaceMesh mesh = (IsosurfaceMesh) getMesh((String) data[0]);
-      if (mesh == null)
+      if (mesh == null || data.length < 4)
         return false;
       data[3] = Integer.valueOf(mesh.modelIndex);
       mesh.getMeshSlicer().getIntersection(0, (P4) data[1], null, (Lst<P3[]>) 
data[2], null, null, null, false, false, T.plane, false);
@@ -847,13 +853,16 @@
 
   @Override
   public Object getProperty(String property, int index) {
-    return getPropI(property);
+    return getPropI(property, index);
   }
 
-  protected Object getPropI(String property) {
-    Object ret = getPropMC(property);
+  protected Object getPropI(String property, int index) {
+    IsosurfaceMesh thisMesh = this.thisMesh;
+    if (index >= 0 && (index >= meshCount || (thisMesh = isomeshes[index]) == 
null))
+      return null;
+    Object ret = getPropMC(property, index);
     if (ret != null)
-      return ret;
+      return ret;      
     if (property == "message") {
       String s = "";
       if (shapeID == JC.SHAPE_ISOSURFACE)
@@ -861,13 +870,13 @@
       if (jvxlData.dataMin != Float.MAX_VALUE)
         s += " min=" + jvxlData.dataMin + " max=" + jvxlData.dataMax;
       s += "; " + JC.shapeClassBases[shapeID].toLowerCase() + " count: "
-          + getPropMC("count");
-      return s + getPropI("dataRangeStr") + jvxlData.msg;
+          + getPropMC("count", index);
+      return s + getPropI("dataRangeStr", index) + jvxlData.msg;
     }
     if (property == "dataRange")
-      return getDataRange();
+      return getDataRange(thisMesh);
     if (property == "dataRangeStr") {
-      float[] dataRange = getDataRange();
+      float[] dataRange = getDataRange(thisMesh);
       return (dataRange != null && dataRange[0] != Float.MAX_VALUE
           && dataRange[0] != dataRange[1] ? "\nisosurface"
           + " full data range " + dataRange[0] + " to " + dataRange[1]
@@ -881,9 +890,9 @@
     if (property == "nSets")
       return Integer.valueOf(thisMesh == null ? 0 : thisMesh.nSets);
     if (property == "area") // could be Float or double[]
-      return (thisMesh == null ? Float.valueOf(Float.NaN) : 
calculateVolumeOrArea(true));
+      return (thisMesh == null ? Float.valueOf(Float.NaN) : 
calculateVolumeOrArea(thisMesh, true));
     if (property == "volume") // could be Float or double[]
-      return (thisMesh == null ? Float.valueOf(Float.NaN) : 
calculateVolumeOrArea(false));
+      return (thisMesh == null ? Float.valueOf(Float.NaN) : 
calculateVolumeOrArea(thisMesh, false));
     if (thisMesh == null)
       return null;//"no current isosurface";
     if (property == "cutoff")
@@ -899,7 +908,7 @@
       jvxlData.slabInfo = null;
       if (property == "jvxlMeshXml" || jvxlData.vertexDataOnly || 
thisMesh.bsSlabDisplay != null && thisMesh.bsSlabGhost == null) {
         meshData = new MeshData();
-        fillMeshData(meshData, MeshData.MODE_GET_VERTICES, null);
+        fillMeshData(meshData, MeshData.MODE_GET_VERTICES, thisMesh);
         meshData.polygonColorData = getPolygonColorData(meshData.pc, 
meshData.pcs, (meshData.colorsExplicit ? meshData.pis : null), 
meshData.bsSlabDisplay);
       } else if (thisMesh.bsSlabGhost != null) {
         jvxlData.slabInfo = thisMesh.slabOptions.toString();
@@ -915,7 +924,7 @@
     }
     if (property == "command") {
       SB sb = new SB();
-      Lst<Mesh> list = getMeshList(previousMeshID, false);
+      Lst<Mesh> list = getMeshList((index < 0 ? previousMeshID : 
thisMesh.thisID), false);
       for (int i = list.size(); --i >= 0;)
          getMeshCommand(sb, i);
       return sb.toString();
@@ -923,41 +932,34 @@
     return null;
   }
 
-  private float[] getDataRange() {
-    return (thisMesh == null || jvxlData.jvxlPlane != null
-        && thisMesh.colorEncoder == null ? null : new float[] {
-        jvxlData.mappedDataMin,
-        jvxlData.mappedDataMax,
-        (jvxlData.isColorReversed ? jvxlData.valueMappedToBlue
-            : jvxlData.valueMappedToRed),
-        (jvxlData.isColorReversed ? jvxlData.valueMappedToRed
-            : jvxlData.valueMappedToBlue) });
+  private float[] getDataRange(IsosurfaceMesh mesh) {
+    return (mesh == null ? null : mesh.getDataRange());
   }
 
-  private Object calculateVolumeOrArea(boolean isArea) {
+  private Object calculateVolumeOrArea(IsosurfaceMesh mesh, boolean isArea) {
     if (isArea) {
-      if (thisMesh.calculatedArea != null)
-        return thisMesh.calculatedArea;
+      if (mesh.calculatedArea != null)
+        return mesh.calculatedArea;
     } else {
-      if (thisMesh.calculatedVolume != null)
-        return thisMesh.calculatedVolume;
+      if (mesh.calculatedVolume != null)
+        return mesh.calculatedVolume;
     }
     MeshData meshData = new MeshData();
-    fillMeshData(meshData, MeshData.MODE_GET_VERTICES, null);
-    meshData.nSets = thisMesh.nSets;
-    meshData.vertexSets = thisMesh.vertexSets;
-    if (!isArea && thisMesh.jvxlData.colorDensity) {
-      float f = thisMesh.jvxlData.voxelVolume;
-      f *= (thisMesh.bsSlabDisplay == null ? thisMesh.vc : 
thisMesh.bsSlabDisplay.cardinality());
-      return  thisMesh.calculatedVolume = Float.valueOf(f); 
+    fillMeshData(meshData, MeshData.MODE_GET_VERTICES, mesh);
+    meshData.nSets = mesh.nSets;
+    meshData.vertexSets = mesh.vertexSets;
+    if (!isArea && mesh.jvxlData.colorDensity) {
+      float f = mesh.jvxlData.voxelVolume;
+      f *= (mesh.bsSlabDisplay == null ? mesh.vc : 
mesh.bsSlabDisplay.cardinality());
+      return  mesh.calculatedVolume = Float.valueOf(f); 
     }
-    Object ret = MeshData.calculateVolumeOrArea(meshData, 
thisMesh.jvxlData.thisSet, isArea, false);
-    if (thisMesh.nSets <= 0)
-      thisMesh.nSets = -meshData.nSets;
+    Object ret = MeshData.calculateVolumeOrArea(meshData, 
mesh.jvxlData.thisSet, isArea, false);
+    if (mesh.nSets <= 0)
+      mesh.nSets = -meshData.nSets;
     if (isArea)
-      thisMesh.calculatedArea = ret;
+      mesh.calculatedArea = ret;
     else
-      thisMesh.calculatedVolume = ret;
+      mesh.calculatedVolume = ret;
     return ret;
   }
 

Modified: trunk/Jmol/src/org/jmol/shapesurface/IsosurfaceMesh.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapesurface/IsosurfaceMesh.java    2015-10-17 
23:45:49 UTC (rev 20836)
+++ trunk/Jmol/src/org/jmol/shapesurface/IsosurfaceMesh.java    2015-10-19 
06:22:30 UTC (rev 20837)
@@ -1003,4 +1003,15 @@
     recalcAltVertices = true;
   }
 
+  float[] getDataRange() {
+    return (jvxlData.jvxlPlane != null
+        && colorEncoder == null ? null : new float[] {
+        jvxlData.mappedDataMin,
+        jvxlData.mappedDataMax,
+        (jvxlData.isColorReversed ? jvxlData.valueMappedToBlue
+            : jvxlData.valueMappedToRed),
+        (jvxlData.isColorReversed ? jvxlData.valueMappedToRed
+            : jvxlData.valueMappedToBlue) });
+  }
+
 }

Modified: trunk/Jmol/src/org/jmol/shapesurface/MolecularOrbital.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapesurface/MolecularOrbital.java  2015-10-17 
23:45:49 UTC (rev 20836)
+++ trunk/Jmol/src/org/jmol/shapesurface/MolecularOrbital.java  2015-10-19 
06:22:30 UTC (rev 20837)
@@ -315,11 +315,11 @@
 
   @SuppressWarnings("unchecked")
   @Override
-  public Object getProperty(String propertyName, int param) {
+  public Object getProperty(String propertyName, int index) {
     if (propertyName.startsWith("list")) {
       String s = "";
       if (propertyName.equals("list")) {
-        s = (String) getPropI("list");
+        s = (String) getPropI("list", index);
         if (s.length() > 1)
           s += "cutoff = " + jvxlData.cutoff + "\n";
         s = "\n" + s;
@@ -335,7 +335,7 @@
       Lst<Map<String, Object>> mos = (Lst<Map<String, Object>>) 
(sg.params.moData
           .get("mos"));
       int nOrb = (mos == null ? 0 : mos.size());
-      int thisMO = param;
+      int thisMO = index;
       int currentMO = moNumber;
       boolean isShowCurrent = (thisMO == Integer.MIN_VALUE);
       if (thisMO == Integer.MAX_VALUE) {
@@ -374,7 +374,7 @@
           true, 0, null, null));
       return str.toString();
     }
-    return getPropI(propertyName);
+    return getPropI(propertyName, index);
   }
 
   @SuppressWarnings("unchecked")

Modified: trunk/Jmol/src/org/jmol/shapesurface/Pmesh.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapesurface/Pmesh.java     2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/shapesurface/Pmesh.java     2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -24,10 +24,106 @@
 
 package org.jmol.shapesurface;
 
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.jmol.shape.Mesh;
+
+import javajs.util.Measure;
+import javajs.util.P3;
+import javajs.util.T3;
+import javajs.util.V3;
+
 public class Pmesh extends Isosurface {
   @Override
   public void initShape() {
     super.initShape();
     myType = "pmesh";
   }
+  
+  @Override
+  public Object getProperty(String property, int index) {
+    if (property == "face") {
+      Mesh m = currentMesh;
+      if (index >= 0
+          && (index >= meshCount || (m = meshes[index]) == null))
+        return null;
+      return  m == null ? null : getFace(m);
+    }
+    return getPropI(property, index);
+  }
+  
+  /**
+   * return a cycle of points generating this face
+   * used after slabbing
+   * 
+   * @param m
+   * @return set of points constituting this face
+   */
+  private P3[] getFace(Mesh m) {
+    if (m.haveQuads)
+      return null;
+    T3[] vs = m.vs;
+    Map<String, int[]> htEdges = new Hashtable<String, int[]>();
+    int v1 = 0;
+    int n = 0;
+    for (int i = m.pc; --i >= 0;) {
+      if (m.bsSlabDisplay != null && !m.bsSlabDisplay.get(i))
+        continue;
+      int[] face = m.pis[i];
+      int mask = face[3];
+      for (int j = 0; j < 3; j++)
+        if ((mask & (1 << j)) != 0) {
+          v1 = face[j];
+          int v2 = face[(j + 1) % 3];
+          String key = v2 + "_" + v1;
+          if (htEdges.containsKey(key)) {
+            htEdges.remove(key);
+            n--;
+          } else {
+            n++;
+            htEdges.put(v1 + "_" + v2, new int[] { v1, v2 });
+            htEdges.put("" + v1, new int[] { v1, v2 });
+          }
+        }
+    }
+    if (n == 0)
+      return null;
+    int[][] a = new int[n][2];
+    for (String e : htEdges.keySet()) {
+      a[0] = htEdges.get(e);
+      break;
+    }
+    V3 vectorBA = new V3();
+    V3 vectorBC = new V3();
+    int v0 = a[0][0];
+    int v01 = v0;
+    v1 = a[0][1];
+    int pt = 0;
+    while (v1 != v0) {
+      int[] edge = htEdges.get("" + v1);
+      if (edge == null)
+        break;
+      float angle = Measure.computeAngle(vs[v01], vs[v1], vs[edge[1]],
+          vectorBA, vectorBC, true);
+      v1 = edge[1];
+      if (angle < 179) {
+        a[++pt] = edge;
+        v01 = edge[0];
+      } else {
+        a[pt][1] = v1;
+      }
+    }
+    if (Measure.computeAngle(vs[v01], vs[v1], vs[a[0][1]],
+          vectorBA, vectorBC, true) >= 179) {
+      a[0][0] = a[pt--][0];
+    }
+    n = ++pt;
+    P3[] pts = new P3[n];
+    for (int i = 0; i < n; i++)
+      pts[i] = P3.newP(vs[a[i][0]]);
+    return pts;
+  }
+
+
 }

Modified: trunk/Jmol/src/org/jmol/symmetry/Symmetry.java
===================================================================
--- trunk/Jmol/src/org/jmol/symmetry/Symmetry.java      2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/symmetry/Symmetry.java      2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -318,12 +318,12 @@
 
   @Override
   public int[] getCellRange() {
-    return symmetryInfo.cellRange;
+    return symmetryInfo == null ? null : symmetryInfo.cellRange;
   }
 
   @Override
   public String getSymmetryInfoStr() {
-    return symmetryInfo.infoStr;
+    return (symmetryInfo == null ? "" : symmetryInfo.infoStr);
   }
 
   @Override

Modified: trunk/Jmol/src/org/jmol/util/MeshCapper.java
===================================================================
--- trunk/Jmol/src/org/jmol/util/MeshCapper.java        2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/util/MeshCapper.java        2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -85,6 +85,8 @@
 
   private Lst<int[]> lstTriangles;
 
+  private int nPoints;
+
   /////////////// initialization //////////////////
 
   /**
@@ -107,21 +109,22 @@
    * generic entry for a polygon
    * 
    * @param points
-   * @return int[][i j k 7]
+   * @return int[][i j k mask]
    */
   public int[][] triangulatePolygon(P3[] points) {
     clear();
-    
-    int n = points.length;
+    // this is winding backward 
+    nPoints = points.length;
     CapVertex v0 = null;
-    for (int i = 0; i < n; i++) {
+    for (int i = 0; i < nPoints; i++) {
       CapVertex v = new CapVertex(points[i], i);
       vertices.addLast(v);
-      if (v0 != null)
-        v.link(v0);
+      if (v0 != null) {
+        v0.link(v);
+      }
       v0 = v;
     }
-    vertices.get(0).link(v0);
+    v0.link(vertices.get(0));
     lstTriangles = new Lst<int[]>();
     createCap(null);
     int[][] a = AU.newInt2(lstTriangles.size());
@@ -188,12 +191,24 @@
    * @param ipt3
    */
   private void outputTriangle(int ipt1, int ipt2, int ipt3) {
-    if (slicer == null)
-      lstTriangles.addLast(new int[] { ipt1, ipt2, ipt3, 7 });
-    else
+    if (slicer == null) {
+      int mask = 0;
+      if (isEdge(ipt1, ipt2))
+        mask |= 1;
+      if (isEdge(ipt2, ipt3))
+        mask |= 2;
+      if (isEdge(ipt3, ipt1))
+        mask |= 4;
+      lstTriangles.addLast(new int[] { ipt1, ipt2, ipt3, mask });
+    } else {
       slicer.addTriangle(ipt1, ipt2, ipt3);
+    }
   }
 
+  private boolean isEdge(int i, int j) {
+    return (j == (i + 1) % nPoints);
+  }
+
   private CapVertex[] test(CapVertex[] vs) {
     //  dumping = testing = true;
     //  int n = 0;
@@ -242,7 +257,7 @@
     V3 vab = V3.newVsub(vertices.get(0), vertices.get(1));
     V3 vac;
     if (norm == null) {
-      vac = V3.newVsub(vertices.get(vertices.size() - 1), vertices.get(0));
+      vac = V3.newVsub(vertices.get(0), vertices.get(vertices.size() - 1));
     } else {
       vac = V3.newV(norm);
       vac.cross(vac, vab);

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -62,8 +62,16 @@
 
 TODO: consider if models with no atoms will cause issues in relation to 
model.firstAtomIndex
 
-Jmol.___JmolVersion="14.5.0_2015.10.17"
+TODO: working on ID for polyhedra without atom refs
 
+Jmol.___JmolVersion="14.4.0_2015.10.18"
+
+bug fix: Polyhedra can have missing triangle for hexagonal faces
+bug fix: calculate symmetry can break Jmol if unit cell has been changed
+bug fix: DRAW POLYGON front/back nature of winding was reversed.
+
+JmolVersion="14.5.0_2015.10.17"
+
 bug fix: if (...) \n { .... not working
 bug fix: CIF reader will read empty second model for IUCr files with terminal 
data_global block
 bug fix: polyhedra bonds unitcell can cause error in HTML5

Modified: trunk/Jmol/src/org/jmol/viewer/PropertyManager.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/PropertyManager.java 2015-10-17 23:45:49 UTC 
(rev 20836)
+++ trunk/Jmol/src/org/jmol/viewer/PropertyManager.java 2015-10-19 06:22:30 UTC 
(rev 20837)
@@ -779,9 +779,9 @@
           params.indexOf("g64") < 0 && params.indexOf("base64") < 0
               && (returnType == null || returnType.equalsIgnoreCase("java")));
     case PROP_ISOSURFACE_INFO:
-      return vwr.getShapeProperty(JC.SHAPE_ISOSURFACE, "getInfo");
+      return vwr.getShapeProperty(JC.SHAPE_ISOSURFACE, "info");
     case PROP_ISOSURFACE_DATA:
-      return vwr.getShapeProperty(JC.SHAPE_ISOSURFACE, "getData");
+      return vwr.getShapeProperty(JC.SHAPE_ISOSURFACE, "data");
     case PROP_NMR_INFO:
       return vwr.getNMRCalculation().getInfo(myParam.toString());
     case PROP_VAR_INFO:

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