1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2007-03-30 11:40:16 -0500 (Fri, 30 Mar 2007) $ 4 * $Revision: 7273 $ 5 * 6 * Copyright (C) 2007 Miguel, Bob, Jmol Development 7 * 8 * Contact: hansonr@stolaf.edu 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 23 */ 24 package org.jmol.jvxl.readers; 25 26 27 import java.io.BufferedReader; 28 29 import javajs.util.AU; 30 import javajs.util.CU; 31 import javajs.util.Lst; 32 import javajs.util.PT; 33 import javajs.util.SB; 34 import javajs.util.T3; 35 36 import java.util.Hashtable; 37 38 39 40 import javajs.util.BS; 41 import org.jmol.jvxl.data.JvxlCoder; 42 import org.jmol.jvxl.data.JvxlData; 43 import org.jmol.jvxl.data.MeshData; 44 import org.jmol.shapesurface.IsosurfaceMesh; 45 import org.jmol.util.C; 46 import org.jmol.util.ColorEncoder; 47 import org.jmol.util.Escape; 48 import org.jmol.util.Logger; 49 50 import javajs.util.P3; 51 import javajs.util.P4; 52 import javajs.util.V3; 53 54 public class JvxlXmlReader extends VolumeFileReader { 55 56 protected String JVXL_VERSION = "2.3"; 57 // 2.3 adds encoding "none" 58 // 2.2 adds full support for return of rendering information, 59 // retrieval of triangle edge data when edges have been modified by slabbing. 60 61 protected int surfaceDataCount; 62 protected int edgeDataCount; 63 protected int colorDataCount; 64 private int excludedTriangleCount; 65 private int excludedVertexCount; 66 private int invalidatedVertexCount; 67 protected boolean haveContourData; 68 69 private XmlReader xr; 70 71 protected boolean isXmlFile= true; 72 JvxlXmlReader()73 JvxlXmlReader(){} 74 75 @Override init2(SurfaceGenerator sg, BufferedReader br)76 void init2(SurfaceGenerator sg, BufferedReader br) { 77 init2JXR(sg, br); 78 } 79 init2JXR(SurfaceGenerator sg, BufferedReader br)80 void init2JXR(SurfaceGenerator sg, BufferedReader br) { 81 init2VFR(sg, br); 82 jvxlData.wasJvxl = isJvxl = true; 83 isXLowToHigh = canDownsample = false; 84 xr = new XmlReader(br); 85 } 86 87 protected boolean thisInside; 88 89 /////////////reading the format/////////// 90 91 @Override readVolumeData(boolean isMapData)92 protected boolean readVolumeData(boolean isMapData) { 93 if (!readVolumeDataVFR(isMapData)) 94 return false; 95 strFractionTemp = jvxlEdgeDataRead; 96 fractionPtr = 0; 97 return true; 98 } 99 100 @Override gotoAndReadVoxelData(boolean isMapData)101 protected boolean gotoAndReadVoxelData(boolean isMapData) { 102 initializeVolumetricData(); 103 if (nPointsX < 0 || nPointsY < 0 || nPointsZ < 0) 104 return true; 105 try { 106 gotoData(params.fileIndex - 1, nPointsX * nPointsY * nPointsZ); 107 if (vertexDataOnly) 108 return true; 109 volumeData.setMappingPlane(params.thePlane); 110 readSurfaceData(isMapData); 111 volumeData.setMappingPlane(null); 112 113 if (edgeDataCount > 0) 114 jvxlEdgeDataRead = jvxlReadFractionData("edge", edgeDataCount); 115 params.bsExcluded = jvxlData.jvxlExcluded = new BS[4]; 116 hasColorData = (colorDataCount > 0); // for nonXML version of JVXL 117 if (hasColorData) 118 jvxlColorDataRead = jvxlReadFractionData("color", colorDataCount); 119 if (excludedVertexCount > 0) { 120 jvxlData.jvxlExcluded[0] = JvxlCoder.jvxlDecodeBitSet(xr.getXmlData( 121 "jvxlExcludedVertexData", null, false, false)); 122 if (xr.isNext("jvxlExcludedPlaneData")) 123 jvxlData.jvxlExcluded[2] = JvxlCoder.jvxlDecodeBitSet(xr.getXmlData( 124 "jvxlExcludedPlaneData", null, false, false)); 125 } 126 if (excludedTriangleCount > 0) 127 jvxlData.jvxlExcluded[3] = JvxlCoder.jvxlDecodeBitSet(xr.getXmlData( 128 "jvxlExcludedTriangleData", null, false, false)); 129 if (invalidatedVertexCount > 0) 130 jvxlData.jvxlExcluded[1] = JvxlCoder.jvxlDecodeBitSet(xr.getXmlData( 131 "jvxlInvalidatedVertexData", null, false, false)); 132 if (haveContourData) 133 jvxlDecodeContourData(jvxlData, xr.getXmlData("jvxlContourData", null, 134 false, false)); 135 if (jvxlDataIsColorMapped && jvxlData.nVertexColors > 0) { 136 jvxlData.vertexColorMap = new Hashtable<String, BS>(); 137 String vdata = xr.getXmlData("jvxlVertexColorData", null, true, false); 138 String baseColor = XmlReader.getXmlAttrib(vdata, "baseColor"); 139 jvxlData.baseColor = (baseColor.length() > 0 ? baseColor : null); 140 for (int i = 0; i < jvxlData.nVertexColors; i++) { 141 String s = xr.getXmlData("jvxlColorMap", vdata, true, false); 142 String color = XmlReader.getXmlAttrib(s, "color"); 143 BS bs = JvxlCoder.jvxlDecodeBitSet(xr.getXmlData("jvxlColorMap", 144 s, false, false)); 145 jvxlData.vertexColorMap.put(color, bs); 146 } 147 } 148 149 } catch (Exception e) { 150 Logger.error(e.toString()); 151 return false; 152 } 153 return true; 154 } 155 156 String tempDataXml; 157 158 @Override readParameters()159 protected void readParameters() throws Exception { 160 String s = xr.getXmlDataLF("jvxlFileTitle", null, false, false, true); 161 jvxlFileHeaderBuffer = SB.newS(s == null ? "" : s); 162 xr.toTag("jvxlVolumeData"); 163 String data = tempDataXml = xr.getXmlData("jvxlVolumeData", null, true, false); 164 volumetricOrigin.setT(xr.getXmlPoint(data, "origin")); 165 isAngstroms = true; 166 readVector(0); 167 readVector(1); 168 readVector(2); 169 line = xr.toTag("jvxlSurfaceSet"); 170 nSurfaces = parseIntStr(XmlReader.getXmlAttrib(line, "count")); 171 Logger.info("jvxl file surfaces: " + nSurfaces); 172 Logger.info("using default edge fraction base and range"); 173 Logger.info("using default color fraction base and range"); 174 cJvxlEdgeNaN = (char) (edgeFractionBase + edgeFractionRange); 175 } 176 readVector(int voxelVectorIndex)177 protected void readVector(int voxelVectorIndex) throws Exception { 178 String data = xr.getXmlData("jvxlVolumeVector", tempDataXml, true, true); 179 tempDataXml = tempDataXml.substring(tempDataXml.indexOf(data) + data.length()); 180 int n = parseIntStr(XmlReader.getXmlAttrib(data, "count")); 181 if (n == Integer.MIN_VALUE) 182 vertexDataOnly = true; 183 voxelCounts[voxelVectorIndex] = (n < 0 ? 0 : n); 184 volumetricVectors[voxelVectorIndex].setT(xr.getXmlPoint(data, "vector")); 185 if (isAnisotropic) 186 setVectorAnisotropy(volumetricVectors[voxelVectorIndex]); 187 } 188 189 @Override gotoData(int n, int nPoints)190 protected void gotoData(int n, int nPoints) throws Exception { 191 if (n > 0) 192 Logger.info("skipping " + n + " data sets, " + nPoints + " points each"); 193 vertexDataOnly = jvxlData.vertexDataOnly = (nPoints == 0); 194 for (int i = 0; i < n; i++) { 195 jvxlSkipData(nPoints, true); 196 } 197 xr.toTag("jvxlSurface"); 198 jvxlReadSurfaceInfo(); 199 } 200 jvxlSkipData(@uppressWarningsR) int nPoints, @SuppressWarnings(R) boolean doSkipColorData)201 protected void jvxlSkipData(@SuppressWarnings("unused") int nPoints, 202 @SuppressWarnings("unused") boolean doSkipColorData) 203 throws Exception { 204 rd(); 205 xr.skipTag("jvxlSurface"); 206 } 207 jvxlReadSurfaceInfo()208 protected void jvxlReadSurfaceInfo() throws Exception { 209 String s; 210 String data = xr.getXmlData("jvxlSurfaceInfo", null, true, true); 211 isXLowToHigh = XmlReader.getXmlAttrib(data, "isXLowToHigh").equals("true"); 212 jvxlCutoff = parseFloatStr(XmlReader.getXmlAttrib(data, "cutoff")); 213 if (!Float.isNaN(jvxlCutoff)) 214 Logger.info("JVXL read: cutoff " + jvxlCutoff); 215 int nContourData = parseIntStr(XmlReader.getXmlAttrib(data, "nContourData")); 216 haveContourData = (nContourData > 0); 217 params.isContoured = jvxlData.isModelConnected = XmlReader.getXmlAttrib(data, "contoured").equals("true"); 218 params.isModelConnected = XmlReader.getXmlAttrib(data, "isModelConnected").equals("true"); 219 if (params.isContoured) { 220 int nContoursRead = parseIntStr(XmlReader.getXmlAttrib(data, "nContours")); 221 if (nContoursRead <= 0) { 222 nContoursRead = 0; 223 } else { 224 if (params.thisContour < 0) 225 params.thisContour = parseIntStr(XmlReader.getXmlAttrib(data, "thisContour")); 226 s = XmlReader.getXmlAttrib(data, "contourValues"); 227 if (s.length() > 0) { 228 s = s.replace('[',' ').replace(']',' '); 229 jvxlData.contourValues = params.contoursDiscrete = parseFloatArrayStr(s); 230 Logger.info("JVXL read: contourValues " + Escape.eAF(jvxlData.contourValues)); 231 } 232 s = XmlReader.getXmlAttrib(data, "contourColors"); 233 if (s.length() > 0) { 234 jvxlData.contourColixes = params.contourColixes = C.getColixArray(s); 235 jvxlData.contourColors = C.getHexCodes(jvxlData.contourColixes); 236 Logger.info("JVXL read: contourColixes " + 237 C.getHexCodes(jvxlData.contourColixes)); } 238 params.contourFromZero = XmlReader.getXmlAttrib(data, "contourFromZero").equals("true"); 239 } 240 params.nContours = (haveContourData ? nContourData : nContoursRead); 241 //TODO ? params.contourFromZero = false; // MEP data to complete the plane 242 } 243 244 jvxlData.nVertexColors = parseIntStr(XmlReader.getXmlAttrib(data, "nVertexColors")); 245 params.isBicolorMap = XmlReader.getXmlAttrib(data, "bicolorMap").equals("true"); 246 if (params.isBicolorMap) { 247 // TODO -- not quite right, because 248 s = XmlReader.getXmlAttrib(data, "colorPositive"); 249 if (s.length() > 0 && params.colorRgb == Integer.MIN_VALUE 250 && params.colorPos == Parameters.defaultColorPositive) 251 params.colorPos = CU.getArgbFromString(s); 252 s = XmlReader.getXmlAttrib(data, "colorNegative"); 253 if (s.length() > 0 && params.colorRgb == Integer.MIN_VALUE 254 && params.colorNeg == Parameters.defaultColorNegative) 255 params.colorNeg = CU.getArgbFromString(s); 256 } 257 if (params.isBicolorMap || params.colorBySign) 258 jvxlCutoff = 0; 259 jvxlDataIsColorMapped = 260 ((params.colorRgb == Integer.MIN_VALUE || params.colorRgb == Integer.MAX_VALUE) 261 && (params.isBicolorMap || XmlReader.getXmlAttrib(data, "colorMapped").equals("true"))); 262 //isJvxlPrecisionColor is for information only -- will be superceded by encoding attribute of jvxlColorData 263 jvxlData.isJvxlPrecisionColor = XmlReader.getXmlAttrib(data, "precisionColor").equals("true"); 264 jvxlData.jvxlDataIsColorDensity = params.colorDensity = (params.colorRgb == Integer.MIN_VALUE && XmlReader.getXmlAttrib(data, "colorDensity").equals("true")); 265 if (jvxlData.jvxlDataIsColorDensity && Float.isNaN(params.pointSize)) { 266 s = XmlReader.getXmlAttrib(data, "pointSize"); 267 if (s.length() > 0) 268 jvxlData.pointSize = params.pointSize = parseFloatStr(s); 269 } 270 s = XmlReader.getXmlAttrib(data, "allowVolumeRender"); 271 jvxlData.allowVolumeRender = params.allowVolumeRender = (s.length() == 0 || s.equalsIgnoreCase("true")); 272 s = XmlReader.getXmlAttrib(data, "plane"); 273 if (s.indexOf("{") >= 0) { 274 params.thePlane = null; 275 params.mapLattice = null; 276 try { 277 params.thePlane = (P4) Escape.uP(s); 278 s = XmlReader.getXmlAttrib(data, "maplattice"); 279 Logger.info("JVXL read: plane " + params.thePlane); 280 if (s.indexOf("{") >= 0) { 281 params.mapLattice = (P3) Escape.uP(s); 282 Logger.info("JVXL read: mapLattice " + params.mapLattice); 283 } 284 if (params.scale3d == 0) 285 params.scale3d = parseFloatStr(XmlReader.getXmlAttrib(data, "scale3d")); 286 if (Float.isNaN(params.scale3d)) 287 params.scale3d = 0; 288 } catch (Exception e) { 289 if (params.thePlane == null) { 290 Logger 291 .error("JVXL Error reading plane definition -- setting to 0 0 1 0 (z=0)"); 292 params.thePlane = P4.new4(0, 0, 1, 0); 293 } else { 294 Logger 295 .error("JVXL Error reading mapLattice definition -- ignored"); 296 } 297 } 298 surfaceDataCount = 0; 299 edgeDataCount = 0; 300 } else { 301 params.thePlane = null; 302 surfaceDataCount = parseIntStr(XmlReader.getXmlAttrib(data, "nSurfaceInts")); 303 edgeDataCount = parseIntStr(XmlReader.getXmlAttrib(data, "nBytesUncompressedEdgeData")); 304 s = XmlReader.getXmlAttrib(data, "fixedLattice"); 305 if (s.indexOf("{") >= 0) 306 jvxlData.fixedLattice = (P3) Escape.uP(s); 307 308 } 309 excludedVertexCount = parseIntStr(XmlReader.getXmlAttrib(data, "nExcludedVertexes")); 310 excludedTriangleCount = parseIntStr(XmlReader.getXmlAttrib(data, "nExcludedTriangles")); 311 invalidatedVertexCount = parseIntStr(XmlReader.getXmlAttrib(data, "nInvalidatedVertexes")); 312 s = XmlReader.getXmlAttrib(data, "slabInfo"); 313 if (s.length() > 0) 314 jvxlData.slabInfo = s; 315 colorDataCount = Math.max(0, parseIntStr(XmlReader.getXmlAttrib(data, "nBytesUncompressedColorData"))); 316 jvxlDataIs2dContour = (params.thePlane != null && jvxlDataIsColorMapped); 317 318 // new Jmol 12.1.50 319 jvxlData.color = XmlReader.getXmlAttrib(data, "color"); 320 if (jvxlData.color.length() == 0 || jvxlData.color.indexOf("null") >= 0) 321 jvxlData.color = "orange"; 322 jvxlData.translucency = parseFloatStr(XmlReader.getXmlAttrib(data, "translucency")); 323 if (Float.isNaN(jvxlData.translucency)) 324 jvxlData.translucency = 0; 325 s = XmlReader.getXmlAttrib(data, "meshColor"); 326 if (s.length() > 0) 327 jvxlData.meshColor = s; 328 s = XmlReader.getXmlAttrib(data, "rendering"); 329 if (s.length() > 0) 330 jvxlData.rendering = s; 331 jvxlData.colorScheme = XmlReader.getXmlAttrib(data, "colorScheme"); 332 if (jvxlData.colorScheme.length() == 0) 333 jvxlData.colorScheme = (jvxlDataIsColorMapped ? "roygb": null); // allow for legacy default 334 if (jvxlData.thisSet == null) { 335 int n = parseIntStr(XmlReader.getXmlAttrib(data, "set")); 336 if (n > 0) { 337 jvxlData.thisSet = new BS(); 338 jvxlData.thisSet.set(n - 1); 339 } 340 String a = XmlReader.getXmlAttrib(data, "subset"); 341 if (a != null && a.length() > 2) { 342 String[] sets = a.replace('[', ' ').replace(']', ' ').trim().split(" "); 343 if (sets.length > 0) { 344 jvxlData.thisSet = new BS(); 345 for (int i = sets.length; --i >= 0;) { 346 jvxlData.thisSet.set(PT.parseInt(sets[i]) - 1); 347 } 348 349 } 350 } 351 } 352 jvxlData.slabValue = parseIntStr(XmlReader.getXmlAttrib(data, "slabValue")); 353 jvxlData.isSlabbable = (XmlReader.getXmlAttrib(data, "slabbable").equalsIgnoreCase("true")); 354 jvxlData.diameter = parseIntStr(XmlReader.getXmlAttrib(data, "diameter")); 355 if (jvxlData.diameter == Integer.MIN_VALUE) 356 jvxlData.diameter = 0; 357 358 if (jvxlDataIs2dContour) 359 params.isContoured = true; 360 361 if (params.colorBySign) 362 params.isBicolorMap = true; 363 boolean insideOut = XmlReader.getXmlAttrib(data, "insideOut").equals("true"); 364 float dataMin = Float.NaN; 365 float dataMax = Float.NaN; 366 float red = Float.NaN; 367 float blue = Float.NaN; 368 if (jvxlDataIsColorMapped) { 369 dataMin = parseFloatStr(XmlReader.getXmlAttrib(data, "dataMinimum")); 370 dataMax = parseFloatStr(XmlReader.getXmlAttrib(data, "dataMaximum")); 371 red = parseFloatStr(XmlReader.getXmlAttrib(data, "valueMappedToRed")); 372 blue = parseFloatStr(XmlReader.getXmlAttrib(data, "valueMappedToBlue")); 373 if (Float.isNaN(dataMin)) { 374 dataMin = red = -1f; 375 dataMax = blue = 1f; 376 } 377 } 378 jvxlSetColorRanges(dataMin, dataMax, red, blue, insideOut); 379 } 380 jvxlSetColorRanges(float dataMin, float dataMax, float red, float blue, boolean insideOut)381 protected void jvxlSetColorRanges(float dataMin, float dataMax, float red, 382 float blue, boolean insideOut) { 383 if (jvxlDataIsColorMapped) { 384 if (!Float.isNaN(dataMin) && !Float.isNaN(dataMax)) { 385 if (dataMax == 0 && dataMin == 0) { 386 //set standard -1/1; bit of a hack 387 dataMin = -1; 388 dataMax = 1; 389 } 390 params.mappedDataMin = dataMin; 391 params.mappedDataMax = dataMax; 392 Logger.info("JVXL read: data_min/max " + params.mappedDataMin + "/" 393 + params.mappedDataMax); 394 } 395 if (!params.rangeDefined) 396 if (!Float.isNaN(red) && !Float.isNaN(blue)) { 397 if (red == 0 && blue == 0) { 398 //set standard -1/1; bit of a hack 399 red = -1; 400 blue = 1; 401 } 402 params.valueMappedToRed = Math.min(red, blue); 403 params.valueMappedToBlue = Math.max(red, blue); 404 params.isColorReversed = (red > blue); 405 params.rangeDefined = true; 406 } else { 407 params.valueMappedToRed = 0f; 408 params.valueMappedToBlue = 1f; 409 params.rangeDefined = true; 410 } 411 Logger.info("JVXL read: color red/blue: " + params.valueMappedToRed + "/" 412 + params.valueMappedToBlue); 413 } 414 jvxlData.valueMappedToRed = params.valueMappedToRed; 415 jvxlData.valueMappedToBlue = params.valueMappedToBlue; 416 jvxlData.mappedDataMin = params.mappedDataMin; 417 jvxlData.mappedDataMax = params.mappedDataMax; 418 jvxlData.isColorReversed = params.isColorReversed; 419 if (params.insideOut) 420 insideOut = !insideOut; 421 params.insideOut = jvxlData.insideOut = insideOut; 422 } 423 424 @Override readSurfaceData(boolean isMapDataIgnored)425 protected void readSurfaceData(boolean isMapDataIgnored) throws Exception { 426 thisInside = !params.isContoured; 427 if (readSurfaceDataXML()) 428 return; 429 tempDataXml = xr.getXmlData("jvxlEdgeData", null, true, false); 430 bsVoxelBitSet = JvxlCoder.jvxlDecodeBitSet(xr.getXmlData("jvxlEdgeData", 431 tempDataXml, false, false)); 432 // if (thisInside) 433 // bsVoxelBitSet = BitSetUtil.copyInvert(bsVoxelBitSet, 434 // bsVoxelBitSet.size()); 435 readSurfaceDataJXR(); 436 } 437 readSurfaceDataXML()438 protected boolean readSurfaceDataXML() throws Exception { 439 if (vertexDataOnly) { 440 getEncodedVertexData(); 441 return true; 442 } 443 if (params.thePlane != null) { 444 volumeData.setDataDistanceToPlane(params.thePlane); 445 setVolumeDataV(volumeData); 446 params.cutoff = 0f; 447 jvxlData.setSurfaceInfo(params.thePlane, params.mapLattice, 0, ""); 448 jvxlData.scale3d = params.scale3d; 449 return true; 450 } 451 return false; 452 } 453 readSurfaceDataJXR()454 protected void readSurfaceDataJXR() throws Exception { 455 readSurfaceDataVFR(false); 456 volumeData.setMappingPlane(null); 457 } 458 459 /** 460 * "edge" data includes two parts -- a compressed bitset indicating exactly which edges, 461 * in order or processing by Jmol, are crossed by the surface, and a set of fractions 462 * indicating how far along that edge (good to 1 part in 8100) that surface crosses that edge. 463 * We are just reading he fractions here. 464 * 465 * "color" data comprises the corresponding sequence of data mapping values, again stored to 466 * a precision of 1 part in 8100, relative to a range of values. 467 * 468 * @param type 469 * @param nPoints 470 * @return data 471 */ jvxlReadFractionData(String type, int nPoints)472 protected String jvxlReadFractionData(String type, 473 int nPoints) { 474 String str; 475 try { 476 if (type.equals("edge")) { 477 str = JvxlCoder.jvxlDecompressString(XmlReader.getXmlAttrib(tempDataXml, "data")); 478 } else { 479 String data = xr.getXmlData("jvxlColorData", null, true, false); 480 jvxlData.isJvxlPrecisionColor = getEncoding(data).endsWith("2"); 481 str = JvxlCoder.jvxlDecompressString(XmlReader.getXmlAttrib(data, "data")); 482 } 483 } catch (Exception e) { 484 Logger.error("Error reading " + type + " data " + e); 485 throw new NullPointerException(); 486 } 487 return str; 488 } 489 490 protected BS bsVoxelBitSet; 491 492 @Override getVoxelBitSet(int nPoints)493 protected BS getVoxelBitSet(int nPoints) throws Exception { 494 if (bsVoxelBitSet != null) 495 return bsVoxelBitSet; 496 BS bs = new BS(); 497 int bsVoxelPtr = 0; 498 if (surfaceDataCount <= 0) 499 return bs; //unnecessary -- probably a plane or color density 500 int nThisValue = 0; 501 while (bsVoxelPtr < nPoints) { 502 nThisValue = parseInt(); 503 if (nThisValue == Integer.MIN_VALUE) { 504 rd(); 505 // note -- does not allow for empty lines; 506 // must be a continuous block of numbers. 507 if (line == null || (nThisValue = parseIntStr(line)) == Integer.MIN_VALUE) { 508 if (!endOfData) 509 Logger.error("end of file in JvxlReader?" + " line=" + line); 510 endOfData = true; 511 nThisValue = 10000; 512 //throw new NullPointerException(); 513 } 514 } 515 thisInside = !thisInside; 516 ++jvxlNSurfaceInts; 517 if (thisInside) 518 bs.setBits(bsVoxelPtr, bsVoxelPtr + nThisValue); 519 bsVoxelPtr += nThisValue; 520 } 521 return bs; 522 } 523 524 @Override getSurfacePointAndFraction(float cutoff, boolean isCutoffAbsolute, float valueA, float valueB, T3 pointA, V3 edgeVector, int x, int y, int z, int vA, int vB, float[] fReturn, T3 ptReturn)525 protected float getSurfacePointAndFraction(float cutoff, 526 boolean isCutoffAbsolute, 527 float valueA, float valueB, 528 T3 pointA, 529 V3 edgeVector, 530 int x, int y, int z, int vA, int vB, float[] fReturn, T3 ptReturn) { 531 if (edgeDataCount <= 0) 532 return getSPFv(cutoff, isCutoffAbsolute, valueA, 533 valueB, pointA, edgeVector, x, y, z, vA, vB, fReturn, ptReturn); 534 ptReturn.scaleAdd2(fReturn[0] = jvxlGetNextFraction(edgeFractionBase, 535 edgeFractionRange, 0.5f), edgeVector, pointA); 536 if (Float.isNaN(valueMin)) 537 setValueMinMax(); 538 return (valueCount == 0 || includeValueNaN && Float.isNaN(fReturn[0]) 539 ? fReturn[0] : getNextValue()); 540 } 541 getNextValue()542 private float getNextValue() { 543 float fraction = Float.NaN; 544 while (colorPtr < valueCount && Float.isNaN(fraction)) { 545 if (jvxlData.isJvxlPrecisionColor) { 546 // this COULD be an option for mapped surfaces; 547 // necessary for planes; used for vertex/triangle 2.0 style 548 // precision is used for FULL-data range encoding, allowing full 549 // treatment of JVXL files as though they were CUBE files. 550 // the two parts of the "double-character-precision" value 551 // are in separate lines, separated by n characters. 552 fraction = JvxlCoder.jvxlFractionFromCharacter2(jvxlColorDataRead 553 .charAt(colorPtr), jvxlColorDataRead.charAt((colorPtr++) 554 + valueCount), colorFractionBase, colorFractionRange); 555 } else { 556 // my original encoding scheme 557 // low precision only allows for mapping relative to the defined color range 558 fraction = JvxlCoder.jvxlFractionFromCharacter(jvxlColorDataRead 559 .charAt(colorPtr++), colorFractionBase, colorFractionRange, 0.5f); 560 } 561 break; 562 } 563 return valueMin + fraction * valueRange; 564 } 565 setValueMinMax()566 private void setValueMinMax() { 567 valueCount = jvxlColorDataRead.length(); 568 if (jvxlData.isJvxlPrecisionColor) 569 valueCount /= 2; 570 includeValueNaN = (valueCount != jvxlEdgeDataRead.length()); 571 valueMin = (!jvxlData.isJvxlPrecisionColor ? params.valueMappedToRed 572 : params.mappedDataMin == Float.MAX_VALUE ? defaultMappedDataMin 573 : params.mappedDataMin); 574 valueRange = (!jvxlData.isJvxlPrecisionColor ? params.valueMappedToBlue 575 : params.mappedDataMin == Float.MAX_VALUE ? defaultMappedDataMax 576 : params.mappedDataMax) 577 - valueMin; 578 haveReadColorData = true; 579 } 580 581 private boolean includeValueNaN = true; 582 private int valueCount; 583 private float valueMin = Float.NaN; 584 private float valueRange = Float.NaN; 585 private int fractionPtr; 586 private int colorPtr; 587 private String strFractionTemp = ""; 588 jvxlGetNextFraction(int base, int range, float fracOffset)589 private float jvxlGetNextFraction(int base, int range, float fracOffset) { 590 if (fractionPtr >= strFractionTemp.length()) { 591 if (!endOfData) 592 Logger.error("end of file reading compressed fraction data"); 593 endOfData = true; 594 strFractionTemp = "" + (char) base; 595 fractionPtr = 0; 596 } 597 return JvxlCoder.jvxlFractionFromCharacter(strFractionTemp.charAt(fractionPtr++), 598 base, range, fracOffset); 599 } 600 601 boolean haveReadColorData; 602 603 private String jvxlColorEncodingRead; 604 605 @Override readColorData()606 protected String readColorData() { 607 if (!jvxlDataIsColorMapped) 608 return ""; 609 // overloads SurfaceReader 610 // standard jvxl file read for color 611 612 int vertexCount = jvxlData.vertexCount = meshData.vc; 613 // the problem is that the new way to read data in Marching Cubes 614 // is to ignore all points that are NaN. But then we also have to 615 // remove those points from the color string. 616 617 short[] colixes = meshData.vcs; 618 float[] vertexValues = meshData.vvs; 619 /* 620 * haveReadColorData? 621 = (isJvxl ? jvxlColorDataRead : ""); 622 if (isJvxl && strValueTemp.length() == 0) { 623 Logger 624 .error("You cannot use JVXL data to map onto OTHER data, because it only contains the data for one surface. Use ISOSURFACE \"file.jvxl\" not ISOSURFACE .... MAP \"file.jvxl\"."); 625 return ""; 626 } 627 */ 628 629 if ("none".equals(jvxlColorEncodingRead)) { 630 jvxlData.vertexColors = new int[vertexCount]; 631 int[] nextc = new int[1]; 632 int n = PT.parseIntNext(jvxlColorDataRead, nextc); 633 n = Math.min(n, vertexCount); 634 String[] tokens = PT.getTokens(jvxlColorDataRead.substring(nextc[0])); 635 boolean haveTranslucent = false; 636 float trans = jvxlData.translucency; 637 int lastColor = 0; 638 for (int i = 0; i < n; i++) 639 // colix will be one of 8 shades of translucent if A in ARGB is not FF. 640 try{ 641 int c = getColor(tokens[i]); 642 if (c == 0) 643 c = lastColor; 644 else 645 lastColor = c; 646 colixes[i] = C.getColixTranslucent(jvxlData.vertexColors[i] = c); 647 if (C.isColixTranslucent(colixes[i])) 648 haveTranslucent = true; 649 else if (trans != 0) 650 colixes[i] = C.getColixTranslucent3(colixes[i], true, trans); 651 } catch (Exception e) { 652 Logger.info("JvxlXmlReader: Cannot interpret color code: " + tokens[i]); 653 // ignore this color if parsing error 654 } 655 if (haveTranslucent && trans == 0){ 656 // set to show in pass2 657 jvxlData.translucency = 0.5f; 658 } 659 return "-"; 660 } 661 if (params.colorEncoder == null) 662 params.colorEncoder = new ColorEncoder(null, null); 663 params.colorEncoder.setColorScheme(null, false); 664 params.colorEncoder.setRange(params.valueMappedToRed, 665 params.valueMappedToBlue, params.isColorReversed); 666 Logger.info("JVXL reading color data mapped min/max: " 667 + params.mappedDataMin + "/" + params.mappedDataMax + " for " 668 + vertexCount + " vertices." + " using encoding keys " 669 + colorFractionBase + " " + colorFractionRange); 670 Logger.info("mapping red-->blue for " + params.valueMappedToRed + " to " 671 + params.valueMappedToBlue + " colorPrecision:" 672 + jvxlData.isJvxlPrecisionColor); 673 boolean getValues = (Float.isNaN(valueMin)); 674 if (getValues) 675 setValueMinMax(); 676 float contourPlaneMinimumValue = Float.MAX_VALUE; 677 float contourPlaneMaximumValue = -Float.MAX_VALUE; 678 if (colixes == null || colixes.length < vertexCount) 679 meshData.vcs = colixes = new short[vertexCount]; 680 //hasColorData = true; 681 short colixNeg = 0, colixPos = 0; 682 if (params.colorBySign) { 683 colixPos = C.getColix(params.isColorReversed ? params.colorNeg 684 : params.colorPos); 685 colixNeg = C.getColix(params.isColorReversed ? params.colorPos 686 : params.colorNeg); 687 } 688 int vertexIncrement = meshData.vertexIncrement; 689 // here's the problem: we are assuming here that vertexCount == nPointsRead 690 boolean needContourMinMax = (params.mappedDataMin == Float.MAX_VALUE); 691 for (int i = 0; i < vertexCount; i += vertexIncrement) { 692 float value; 693 if (getValues) 694 value = vertexValues[i] = getNextValue(); 695 else 696 value = vertexValues[i]; 697 if (needContourMinMax) { 698 if (value < contourPlaneMinimumValue) 699 contourPlaneMinimumValue = value; 700 if (value > contourPlaneMaximumValue) 701 contourPlaneMaximumValue = value; 702 } 703 } 704 if (needContourMinMax) { 705 params.mappedDataMin = contourPlaneMinimumValue; 706 params.mappedDataMax = contourPlaneMaximumValue; 707 } 708 if (jvxlData.colorScheme != null) { 709 boolean setContourValue = (marchingSquares != null && params.isContoured); 710 for (int i = 0; i < vertexCount; i += vertexIncrement) { 711 float value = vertexValues[i]; 712 //note: these are just default colorings 713 //orbital color had a bug through 11.2.6/11.3.6 714 if (setContourValue) { 715 marchingSquares.setContourData(i, value); 716 continue; 717 } 718 short colix = (!params.colorBySign ? params.colorEncoder 719 .getColorIndex(value) : (params.isColorReversed ? value > 0 720 : value <= 0) ? colixNeg : colixPos); 721 colixes[i] = C.getColixTranslucent3(colix, true, 722 jvxlData.translucency); 723 } 724 } 725 return jvxlColorDataRead + "\n"; 726 } 727 getColor(String c)728 private static int getColor(String c) { 729 int n = 0; 730 try { 731 switch (c.charAt(0)) { 732 case '[': 733 n = CU.getArgbFromString(c); 734 break; 735 case '0': //0x 736 n = PT.parseIntRadix(c.substring(2), 16); 737 break; 738 default: 739 n = PT.parseIntRadix(c, 10); 740 } 741 //if (n < 0x1000000) 742 //n |= 0xFF000000; 743 } catch (Exception e) { 744 } 745 return n; 746 } 747 748 749 /** 750 * retrieve Jvxl 2.0 format vertex/triangle/edge/color data found 751 * within <jvxlSurfaceData> element 752 * 753 * @throws Exception 754 */ getEncodedVertexData()755 protected void getEncodedVertexData() throws Exception { 756 // get vertices 757 String sdata = xr.getXmlData("jvxlSurfaceData", null, true, false); 758 jvxlDecodeVertexData(xr.getXmlData("jvxlVertexData", sdata, true, false), false); 759 // get triangles 760 String tData = xr.getXmlData("jvxlTriangleData", sdata, true, false); 761 String edgeData = xr.getXmlData("jvxlTriangleEdgeData", sdata, true, false); 762 // note: polygon color data is always between tags, not an attribute, and not compressed: 763 String polygonColorData = xr.getXmlData("jvxlPolygonColorData", sdata, false, false); 764 jvxlDecodeTriangleData(tData, edgeData, polygonColorData); 765 // get vertex value data or vertex color data: 766 String cData = xr.getXmlData("jvxlColorData", sdata, true, false); 767 jvxlColorEncodingRead = getEncoding(cData); 768 jvxlData.isJvxlPrecisionColor = jvxlColorEncodingRead.endsWith("2"); 769 cData = getData(cData, "jvxlColorData"); 770 jvxlColorDataRead = (jvxlColorEncodingRead.equals("none") ? cData : JvxlCoder.jvxlDecompressString(cData)); 771 jvxlDataIsColorMapped = ((params.colorRgb == Integer.MIN_VALUE || params.colorRgb == Integer.MAX_VALUE) && jvxlColorDataRead.length() > 0); 772 // get contours 773 if (haveContourData) 774 jvxlDecodeContourData(jvxlData, xr.getXmlData("jvxlContourData", null, false, false)); 775 } 776 getData(String sdata, String name)777 private String getData(String sdata, String name) throws Exception { 778 String data = XmlReader.getXmlAttrib(sdata, "data"); 779 if (data.length() == 0) 780 data = xr.getXmlData(name, sdata, false, false); 781 return data; 782 } 783 getEncoding(String data)784 private static String getEncoding(String data) { 785 // original JVXL does not include "encoding" 786 if (XmlReader.getXmlAttrib(data, "len").length() > 0) 787 return ""; 788 String s = XmlReader.getXmlAttrib(data, "encoding"); 789 return (s.length() == 0 ? "none" : s); 790 } 791 792 /** 793 * decode vertex data found within <jvxlVertexData> element as created by 794 * jvxlEncodeVertexData (see above) 795 * 796 * @param data 797 * tag and contents 798 * @param asArray 799 * or just addVertexCopy 800 * @return Point3f[] if desired 801 * @throws Exception 802 * 803 */ jvxlDecodeVertexData(String data, boolean asArray)804 public P3[] jvxlDecodeVertexData(String data, boolean asArray) 805 throws Exception { 806 int vertexCount = parseIntStr(XmlReader.getXmlAttrib(data, "count")); 807 if (!asArray) 808 Logger.info("Reading " + vertexCount + " vertices"); 809 int ptCount = vertexCount * 3; 810 P3[] vertices = (asArray ? new P3[vertexCount] : null); 811 float fraction; 812 String vData = XmlReader.getXmlAttrib(data, "data"); 813 String encoding = getEncoding(data); 814 if ("none".equals(encoding)) { 815 if (vData.length() == 0) 816 vData = xr.getXmlData("jvxlVertexData", data, false, false); 817 float[] fdata = PT.parseFloatArray(vData); 818 // first point is count -- ignored. 819 if (fdata[0] != vertexCount * 3) 820 Logger.info("JvxlXmlReader: vertexData count=" + ((int)fdata[0]) + "; expected " + (vertexCount * 3)); 821 for (int i = 0, pt = 1; i < vertexCount; i++) { 822 P3 p = P3.new3(fdata[pt++], fdata[pt++], fdata[pt++]); 823 if (asArray) 824 vertices[i] = p; 825 else 826 addVertexCopy(p, 0, i, false); 827 } 828 } else { 829 P3 min = xr.getXmlPoint(data, "min"); 830 P3 range = xr.getXmlPoint(data, "max"); 831 range.sub(min); 832 int colorFractionBase = jvxlData.colorFractionBase; 833 int colorFractionRange = jvxlData.colorFractionRange; 834 String s = JvxlCoder.jvxlDecompressString(vData); 835 if (s.length() == 0) 836 s = xr.getXmlData("jvxlVertexData", data, false, false); 837 for (int i = 0, pt = -1; i < vertexCount; i++) { 838 P3 p = new P3(); 839 fraction = JvxlCoder.jvxlFractionFromCharacter2(s.charAt(++pt), s 840 .charAt(pt + ptCount), colorFractionBase, colorFractionRange); 841 p.x = min.x + fraction * range.x; 842 fraction = JvxlCoder.jvxlFractionFromCharacter2(s.charAt(++pt), s 843 .charAt(pt + ptCount), colorFractionBase, colorFractionRange); 844 p.y = min.y + fraction * range.y; 845 fraction = JvxlCoder.jvxlFractionFromCharacter2(s.charAt(++pt), s 846 .charAt(pt + ptCount), colorFractionBase, colorFractionRange); 847 p.z = min.z + fraction * range.z; 848 if (asArray) 849 vertices[i] = p; 850 else 851 addVertexCopy(p, 0, i, false); 852 } 853 } 854 return vertices; 855 } 856 857 /** 858 * decode triangle data found within <jvxlTriangleData> element as created 859 * with jvxlEncodeTriangleData (see above) 860 * 861 * @param tdata 862 * tag and contents 863 * @param edgeData 864 * @param colorData 865 * @throws Exception 866 */ jvxlDecodeTriangleData(String tdata, String edgeData, String colorData)867 void jvxlDecodeTriangleData(String tdata, String edgeData, String colorData) 868 throws Exception { 869 int nTriangles = parseIntStr(XmlReader.getXmlAttrib(tdata, "count")); 870 if (nTriangles < 0) 871 return; 872 int[] nextc = new int[1]; 873 int nColors = (colorData == null ? -1 : 1); 874 int color = 0; 875 Logger.info("Reading " + nTriangles + " triangles"); 876 String encoding = getEncoding(tdata); 877 tdata = getData(tdata, "jvxlTriangleData"); 878 String edata = getData(edgeData, "jvxlTriangleEdgeData"); 879 int[] vertex = new int[3]; 880 int[] nextp = new int[1]; 881 int[] nexte = null; 882 int edgeMask = 7; 883 boolean haveEdgeInfo; 884 boolean haveEncoding = !"none".equals(encoding); 885 if (haveEncoding) { 886 tdata = JvxlCoder.jvxlDecompressString(tdata); 887 edata = JvxlCoder.jvxlDecompressString(edata).trim(); 888 haveEdgeInfo = (edata.length() == nTriangles); 889 } else { 890 int n = PT.parseIntNext(tdata, nextp); 891 haveEdgeInfo = (edata.length() > 0); 892 if (haveEdgeInfo) { 893 nexte = new int[1]; 894 PT.parseIntNext(edata, nexte); // throw away count 895 } else if (n > 0) { 896 Logger.info("JvxlXmlReader: jvxlTriangleEdgeData count=" + n 897 + "; expected " + nTriangles); 898 } 899 } 900 for (int i = 0, v = 0, p = 0, pt = -1; i < nTriangles;) { 901 if (haveEncoding) { 902 char ch = tdata.charAt(++pt); 903 int diff; 904 switch (ch) { 905 case '!': 906 diff = 0; 907 break; 908 case '+': 909 case '.': 910 case ' ': 911 case '\n': 912 case '\r': 913 case '\t': 914 case ',': 915 continue; 916 case '-': 917 case '0': 918 case '1': 919 case '2': 920 case '3': 921 case '4': 922 case '5': 923 case '6': 924 case '7': 925 case '8': 926 case '9': 927 nextp[0] = pt; 928 diff = PT.parseIntNext(tdata, nextp); 929 pt = nextp[0] - 1; 930 break; 931 default: 932 diff = ch - 92; // '\' character 933 } 934 v += diff; 935 } else { 936 v = PT.parseIntNext(tdata, nextp) - 1; 937 } 938 vertex[p] = v; 939 if (++p == 3) { 940 p = 0; 941 if (haveEdgeInfo) { 942 edgeMask = (nexte == null ? edata.charAt(i) - '0' : javajs.util.PT 943 .parseIntNext(edata, nexte)); 944 if (edgeMask < 0 || edgeMask > 7) 945 edgeMask = 7; 946 } 947 if (--nColors == 0) { 948 nColors = (PT.parseIntNext(colorData, nextc)); 949 int c = PT.parseIntNext(colorData, nextc); 950 if (c == Integer.MIN_VALUE) 951 nColors = 0; 952 else 953 color = c | 0xFF000000; 954 } 955 addTriangleCheck(vertex[0], vertex[1], vertex[2], edgeMask, color, false, 956 color); 957 i++; 958 } 959 } 960 } 961 jvxlDecodeContourData(JvxlData jvxlData, String data)962 protected void jvxlDecodeContourData(JvxlData jvxlData, String data) 963 throws Exception { 964 Lst<Lst<Object>> vs = new Lst<Lst<Object>>(); 965 SB values = new SB(); 966 SB colors = new SB(); 967 int pt = -1; 968 jvxlData.vContours = null; 969 if (data == null) 970 return; 971 while ((pt = data.indexOf("<jvxlContour", pt + 1)) >= 0) { 972 Lst<Object> v = new Lst<Object>(); 973 String s = xr.getXmlData("jvxlContour", data.substring(pt), true, false); 974 float value = parseFloatStr(XmlReader.getXmlAttrib(s, "value")); 975 values.append(" ").appendF(value); 976 int color = getColor(XmlReader.getXmlAttrib(s, "color")); 977 short colix = C.getColix(color); 978 colors.append(" ").append(Escape.escapeColor(color)); 979 String fData = JvxlCoder.jvxlDecompressString(XmlReader.getXmlAttrib(s, 980 "data")); 981 BS bs = JvxlCoder.jvxlDecodeBitSet(xr.getXmlData("jvxlContour", s, 982 false, false)); 983 int n = bs.length(); 984 IsosurfaceMesh.setContourVector(v, n, bs, value, colix, color, 985 SB.newS(fData)); 986 vs.addLast(v); 987 } 988 int n = vs.size(); 989 if (n > 0) { 990 jvxlData.vContours = AU.createArrayOfArrayList(n); 991 // 3D contour values and colors 992 jvxlData.contourColixes = params.contourColixes = new short[n]; 993 jvxlData.contourValues = params.contoursDiscrete = new float[n]; 994 for (int i = 0; i < n; i++) { 995 jvxlData.vContours[i] = vs.get(i); 996 jvxlData.contourValues[i] = ((Float) jvxlData.vContours[i].get(2)) 997 .floatValue(); 998 jvxlData.contourColixes[i] = ((short[]) jvxlData.vContours[i].get(3))[0]; 999 } 1000 jvxlData.contourColors = C.getHexCodes(jvxlData.contourColixes); 1001 Logger.info("JVXL read: " + n + " discrete contours"); 1002 Logger.info("JVXL read: contour values: " + values); 1003 Logger.info("JVXL read: contour colors: " + colors); 1004 } 1005 } 1006 1007 @Override postProcessVertices()1008 protected void postProcessVertices() { 1009 BS bsInvalid = params.bsExcluded[1]; 1010 if (bsInvalid != null) { 1011 if (meshDataServer != null) 1012 meshDataServer.fillMeshData(meshData, MeshData.MODE_GET_VERTICES, null); 1013 meshData.invalidateVertices(bsInvalid); 1014 if (meshDataServer != null) { 1015 meshDataServer.fillMeshData(meshData, MeshData.MODE_PUT_VERTICES, null); 1016 meshData = new MeshData(); 1017 } 1018 updateTriangles(); 1019 } 1020 } 1021 1022 } 1023