Revision: 21451
          http://sourceforge.net/p/jmol/code/21451
Author:   hansonr
Date:     2017-03-25 19:37:24 +0000 (Sat, 25 Mar 2017)
Log Message:
-----------
Jmol.___JmolVersion="14.10.0" // released 3/25/2017

new feature: x = {*}.find(smartsString,"map")
 -- returns an array of arrays of atom indices (0-based)
 -- indicates exact correlation between atoms in {*} and atoms of smartsString
 -- only unique sets of atoms are found, not every possibility
 -- for example:
 
      load $caffeine
      print {*}.find("*1*****1", "map").format("JSON")

        [ [ 0,2,4,6,11,12 ] ]

new feature: SELECT @x  where x is an array of integers or array of array of 
integers
 -- selects atoms from array rather than from a bitset
 -- note that variable must be used, as SELECT [1,2,3] would look for PDB group 
"1,2,3"
 -- for example:

      load $caffeine
      x = {*}.find("*1*****1", "map")[0]
      select @x
      
        6 atoms selected

new feature: DRAW polyhedron @faces @points 
 -- draws sets of polygons based on arrays of atom indices
 -- @faces is an array of array of integers, not necessarily wound correctly
 -- @points is an atom bitset or an array of points (optional, defaults to {*}
 -- for example:

          load $caffeine
          draw polyhedra @{{*}.find("*1****1||*1*****1","map")}

new feature: POLYHEDRON ID xxx @faces @points
 -- @faces is an array of array of integers, not necessarily wound correctly
 -- @points is an atom bitset or an array of points (optional, defaults to {*}

        
new feature: 4-order bond in MOL file using 14 for bond order
 -- Jmol extension for MOL file format to allow 4-bond
 -- example: [Re2Cl8](2-)
 -- see https://en.wikipedia.org/wiki/Quadruple_bond
 
new feature: 5-order bond in MOL file using 15 for bond order
 -- Jmol extension for MOL file format to allow 5-bond
 -- example: [Mo2Cl8](4-)
 -- see https://en.wikipedia.org/wiki/Quintuple_bond 

new feature: 6-order bond in MOL file using 16 for bond order
 -- Jmol extension for MOL file format to allow 6-bond
 -- example: Mo2
 -- see https://en.wikipedia.org/wiki/Sextuple_bond 

bug fix: DSSR fix for multi-model PDB file
bug fix: EXIT command with -n command line flag does not exit Jmol
bug fix: echo renderer may not show correct font size
bug fix: POLYHEDRA ID id OFFSET {x y z} broken
bug fix: ScriptManager debug output being sent even if -i (silent) command line 
option set.

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
    trunk/Jmol/src/org/jmol/scriptext/IsoExt.java
    trunk/Jmol/src/org/jmol/scriptext/ScriptExt.java
    trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java
    trunk/Jmol/src/org/jmol/viewer/Jmol.properties

Modified: trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2017-03-25 16:29:28 UTC 
(rev 21450)
+++ trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2017-03-25 19:37:24 UTC 
(rev 21451)
@@ -3238,6 +3238,8 @@
     P3 offset = null;
     String id = null;
     boolean ok = false;
+    int[][] faces = null;
+    P3[] points = null;
     for (int i = 1; i < slen; ++i) {
       String propertyName = null;
       Object propertyValue = null;
@@ -3249,7 +3251,8 @@
         break;
       case T.point:
         propertyName = "points";
-        propertyValue = Float.valueOf(tokAt(++i) == T.off ? 0 : 
e.floatParameter(i));
+        propertyValue = Float.valueOf(tokAt(++i) == T.off ? 0 : e
+            .floatParameter(i));
         ok = true;
         break;
       case T.scale:
@@ -3276,6 +3279,18 @@
             : eval.theTok == T.on ? "on" : "delete");
         onOffDelete = true;
         break;
+      case T.varray:
+        if (id == null || needsGenerating)
+          invArg();
+        needsGenerating = true;
+        faces = getIntArray2(i);
+        points = getAllPoints(eval.iToken + 1);
+        i = eval.iToken;
+        if (points[0] instanceof Atom)
+          setShapeProperty(JC.SHAPE_POLYHEDRA, "model", 
Integer.valueOf(((Atom) points[0]).getModelIndex()));
+       propertyName = "definedFaces";
+        propertyValue = new Object[] { faces, points };
+        break;
       case T.full:
         propertyName = "full";
         break;
@@ -3312,7 +3327,8 @@
         if (nAtomSets > 0)
           invPO();
         propertyName = (radius <= 0 ? "radius" : "radius1");
-        propertyValue = Float.valueOf(radius = (radius == 0 ? 0 : 
floatParameter(i)));
+        propertyValue = Float.valueOf(radius = (radius == 0 ? 0
+            : floatParameter(i)));
         needsGenerating = true;
         break;
       case T.offset:
@@ -5304,5 +5320,4 @@
     return data;
   }
   
-
 }

