Revision: 20771 http://sourceforge.net/p/jmol/code/20771 Author: hansonr Date: 2015-09-14 04:27:09 +0000 (Mon, 14 Sep 2015) Log Message: ----------- polyhedra update
Modified Paths: -------------- trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java trunk/Jmol/src/org/jmol/script/ScriptTokenParser.java trunk/Jmol/src/org/jmol/scriptext/CmdExt.java trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java trunk/Jmol/src/org/jmol/smiles/SmilesGenerator.java trunk/Jmol/src/org/jmol/smiles/SmilesMatcher.java trunk/Jmol/src/org/jmol/smiles/SmilesParser.java trunk/Jmol/src/org/jmol/symmetry/UnitCellIterator.java trunk/Jmol/src/org/jmol/viewer/GlobalSettings.java trunk/Jmol/src/org/jmol/viewer/JC.java Modified: trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java =================================================================== --- trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/renderspecial/PolyhedraRenderer.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -84,7 +84,7 @@ screens3f[i] = new P3(); } P3[] sc = this.screens3f; - int[][] planes = p.faces; + int[][] planes = p.triangles; for (int i = vertices.length; --i >= 0;) { Atom atom = (vertices[i] instanceof Atom ? (Atom) vertices[i] : null); if (atom == null) { Modified: trunk/Jmol/src/org/jmol/script/ScriptTokenParser.java =================================================================== --- trunk/Jmol/src/org/jmol/script/ScriptTokenParser.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/script/ScriptTokenParser.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -628,8 +628,9 @@ } else if (isImplicitExpression) { addTokenToPostfixToken(T.tokenExpressionEnd); tokenNext(); - } else if (isEmbeddedExpression && !isHash) { - tokenNext(); + } else if (isEmbeddedExpression) { + if (!isHash) + tokenNext(); } else { addNextToken(); } Modified: trunk/Jmol/src/org/jmol/scriptext/CmdExt.java =================================================================== --- trunk/Jmol/src/org/jmol/scriptext/CmdExt.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/scriptext/CmdExt.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -4079,6 +4079,13 @@ if (!chk) msg = vwr.fm.getPathForAllFiles(); break; + case T.polyhedra: + if (!chk) { + Object[] info = new Object[2]; + vwr.shm.getShapePropertyData(JC.SHAPE_POLYHEDRA, "allInfo", info); + msg = SV.getVariable(info[1]).asString(); + } + break; case T.nmr: if (eval.optParameterAsString(2).equalsIgnoreCase("1H")) { len = 3; Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java =================================================================== --- trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -55,7 +55,7 @@ public class Polyhedra extends AtomShape { - private final static float DEFAULT_DISTANCE_FACTOR = 1.85f; +// private final static float DEFAULT_DISTANCE_FACTOR = 1.85f; private final static float DEFAULT_FACECENTEROFFSET = 0.25f; private final static int EDGES_NONE = 0; public final static int EDGES_ALL = 1; @@ -69,7 +69,7 @@ private static final int MODE_BONDING = 1; private static final int MODE_POINTS = 2; - private static final int MODE_ITERATE = 3; + private static final int MODE_RADIUS = 3; private static final int MODE_BITSET = 4; private static final int MODE_UNITCELL = 5; private static final int MODE_INFO = 6; @@ -77,6 +77,7 @@ * a dot product comparison term */ private static final float DEFAULT_PLANAR_PARAM = 0.98f; + private static final float CONVEX_HULL_MAX = 0.02f; public int polyhedronCount; public Polyhedron[] polyhedrons = new Polyhedron[32]; @@ -354,7 +355,7 @@ nv = Integer.MIN_VALUE; for (int i = polyhedronCount; --i >= 0;) { if (nv > 0 && polyhedrons[i].nVertices != nv || nv > Integer.MIN_VALUE - && nv < 0 && polyhedrons[i].faces.length != -nv) + && nv < 0 && polyhedrons[i].triangles.length != -nv) continue; if (smiles == null) { bs.set(polyhedrons[i].centralAtom.i); @@ -372,6 +373,13 @@ data[2] = bs; return true; } + if (property == "allInfo") { + Lst<Map<String, Object>> info = new Lst<Map<String, Object>>(); + for (int i = polyhedronCount; --i >= 0;) + info.addLast(polyhedrons[i].getInfo(vwr, true)); + data[1] = info; + return false; + } if (property == "info") { iatom = ((Integer) data[0]).intValue(); for (int i = polyhedronCount; --i >= 0;) { @@ -443,15 +451,14 @@ boolean useBondAlgorithm = radius == 0 || bondedOnly; buildMode = (info != null ? MODE_INFO : nPoints > 0 ? MODE_POINTS : haveBitSetVertices ? MODE_BITSET : useUnitCell ? MODE_UNITCELL - : useBondAlgorithm ? MODE_BONDING : MODE_ITERATE); - AtomIndexIterator iter = (buildMode == MODE_ITERATE ? ms + : 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: - bsVertices.clear(i); p = constructBitSetPolyhedron(atom); break; case MODE_UNITCELL: @@ -460,16 +467,16 @@ case MODE_BONDING: p = constructBondsPolyhedron(atom, 0); break; - case MODE_POINTS: - p = constructPointPolyhedron(atom); - break; - case MODE_ITERATE: + 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) { if (polyhedronCount == polyhedrons.length) @@ -483,8 +490,29 @@ iter.release(); } - private Polyhedron constructPointPolyhedron(Atom atom) { - return validatePolyhedron(atom, nPoints, otherAtoms); + private Polyhedron constructBondsPolyhedron(Atom atom, int otherAtomCount) { + if (otherAtomCount == 0) { + Bond[] bonds = atom.bonds; + if (bonds == null) + return null; + float r2 = radius * radius; + for (int i = bonds.length; --i >= 0;) { + Bond bond = bonds[i]; + if (!bond.isCovalent()) + continue; + Atom other = bond.getOtherAtom(atom); + if (bsVertices != null && !bsVertices.get(other.i) || radius > 0 + && other.distanceSquared(atom) > r2) + continue; + otherAtoms[otherAtomCount++] = other; + if (otherAtomCount >= MAX_VERTICES) + break; + } + } + distanceRef = 0; + return (otherAtomCount < 3 || otherAtomCount >= MAX_VERTICES || nVertices > 0 + && !bsVertexCount.get(otherAtomCount) ? null : validatePolyhedron(atom, + otherAtomCount)); } private Polyhedron constructUnitCellPolygon(Atom atom, @@ -507,8 +535,8 @@ float bondTolerance = vwr.getFloat(T.bondtolerance); float minBondDistance = vwr.getFloat(T.minbonddistance); float minBondDistance2 = minBondDistance * minBondDistance; - int bondCount = 0; - while (iter.hasNext()) { + int otherAtomCount = 0; + outer: while (iter.hasNext()) { Atom other = atoms[iter.next()]; float otherRadius = other.getBondingRadius(); P3 pt = iter.getPosition(); @@ -516,129 +544,70 @@ if (!vwr.ms.isBondable(myBondingRadius, otherRadius, distance2, minBondDistance2, bondTolerance)) continue; - otherAtoms[bondCount++] = pt; - if (bondCount >= MAX_VERTICES) + for (int i = 0; i < otherAtomCount; i++) + if (otherAtoms[i].distanceSquared(pt) < 0.01f) + continue outer; + otherAtoms[otherAtomCount++] = pt; + if (otherAtomCount >= MAX_VERTICES) break; } - return constructBondsPolyhedron(atom, bondCount); + return constructBondsPolyhedron(atom, otherAtomCount); } - private Polyhedron constructBondsPolyhedron(Atom atom, int bondCount) { - if (bondCount == 0) { - Bond[] bonds = atom.bonds; - if (bonds == null) - return null; - for (int i = bonds.length; --i >= 0;) { - Bond bond = bonds[i]; - if (!bond.isCovalent()) - continue; - Atom other = bond.getOtherAtom(atom); - if (bsVertices != null && !bsVertices.get(other.i) || radius > 0 - && other.distance(atom) > radius) - continue; - otherAtoms[bondCount++] = other; - if (bondCount >= MAX_VERTICES) - break; - } - } - distanceRef = 0; - return (bondCount < 3 || bondCount >= MAX_VERTICES || nVertices > 0 - && !bsVertexCount.get(bondCount) ? null : validatePolyhedron(atom, - bondCount, otherAtoms)); - } - private Polyhedron constructBitSetPolyhedron(Atom atom) { + bsVertices.clear(atom.i); int otherAtomCount = 0; distanceRef = 0; for (int i = bsVertices.nextSetBit(0); i >= 0; i = bsVertices .nextSetBit(i + 1)) otherAtoms[otherAtomCount++] = atoms[i]; - return validatePolyhedron(atom, otherAtomCount, otherAtoms); + return validatePolyhedron(atom, otherAtomCount); } private Polyhedron constructRadiusPolyhedron(Atom atom, AtomIndexIterator iter) { int otherAtomCount = 0; distanceRef = radius; - while (iter.hasNext()) { + float r2 = radius * radius; + outer: while (iter.hasNext()) { Atom other = atoms[iter.next()]; P3 pt = iter.getPosition(); if (pt == null) { // this will happen with standard radius atom iterator pt = other; if (bsVertices != null && !bsVertices.get(other.i) - || atom.distance(pt) > radius) + || atom.distanceSquared(pt) > r2) continue; } if (other.altloc != atom.altloc && other.altloc != 0 && atom.altloc != 0) continue; if (otherAtomCount == MAX_VERTICES) break; + for (int i = 0; i < otherAtomCount; i++) + if (otherAtoms[i].distanceSquared(pt) < 0.01f) + continue outer; + otherAtoms[otherAtomCount++] = pt; } return (otherAtomCount < 3 || nVertices > 0 && !bsVertexCount.get(otherAtomCount) ? null : validatePolyhedron(atom, - otherAtomCount, otherAtoms)); + otherAtomCount)); } - private Polyhedron validatePolyhedron(Atom centralAtom, int vertexCount, - P3[] points) { + private Polyhedron validatePolyhedron(Atom centralAtom, int vertexCount) { + P3[] points = otherAtoms; boolean collapsed = isCollapsed; - boolean checkDist = (distanceRef != 0); - int planeCount = 0; + 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); -// float factor = (!Float.isNaN(distanceFactor) ? distanceFactor -// : DEFAULT_DISTANCE_FACTOR); -// BS bs = BS.newN(vertexCount); - // here we are assuring that at least ONE face is drawn to - // all matching vertices -- skip this for BOND polyhedra - points[vertexCount] = centralAtom; - P3 ptAve = new P3(); + P3 ptAve = P3.newP(centralAtom); for (int i = 0; i < vertexCount; i++) ptAve.add(points[i]); - ptAve.scale(1f / vertexCount); -// float distMax = 0; -// if (checkDist) { -// float dAverage = 0; -// for (int i = 0; i < vertexCount; i++) -// dAverage += points[vertexCount].distance(points[i]); -// dAverage /= vertexCount; -// boolean isOK = (dAverage == 0); -// while (!isOK && factor < 10.0f) { -// distMax = dAverage * factor; -// bs.setBits(0, vertexCount); -// for (int i = 0; i < ni; i++) -// for (int j = i + 1; j < nj; j++) { -// if (points[i].distance(points[j]) > distMax) -// continue; -// for (int k = j + 1; k < vertexCount; k++) { -// if (points[i].distance(points[k]) > distMax -// || points[j].distance(points[k]) > distMax) -// continue; -// bs.clear(i); -// bs.clear(j); -// bs.clear(k); -// } -// } -// isOK = true; -// for (int i = 0; i < vertexCount; i++) -// if (bs.get(i)) { -// isOK = false; -// factor *= 1.05f; -// if (Logger.debugging) { -// Logger.debug("Polyhedra distanceFactor for " + vertexCount -// + " atoms increased to " + factor + " in order to include " -// + points[i]); -// } -// break; -// } -// } -// } + 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 @@ -664,30 +633,22 @@ if (isPlanar(points[i], points[j], points[k], ptRef)) bsThroughCenter.set(pt); // this next check for distance allows for bond AND distance constraints - int[][] faces = planesT; + 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(); - BS bsTemp1 = new BS(); V3[] normals = normalsT; - Map<Object, Object> htNormMap = new Hashtable<Object, Object>(); + Map<Integer, Object[]> htNormMap = new Hashtable<Integer, Object[]>(); + Map<String, Object> htEdgeMap = new Hashtable<String, Object>(); BS bsCenterPlanes = new BS(); - V3 vTemp = vAC; + V3 vAC = this.vAC; for (int i = 0, pt = 0; i < ni; i++) for (int j = i + 1; j < nj; j++) { -// if (checkDist && points[i].distance(points[j]) > distMax) { -// pt += vertexCount - j - 1; -// continue; -// } for (int k = j + 1; k < vertexCount; k++, pt++) { -// if (checkDist -// && (points[i].distance(points[k]) > distMax || points[j] -// .distance(points[k]) > distMax)) -// continue; - if (planeCount >= fmax) { + if (triangleCount >= fmax) { Logger.error("Polyhedron error: maximum face(" + fmax + ") -- reduce RADIUS"); return null; @@ -701,42 +662,43 @@ P3 rpt = (isThroughCenter ? randomPoint : ptAve); V3 normal = new V3(); boolean isWindingOK = Measure.getNormalFromCenter(rpt, points[i], points[j], - points[k], !isThroughCenter, normal, vTemp); + points[k], !isThroughCenter, normal, vAC); // the standard face: - normals[planeCount] = normal; - faces[planeCount] = new int[] { isWindingOK ? i : j, isWindingOK ? j : i, + normals[triangleCount] = normal; + triangles[triangleCount] = new int[] { isWindingOK ? i : j, isWindingOK ? j : i, k, -7 }; - if (!checkFace(points, vertexCount, faces, normals, planeCount, pTemp, nTemp, - vTemp, htNormMap, planarParam, bsTemp, bsTemp1)) + if (!checkFace(points, vertexCount, triangles, normals, triangleCount, pTemp, nTemp, + vAC, htNormMap, htEdgeMap, planarParam, bsTemp)) continue; if (isThroughCenter) { - bsCenterPlanes.set(planeCount++); + bsCenterPlanes.set(triangleCount++); } else if (collapsed) { ptRef.setT(points[nPoints] = new P3()); points[nPoints].scaleAdd2(offset, normal, centralAtom); - addFacet(i, j, k, ptRef, points, normals, faces, planeCount++, nPoints, - isWindingOK, vTemp); - addFacet(k, i, j, ptRef, points, normals, faces, planeCount++, nPoints, - isWindingOK, vTemp); - addFacet(j, k, i, ptRef, points, normals, faces, planeCount++, nPoints, - isWindingOK, vTemp); + 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 { - planeCount++; + triangleCount++; } } } nPoints--; if (Logger.debugging) { Logger - .info("Polyhedron planeCount=" + planeCount + " nPoints=" + nPoints); - for (int i = 0; i < planeCount; i++) - Logger.info("Polyhedron " + PT.toJSON("face[" +i + "]", faces[i])); + .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, htEdgeMap)); return new Polyhedron().set(centralAtom, points, nPoints, vertexCount, - faces, planeCount, normals, bsCenterPlanes, collapsed, distanceRef); + triangles, triangleCount, getFaces(triangles, triangleCount, htNormMap), normals, bsCenterPlanes, collapsed, distanceRef); } - + /** * Add one of the three "facets" that compose the planes of a "collapsed" polyhedron. * A mask of -2 ensures that only the [1-2] edge is marked as an outer edge. @@ -778,51 +740,71 @@ * @param index * @param pTemp * @param vNorm - * @param vTemp + * @param vAC * @param htNormMap + * @param htEdgeMap * @param planarParam * @param bsTemp - * @param bsPts * @return true if valid */ private boolean checkFace(P3[] points, int nPoints, int[][] planes, V3[] normals, int index, P4 pTemp, V3 vNorm, - V3 vTemp, Map<Object, Object> htNormMap, - float planarParam, BS bsTemp, BS bsPts) { + V3 vAC, Map<Integer, Object[]> htNormMap, + Map<String, Object> htEdgeMap, float planarParam, + BS bsTemp) { int[] p1 = planes[index]; - // Check here for a 3D convex hull: - pTemp = Measure.getPlaneThroughPoints(points[p1[0]], points[p1[1]], - points[p1[2]], vNorm, vTemp, pTemp); - // See if all vertices are OUTSIDE the the plane we are considering. + // Check here for a 3D convex hull: + int i0 = p1[0]; + pTemp = Measure.getPlaneThroughPoints(points[i0], points[p1[1]], + points[p1[2]], vNorm, vAC, pTemp); + // See if all vertices are OUTSIDE the the plane we are considering. + //System.out.println(PT.toJSON(null, p1)); + P3 pt = points[i0]; for (int j = 0; j < nPoints; j++) { - vTemp.sub2(points[p1[0]], points[j]); - float v = vTemp.dot(vNorm); - if (v < -0.15) { + if (j == i0) + continue; + vAC.sub2(points[j], pt); + vAC.normalize(); + float v = vAC.dot(vNorm); + // we cannot just take a negative dot product as indication of being + // inside the convex hull. That would be fine if this were about regular + // polyhedra. But we can have imperfect quadrilateral faces that are slightly + // bowed inward. + if (v > CONVEX_HULL_MAX) { return false; } } V3 norm = normals[index]; Integer normix = Integer.valueOf(Normix.getNormixV(norm, bsTemp)); - Object o = htNormMap.get(normix); + Object[] o = htNormMap.get(normix); + //System.out.println(PT.toJSON(null, p1) + " " + normix); if (o == null) { - // we must see if there is a close normix to this + // We must see if there is a close normix to this. + // The Jmol lighting model uses 642 normals, + // which have a neighboring vertex dot product of 0.990439. + // This is too tight for polyhedron planarity. We relax this + // requirement to 0.98 by default, but this can be relaxed even + // more if desired. + V3[] norms = Normix.getVertexVectors(); - for (Entry<Object, Object> e : htNormMap.entrySet()) { - Object ikey = e.getKey(); - if (ikey instanceof Integer) { - Integer n = (Integer) ikey; - if (norms[n.intValue()].dot(norm) > planarParam) { - normix = n; - break; - } + for (Entry<Integer, Object[]> e : htNormMap.entrySet()) { + Integer n = e.getKey(); + if (norms[n.intValue()].dot(norm) > planarParam) { + normix = n; + o = e.getValue(); + break; } } - htNormMap.put(normix, Boolean.TRUE); + if (o == null) + htNormMap.put(normix, o = new Object[] {new BS(), new Lst<int[]>()}); } - bsPts.clearAll(); + //System.out.println(PT.toJSON(null, p1) + " " + normix); + BS bsPts = (BS) o[0]; + @SuppressWarnings("unchecked") + Lst<int[]> lst = (Lst<int[]>) o[1]; for (int i = 0; i < 3; i++) - if (!addEdge(htNormMap, normix, p1, i, points, bsPts)) + if (!addEdge(lst, htEdgeMap, normix, p1, i, points, bsPts)) return false; return true; } @@ -835,8 +817,8 @@ * (b) it does not have vertex points on both sides of it * * (c) if it runs opposite another edge, then both edge masks are set properly - * - * @param htNormMap + * @param faceList + * @param htEdgeMap * @param normix * @param p1 * @param i @@ -845,7 +827,7 @@ * @return true if this triangle is OK * */ - private boolean addEdge(Map<Object, Object> htNormMap, Integer normix, + private boolean addEdge(Lst<int[]>faceList, Map<String, Object> htEdgeMap, Integer normix, int[] p1, int i, P3[] points, BS bsPts) { // forward maps are out int pt1 = p1[(i + 1) % 3]; @@ -853,11 +835,12 @@ int pt = p1[i]; String s = "_" + pt; String edge = normix + s + s1; - if (htNormMap.containsKey(edge)) + if (htEdgeMap.containsKey(edge)) return false; //reverse maps are in String edge0 = normix + s1 + s; - Object o = htNormMap.get(edge0); + Object o = htEdgeMap.get(edge0); + int[] b; if (o == null) { // first check that we have all points on the same side of this line. P3 coord2 = points[pt1]; @@ -878,14 +861,18 @@ } bsPts.set(pt); bsPts.set(pt1); + b = new int[] {pt, pt1}; + faceList.addLast(b); + htEdgeMap.put(edge, new Object[] { p1, Integer.valueOf(i), b }); } else { // set mask to exclude both of these. int[] p10 = (int[]) ((Object[]) o)[0]; int i0 = ((Integer) ((Object[]) o)[1]).intValue(); p10[3] = -((-p10[3]) ^ (1 << i0)); p1[3] = -((-p1[3]) ^ (1 << i)); + b = (int[])((Object[]) o)[2]; + faceList.removeObj(b); } - htNormMap.put(edge, new Object[] { p1, Integer.valueOf(i) }); return true; } @@ -908,6 +895,47 @@ return (Math.abs(d) < MAX_DISTANCE_TO_PLANE); } + + private int[][] getFaces(int[][] triangles, int triangleCount, + Map<Integer, Object[]> htNormMap) { + int n = htNormMap.size(); + int[][] faces = AU.newInt2(n); + if (triangleCount == n) { + for (int i = triangleCount; --i >= 0;) + faces[i] = AU.arrayCopyI(triangles[i], 3); + return faces; + } + int fpt = 0; + for (Entry<Integer, Object[]> e : htNormMap.entrySet()) { + @SuppressWarnings("unchecked") + Lst<int[]> faceList = (Lst<int[]>)e.getValue()[1]; + n = faceList.size(); + int[] face = faces[fpt++] = new int[n]; + if (n < 2) + continue; + int[] edge = faceList.get(0); + //System.out.println("poly edge=" + PT.toJSON(null, edge)); + face[0] = edge[0]; + face[1] = edge[1]; + int pt = 2; + int i0 = 1; + int pt0 = -1; + while (pt < n && pt0 != pt) { + pt0 = pt; + for (int i = i0; i < n; i++) { + edge = faceList.get(i); + if (edge[0] == face[pt - 1]) { + face[pt++] = edge[1]; + if (i == i0) + i0++; + break; + } + } + } + } + return faces; + } + @Override public void setModelVisibilityFlags(BS bsModels) { /* Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java =================================================================== --- trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -17,7 +17,9 @@ import org.jmol.script.SV; import org.jmol.script.T; import org.jmol.util.C; +import org.jmol.util.Elements; import org.jmol.util.Escape; +import org.jmol.util.Logger; import org.jmol.util.Node; import org.jmol.util.Normix; import org.jmol.util.Point3fi; @@ -28,6 +30,7 @@ public Atom centralAtom; public P3[] vertices; + public int[][] triangles; public int[][] faces; int nVertices; boolean collapsed; @@ -50,76 +53,26 @@ } Polyhedron set(Atom centralAtom, P3[] points, int nPoints, int vertexCount, - int[][] planes, int planeCount, V3[] normals, BS bsFlat, boolean collapsed, float distanceRef) { + int[][] triangles, int triangleCount, int[][] faces, V3[] normals, BS bsFlat, boolean collapsed, float distanceRef) { this.distanceRef = distanceRef; this.centralAtom = centralAtom; this.nVertices = vertexCount; this.vertices = new P3[nPoints + 1]; - this.normals = new V3[planeCount]; + this.normals = new V3[triangleCount]; + this.faces = faces; this.bsFlat = bsFlat; - this.faces = AU.newInt2(planeCount); + this.triangles = AU.newInt2(triangleCount); for (int i = nPoints + 1; --i >= 0;) // includes central atom as last atom or possibly reference point vertices[i] = points[i]; - for (int i = planeCount; --i >= 0;) + for (int i = triangleCount; --i >= 0;) this.normals[i] = V3.newV(normals[i]); - for (int i = planeCount; --i >= 0;) - this.faces[i] = planes[i]; + for (int i = triangleCount; --i >= 0;) + this.triangles[i] = triangles[i]; this.collapsed = collapsed; return this; } - Map<String, Object> info; - - Map<String, Object> getInfo(Viewer vwr, boolean isAll) { - if (isAll && this.info != null) - return this.info; - Map<String, Object> info = new Hashtable<String, Object>(); - if (isAll) { - this.info = info; - 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()); - info.put("element", centralAtom.getElementSymbol()); - info.put("faceCount", Integer.valueOf(faces.length)); - info.put("volume", getVolume()); - if (smarts != null) - info.put("smarts", smarts); - if (smiles != null) - info.put("smiles", smiles); - if (polySmiles != null) - info.put("polySmiles", polySmiles); - if (pointGroup != null) - info.put("pointGroup", pointGroup.getPointGroupName()); - Object energy = vwr.ms.getInfo(centralAtom.mi, "Energy"); - if (energy != null) - info.put("energy", energy); - } else { - info.put("bsFlat", bsFlat); - if (collapsed) - info.put("collapsed", Boolean.valueOf(collapsed)); - info.put("distanceRef", Float.valueOf(distanceRef)); - } - info.put("vertexCount", Integer.valueOf(nVertices)); - info.put("atomIndex", Integer.valueOf(centralAtom.i)); - info.put("vertices", AU.arrayCopyPt(vertices, (isAll ? nVertices : vertices.length))); - P3[] n = new P3[normals.length]; - for (int i = n.length; --i >= 0;) - n[i] = P3.newP(normals[i]); - info.put("normals", n); - info.put("faces", AU.arrayCopyII(faces, faces.length)); - int[] elemNos = new int[nVertices]; - for (int i = 0; i < nVertices; i++) { - P3 pt = vertices[i]; - elemNos[i] = (pt instanceof Node ? ((Node) pt).getElementNumber() - : pt instanceof Point3fi ? ((Point3fi) pt).sD : -2); - } - info.put("elemNos", elemNos); - return info; - } - Polyhedron setInfo(Map<String, SV> info, Atom[] at) { try { collapsed = info.containsKey("collapsed"); @@ -134,7 +87,7 @@ } else { nVertices = vc.intValue; vertices = new P3[lst.size()]; - vc = info.get("distanceRef"); + vc = info.get("r"); if (vc != null) distanceRef = vc.asFloat(); } @@ -152,17 +105,19 @@ vertices[i] = p; } } - lst = info.get("faces").getList(); - faces = AU.newInt2(lst.size()); - normals = new V3[faces.length]; + SV faces = info.get("faces"); + SV o = info.get("triangles"); + if (o == null) { // formerly + o = faces; + } else { + this.faces = toInt2(faces); + } + triangles = toInt2(o); + normals = new V3[triangles.length]; V3 vAB = new V3(); - for (int i = faces.length; --i >= 0;) { - Lst<SV> lst2 = lst.get(i).getList(); - int[] a = new int[lst2.size()]; - for (int j = a.length; --j >= 0;) - a[j] = lst2.get(j).intValue; - faces[i] = a; + for (int i = triangles.length; --i >= 0;) { normals[i] = new V3(); + int[] a = triangles[i]; Measure.getNormalThroughPoints(vertices[a[0]], vertices[a[1]], vertices[a[2]], normals[i], vAB); } @@ -173,15 +128,93 @@ return this; } + private int[][] toInt2(SV o) { + Lst<SV> lst = o.getList(); + int[][] ai = AU.newInt2(lst.size()); + for (int i = ai.length; --i >= 0;) { + Lst<SV> lst2 = lst.get(i).getList(); + int[] a = ai[i] = new int[lst2.size()]; + for (int j = a.length; --j >= 0;) + a[j] = lst2.get(j).intValue; + } + return ai; + } + + Map<String, Object> info; + + Map<String, Object> getInfo(Viewer vwr, boolean isAll) { + if (isAll && this.info != null && !Logger.debugging) + return this.info; + Map<String, Object> info = new Hashtable<String, Object>(); + if (isAll) { + this.info = info; + 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()); + info.put("element", centralAtom.getElementSymbol()); + info.put("triangleCount", Integer.valueOf(triangles.length)); + info.put("volume", getVolume()); + String[] names = new String[nVertices]; + for (int i = nVertices; --i >= 0;) { + P3 pt = vertices[i]; + names[i] = (pt instanceof Node ? ((Node) pt).getAtomName() + : pt instanceof Point3fi ? Elements + .elementSymbolFromNumber(((Point3fi) pt).sD) : ""); + } + if (faces != null) + info.put("faceCount", Integer.valueOf(faces.length)); + info.put("atomNames", names); + if (smarts != null) + info.put("smarts", smarts); + if (smiles != null) + info.put("smiles", smiles); + if (polySmiles != null) + info.put("polySmiles", polySmiles); + if (pointGroup != null) + info.put("pointGroup", pointGroup.getPointGroupName()); + Object energy = vwr.ms.getInfo(centralAtom.mi, "Energy"); + if (energy != null) + info.put("energy", energy); + } + if (faces != null) + info.put("faces", faces); + if (!isAll || Logger.debugging) { + info.put("bsFlat", bsFlat); + if (collapsed) + info.put("collapsed", Boolean.valueOf(collapsed)); + if (distanceRef != 0) + info.put("r", Float.valueOf(distanceRef)); + P3[] n = new P3[normals.length]; + for (int i = n.length; --i >= 0;) + n[i] = P3.newP(normals[i]); + info.put("normals", n); + info.put("triangles", AU.arrayCopyII(triangles, triangles.length)); + } + info.put("vertexCount", Integer.valueOf(nVertices)); + info.put("atomIndex", Integer.valueOf(centralAtom.i)); + info.put("vertices", + AU.arrayCopyPt(vertices, (isAll ? nVertices : vertices.length))); + int[] elemNos = new int[nVertices]; + for (int i = 0; i < nVertices; i++) { + P3 pt = vertices[i]; + elemNos[i] = (pt instanceof Node ? ((Node) pt).getElementNumber() + : pt instanceof Point3fi ? ((Point3fi) pt).sD : -2); + } + info.put("elemNos", elemNos); + return info; + } + String getSymmetry(Viewer vwr, boolean withPointGroup) { info = null; SmilesMatcherInterface sm = vwr.getSmilesMatcher(); try { - String details = (distanceRef <= 0 ? null : "" + distanceRef); + String details = (distanceRef <= 0 ? null : "r=" + distanceRef); if (smarts == null) { - smarts = sm.polyhedronToSmiles(centralAtom, faces, nVertices, null, JC.SMILES_TOPOLOGY | JC.SMILES_NOSTEREO, null); - smiles = sm.polyhedronToSmiles(centralAtom, faces, nVertices, vertices, JC.SMILES_TYPE_SMILES | JC.SMILES_NOSTEREO, null); - polySmiles = sm.polyhedronToSmiles(centralAtom, faces, nVertices, vertices, JC.SMILES_TYPE_SMILES | JC.SMILES_ATOM_COMMENT, details); + smarts = sm.polyhedronToSmiles(centralAtom, faces, nVertices, null, JC.SMILES_TOPOLOGY, null); + smiles = sm.polyhedronToSmiles(centralAtom, faces, nVertices, vertices, JC.SMILES_TYPE_SMILES, null); + polySmiles = sm.polyhedronToSmiles(centralAtom, faces, nVertices, vertices, JC.SMILES_TYPE_SMILES | JC.SMILES_POLYHEDRAL | JC.SMILES_ATOM_COMMENT, details); } } catch (Exception e) { } @@ -207,9 +240,9 @@ V3 vAC = new V3(); V3 vTemp = new V3(); float v = 0; - if (bsFlat.cardinality() < faces.length) - for (int i = faces.length; --i >= 0;) { - int[] face = faces[i]; + if (bsFlat.cardinality() < triangles.length) + for (int i = triangles.length; --i >= 0;) { + int[] face = triangles[i]; for (int j = face.length - 2; --j >= 0;) if (face[j + 2] >= 0) v += triangleVolume(face[j], face[j + 1], face[j + 2], vAB, vAC, @@ -228,7 +261,7 @@ } String getState(Viewer vwr) { - return "polyhedron @" + Escape.e(getInfo(vwr, false)) + return " polyhedron @{" + Escape.e(getInfo(vwr, false)) + "} " + (isFullyLit ? " fullyLit" : "") + ";" + (visible ? "" : "polyhedra ({"+centralAtom.i+"}) off;") + "\n"; } Modified: trunk/Jmol/src/org/jmol/smiles/SmilesGenerator.java =================================================================== --- trunk/Jmol/src/org/jmol/smiles/SmilesGenerator.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/smiles/SmilesGenerator.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -88,6 +88,7 @@ private boolean noStereo; public P3 stereoReference; private SmilesStereo smilesStereo; + private boolean isPolyhedral; // generation of SMILES strings @@ -109,6 +110,7 @@ topologyOnly = JC.checkFlag(flags, JC.SMILES_TOPOLOGY); getAromatic = !JC.checkFlag(flags, JC.SMILES_NOAROMATIC); noStereo = JC.checkFlag(flags, JC.SMILES_NOSTEREO); + isPolyhedral = JC.checkFlag(flags, JC.SMILES_POLYHEDRAL); return getSmilesComponent(atoms[ipt], bsSelected, true, false, false); } @@ -265,17 +267,19 @@ * * @param atom * @param bs - * @param allowBioResidues + * @param allowBioResidues * @param allowConnectionsToOutsideWorld - * @param forceBrackets + * @param forceBrackets * @return SMILES * @throws InvalidSmilesException */ private String getSmilesComponent(Node atom, BS bs, boolean allowBioResidues, - boolean allowConnectionsToOutsideWorld, boolean forceBrackets) + boolean allowConnectionsToOutsideWorld, + boolean forceBrackets) throws InvalidSmilesException { - if (!explicitH && atom.getElementNumber() == 1 && atom.getEdges().length > 0) + if (!explicitH && atom.getElementNumber() == 1 + && atom.getEdges().length > 0) atom = atoms[atom.getBondedAtomIndex(0)]; // don't start with H bsSelected = JmolMolecule.getBranchBitSet(atoms, atom.getIndex(), BSUtil.copy(bs), null, -1, true, allowBioResidues); @@ -307,19 +311,18 @@ bsToDo = BSUtil.copy(bsSelected); SB sb = new SB(); - // The idea hear is to allow a hypervalent atom to be listed first - for (int i = bsToDo.nextSetBit(0); i >= 0; i = bsToDo.nextSetBit(i + 1)) - if (atoms[i].getCovalentBondCount() > 4) { - if (atom == null) - sb.append("."); - getSmilesAt(sb, atoms[i], allowConnectionsToOutsideWorld, false, - explicitH, forceBrackets); - atom = null; - } + for (int i = bsToDo.nextSetBit(0); i >= 0; i = bsToDo.nextSetBit(i + 1)) + if (atoms[i].getCovalentBondCount() > 4 || isPolyhedral) { + if (atom == null) + sb.append("."); + getSmilesAt(sb, atoms[i], allowConnectionsToOutsideWorld, false, + explicitH, forceBrackets); + atom = null; + } if (atom != null) - while ((atom = getSmilesAt(sb, atom, allowConnectionsToOutsideWorld, true, - explicitH, forceBrackets)) != null) { + while ((atom = getSmilesAt(sb, atom, allowConnectionsToOutsideWorld, + true, explicitH, forceBrackets)) != null) { } while (bsToDo.cardinality() > 0 || !htRings.isEmpty()) { Iterator<Object[]> e = htRings.values().iterator(); @@ -333,8 +336,8 @@ sb.append("."); prevSp2Atoms = null; prevAtom = null; - while ((atom = getSmilesAt(sb, atom, allowConnectionsToOutsideWorld, true, - explicitH, forceBrackets)) != null) { + while ((atom = getSmilesAt(sb, atom, allowConnectionsToOutsideWorld, + true, explicitH, forceBrackets)) != null) { } } if (!htRings.isEmpty()) { @@ -508,13 +511,7 @@ Edge[] bonds = atom.getEdges(); if (stereoReference != null) { allowBranches = false; - if (smilesStereo == null) - try { - smilesStereo = SmilesStereo.newStereo(null); - } catch (InvalidSmilesException e) { - // not possible - } - smilesStereo.sortBondsByStereo(atom, prevAtom, stereoReference, bonds, vTemp.vA); + sortBonds(atom, prevAtom, stereoReference); } Node aH = null; int stereoFlag = (isAromatic ? 10 : 0); @@ -748,6 +745,16 @@ return atomNext; } + void sortBonds(Node atom, Node refAtom, P3 center) { + if (smilesStereo == null) + try { + smilesStereo = SmilesStereo.newStereo(null); + } catch (InvalidSmilesException e) { + // not possible + } + smilesStereo.sortBondsByStereo(atom, refAtom, center, atom.getEdges(), vTemp.vA); + } + /** * We must sort the bond vector such that a diaxial pair is * first and last. Then we assign stereochemistry based on what Modified: trunk/Jmol/src/org/jmol/smiles/SmilesMatcher.java =================================================================== --- trunk/Jmol/src/org/jmol/smiles/SmilesMatcher.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/smiles/SmilesMatcher.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -379,20 +379,12 @@ for (int i = faces.length; --i >= 0;) { int[] face = faces[i]; int n = face.length; - int mask = face[n - 1]; - if (mask < 0) { - mask = -mask; - n--; - } else { - mask = -1; - } int iatom, iatom2; for (int j = n; --j >= 0;) { if ((iatom = face[j]) >= atomCount || (iatom2 = face[(j + 1) % n]) >= atomCount) continue; - if ((mask & (1 << j)) != 0 - && atoms[iatom].getBondTo(atoms[iatom2]) == null) { + if (atoms[iatom].getBondTo(atoms[iatom2]) == null) { SmilesBond b = new SmilesBond(atoms[iatom], atoms[iatom2], SmilesBond.TYPE_SINGLE, false); b.index = nBonds++; @@ -404,18 +396,20 @@ if (n == 0 || n != atoms[i].bonds.length) atoms[i].bonds = (SmilesBond[]) AU.arrayCopyObject(atoms[i].bonds, n); } + String s = null; SmilesGenerator g = new SmilesGenerator(); if (points != null) g.stereoReference = (P3) center; InvalidSmilesException.clear(); - String s = g.getSmiles(atoms, atomCount, BSUtil.newBitSet2(0, atomCount), + s = g.getSmiles(atoms, atomCount, BSUtil.newBitSet2(0, atomCount), null, flags | JC.SMILES_EXPLICIT_H | JC.SMILES_NOAROMATIC | JC.SMILES_NOSTEREO); - if (!JC.checkFlag(flags, JC.SMILES_NOSTEREO)) { + if (JC.checkFlag(flags, JC.SMILES_POLYHEDRAL)) { s = "//* " + center + " *//\t[" + Elements.elementSymbolFromNumber(center.getElementNumber()) + "@PH" + atomCount + (details == null ? "" : "/" + details + "/") + "]." + s; } + return s; } Modified: trunk/Jmol/src/org/jmol/smiles/SmilesParser.java =================================================================== --- trunk/Jmol/src/org/jmol/smiles/SmilesParser.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/smiles/SmilesParser.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -1096,7 +1096,8 @@ * * @param newAtom * @param name - * @param ret set [0] to 1 for new atom; 0 otherwise + * @param ret + * set [0] to 1 for new atom; 0 otherwise * @return new or old atom */ private SmilesAtom checkReference(SmilesAtom newAtom, String name, int[] ret) { @@ -1106,9 +1107,20 @@ if (ref == null) { // this is a new atom atomRefs.put(newAtom.referance = name, ref = newAtom); + if (!newAtom.hasSymbol) { + if (name.length() > 0) { + String s = null; + if (name.length() >= 2 + && (Elements.elementNumberFromSymbol(s = name.substring(0, 2), + true) > 0 || Elements.elementNumberFromSymbol( + s = name.substring(0, 1), true) > 0)) { + newAtom.setSymbol(s); + } + } + } ret[0] = 1; } else { - ret[0] = 0; + ret[0] = 0; } return ref; } Modified: trunk/Jmol/src/org/jmol/symmetry/UnitCellIterator.java =================================================================== --- trunk/Jmol/src/org/jmol/symmetry/UnitCellIterator.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/symmetry/UnitCellIterator.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -191,6 +191,8 @@ Atom a = getAtom(); if (Logger.debugging) Logger.info("draw ID p_" + nFound + " " + p + " //" + a + " " + t); + if (this.p.distanceSquared(a) < 0.0001f) + return a; Point3fi p = new Point3fi(); p.setT(this.p); p.i = a.i; Modified: trunk/Jmol/src/org/jmol/viewer/GlobalSettings.java =================================================================== --- trunk/Jmol/src/org/jmol/viewer/GlobalSettings.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/viewer/GlobalSettings.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -898,14 +898,13 @@ else if (database.equals("nci")) id += "/file?format=sdf&get3d=True"; } - while (format.indexOf("%c") >= 0) { - try { + try { + while (format.indexOf("%c") >= 0) for (int i = 1; i < 10; i++) { format = PT.rep(format, "%c" + i, id.substring(i - 1, i)); } - } catch (Exception e) { - // too bad. - } + } catch (Exception e) { + // too bad. } return (format.indexOf("%FILE") < 0 ? format + id : PT.formatStringS( format, "FILE", id)); Modified: trunk/Jmol/src/org/jmol/viewer/JC.java =================================================================== --- trunk/Jmol/src/org/jmol/viewer/JC.java 2015-09-10 12:34:16 UTC (rev 20770) +++ trunk/Jmol/src/org/jmol/viewer/JC.java 2015-09-14 04:27:09 UTC (rev 20771) @@ -1044,6 +1044,7 @@ public static final int SMILES_TOPOLOGY = 0x00200; public static final int SMILES_NOAROMATIC = 0x00400; public static final int SMILES_NOSTEREO = 0x00800; + public static final int SMILES_POLYHEDRAL = 0x01000; public static final int SMILES_BIO = 0x10000; public static final int SMILES_BIO_ALLOW_UNMATCHED_RINGS = 0x11000; public static final int SMILES_BIO_COV_CROSSLINK = 0x12000; 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