Revision: 20757 http://sourceforge.net/p/jmol/code/20757 Author: hansonr Date: 2015-09-06 04:09:52 +0000 (Sun, 06 Sep 2015) Log Message: ----------- Jmol.___JmolVersion="14.3.16_2015.09.05"
new feature: POLYHEDRA -- same as POLYHEDRA BONDS {selected} new feature: POLYHEDRA 4 -- same as POLYHEDRA 4 BONDS {selected} new feature: POLYHEDRA OFFSET 1.4 -- same as POLYHEDRA COLLAPSED faceCenterOffset 1.4 new feature: POLYHEDRA COLLAPSED 1.4 -- same as POLYHEDRA COLLAPSED faceCenterOffset 1.4 code: Polyhedra work, including more efficient algorithms for completing set of faces bug fix: tracking down thread-safe issue in application console bug fix: in Java, mouse should not lose control if moved out of application undocumented POLYHEDRA FLAT removed Modified Paths: -------------- trunk/Jmol/src/org/jmol/awt/Mouse.java trunk/Jmol/src/org/jmol/script/ScriptExpr.java trunk/Jmol/src/org/jmol/script/T.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/viewer/Jmol.properties trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/ConsoleTextArea.java Modified: trunk/Jmol/src/org/jmol/awt/Mouse.java =================================================================== --- trunk/Jmol/src/org/jmol/awt/Mouse.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/jmol/awt/Mouse.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -102,7 +102,7 @@ mousePressed(time, x, y, modifiers, false); break; case Event.MOUSE_DRAG: - mouseDragged(time, x, y, modifiers); + mouseDragged(time, x, y); break; case Event.MOUSE_ENTER: mouseEntered(time, x, y); @@ -157,16 +157,7 @@ @Override public void mouseDragged(MouseEvent e) { - int modifiers = e.getModifiers(); - /**************************************************************** - * Netscape 4.* Win32 has a problem with mouseDragged if you left-drag then - * none of the modifiers are selected we will try to fix that here - ****************************************************************/ - if ((modifiers & Event.BUTTON_MASK) == 0) - modifiers |= Event.MOUSE_LEFT; - - /****************************************************************/ - mouseDragged(e.getWhen(), e.getX(), e.getY(), modifiers); + mouseDragged(e.getWhen(), e.getX(), e.getY()); } @Override @@ -308,15 +299,11 @@ private void mouseEntered(long time, int x, int y) { wheeling = false; - isMouseDown = false; - modifiersDown = 0; manager.mouseEnterExit(time, x, y, false); } private void mouseExited(long time, int x, int y) { wheeling = false; - isMouseDown = false; - modifiersDown = 0; manager.mouseEnterExit(time, x, y, true); } @@ -378,7 +365,7 @@ manager.mouseAction(Event.RELEASED, time, x, y, 0, modifiers); } - private void mouseDragged(long time, int x, int y, int modifiers) { + private void mouseDragged(long time, int x, int y) { if (wheeling) return; if ((modifiersDown & Event.MAC_COMMAND) == Event.MAC_COMMAND) Modified: trunk/Jmol/src/org/jmol/script/ScriptExpr.java =================================================================== --- trunk/Jmol/src/org/jmol/script/ScriptExpr.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/jmol/script/ScriptExpr.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -2342,6 +2342,7 @@ * these, because they must be integrated with the statement dynamically. * * @param st0 aaToken[i] + * @param pt0 * @return a fixed token set -- with possible overrun of unused null tokens * * @throws ScriptException Modified: trunk/Jmol/src/org/jmol/script/T.java =================================================================== --- trunk/Jmol/src/org/jmol/script/T.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/jmol/script/T.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -1200,7 +1200,7 @@ public final static int filter = misc | 116; public final static int first = misc | 118; public final static int fixedtemp = misc | 122; - public final static int flat = misc | 124; +// public final static int flat = misc | 124; was only in Polyhedra; never documented public final static int fps = misc | 126 | expression; public final static int from = misc | 128; public final static int front = misc | 130; @@ -1209,7 +1209,7 @@ public final static int frontonly = misc | 136; public final static int full = misc | 137; public final static int fullplane = misc | 138; - public final static int fullylit = misc | 140; + public final static int fullylit = misc | 140; public final static int functionxy = misc | 142; public final static int functionxyz = misc | 144; public final static int gridpoints = misc | 146; @@ -2226,7 +2226,7 @@ "first", "fixed", "fix", - "flat", +// "flat", "fps", "from", "frontEdges", @@ -3259,7 +3259,7 @@ first, // "first" fixed, // "fixed" -1, // "fix" - flat, // "flat" +// flat, // "flat" fps, // "fps" from, // "from" frontedges, // "frontEdges" Modified: trunk/Jmol/src/org/jmol/scriptext/CmdExt.java =================================================================== --- trunk/Jmol/src/org/jmol/scriptext/CmdExt.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/jmol/scriptext/CmdExt.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -3156,6 +3156,15 @@ private boolean polyhedra() throws ScriptException { ScriptEval eval = e; + // polyhedra + // polyhedra on/off/delete + // polyhedra [type] + // where [type] is one of + // n [opt. BONDS] + // n-m [opt. BONDS] + // [opt. RADIUS] x.y + // polyhedra [type] [ + /* * needsGenerating: * @@ -3166,17 +3175,15 @@ * * polyhedra [at most one selection set] [type-and/or-edge or on/off/delete] */ - boolean needsGenerating = false; + boolean haveBonds = (slen == 1); + boolean needsGenerating = haveBonds; boolean onOffDelete = false; boolean typeSeen = false; boolean edgeParameterSeen = false; - boolean isDesignParameter = false; - int lighting = 0; + // int lighting = T.nada; // never implemented; fullyLit does nothing int nAtomSets = 0; e.sm.loadShape(JC.SHAPE_POLYHEDRA); setShapeProperty(JC.SHAPE_POLYHEDRA, "init", Boolean.TRUE); - String setPropertyName = "centers"; - String decimalPropertyName = "radius_"; float translucentLevel = Float.MAX_VALUE; int[] colorArgb = new int[] { Integer.MIN_VALUE }; for (int i = 1; i < slen; ++i) { @@ -3191,6 +3198,7 @@ case T.unitcell: propertyName = "unitCell"; propertyValue = Boolean.TRUE; + needsGenerating = true; break; case T.only: e.restrictSelected(false, false); @@ -3199,116 +3207,132 @@ case T.on: case T.delete: case T.off: - if (i + 1 != slen || needsGenerating || nAtomSets > 1 || nAtomSets == 0 - && "to".equals(setPropertyName)) + if (i + 1 != slen || needsGenerating || nAtomSets > 1) error(ScriptError.ERROR_incompatibleArguments); propertyName = (eval.theTok == T.off ? "off" : eval.theTok == T.on ? "on" : "delete"); onOffDelete = true; break; - case T.opEQ: - case T.comma: - continue; + case T.integer: + propertyName = "nVertices"; + propertyValue = Integer.valueOf(intParameter(i)); + needsGenerating = true; + switch (tokAt(i + 1)) { + // wish I had not done this. Inconsistent with general syntax; only used here + case T.opEQ: + case T.comma: + i++; + break; + } + break; case T.bonds: if (nAtomSets > 0) invPO(); needsGenerating = true; propertyName = "bonds"; + haveBonds = true; break; case T.radius: - decimalPropertyName = "radius"; - continue; - case T.integer: + i++; + //$FALL-THROUGH$ case T.decimal: - if (nAtomSets > 0 && !isDesignParameter) + if (nAtomSets > 0) invPO(); - if (eval.theTok == T.integer) { - if (decimalPropertyName == "radius_") { - propertyName = "nVertices"; - propertyValue = Integer.valueOf(intParameter(i)); - needsGenerating = true; - break; - } - } - propertyName = (decimalPropertyName == "radius_" ? "radius" - : decimalPropertyName); + propertyName = "radius"; propertyValue = Float.valueOf(floatParameter(i)); - decimalPropertyName = "radius_"; - isDesignParameter = false; needsGenerating = true; break; - case T.bitset: - case T.expressionBegin: - if (typeSeen) - invPO(); - if (++nAtomSets > 2) - eval.bad(); - if ("to".equals(setPropertyName)) - needsGenerating = true; - propertyName = setPropertyName; - setPropertyName = "to"; - propertyValue = atomExpressionAt(i); - i = eval.iToken; + case T.offset: + eval.theTok = T.facecenteroffset; + //$FALL-THROUGH$ + case T.facecenteroffset: + setShapeProperty(JC.SHAPE_POLYHEDRA, "collapsed", Boolean.TRUE); + //$FALL-THROUGH$ + case T.planarparam: + case T.distancefactor: + propertyName = T.nameOf(eval.theTok); + switch (tokAt(i + 1)) { + // wish I had not done this. Inconsistent with general syntax; only used here + case T.opEQ: + case T.comma: + i++; + break; + } + propertyValue = Float.valueOf(floatParameter(++i)); break; case T.to: if (nAtomSets > 1) invPO(); - if (tokAt(i + 1) == T.bitset || tokAt(i + 1) == T.expressionBegin + if ((tokAt(++i) == T.bitset || tokAt(i) == T.expressionBegin) && !needsGenerating) { + // select... polyhedron .... to .... propertyName = "toBitSet"; - propertyValue = atomExpressionAt(++i); - i = eval.iToken; - needsGenerating = true; + propertyValue = atomExpressionAt(i); + } else if (eval.isArrayParameter(i)) { + // select... polyhedron .... to [...] + // polyhedron {...} to [...] + propertyName = "toVertices"; + propertyValue = eval.getPointArray(i, -1, false); + } else { + error(ScriptError.ERROR_insufficientArguments); + } + i = eval.iToken; + needsGenerating = true; + break; + case T.bitset: + case T.expressionBegin: + if (typeSeen) + invPO(); + switch (++nAtomSets) { + case 1: + propertyName = "centers"; break; - } else if (eval.isArrayParameter(i + 1)) { - propertyName = "toVertices"; - propertyValue = eval.getPointArray(i + 1, -1, false); - i = eval.iToken; + case 2: + propertyName = "to"; needsGenerating = true; break; - } else if (!needsGenerating) { - error(ScriptError.ERROR_insufficientArguments); + default: + eval.bad(); } - setPropertyName = "to"; - continue; - case T.facecenteroffset: - case T.planarparam: - case T.distancefactor: -// if (nAtomSets == 0) -// error(ScriptError.ERROR_insufficientArguments); - decimalPropertyName = T.nameOf(eval.theTok); - isDesignParameter = true; - continue; + propertyValue = atomExpressionAt(i); + i = eval.iToken; + if (i + 1 == slen) + needsGenerating = true; + break; case T.color: case T.translucent: case T.opaque: translucentLevel = getColorTrans(eval, i, true, colorArgb); i = eval.iToken; continue; + // case T.flat: // removed in Jmol 14.4 -- never documented case T.collapsed: - case T.flat: - propertyName = "collapsed"; - propertyValue = (eval.theTok == T.collapsed ? Boolean.TRUE - : Boolean.FALSE); + // COLLAPSED + // COLLAPSED [faceCenterOffset] if (typeSeen) error(ScriptError.ERROR_incompatibleArguments); typeSeen = true; + if (isFloatParameter(i + 1)) + setShapeProperty(JC.SHAPE_POLYHEDRA, "faceCenterOffset", + Float.valueOf(floatParameter(++i))); + propertyName = "collapsed"; + propertyValue = Boolean.TRUE; break; - case T.triangles: - case T.notriangles: - propertyName = "token"; - propertyValue = Integer.valueOf(e.theTok); - break; case T.noedges: case T.edges: case T.frontedges: if (edgeParameterSeen) error(ScriptError.ERROR_incompatibleArguments); - propertyName = paramAsStr(i); edgeParameterSeen = true; + propertyName = T.nameOf(eval.iToken); break; + case T.triangles: + case T.notriangles: + case T.backlit: + case T.frontlit: case T.fullylit: - lighting = eval.theTok; + // never implemented or + // lighting = eval.theTok; continue; default: if (eval.isColorParam(i)) { @@ -3322,18 +3346,21 @@ if (onOffDelete) return false; } - if (!needsGenerating && !typeSeen && !edgeParameterSeen && lighting == 0) + if (needsGenerating) { + if (!typeSeen && haveBonds) + setShapeProperty(JC.SHAPE_POLYHEDRA, "bonds", null); + setShapeProperty(JC.SHAPE_POLYHEDRA, "generate", null); + } else if (!edgeParameterSeen) {// && lighting == T.nada) error(ScriptError.ERROR_insufficientArguments); - if (needsGenerating) - setShapeProperty(JC.SHAPE_POLYHEDRA, "generate", null); + } if (colorArgb[0] != Integer.MIN_VALUE) setShapeProperty(JC.SHAPE_POLYHEDRA, "colorThis", Integer.valueOf(colorArgb[0])); if (translucentLevel != Float.MAX_VALUE) eval.setShapeTranslucency(JC.SHAPE_POLYHEDRA, "", "translucentThis", translucentLevel, null); - if (lighting != 0) - setShapeProperty(JC.SHAPE_POLYHEDRA, "token", Integer.valueOf(lighting)); + // if (lighting != T.nada) + // setShapeProperty(JC.SHAPE_POLYHEDRA, "token", Integer.valueOf(lighting)); setShapeProperty(JC.SHAPE_POLYHEDRA, "init", Boolean.FALSE); return true; } Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java =================================================================== --- trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedra.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -56,16 +56,15 @@ public class Polyhedra extends AtomShape { private final static float DEFAULT_DISTANCE_FACTOR = 1.85f; - // private final static float DEFAULT_MANY_VERTEX_DISTANCE_FACTOR = 1.5f; private final static float DEFAULT_FACECENTEROFFSET = 0.25f; private final static int EDGES_NONE = 0; public final static int EDGES_ALL = 1; public final static int EDGES_FRONT = 2; private final static int MAX_VERTICES = 250; private final static int FACE_COUNT_MAX = MAX_VERTICES - 3; - private P3[] otherAtoms = new P3[MAX_VERTICES + 1]; + private P3[] otherAtoms = new P3[MAX_VERTICES + FACE_COUNT_MAX + 1]; private V3[] normalsT = new V3[MAX_VERTICES + 1]; - private int[][] planesT = new int[MAX_VERTICES][3]; + private int[][] planesT = AU.newInt2(MAX_VERTICES); private final static P3 randomPoint = P3.new3(3141f, 2718f, 1414f); private static final int MODE_BONDING = 1; @@ -103,7 +102,6 @@ private float planarParam; private Map<String, SV> info; private float distanceRef; - private int nBondsRef; @SuppressWarnings("unchecked") @Override @@ -179,7 +177,7 @@ if ("toVertices" == propertyName) { P3[] points = (P3[]) value; - nPoints = points.length; + nPoints = Math.min(points.length, MAX_VERTICES); for (int i = nPoints; --i >= 0;) otherAtoms[i] = points[i]; return; @@ -271,14 +269,15 @@ //allow super } - if ("token" == propertyName) { - int tok = ((Integer) value).intValue(); - 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(); @@ -289,11 +288,10 @@ int modelIndex = ((int[]) ((Object[]) value)[2])[0]; for (int i = polyhedronCount; --i >= 0;) { polyhedrons[i].info = null; - if (polyhedrons[i].modelIndex == modelIndex) { + int mi = polyhedrons[i].centralAtom.mi; + if (mi == modelIndex) { polyhedronCount--; polyhedrons = (Polyhedron[]) AU.deleteElements(polyhedrons, i, 1); - } else if (polyhedrons[i].modelIndex > modelIndex) { - polyhedrons[i].modelIndex--; } } //pass on to AtomShape @@ -310,9 +308,9 @@ s += polyhedrons[i].getSymmetry(vwr, true) + "\n"; return s; } - return null; + return null; } - + @Override public boolean getPropertyData(String property, Object[] data) { int iatom; @@ -329,8 +327,10 @@ return false; } if (property == "move") { + M4 mat = (M4) data[1]; + if (mat == null) + return false; BS bs = (BS) data[0]; - M4 mat = (M4) data[1]; for (int i = polyhedronCount; --i >= 0;) { Polyhedron p = polyhedrons[i]; if (bs.get(p.centralAtom.i)) @@ -391,17 +391,17 @@ return lst; } - private void setLighting(boolean isFullyLit, BS bs) { - for (int i = polyhedronCount; --i >= 0;) - if (bs.get(polyhedrons[i].centralAtom.i)) { - short[] normixes = polyhedrons[i].getNormixes(); - polyhedrons[i].isFullyLit = isFullyLit; - for (int j = normixes.length; --j >= 0;) { - if (normixes[j] < 0 != isFullyLit) - normixes[j] = (short) ~normixes[j]; - } - } - } +// private void setLighting(boolean isFullyLit, BS bs) { +// for (int i = polyhedronCount; --i >= 0;) +// if (bs.get(polyhedrons[i].centralAtom.i)) { +// short[] normixes = polyhedrons[i].getNormixes(); +// polyhedrons[i].isFullyLit = isFullyLit; +// for (int j = normixes.length; --j >= 0;) { +// if (normixes[j] < 0 != isFullyLit) +// normixes[j] = (short) ~normixes[j]; +// } +// } +// } private BS andBitSet(BS bs) { BS bsCenters = new BS(); @@ -435,17 +435,19 @@ } } + private int buildMode; + private void buildPolyhedra() { boolean useBondAlgorithm = radius == 0 || bondedOnly; - int mode = (info != null ? MODE_INFO : nPoints > 0 ? MODE_POINTS + buildMode = (info != null ? MODE_INFO : nPoints > 0 ? MODE_POINTS : haveBitSetVertices ? MODE_BITSET : useUnitCell ? MODE_UNITCELL : useBondAlgorithm ? MODE_BONDING : MODE_ITERATE); - AtomIndexIterator iter = (mode == MODE_ITERATE ? ms + AtomIndexIterator iter = (buildMode == MODE_ITERATE ? 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 (mode) { + switch (buildMode) { case MODE_BITSET: bsVertices.clear(i); p = constructBitSetPolyhedron(atom); @@ -529,7 +531,7 @@ if (!bond.isCovalent()) continue; Atom other = bond.getOtherAtom(atom); - if (bsVertices != null && !bsVertices.get(i) || radius > 0 + if (bsVertices != null && !bsVertices.get(other.i) || radius > 0 && other.distance(atom) > radius) continue; otherAtoms[bondCount++] = other; @@ -537,7 +539,6 @@ break; } } - nBondsRef = bondCount; distanceRef = 0; return (bondCount < 3 || bondCount >= MAX_VERTICES || nVertices > 0 && !bsVertexCount.get(bondCount) ? null : validatePolyhedron(atom, @@ -546,7 +547,6 @@ private Polyhedron constructBitSetPolyhedron(Atom atom) { int otherAtomCount = 0; - nBondsRef = bsVertices.cardinality(); distanceRef = 0; for (int i = bsVertices.nextSetBit(0); i >= 0; i = bsVertices .nextSetBit(i + 1)) @@ -556,12 +556,12 @@ private Polyhedron constructRadiusPolyhedron(Atom atom, AtomIndexIterator iter) { int otherAtomCount = 0; - nBondsRef = 0; distanceRef = radius; 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) @@ -579,62 +579,64 @@ } private Polyhedron validatePolyhedron(Atom centralAtom, int vertexCount, - P3[] otherAtoms) { + P3[] points) { + boolean collapsed = isCollapsed; + boolean checkDist = (distanceRef != 0); int planeCount = 0; - int iCenter = vertexCount; - int nPoints = iCenter + 1; - float distMax = 0; - float dAverage = 0; + int nPoints = vertexCount + 1; + int ni = vertexCount - 2; + int nj = vertexCount - 1; float planarParam = (Float.isNaN(this.planarParam) ? DEFAULT_PLANAR_PARAM : this.planarParam); - P3[] points = new P3[MAX_VERTICES * 3]; - points[iCenter] = otherAtoms[iCenter] = centralAtom; - for (int i = 0; i < iCenter; i++) { - points[i] = otherAtoms[i]; - dAverage += points[iCenter].distance(points[i]); - } - dAverage = dAverage / iCenter; - boolean isOK = (dAverage == 0); - int nRef = iCenter; - int nother1 = iCenter - 1; - int nother2 = iCenter - 2; float factor = (!Float.isNaN(distanceFactor) ? distanceFactor : DEFAULT_DISTANCE_FACTOR); - BS bs = BS.newN(iCenter); + BS bs = BS.newN(vertexCount); // here we are assuring that at least ONE face is drawn to - // all matching vertices + // all matching vertices -- skip this for BOND polyhedra - while (!isOK && factor < 10.0f) { - distMax = dAverage * factor; - bs.setBits(0, iCenter); - for (int i = 0; i < nother2; i++) - for (int j = i + 1; j < nother1; j++) { - if (points[i].distance(points[j]) > distMax) - continue; - for (int k = j + 1; k < iCenter; k++) { - if (points[i].distance(points[k]) > distMax - || points[j].distance(points[k]) > distMax) + points[vertexCount] = centralAtom; + P3 ptAve = new P3(); + 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; - bs.clear(i); - bs.clear(j); - bs.clear(k); + 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 < iCenter; i++) - if (bs.get(i)) { - isOK = false; - factor *= 1.05f; - if (Logger.debugging) { - Logger.debug("Polyhedra distanceFactor for " + iCenter - + " atoms increased to " + factor + " in order to include " - + otherAtoms[i]); + 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; } - break; - } + } } - /* 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 @@ -652,53 +654,40 @@ * For these special cases, then, we define a reference point just behind the plane */ - // produce face-centered catalog and facet-aligned catalog - String facesThroughCenter = ""; - String ignoreFlat = ""; - P3 ptRef = P3.newP(points[iCenter]); - for (int i = 0; i < nother2; i++) - for (int j = i + 1; j < nother1; j++) - for (int k = j + 1; k < iCenter; k++) { - if (isPlanar(points[i], points[j], points[k], ptRef)) { - facesThroughCenter += faceId(i, j, k); - if (isAligned(points[i], points[j], ptRef)) - ignoreFlat += faceId(i, j, -1); - if (isAligned(points[j], points[k], ptRef)) - ignoreFlat += faceId(j, k, -1); - if (isAligned(points[i], points[k], ptRef)) - ignoreFlat += faceId(i, k, -1); - } - } - ptRef = new P3(); + P3 ptRef = P3.newP(ptAve); + BS bsThroughCenter = new BS(); + 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[][] p = planesT; + int[][] faces = planesT; P4 pTemp = new P4(); V3 nTemp = new V3(); float offset = faceCenterOffset; int fmax = FACE_COUNT_MAX; int vmax = MAX_VERTICES; - P3 rpt = randomPoint; BS bsTemp = Normix.newVertexBitSet(); BS bsTemp1 = new BS(); V3[] normals = normalsT; Map<Object, Object> htNormMap = new Hashtable<Object, Object>(); - BS bsFlat = new BS(); - String facet; + BS bsCenterPlanes = new BS(); V3 vTemp = vAC; - boolean isComplex = (iCenter >= 5); - boolean doAllowFlat = !isComplex && !useUnitCell; - boolean collapsed = isCollapsed; - for (int i = 0; i < nother2; i++) - for (int j = i + 1; j < nother1; j++) { - if (points[i].distance(points[j]) > distMax) + 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 < iCenter; k++) { - if (points[i].distance(points[k]) > distMax - || points[j].distance(points[k]) > distMax) + } + 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) { Logger.error("Polyhedron error: maximum face(" + fmax - + ") -- reduce RADIUS or DISTANCEFACTOR"); + + ") -- reduce RADIUS"); return null; } if (nPoints >= vmax) { @@ -706,108 +695,76 @@ + ") -- reduce RADIUS"); return null; } - boolean isFlat = (facesThroughCenter.indexOf(faceId(i, j, k)) >= 0); - if (isFlat && !doAllowFlat) + boolean isThroughCenter = bsThroughCenter.get(pt); + P3 rpt = (isThroughCenter ? randomPoint : ptAve); + V3 normal = new V3(); + boolean isWindingOK = getNormalFromCenter(rpt, points[i], points[j], + points[k], !isThroughCenter, normal); + // the standard face: + normals[planeCount] = normal; + faces[planeCount] = new int[] { isWindingOK ? i : j, isWindingOK ? j : i, + k, -7 }; + if (!checkFace(points, vertexCount, faces, normals, planeCount, pTemp, nTemp, + vTemp, htNormMap, planarParam, bsTemp, bsTemp1)) continue; - // if center is on the face, then we need an arbitrary reference point to - // define the normal - boolean isSpecial = collapsed; - V3 normal = new V3(); - boolean isWindingOK; - if (isFlat) { - isWindingOK = getNormalFromCenter(rpt, points[i], points[j], - points[k], false, normal); + if (isThroughCenter) { + bsCenterPlanes.set(planeCount++); + } 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); + addFacet(k, i, j, ptRef, points, normals, faces, planeCount++, nPoints, + isWindingOK); + addFacet(j, k, i, ptRef, points, normals, faces, planeCount++, nPoints, + isWindingOK); + nPoints++; } else { - isWindingOK = getNormalFromCenter(points[iCenter], points[i], - points[j], points[k], true, normal); - // the standard face: - p[planeCount] = new int[] { isWindingOK ? i : j, - isWindingOK ? j : i, k, -7 }; - normals[planeCount] = normal; - if (isComplex - && !checkFace(points, iCenter, p, normals, planeCount, pTemp, - nTemp, vTemp, htNormMap, planarParam, bsTemp, bsTemp1)) - continue; -// System.out.println("draw ID \"d" + faceId(i, j, k) + "\" VECTOR " -// + ptRef + " " + normal + "\">" + faceId(i, j, k) + isWindingOK -// + "\""); - } - if (!isFlat && !isSpecial) { planeCount++; - continue; } - if (isFlat) { - ptRef.sub2(points[iCenter], normal); - nRef = iCenter; - } else { - nRef = nPoints; - otherAtoms[nPoints] = points[nPoints] = new P3(); - points[nPoints++].scaleAdd2(offset, normal, points[iCenter]); - } - // facet i j k - if (!collapsed) { - facet = faceId(i, j, -1); - isSpecial = (ignoreFlat.indexOf(facet) < 0); - if (isSpecial) { - ignoreFlat += facet; - bsFlat.set(planeCount); - } - } - if (isSpecial) { - p[planeCount] = new int[] { isWindingOK ? i : j, - isWindingOK ? j : i, nRef, isFlat ? -15 : -6 }; - getNormalFromCenter(points[k], points[i], points[j], ptRef, false, - normal); - normals[planeCount++] = normal; - } - // facet i k j - if (!collapsed) { - facet = faceId(i, k, -1); - isSpecial = (ignoreFlat.indexOf(facet) < 0); - if (isSpecial) { - ignoreFlat += facet; - bsFlat.set(planeCount); - } - } - if (isSpecial) { - p[planeCount] = new int[] { isWindingOK ? i : k, nRef, - isWindingOK ? k : i, isFlat ? -15 : -5 }; - getNormalFromCenter(points[j], points[i], ptRef, points[k], false, - normal); - normals[planeCount++] = normal; - } - // face j k i - if (!collapsed) { - facet = faceId(j, k, -1); - isSpecial = (ignoreFlat.indexOf(facet) < 0); - if (isSpecial) { - ignoreFlat += facet; - bsFlat.set(planeCount); - } - } - if (isSpecial) { - p[planeCount] = new int[] { nRef, isWindingOK ? j : k, - isWindingOK ? k : j, isFlat ? -15 : -4 }; - getNormalFromCenter(points[i], ptRef, points[j], points[k], false, - normal); - normals[planeCount++] = normal; - } } } nPoints--; - if (Logger.debugging) { Logger .info("Polyhedron planeCount=" + planeCount + " nPoints=" + nPoints); for (int i = 0; i < planeCount; i++) - Logger.info("Polyhedron " + getKey(p[i], i)); + Logger.info("Polyhedron " + PT.toJSON("face[" +i + "]", faces[i])); } - return new Polyhedron().set(centralAtom, iCenter, nPoints, planeCount, - otherAtoms, normals, bsFlat, p, collapsed, distanceRef); + return new Polyhedron().set(centralAtom, points, nPoints, vertexCount, + faces, planeCount, 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. * + * @param i + * @param j + * @param k + * @param ptRef slightly out from the center; based on centerOffset parameter + * @param points + * @param normals + * @param faces + * @param planeCount + * @param nRef + * @param isWindingOK + */ + private void addFacet(int i, int j, int k, P3 ptRef, P3[] points, + V3[] normals, int[][] faces, int planeCount, int nRef, + boolean isWindingOK) { + V3 normal = new V3(); + getNormalFromCenter(points[k], ptRef, points[i], points[j], false, normal); + normals[planeCount] = normal; + faces[planeCount] = new int[] { nRef, isWindingOK ? i : j, isWindingOK ? j : i, + -2 }; + // System.out.println("draw ID \"d" + faceId(i, j, k) + "\" VECTOR " + // + ptRef + " " + normal + " color blue \">" + faceId(i, j, k) + isWindingOK + // + "\""); + } + + /** + * * @param ptCenter * @param ptA * @param ptB @@ -828,43 +785,38 @@ } /** - * Clean out oeverlapping triangles based on normals and cross products. - * For now, we use normixes, which are approximations of normals. - * It is not 100% guaranteed that this will work. + * Clean out overlapping triangles based on normals and cross products. For + * now, we use normixes, which are approximations of normals. It is not 100% + * guaranteed that this will work. * * @param points - * @param ptCenter + * @param nPoints * @param planes * @param normals * @param index * @param pTemp * @param vNorm + * @param vTemp * @param htNormMap * @param planarParam * @param bsTemp + * @param bsPts * @return true if valid */ - private boolean checkFace(P3[] points, int ptCenter, int[][] planes, - V3[] normals, int index, P4 pTemp, V3 vNorm, V3 vTemp, - Map<Object, Object> htNormMap, float planarParam, - BS bsTemp, BS bsPts) { + 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) { 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); - // P3 ptest = P3.newP(points[p1[0]]); - // ptest.add(points[p1[1]]); - // ptest.add(points[p1[2]]); - // ptest.scale(1/3f); - // System.out.println("$draw ID p" + index +" vector " + ptest + vNorm); - // See if all vertices are OUTSIDE the the plane we are considering. - for (int j = 0; j < ptCenter; j++) { + for (int j = 0; j < nPoints; j++) { vTemp.sub2(points[p1[0]], points[j]); float v = vTemp.dot(vNorm); - if (v < -0.1) { - //System.out.println("$draw ID p" + index + "_" + j + points[j]); + if (v < -0.15) { return false; } } @@ -877,14 +829,14 @@ for (Entry<Object, Object> e : htNormMap.entrySet()) { Object ikey = e.getKey(); if (ikey instanceof Integer) { - Integer n = (Integer)ikey; + Integer n = (Integer) ikey; if (norms[n.intValue()].dot(norm) > planarParam) { normix = n; break; } } } - htNormMap.put(normix, Boolean.TRUE); + htNormMap.put(normix, Boolean.TRUE); } bsPts.clearAll(); for (int i = 0; i < 3; i++) @@ -894,13 +846,13 @@ } /** - * Check each edge to see that + * Check each edge to see that * * (a) it has not been used before * * (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 + * (c) if it runs opposite another edge, then both edge masks are set properly * * @param htNormMap * @param normix @@ -921,7 +873,6 @@ String edge = normix + s + s1; if (htNormMap.containsKey(edge)) return false; -// System.out.println(edge); //reverse maps are in String edge0 = normix + s1 + s; Object o = htNormMap.get(edge0); @@ -956,36 +907,11 @@ return true; } - private String getKey(int[] p1, int index) { - SB sb = new SB(); - for (int i = 0, n = p1.length; i < n; i++) - if (p1[i] >= 0) - sb.append("_").appendI(p1[i]); - sb.append("_").appendI(p1[0]); - sb.append("_,").appendI(index).append(";"); - return sb.toString(); - } - - private String faceId(int i, int j, int k) { - return "[" + i + "," + j + "," + k + "]"; - } - - private V3 align1 = new V3(); - private V3 align2 = new V3(); - - private boolean isAligned(P3 pt1, P3 pt2, P3 pt3) { - align1.sub2(pt1, pt3); - align2.sub2(pt2, pt3); - float angle = align1.angle(align2); - return (angle < 0.01f || angle > 3.13f); - } - private final V3 vAB = new V3(); private final V3 vAC = new V3(); private final V3 vBC = new V3(); - - private static float minDistanceForPlanarity = 0.1f; + private static float MAX_DISTANCE_TO_PLANE = 0.1f; private boolean isPlanar(P3 pt1, P3 pt2, P3 pt3, P3 ptX) { /* @@ -997,7 +923,7 @@ V3 norm = new V3(); float w = Measure.getNormalThroughPoints(pt1, pt2, pt3, norm, vAB); float d = Measure.distanceToPlaneV(norm, w, ptX); - return (Math.abs(d) < minDistanceForPlanarity); + return (Math.abs(d) < MAX_DISTANCE_TO_PLANE); } @Override @@ -1011,7 +937,7 @@ Polyhedron p = polyhedrons[i]; if (ms.at[p.centralAtom.i].isDeleted()) p.isValid = false; - p.visibilityFlags = (p.visible && bsModels.get(p.modelIndex) + 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) Modified: trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java =================================================================== --- trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/jmol/shapespecial/Polyhedron.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -26,16 +26,16 @@ public class Polyhedron { - int modelIndex; public Atom centralAtom; public P3[] vertices; public int[][] faces; int nVertices; - boolean collapsed = false; + boolean collapsed; private BS bsFlat; - + private float distanceRef; private V3[] normals; private short[] normixes; + public String smiles, smarts, stereoSmiles; private SymmetryInterface pointGroup; private Float volume; @@ -45,24 +45,22 @@ public boolean isValid = true; public short colixEdge = C.INHERIT_ALL; public int visibilityFlags = 0; - private float distanceRef; Polyhedron() { } - Polyhedron set(Atom centralAtom, int nVertices, int nPoints, int planeCount, - P3[] otherAtoms, V3[] normals, BS bsFlat, int[][] planes, boolean collapsed, float distanceRef) { + Polyhedron set(Atom centralAtom, P3[] points, int nPoints, int vertexCount, + int[][] planes, int planeCount, V3[] normals, BS bsFlat, boolean collapsed, float distanceRef) { this.distanceRef = distanceRef; this.centralAtom = centralAtom; - modelIndex = centralAtom.mi; - this.nVertices = nVertices; + this.nVertices = vertexCount; this.vertices = new P3[nPoints + 1]; this.normals = new V3[planeCount]; this.bsFlat = bsFlat; this.faces = AU.newInt2(planeCount); for (int i = nPoints + 1; --i >= 0;) // includes central atom as last atom or possibly reference point - vertices[i] = otherAtoms[i]; + vertices[i] = points[i]; for (int i = planeCount; --i >= 0;) this.normals[i] = V3.newV(normals[i]); for (int i = planeCount; --i >= 0;) @@ -85,7 +83,6 @@ info.put("atomNumber", Integer.valueOf(centralAtom.getAtomNumber())); info.put("atomName", centralAtom.getInfo()); info.put("element", centralAtom.getElementSymbol()); - info.put("vertexCount", Integer.valueOf(nVertices)); info.put("faceCount", Integer.valueOf(faces.length)); info.put("volume", getVolume()); if (smarts != null) @@ -103,10 +100,15 @@ info.put("bsFlat", bsFlat); if (collapsed) info.put("collapsed", Boolean.valueOf(collapsed)); - info.put("ptRef", vertices[nVertices]); + 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, nVertices)); + 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++) { @@ -120,12 +122,25 @@ Polyhedron setInfo(Map<String, SV> info, Atom[] at) { try { + collapsed = info.containsKey("collapsed"); centralAtom = at[info.get("atomIndex").intValue]; - modelIndex = centralAtom.mi; Lst<SV> lst = info.get("vertices").getList(); - vertices = new P3[lst.size() + 1]; - nVertices = vertices.length - 1; - for (int i = nVertices; --i >= 0;) + SV vc = info.get("vertexCount"); + if (vc == null) { + // old style + nVertices = lst.size(); + vertices = new P3[nVertices + 1]; + vertices[nVertices] = SV.ptValue(info.get("ptRef")); + } else { + nVertices = vc.intValue; + vertices = new P3[lst.size()]; + vc = info.get("distanceRef"); + if (vc != null) + distanceRef = vc.asFloat(); + } + // note that nVertices will be smaller than lst.size() + // because lst will contain the central atom and any collapsed points + for (int i = lst.size(); --i >= 0;) vertices[i] = SV.ptValue(lst.get(i)); lst = info.get("elemNos").getList(); for (int i = nVertices; --i >= 0;) { @@ -137,7 +152,6 @@ vertices[i] = p; } } - vertices[nVertices] = SV.ptValue(info.get("ptRef")); lst = info.get("faces").getList(); faces = AU.newInt2(lst.size()); normals = new V3[faces.length]; @@ -153,7 +167,6 @@ vertices[a[2]], normals[i], vAB); } bsFlat = SV.getBitSet(info.get("bsFlat"), false); - collapsed = info.containsKey("collapsed"); } catch (Exception e) { return null; } @@ -194,13 +207,14 @@ V3 vAC = new V3(); V3 vTemp = new V3(); float v = 0; - for (int i = faces.length; --i >= 0;) { - int[] face = faces[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, - vTemp); - } + if (bsFlat.cardinality() < faces.length) + for (int i = faces.length; --i >= 0;) { + int[] face = faces[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, + vTemp); + } return Float.valueOf(v / 6); } @@ -214,7 +228,7 @@ } String getState(Viewer vwr) { - return " var p = " + Escape.e(getInfo(vwr, false)) + ";polyhedron @p" + return "polyhedron @" + Escape.e(getInfo(vwr, false)) + (isFullyLit ? " fullyLit" : "") + ";" + (visible ? "" : "polyhedra ({"+centralAtom.i+"}) off;") + "\n"; } Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties =================================================================== --- trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2015-09-06 04:09:52 UTC (rev 20757) @@ -59,8 +59,24 @@ TODO: image off stops JSmol TODO: Rolf's errors in Safari due to move + zoomto -Jmol.___JmolVersion="14.3.16_2015.09.04" +Jmol.___JmolVersion="14.3.16_2015.09.05" +new feature: POLYHEDRA + -- same as POLYHEDRA BONDS {selected} +new feature: POLYHEDRA 4 + -- same as POLYHEDRA 4 BONDS {selected} +new feature: POLYHEDRA OFFSET 1.4 + -- same as POLYHEDRA COLLAPSED faceCenterOffset 1.4 +new feature: POLYHEDRA COLLAPSED 1.4 + -- same as POLYHEDRA COLLAPSED faceCenterOffset 1.4 + +code: Polyhedra work, including more efficient algorithms for completing set of faces + +bug fix: tracking down thread-safe issue in application console +bug fix: in Java, mouse should not lose control if moved out of application + +JmolVersion="14.3.16_2015.09.04" + bug fix: Mac OS does not add modifiers (left, right, ctrl, etc.) to drag operations Modified: trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java =================================================================== --- trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -28,6 +28,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Font; import java.awt.Rectangle; import java.awt.Window; @@ -777,7 +778,16 @@ : 1) : vwr.getSetHistory(up ? -1 : 1)); if (cmd == null) { - hBar.setValue(0); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + try { + hBar.setValue(0); + } catch (Throwable e) { + // + } + } + }); return; } boolean isError = false; @@ -914,16 +924,20 @@ pt = caretPosition.getOffset(); consoleTextPane.setCaretPosition(pt); - try { - vBar.setValue(vBar.getMaximum()); - } catch (Throwable e) { - // - } - } catch (Exception e) { e.printStackTrace(); consoleTextPane.setCaretPosition(getLength()); } + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + try { + vBar.setValue(vBar.getMaximum()); + } catch (Throwable e) { + // + } + } + }); } void outputError(String strError) { Modified: trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/ConsoleTextArea.java =================================================================== --- trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/ConsoleTextArea.java 2015-09-05 04:19:46 UTC (rev 20756) +++ trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/ConsoleTextArea.java 2015-09-06 04:09:52 UTC (rev 20757) @@ -29,10 +29,8 @@ import java.io.InputStreamReader; import java.io.PrintStream; -import javax.swing.JOptionPane; import javax.swing.JTextArea; -import org.jmol.i18n.GT; import org.openscience.jmol.app.jmolpanel.LoopedStreams; public class ConsoleTextArea extends JTextArea { @@ -50,46 +48,35 @@ String redirect = (doRedirect ? System.getProperty("JmolConsole") : "false"); if (redirect == null || redirect.equals("true")) { - // Redirect System.out & System.err. - + // Redirect System.out & System.err. PrintStream ps = new PrintStream(ls.getOutputStream()); System.setOut(ps); System.setErr(ps); } - startConsoleReaderThread(ls.getInputStream()); } // ConsoleTextArea() private void startConsoleReaderThread(InputStream inStream) { - final BufferedReader br = - new BufferedReader(new InputStreamReader(inStream)); + final BufferedReader br = new BufferedReader(new InputStreamReader(inStream)); new Thread(new Runnable() { - - @Override public void run() { Thread.currentThread().setName("ConsoleReaderThread"); - StringBuilder sb = new StringBuilder(); try { String s; //Document doc = getDocument(); - s = br.readLine(); - while (s != null) { + while ((s = br.readLine()) != null) { //boolean caretAtEnd = false; //caretAtEnd = (getCaretPosition() == doc.getLength()); - sb.setLength(0); - append(sb.append(s).append('\n').toString()); + append(s + "\n"); //if (caretAtEnd) { //setCaretPosition(doc.getLength()); //} - s = br.readLine(); } - } catch (IOException e) { - JOptionPane.showMessageDialog(null, GT.o(GT._( - "Error reading from BufferedReader: {0}"), e.getMessage())); - System.exit(1); + } catch (Exception e) { + // } } }).start(); 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