Modified: trunk/Jmol/src/org/jmol/scriptext/IsoExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/IsoExt.java       2017-03-25 16:29:28 UTC 
(rev 21450)
+++ trunk/Jmol/src/org/jmol/scriptext/IsoExt.java       2017-03-25 19:37:24 UTC 
(rev 21451)
@@ -438,7 +438,8 @@
       case T.polyhedra:
       case T.point:
       case T.polygon:
-        boolean isPoints = (eval.theTok == T.point);
+        tok = eval.theTok;
+        boolean isPoints = (tok == T.point);
         propertyName = "polygon";
         havePoints = true;
         Lst<Object> v = new Lst<Object>();
@@ -447,29 +448,22 @@
         P3[] points = null;
         Lst<SV> vpolygons = null;
         int[][] polygons = null;
-        if (eval.isArrayParameter(++i)) {
+        if (tok == T.polyhedra) {
+          // draw POLYHEDRA @x @y 
+          //  where x is [[0,3,4][4,5,6] ...] where numbers are atom indices
+          //  and optional y is an atom bitset or a list of points
+          int[][] faces = getIntArray2(++i);
+          points = getAllPoints(e.iToken + 1);
+          polygons = ((MeshCapper) Interface.getInterface(
+              "org.jmol.util.MeshCapper", vwr, "script")).set(null)
+              .triangulateFaces(faces, points, null);
+          nVertices = points.length;
+        } else if (eval.isArrayParameter(++i)) {
           // draw POLYGON [points]
-          // draw POLYGON @x where x is [[0,3,4][4,5,6] ...] where numbers are 
atom indices
           points = eval.getPointArray(i, -1, true);
-          if (points.length > 0 && points[0] == null && eval.tokAt(i) == 
T.varray) {
-            Lst<SV> list = vwr.evaluateExpressionAsVariable("{*}.xyz.all")
-                .getList();
-            points = new P3[list.size()];
-            for (int vi = points.length; --vi >= 0;)
-              points[vi] = SV.ptValue(list.get(vi));
-            list = ((SV) eval.getToken(i)).getList();
-            int[][] faces = AU.newInt2(list.size());
-            for (int vi = faces.length; --vi >= 0;) {
-              Lst<SV> face = list.get(vi).getList();
-              if (face != null) {
-                faces[vi] = new int[face.size()];
-                for (int vii = faces[vi].length; --vii >= 0;)
-                  faces[vi][vii] = face.get(vii).intValue;
-              }
-            }
-            polygons = ((MeshCapper) Interface.getInterface(
-                "org.jmol.util.MeshCapper", vwr, "script")).set(null)
-                .triangulateFaces(faces, points, null);
+          if (tok == T.polyhedra && points.length > 0 && points[0] == null
+              && eval.tokAt(i) == T.varray) {
+
           }
           nVertices = points.length;
         } else {

Modified: trunk/Jmol/src/org/jmol/scriptext/ScriptExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/ScriptExt.java    2017-03-25 16:29:28 UTC 
(rev 21450)
+++ trunk/Jmol/src/org/jmol/scriptext/ScriptExt.java    2017-03-25 19:37:24 UTC 
(rev 21451)
@@ -1,8 +1,11 @@
 package org.jmol.scriptext;
 
+import javajs.util.AU;
+import javajs.util.Lst;
 import javajs.util.P3;
 
 import org.jmol.java.BS;
+import org.jmol.script.SV;
 import org.jmol.script.ScriptError;
 import org.jmol.script.ScriptEval;
 import org.jmol.script.ScriptException;
@@ -168,5 +171,48 @@
        }
      }
 
+  protected int[][] getIntArray2(int i) throws ScriptException {
+    Lst<SV> list = ((SV) e.getToken(i)).getList();
+    int[][] faces = AU.newInt2(list.size());
+    for (int vi = faces.length; --vi >= 0;) {
+      Lst<SV> face = list.get(vi).getList();
+      if (face != null) {
+        faces[vi] = new int[face.size()];
+        for (int vii = faces[vi].length; --vii >= 0;)
+          faces[vi][vii] = face.get(vii).intValue;
+      }
+    }
+    return faces;
+  }
 
+  protected P3[] getAllPoints(int index) throws ScriptException {
+    P3[] points = null;
+    BS bs = null;
+    try {
+      switch (e.tokAt(index)) {
+      case T.varray:
+        points = e.getPointArray(index, -1, false);
+        break;
+      case T.bitset:
+      case T.expressionBegin:
+        bs = atomExpressionAt(index);
+        break;
+      }
+      if (points == null) {
+        if (bs == null) 
+          bs = vwr.getAllAtoms();
+        points = new P3[bs.cardinality()];
+        for (int i = bs.nextSetBit(0), pt = 0; i >= 0; i = bs.nextSetBit(i + 
1))
+          points[pt++] = vwr.ms.at[i];
+      }
+    } catch (Exception e) {
+    }
+    if (points.length < 3)
+      invArg();
+    return points;
+
+  }
+
+
+
 }

Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java
===================================================================
--- trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2017-03-25 16:29:28 UTC 
(rev 21450)
+++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2017-03-25 19:37:24 UTC 
(rev 21451)
@@ -41,6 +41,7 @@
 import javajs.util.V3;
 
 import org.jmol.api.AtomIndexIterator;
