/* $RCSfile$
* $Author: hansonr $
* $Date: 2007-04-18 01:25:52 -0500 (Wed, 18 Apr 2007) $
* $Revision: 7435 $
*
* Copyright (C) 2002-2005 The Jmol Development Team
*
* Contact: jmol-developers@lists.sf.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jmol.shape;
import org.jmol.g3d.*;
import org.jmol.viewer.JmolConstants;
import org.jmol.viewer.StateManager;
import org.jmol.script.Token;
import java.util.BitSet;
import java.util.Hashtable;
import javax.vecmath.Point3f;
import org.jmol.util.Escape;
import org.jmol.util.ArrayUtil;
import org.jmol.util.Logger;
import org.jmol.util.TextFormat;
public abstract class MeshCollection extends Shape {
// Draw, Isosurface(LcaoCartoon MolecularOrbital Pmesh)
public int meshCount;
public Mesh[] meshes = new Mesh[4];
public Mesh currentMesh;
public int modelCount;
public boolean isFixed;
public String script;
public int nUnnamed;
public short colix;
public String myType;
public boolean explicitID;
public String actualID;
protected String previousMeshID;
protected Mesh linkedMesh;
protected boolean iHaveModelIndex;
protected int modelIndex;
protected boolean allowContourLines;
protected boolean haveContours = false;
public String[] title;
protected boolean allowMesh = true;
private Mesh setMesh(String thisID) {
linkedMesh = null;
if (thisID == null || TextFormat.isWild(thisID)) {
currentMesh = null;
return null;
}
currentMesh = getMesh(thisID);
if (currentMesh == null) {
allocMesh(thisID, null);
} else if (thisID.equals(JmolConstants.PREVIOUS_MESH_ID)) {
linkedMesh = currentMesh.linkedMesh;
}
if (currentMesh.thisID == null) {
currentMesh.thisID = myType + (++nUnnamed);
if (htObjects != null)
htObjects.put(currentMesh.thisID.toUpperCase(), currentMesh);
}
previousMeshID = currentMesh.thisID;
return currentMesh;
}
protected Hashtable htObjects;
public void allocMesh(String thisID, Mesh m) {
// this particular version is only run from privately;
// isosurface and draw both have overriding methods
int index = meshCount++;
meshes = (Mesh[])ArrayUtil.ensureLength(meshes, meshCount * 2);
currentMesh = meshes[index] = (m == null ? new Mesh(thisID, g3d, colix, index) : m);
currentMesh.index = index;
if (thisID != null && htObjects != null)
htObjects.put(thisID.toUpperCase(), currentMesh);
previousMeshID = null;
}
/**
* called by ParallelProcessor at completion
*
* @param shape
*
*/
public void merge(Shape shape) {
MeshCollection mc = (MeshCollection) shape;
for (int i = 0; i < mc.meshCount; i++) {
if (mc.meshes[i] != null) {
Mesh m = mc.meshes[i];
Mesh m0 = getMesh(m.thisID);
if (m0 == null) {
allocMesh(m.thisID, m);
} else {
meshes[m0.index] = m;
m.index = m0.index;
}
}
}
previousMeshID = null;
currentMesh = null;
}
public void initShape() {
super.initShape();
colix = Graphics3D.ORANGE;
modelCount = viewer.getModelCount();
}
public void setProperty(String propertyName, Object value, BitSet bs) {
if (propertyName == "setXml") {
if (currentMesh != null)
currentMesh.xmlProperties = xmlProperties;
}
if ("init" == propertyName) {
title = null;
return;
}
if ("link" == propertyName) {
if (meshCount >= 2 && currentMesh != null)
currentMesh.linkedMesh = meshes[meshCount - 2];
return;
}
if ("lattice" == propertyName) {
if (currentMesh != null)
currentMesh.lattice = (Point3f) value;
return;
}
if ("variables" == propertyName) {
if (currentMesh != null && currentMesh.scriptCommand != null && !currentMesh.scriptCommand.startsWith("{"))
currentMesh.scriptCommand = "{\n" + StateManager.getVariableList((Hashtable) value, 0, false) + "\n" + currentMesh.scriptCommand;
return;
}
if ("commandOption" == propertyName) {
String s = "# " + (String) value;
if (script.indexOf(s) < 0)
script += " " + s;
return;
}
if ("thisID" == propertyName) {
String id = (String) value;
setMesh(id);
checkExplicit(id);
return;
}
if ("title" == propertyName) {
if (value == null) {
title = null;
} else if (value instanceof String[]) {
title = (String[]) value;
} else {
int nLine = 1;
String lines = (String) value;
for (int i = lines.length(); --i >= 0;)
if (lines.charAt(i) == '|')
nLine++;
title = new String[nLine];
nLine = 0;
int i0 = -1;
for (int i = 0; i < lines.length(); i++)
if (lines.charAt(i) == '|') {
title[nLine++] = lines.substring(i0 + 1, i);
i0 = i;
}
title[nLine] = lines.substring(i0 + 1);
}
return;
}
if ("delete" == propertyName) {
deleteMesh();
return;
}
if ("reset" == propertyName) {
String thisID = (String) value;
if (setMesh(thisID) == null)
return;
// deleteMesh();
setMesh(thisID);
return;
}
if ("color" == propertyName) {
if (value == null)
return;
colix = Graphics3D.getColix(value);
setProperty(Token.color, false);
return;
}
if ("translucency" == propertyName) {
setProperty(Token.translucent, (((String) value).equals("translucent")));
return;
}
if ("hidden" == propertyName) {
value = new Integer(((Boolean)value).booleanValue() ? Token.off: Token.on);
propertyName = "token";
//continue
}
if ("token" == propertyName) {
int tok = ((Integer) value).intValue();
int tok2 = 0;
boolean test = true;
switch (tok) {
case Token.on:
case Token.frontlit:
case Token.backlit:
case Token.fullylit:
case Token.dots:
case Token.fill:
case Token.triangles:
case Token.frontonly:
break;
case Token.off:
test = false;
tok = Token.on;
break;
case Token.contourlines:
tok2 = Token.mesh;
break;
case Token.nocontourlines:
test = false;
tok = (true || allowContourLines ? Token.contourlines : Token.mesh);
tok2 = Token.mesh;
break;
case Token.mesh:
tok2 = Token.contourlines;
break;
case Token.nomesh:
test = false;
tok = Token.mesh;
tok2 = Token.contourlines;
break;
case Token.nodots:
test = false;
tok = Token.dots;
break;
case Token.nofill:
test = false;
tok = Token.fill;
break;
case Token.notriangles:
test = false;
tok = Token.triangles;
break;
case Token.notfrontonly:
test = false;
tok = Token.frontonly;
break;
default:
Logger.error("PROBLEM IN MESHCOLLECTION: token? " + Token.nameOf(tok));
}
setProperty(tok, test);
if (tok2 != 0) {
if (currentMesh.havePlanarContours && currentMesh.drawTriangles != currentMesh.showContourLines)
setProperty(tok2, test);
}
return;
}
super.setProperty(propertyName, value, bs);
}
protected void checkExplicit(String id) {
if (explicitID) // not twice
return;
explicitID = (id != null && !id.equals(JmolConstants.PREVIOUS_MESH_ID));
if (explicitID)
previousMeshID = id;
}
private void setProperty(int tokProp, boolean bProp) {
if (currentMesh != null) {
switch (tokProp) {
case Token.on:
currentMesh.visible = bProp;
return;
case Token.color:
currentMesh.colix = colix;
if (linkedMesh != null)
linkedMesh.colix = colix;
return;
case Token.translucent:
currentMesh.setTranslucent(bProp, translucentLevel);
if (linkedMesh != null)
linkedMesh.setTranslucent(bProp, translucentLevel);
return;
case Token.frontlit:
case Token.backlit:
case Token.fullylit:
currentMesh.setLighting(tokProp);
if (linkedMesh != null)
linkedMesh.setLighting(tokProp);
return;
case Token.contourlines:
currentMesh.showContourLines = bProp;
if (linkedMesh != null)
linkedMesh.showContourLines = bProp;
return;
case Token.mesh:
currentMesh.drawTriangles = bProp;
if (linkedMesh != null)
linkedMesh.drawTriangles = bProp;
return;
case Token.dots:
currentMesh.showPoints = bProp;
if (linkedMesh != null)
linkedMesh.showPoints = bProp;
return;
case Token.fill:
currentMesh.fillTriangles = bProp;
if (linkedMesh != null)
linkedMesh.fillTriangles = bProp;
return;
case Token.triangles:
currentMesh.showTriangles = bProp;
if (linkedMesh != null)
linkedMesh.showTriangles = bProp;
return;
case Token.frontonly:
currentMesh.frontOnly = bProp;
if (linkedMesh != null)
linkedMesh.frontOnly = bProp;
return;
}
return;
}
String key = (explicitID && previousMeshID != null
&& TextFormat.isWild(previousMeshID) ? previousMeshID.toUpperCase()
: null);
if (key != null && key.length() == 0)
key = null;
for (int i = 0; i < meshCount; i++) {
Mesh m = meshes[i];
if (key == null
|| TextFormat.isMatch(m.thisID.toUpperCase(), key, true, true))
switch (tokProp) {
case Token.on:
m.visible = bProp;
break;
case Token.color:
m.colix = colix;
break;
case Token.translucent:
m.setTranslucent(bProp, translucentLevel);
break;
case Token.frontlit:
case Token.backlit:
case Token.fullylit:
m.setLighting(tokProp);
break;
case Token.dots:
m.showPoints = bProp;
break;
case Token.mesh:
m.drawTriangles = bProp;
break;
case Token.fill:
m.fillTriangles = bProp;
break;
case Token.triangles:
m.showTriangles = bProp;
break;
}
}
}
public boolean getProperty(String property, Object[] data) {
if (property == "checkID") {
String key = ((String) data[0]).toUpperCase();
boolean isWild = TextFormat.isWild(key);
for (int i = meshCount; --i >= 0;) {
String id = meshes[i].thisID;
if (id.equalsIgnoreCase(key) || isWild
&& TextFormat.isMatch(id.toUpperCase(), key, true, true)) {
data[1] = id;
return true;
}
}
return false;
}
if (property == "getCenter") {
String id = (String) data[0];
int index = ((Integer)data[1]).intValue();
Mesh m;
if (index < 0 || (m = getMesh(id)) == null
|| m.vertices == null
|| m.vertexCount <= index)
return false;
data[2] = m.vertices[index];
return true;
}
return false;
}
public Object getProperty(String property, int index) {
Mesh m;
if (property == "count") {
int n = 0;
for (int i = 0; i < meshCount; i++)
if ((m = meshes[i]) != null && m.vertexCount > 0)
n++;
return new Integer(n);
}
if (property == "ID")
return (currentMesh == null ? null : currentMesh.thisID);
if (property == "list") {
StringBuffer sb = new StringBuffer();
int k = 0;
for (int i = 0; i < meshCount; i++) {
if ((m = meshes[i]) == null || m.vertexCount == 0)
continue;
sb.append((++k)).append(" id:" + m.thisID).append(
"; model:" + viewer.getModelNumberDotted(m.modelIndex)).append(
"; vertices:" + m.vertexCount).append(
"; polygons:" + m.polygonCount).append("; visible:" + m.visible);
if (m.title != null) {
String s = "";
for (int j = 0; j < m.title.length; j++)
s += (j == 0 ? "; title:" : " | ") + m.title[j];
if (s.length() > 100)
s = s.substring(0, 100) + "...";
sb.append(s);
}
sb.append('\n');
}
return sb.toString();
}
if (property == "command") {
String key = previousMeshID.toUpperCase();
boolean isWild = TextFormat.isWild(key);
StringBuffer sb = new StringBuffer();
for (int i = meshCount; --i >= 0;) {
String id = meshes[i].thisID.toUpperCase();
if (id.equals(key) || isWild && TextFormat.isMatch(id, key, true, true))
getMeshCommand(sb, i);
}
return sb.toString();
}
if (property == "vertices")
return getVertices(currentMesh);
return null;
}
private Object getVertices(Mesh mesh) {
if (mesh == null)
return null;
return mesh.vertices;
}
private void deleteMesh() {
if (explicitID && currentMesh != null)
deleteMesh(currentMesh.index);
else
deleteMesh(explicitID && previousMeshID != null
&& TextFormat.isWild(previousMeshID) ?
previousMeshID : null);
currentMesh = null;
}
protected void deleteMesh(String key) {
if (key == null || key.length() == 0) {
for (int i = meshCount; --i >= 0; )
meshes[i] = null;
meshCount = 0;
nUnnamed = 0;
if (htObjects != null)
htObjects.clear();
} else {
key = key.toLowerCase();
for (int i = meshCount; --i >= 0; ) {
if (TextFormat.isMatch(meshes[i].thisID.toLowerCase(), key, true, true))
deleteMesh(i);
}
}
}
public void deleteMesh(int i) {
if (htObjects != null)
htObjects.remove(meshes[i].thisID.toUpperCase());
for (int j = i + 1; j < meshCount; ++j)
meshes[--meshes[j].index] = meshes[j];
meshes[--meshCount] = null;
}
public Mesh getMesh(String thisID) {
int i = getIndexFromName(thisID);
return (i < 0 ? null : meshes[i]);
}
public int getIndexFromName(String thisID) {
if (JmolConstants.PREVIOUS_MESH_ID.equals(thisID))
return (previousMeshID == null ? meshCount - 1
: getIndexFromName(previousMeshID));
if (TextFormat.isWild(thisID)) {
thisID = thisID.toLowerCase();
for (int i = meshCount; --i >= 0;) {
if (meshes[i] != null
&& TextFormat.isMatch(meshes[i].thisID, thisID, true, true))
return i;
}
} else {
if (htObjects != null) {
Mesh m = (Mesh)(htObjects.get(thisID.toUpperCase()));
return (m == null ? -1 : m.index);
}
for (int i = meshCount; --i >= 0;) {
if (meshes[i] != null && thisID.equalsIgnoreCase(meshes[i].thisID))
return i;
}
}
return -1;
}
public void setModelIndex(int atomIndex, int modelIndex) {
if (currentMesh == null)
return;
currentMesh.visible = true;
if ((currentMesh.atomIndex = atomIndex) >= 0)
currentMesh.modelIndex = viewer.getAtomModelIndex(atomIndex);
else if (isFixed)
currentMesh.modelIndex = -1;
else if (modelIndex >= 0)
currentMesh.modelIndex = modelIndex;
else
currentMesh.modelIndex = viewer.getCurrentModelIndex();
currentMesh.scriptCommand = script;
}
public String getShapeState() {
StringBuffer sb = new StringBuffer("\n");
for (int i = 0; i < meshCount; i++)
getMeshCommand(sb, i);
return sb.toString();
}
private void getMeshCommand(StringBuffer sb, int i) {
Mesh mesh = meshes[i];
String cmd = mesh.scriptCommand;
if (cmd == null)
return;
cmd = cmd.replace('\t', ' ');
cmd = TextFormat.simpleReplace(cmd, ";#", "; #");
int pt = cmd.indexOf("; #");
/*
not perfect -- user may have that in a title, I suppose...
String options = "";
if (pt >= 0) {
options = cmd.substring(pt + 1);
cmd = cmd.substring(0, pt);
pt = options.indexOf("# ({");
if (pt >= 0)
options = options.substring(0, pt);
pt = options.indexOf("# ID");
if (pt >= 0)
options = options.substring(0, pt);
}
*/
if (pt >= 0) {
cmd = cmd.substring(0, pt);
}
cmd = TextFormat.trim(cmd, ";");
if (mesh.linkedMesh != null)
cmd += " LINK"; // for lcaoCartoon state
/*
cmd = TextFormat.trim(cmd, ";") + ";" + options;
if (mesh.bitsets != null) {
cmd += "# "
+ (mesh.bitsets[0] == null ? "({null})" : Escape
.escape(mesh.bitsets[0]))
+ " "
+ (mesh.bitsets[1] == null ? "({null})" : Escape
.escape(mesh.bitsets[1]))
+ (mesh.bitsets[2] == null ? "" : "/"
+ Escape.escape(mesh.bitsets[2]));
}
if (!myType.equals("mo"))
cmd += "# ID=\"" + mesh.thisID + "\"";
if (mesh.modelIndex >= 0)
cmd += "# MODEL({" + mesh.modelIndex + "})";
if (mesh.cappingObject != null)
cmd += "# CAP=\"" + Escape.escape(mesh.cappingObject) + "\"";
if (mesh.slabbingObject != null)
cmd += "# SLAB=\"" + Escape.escape(mesh.slabbingObject) + "\"";
if (mesh.data1 != null)
cmd = encapsulateData(cmd, mesh.data1, "");
if (mesh.data2 != null)
cmd = encapsulateData(cmd, mesh.data2, "2");
*/
if (mesh.modelIndex >= 0 && modelCount > 1)
appendCmd(sb, "frame " + viewer.getModelNumberDotted(mesh.modelIndex));
appendCmd(sb, cmd);
if (mesh.ptOffset != null)
appendCmd(sb, myType + " ID " + Escape.escape(mesh.thisID) + " offset " + Escape.escape(mesh.ptOffset));
if (mesh.scale3d != 0)
appendCmd(sb, myType + " ID " + Escape.escape(mesh.thisID) + " scale3d " + mesh.scale3d);
if (cmd.charAt(0) != '#') {
if (allowMesh)
appendCmd(sb, mesh.getState(myType));
if (mesh.colorCommand != null) {
if (!mesh.isColorSolid && Graphics3D.isColixTranslucent(mesh.colix))
appendCmd(sb, getColorCommand(myType, mesh.colix));
appendCmd(sb, mesh.colorCommand);
}
getColorState(sb, mesh);
}
}
/*
private String encapsulateData(String cmd, Vector data, String ext) {
String name = ((String) data.elementAt(0)).toLowerCase();
Object array = data.elementAt(5);
if (array instanceof float[][] && name.indexOf("data2d_") != 0)
name = "data2d_" + name;
else if (array instanceof float[][][] && name.indexOf("data3d_") != 0)
name = "data3d_" + name;
cmd = Escape.encapsulateData(name, array)
+ " " + cmd + "# DATA" + ext + "=\"" + name + "\"";
return cmd;
}
*/
protected void getColorState(StringBuffer sb, Mesh mesh) {
getColorState(sb, mesh);
if (mesh.isColorSolid)
appendCmd(sb, getColorCommand(myType, mesh.colix));
}
public void setVisibilityFlags(BitSet bs) {
/*
* set all fixed objects visible; others based on model being displayed
*
*/
for (int i = meshCount; --i >= 0;) {
Mesh mesh = meshes[i];
mesh.visibilityFlags = (mesh.visible && mesh.isValid
&& (mesh.modelIndex < 0 || bs.get(mesh.modelIndex)
&& (mesh.atomIndex < 0 || !modelSet.isAtomHidden(mesh.atomIndex))
) ? myVisibilityFlag
: 0);
}
}
protected void getModelIndex(String script) {
//pmesh and isosurface state
int i;
iHaveModelIndex = false;
modelIndex = -1;
if (script == null || (i = script.indexOf("MODEL({")) < 0)
return;
int j = script.indexOf("})", i);
if (j < 0)
return;
BitSet bs = Escape.unescapeBitset(script.substring(i + 3, j + 1));
modelIndex = (bs == null ? -1 : bs.nextSetBit(0));
iHaveModelIndex = (modelIndex >= 0);
}
}
|