+import org.jmol.api.Interface;
 import org.jmol.api.SmilesMatcherInterface;
 import org.jmol.api.SymmetryInterface;
 import org.jmol.c.PAL;
@@ -47,6 +48,7 @@
 import org.jmol.java.BS;
 import org.jmol.modelset.Atom;
 import org.jmol.modelset.Bond;
+import org.jmol.modelset.Model;
 import org.jmol.script.SV;
 import org.jmol.script.T;
 import org.jmol.shape.AtomShape;
@@ -53,6 +55,7 @@
 import org.jmol.util.BSUtil;
 import org.jmol.util.C;
 import org.jmol.util.Logger;
+import org.jmol.util.MeshCapper;
 import org.jmol.util.Normix;
 
 public class Polyhedra extends AtomShape implements Comparator<Object[]>{
@@ -119,6 +122,7 @@
   private float distanceRef;
   private int modelIndex;
   private boolean isAuto;
+   private int[][] explicitFaces;
 
   @SuppressWarnings("unchecked")
   @Override
@@ -144,6 +148,10 @@
       return;
     }
 
+    if ("definedFaces" == propertyName) {
+      setDefinedFaces((P3[]) ((Object[]) value)[1], (int[][]) ((Object[]) 
value)[0]);
+      return;
+    }
     if ("generate" == propertyName) {
       if (!iHaveCenterBitSet) {
         centers = bs;
@@ -401,6 +409,48 @@
     setPropAS(propertyName, value, bs);
   }
 
+  private void setDefinedFaces(P3[] points, int[][] faces) {
+    BS bsUsed = new BS();
+    for (int i = faces.length; --i >= 0;) {
+      int[] face = faces[i];
+      for (int j = face.length; --j >= 0;)
+        bsUsed.set(face[j]);
+    }
+    BS bsNot = BSUtil.newBitSet2(0,  bsUsed.length());
+    bsNot.andNot(bsUsed);
+    int nNot = bsNot.cardinality(); 
+    if (nNot > 0) {
+      int np = points.length;
+      int[] mapOldToNew = new int[np];
+      int[] mapNewToOld = new int[np];
+      int n = 0;
+      for (int i = 0; i < np; i++)
+        if (!bsNot.get(i)) {
+          mapNewToOld[n] = i;
+          mapOldToNew[i] = n++;
+        }
+      P3[] pnew = new P3[n];
+      for (int i = 0; i < n; i++) 
+        pnew[i] = points[mapNewToOld[i]]; 
+      points = pnew;
+      for (int i = faces.length; --i >= 0;) {
+        int[] face = faces[i];
+        for (int j = face.length; --j >= 0;)
+          face[j] = mapOldToNew[face[j]];
+      }
+    }
+    int n = nPoints = points.length;
+    center = new P3();
+    otherAtoms = new P3[n + 1];
+    if (n > 0) {
+      otherAtoms[n] = center;
+      for (int i = 0; i < n; i++)
+        center.add(otherAtoms[i] = points[i]);
+      center.scale(1f / n);
+    }
+    explicitFaces = faces;
+  }
+
   private void pointsPolyhedra(BS bs, float pointScale) {
     bs = findPolyBS(thisID == null ? bs : null);
     for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
@@ -831,126 +881,171 @@
 
   private Polyhedron validatePolyhedron(P3 atomOrPt, int vertexCount) {
     P3[] points = otherAtoms;
+    int[][] faces = explicitFaces;
+    int[][] faceTriangles;
+    V3[] normals;
     boolean collapsed = isCollapsed;
     int triangleCount = 0;
-    int nPoints = vertexCount + 1;
-    int ni = vertexCount - 2;
-    int nj = vertexCount - 1;
-    float planarParam = (Float.isNaN(this.planarParam) ? DEFAULT_PLANAR_PARAM
-        : this.planarParam);
 
-    points[vertexCount] = atomOrPt;
-    P3 ptAve = P3.newP(atomOrPt);
-    for (int i = 0; i < vertexCount; i++)
-      ptAve.add(points[i]);
-    ptAve.scale(1f / (vertexCount + 1));
-    /*  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 
-     *  a "simple" atom near the center but not quite the center, 
-     *  so that our planes on either side of the facet don't overlap. 
-     *  We step out faceCenterOffset * normal from the center.
-     *  
-     *  Alan Hewat pointed out the issue of faces that CONTAIN the center --
-     *  square planar, trigonal and square pyramids, see-saw. In these cases 
with no
-     *  additional work, you get a brilliance effect when two faces are drawn 
over
-     *  each other. The solution is to identify this sort of face and, if not 
collapsed,
-     *  to cut them into smaller pieces and only draw them ONCE by producing a 
little
-     *  catalog. This uses the Point3i().toString() method.
-     *  
-     *  For these special cases, then, we define a reference point just behind 
the plane
-     *  
-     *  Note that this is NOT AN OPTION for ID-named polyhedra (Jmol 14.5.0 
10/31/2015)
-     */
+    BS bsCenterPlanes = new BS();
+    int[][] triangles;
+    if (faces != null) {
+      collapsed = false;
+      faceTriangles = AU.newInt2(faces.length);
+      normals = new V3[faces.length];
+      for (int i = faces.length; --i >= 0;)
+        faces[i] = fixExplicitFaceWinding(faces[i], i, points, normals);
+      triangles = ((MeshCapper) Interface.getInterface(
+          "org.jmol.util.MeshCapper", vwr, "script")).set(null)
+          .triangulateFaces(faces, points, faceTriangles);
+      triangleCount = triangles.length;
+    } else {
 
-    P3 ptRef = P3.newP(ptAve);
-    BS bsThroughCenter = new BS();
-    if (thisID == null)
-      for (int pt = 0, i = 0; i < ni; i++)
-        for (int j = i + 1; j < nj; j++)
-          for (int k = j + 1; k < vertexCount; k++, pt++)
-            if (isPlanar(points[i], points[j], points[k], ptRef))
-              bsThroughCenter.set(pt);
-    // this next check for distance allows for bond AND distance constraints
-    int[][] triangles = planesT;
-    P4 pTemp = new P4();
-    V3 nTemp = new V3();
-    float offset = faceCenterOffset;
-    int fmax = FACE_COUNT_MAX;
-    int vmax = MAX_VERTICES;
-    BS bsTemp = Normix.newVertexBitSet();
-    V3[] normals = normalsT;
-    Map<Integer, Object[]> htNormMap = new Hashtable<Integer, Object[]>();
-    Map<String, Object> htEdgeMap = new Hashtable<String, Object>();
-    BS bsCenterPlanes = new BS();
-    Lst<int[]> lstRejected = (isFull ? new Lst<int[]>() : null);
-    Object[] edgeTest = new Object[3];
-    V3 vAC = this.vAC;
-    for (int i = 0, pt = 0; i < ni; i++)
-      for (int j = i + 1; j < nj; j++) {
-        for (int k = j + 1; k < vertexCount; k++, pt++) {
-          if (triangleCount >= fmax) {
-            Logger.error("Polyhedron error: maximum face(" + fmax
-                + ") -- reduce RADIUS");
-            return null;
-          }
-          if (nPoints >= vmax) {
-            Logger.error("Polyhedron error: maximum vertex count(" + vmax
-                + ") -- reduce RADIUS");
-            return null;
-          }
-          boolean isThroughCenter = bsThroughCenter.get(pt);
-          P3 rpt = (isThroughCenter ? randomPoint : ptAve);
-          V3 normal = new V3();
-          boolean isWindingOK = Measure.getNormalFromCenter(rpt, points[i],
-              points[j], points[k], !isThroughCenter, normal, vAC);
-          // the standard face:
-          int[] t = new int[] { isWindingOK ? i : j, isWindingOK ? j : i, k, 
-7 };
-          float err = checkFacet(points, vertexCount, t, triangleCount, 
normal, pTemp, nTemp,
-              vAC, htNormMap, htEdgeMap, planarParam, bsTemp, edgeTest);
-          if (err != 0) {
-            if (isFull && err != Float.MAX_VALUE && err < 0.5f) {
-              t[3] = (int) (err * 100);
-              lstRejected.addLast(t);
+      int nPoints = vertexCount + 1;
+      int ni = vertexCount - 2;
+      int nj = vertexCount - 1;
+      float planarParam = (Float.isNaN(this.planarParam) ? DEFAULT_PLANAR_PARAM
+          : this.planarParam);
+
+      points[vertexCount] = atomOrPt;
+      P3 ptAve = P3.newP(atomOrPt);
+      for (int i = 0; i < vertexCount; i++)
+        ptAve.add(points[i]);
+      ptAve.scale(1f / (vertexCount + 1));
+      /*  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 
+       *  a "simple" atom near the center but not quite the center, 
+       *  so that our planes on either side of the facet don't overlap. 
+       *  We step out faceCenterOffset * normal from the center.
+       *  
+       *  Alan Hewat pointed out the issue of faces that CONTAIN the center --
+       *  square planar, trigonal and square pyramids, see-saw. In these cases 
with no
+       *  additional work, you get a brilliance effect when two faces are 
drawn over
+       *  each other. The solution is to identify this sort of face and, if 
not collapsed,
+       *  to cut them into smaller pieces and only draw them ONCE by producing 
a little
+       *  catalog. This uses the Point3i().toString() method.
+       *  
+       *  For these special cases, then, we define a reference point just 
behind the plane
+       *  
+       *  Note that this is NOT AN OPTION for ID-named polyhedra (Jmol 14.5.0 
10/31/2015)
+       */
+
+      P3 ptRef = P3.newP(ptAve);
+      BS bsThroughCenter = new BS();
+      if (thisID == null)
+        for (int pt = 0, i = 0; i < ni; i++)
+          for (int j = i + 1; j < nj; j++)
+            for (int k = j + 1; k < vertexCount; k++, pt++)
+              if (isPlanar(points[i], points[j], points[k], ptRef))
+                bsThroughCenter.set(pt);
+      // this next check for distance allows for bond AND distance constraints
+      triangles = planesT;
+      P4 pTemp = new P4();
+      V3 nTemp = new V3();
+      float offset = faceCenterOffset;
+      int fmax = FACE_COUNT_MAX;
+      int vmax = MAX_VERTICES;
+      BS bsTemp = Normix.newVertexBitSet();
+      normals = normalsT;
+      Map<Integer, Object[]> htNormMap = new Hashtable<Integer, Object[]>();
+      Map<String, Object> htEdgeMap = new Hashtable<String, Object>();
+      Lst<int[]> lstRejected = (isFull ? new Lst<int[]>() : null);
+      Object[] edgeTest = new Object[3];
+      V3 vAC = this.vAC;
+      for (int i = 0, pt = 0; i < ni; i++)
+        for (int j = i + 1; j < nj; j++) {
+          for (int k = j + 1; k < vertexCount; k++, pt++) {
+            if (triangleCount >= fmax) {
+              Logger.error("Polyhedron error: maximum face(" + fmax
+                  + ") -- reduce RADIUS");
+              return null;
             }
-            continue;
+            if (nPoints >= vmax) {
+              Logger.error("Polyhedron error: maximum vertex count(" + vmax
+                  + ") -- reduce RADIUS");
+              return null;
+            }
+            boolean isThroughCenter = bsThroughCenter.get(pt);
+            P3 rpt = (isThroughCenter ? randomPoint : ptAve);
+            V3 normal = new V3();
+            boolean isWindingOK = Measure.getNormalFromCenter(rpt, points[i],
+                points[j], points[k], !isThroughCenter, normal, vAC);
+            // the standard face:
+            int[] t = new int[] { isWindingOK ? i : j, isWindingOK ? j : i, k,
+                -7 };
+            float err = checkFacet(points, vertexCount, t, triangleCount,
+                normal, pTemp, nTemp, vAC, htNormMap, htEdgeMap, planarParam,
+                bsTemp, edgeTest);
+            if (err != 0) {
+              if (isFull && err != Float.MAX_VALUE && err < 0.5f) {
+                t[3] = (int) (err * 100);
+                lstRejected.addLast(t);
+              }
+              continue;
+            }
+            normals[triangleCount] = normal;
+            triangles[triangleCount] = t;
+            if (isThroughCenter) {
+              bsCenterPlanes.set(triangleCount++);
+            } else if (collapsed) {
+              points[nPoints] = new P3();
+              points[nPoints].scaleAdd2(offset, normal, atomOrPt);
+              ptRef.setT(points[nPoints]);
+              addFacet(i, j, k, ptRef, points, normals, triangles,
+                  triangleCount++, nPoints, isWindingOK, vAC);
+              addFacet(k, i, j, ptRef, points, normals, triangles,
+                  triangleCount++, nPoints, isWindingOK, vAC);
+              addFacet(j, k, i, ptRef, points, normals, triangles,
+                  triangleCount++, nPoints, isWindingOK, vAC);
+              nPoints++;
+            } else {
+              triangleCount++;
+            }
           }
-          normals[triangleCount] = normal;
-          triangles[triangleCount] = t;
-          if (isThroughCenter) {
-            bsCenterPlanes.set(triangleCount++);
-          } else if (collapsed) {
-            points[nPoints] = new P3();
-            points[nPoints].scaleAdd2(offset, normal, atomOrPt);
-            ptRef.setT(points[nPoints]);
-            addFacet(i, j, k, ptRef, points, normals, triangles,
-                triangleCount++, nPoints, isWindingOK, vAC);
-            addFacet(k, i, j, ptRef, points, normals, triangles,
-                triangleCount++, nPoints, isWindingOK, vAC);
-            addFacet(j, k, i, ptRef, points, normals, triangles,
-                triangleCount++, nPoints, isWindingOK, vAC);
-            nPoints++;
-          } else {
-            triangleCount++;
-          }
         }
+      nPoints--;
+      if (Logger.debugging) {
+        Logger.info("Polyhedron planeCount=" + triangleCount + " nPoints="
+            + nPoints);
+        for (int i = 0; i < triangleCount; i++)
+          Logger.info("Polyhedron "
+              + PT.toJSON("face[" + i + "]", triangles[i]));
       }
-    nPoints--;
-    if (Logger.debugging) {
-      Logger.info("Polyhedron planeCount=" + triangleCount + " nPoints="
-          + nPoints);
-      for (int i = 0; i < triangleCount; i++)
-        Logger.info("Polyhedron " + PT.toJSON("face[" + i + "]", 
triangles[i]));
+      //System.out.println(PT.toJSON(null, lstRejected));
+      faces = getFaces(triangles, triangleCount, htNormMap);
+      faceTriangles = getFaceTriangles(faces.length, htNormMap, triangleCount);
     }
-    //System.out.println(PT.toJSON(null, lstRejected));
-    int[][] faces = getFaces(triangles, triangleCount, htNormMap);
-    int[][] faceTriangles = getFaceTriangles(faces.length, htNormMap, 
triangleCount);
     return new Polyhedron().set(thisID, modelIndex, atomOrPt, points, nPoints,
-        vertexCount, triangles, triangleCount,
-        faces, faceTriangles, normals, bsCenterPlanes,
-        collapsed, distanceRef, pointScale);
+        vertexCount, triangles, triangleCount, faces, faceTriangles, normals,
+        bsCenterPlanes, collapsed, distanceRef, pointScale);
   }
-  
+
+  /**
+   * Check to see that the winding of the explicit face is correct. If not,
+   * correct it. Also set the normals.
+   * @param face
+   * @param ipt
+   * @param points
+   * @param normals
+   * @return correctly wound face
+   */
+  private int[] fixExplicitFaceWinding(int[] face, int ipt, P3[] points, V3[] 
normals) {
+    int n = face.length;
+    for (int i = 0, nlast = n - 2; i < nlast; i++) {
+      P3 a = points[face[i]];
+      P3 b = points[face[(i + 1) % n]];
+      P3 c = points[face[(i + 2) % n]];
+      if (Measure.computeAngleABC(a, b, c, true) < 178) {
+        // ignore nearly linear angles -- we only need one
+        if (!Measure.getNormalFromCenter(center, a, b, c, true, normals[ipt] = 
new V3(), vAC))
+          face = AU.arrayCopyRangeRevI(face, 0, -1);
+        break;
+      }
+    }
+    return face;
+  }
+
   private int[][] getFaceTriangles(int n, Map<Integer, Object[]> htNormMap, 
int triangleCount) {
     int[][] faceTriangles = AU.newInt2(n);
     if (triangleCount == n) {

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-03-25 16:29:28 UTC 
(rev 21450)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-03-25 19:37:24 UTC 
(rev 21451)
@@ -49,7 +49,7 @@
 # 10. Run jmol/tools build-release.xml
 #
 
-Jmol.___JmolVersion="14.10.0-beta-2017-3-25"
+Jmol.___JmolVersion="14.10.0" // released 3/25/2017
 
 new feature: x = {*}.find(smartsString,"map")
  -- returns an array of arrays of atom indices (0-based)
@@ -73,12 +73,19 @@
       
         6 atoms selected
 
-new feature: DRAW polyhedron @x where x is an array of array of integers
+new feature: DRAW polyhedron @faces @points 
  -- draws sets of polygons based on arrays of atom indices
+ -- @faces is an array of array of integers, not necessarily wound correctly
+ -- @points is an atom bitset or an array of points (optional, defaults to {*}
  -- for example:
 
          load $caffeine
          draw polyhedra @{{*}.find("*1****1||*1*****1","map")}
+
+new feature: POLYHEDRON ID xxx @faces @points
+ -- @faces is an array of array of integers, not necessarily wound correctly
+ -- @points is an atom bitset or an array of points (optional, defaults to {*}
+
         
 new feature: 4-order bond in MOL file using 14 for bond order
  -- Jmol extension for MOL file format to allow 4-bond

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


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Jmol-commits mailing list
Jmol-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jmol-commits

Reply via email to