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.data; 25 26 27 28 import java.util.Map; 29 30 import javajs.J2SIgnoreImport; 31 import javajs.util.Lst; 32 import javajs.util.P3; 33 import javajs.util.PT; 34 import javajs.util.SB; 35 import javajs.util.T3; 36 import javajs.util.XmlUtil; 37 38 import org.jmol.api.Interface; 39 import javajs.util.BS; 40 import org.jmol.util.BSUtil; 41 import org.jmol.util.C; 42 import org.jmol.util.Escape; 43 import org.jmol.util.Logger; 44 import org.jmol.viewer.Viewer; 45 46 47 @J2SIgnoreImport({ javajs.util.XmlUtil.class }) 48 public class JvxlCoder { 49 50 //TODO -- need to escapeXml for text data 51 52 final public static String JVXL_VERSION1 = "2.0"; 53 final public static String JVXL_VERSION_XML = "2.3"; 54 55 56 // 1.4 adds -nContours to indicate contourFromZero for MEP data mapped onto planes 57 // 2.0 adds vertex/triangle compression when no grid is present 58 // Jmol 11.7.25 -- recoded so that we do not create voxelData[nx][ny][nz] and instead 59 // simply create a BitSet of length nx * ny * nz. This saves memory hugely. 60 // 2.1 adds JvxlXmlReader 61 // 2.2 adds color density Jmol 12.0.15/12.1.13 62 // 2.3 adds discrete colors for vertex-only data (encoding="none") 63 64 /** 65 * @j2sIgnore 66 * 67 * @param volumeData 68 * @param jvxlData 69 * @param title 70 * @return XML string 71 */ jvxlGetFile(VolumeData volumeData, JvxlData jvxlData, String[] title)72 public static String jvxlGetFile(VolumeData volumeData, JvxlData jvxlData, 73 String[] title) { 74 // for the simple writer 75 int[] counts = volumeData.getVoxelCounts(); 76 jvxlData.nPointsX = counts[0]; 77 jvxlData.nPointsY = counts[1]; 78 jvxlData.nPointsZ = counts[2]; 79 jvxlData.jvxlVolumeDataXml = volumeData.setVolumetricXml(); 80 return jvxlGetFile(jvxlData, null, title, null, true, 1, null, null); 81 } 82 83 private static boolean haveXMLUtil; 84 85 /** 86 * 87 * @param jvxlData 88 * @param meshData 89 * @param title 90 * @param msg 91 * @param includeHeader 92 * @param nSurfaces 93 * @param state 94 * @param comment 95 * @return JVXL file XML 96 */ jvxlGetFile(JvxlData jvxlData, MeshData meshData, String[] title, String msg, boolean includeHeader, int nSurfaces, String state, String comment)97 public static String jvxlGetFile(JvxlData jvxlData, MeshData meshData, 98 String[] title, String msg, 99 boolean includeHeader, int nSurfaces, 100 String state, String comment) { 101 checkHaveXMLUtil(); 102 SB data = new SB(); 103 if ("TRAILERONLY".equals(msg)) { 104 XmlUtil.closeTag(data, "jvxlSurfaceSet"); 105 XmlUtil.closeTag(data, "jvxl"); 106 return data.toString(); 107 } 108 109 boolean vertexDataOnly = (meshData != null); 110 boolean isHeaderOnly = ("HEADERONLY".equals(msg)); 111 if (includeHeader) { 112 XmlUtil.openDocument(data); 113 XmlUtil.openTagAttr(data, "jvxl", new String[] { 114 "version", JVXL_VERSION_XML, 115 "jmolVersion", jvxlData.version, 116 "xmlns", "http://jmol.org/jvxl_schema", 117 "xmlns:cml", "http://www.xml-cml.org/schema" }); 118 XmlUtil.appendCdata(data, "jvxlFileTitle", null, jvxlData.jvxlFileTitle == null ? "\n" : "\n" + jvxlData.jvxlFileTitle); 119 if (jvxlData.moleculeXml != null) 120 data.append(jvxlData.moleculeXml); 121 String volumeDataXml = (vertexDataOnly ? null : jvxlData.jvxlVolumeDataXml); 122 if (volumeDataXml == null) 123 volumeDataXml = (new VolumeData()).setVolumetricXml(); 124 data.append(volumeDataXml); 125 XmlUtil.openTagAttr(data,"jvxlSurfaceSet", 126 new String[] { "count", "" + (nSurfaces > 0 ? nSurfaces : 1) }); 127 if (isHeaderOnly) 128 return data.toString(); 129 } 130 SB sb; 131 String type = (vertexDataOnly ? "pmesh" 132 : jvxlData.jvxlPlane == null ? "isosurface" : "plane"); 133 // TODO: contours mentioned here? when discrete? 134 if (jvxlData.jvxlColorData != null && jvxlData.jvxlColorData.length() > 0) 135 type = "mapped " + type; 136 XmlUtil.openTagAttr(data, "jvxlSurface", new String[] { "type", type }); 137 data.append(jvxlGetInfoData(jvxlData, vertexDataOnly)); 138 jvxlAppendCommandState(data, comment, state); 139 if (title != null || msg != null && msg.length() > 0) { 140 sb = new SB(); 141 if (msg != null && msg.length() > 0) 142 sb.append(msg).append("\n"); 143 if (title != null) 144 for (int i = 0; i < title.length; i++) 145 sb.append(title[i]).appendC('\n'); 146 XmlUtil.appendCdata(data, "jvxlSurfaceTitle", null, sb.toString()); 147 } 148 sb = new SB(); 149 150 XmlUtil.openTagAttr(sb, "jvxlSurfaceData", (vertexDataOnly || jvxlData.jvxlPlane == null ? null : 151 jvxlData.mapLattice == null ? new String[] { "plane", Escape.eP4(jvxlData.jvxlPlane) } 152 : new String[] { "plane", Escape.eP4(jvxlData.jvxlPlane), "maplattice", Escape.eP(jvxlData.mapLattice) })); 153 if (vertexDataOnly) { 154 appendXmlVertexOnlyData(sb, jvxlData, meshData, true); 155 } else if (jvxlData.jvxlPlane == null) { 156 if (jvxlData.jvxlEdgeData == null) 157 return ""; 158 appendXmlEdgeData(sb, jvxlData); 159 appendXmlColorData(sb, jvxlData.jvxlColorData, 160 true, jvxlData.isJvxlPrecisionColor, jvxlData.valueMappedToRed, 161 jvxlData.valueMappedToBlue); 162 } else { 163 appendXmlColorData(sb, jvxlData.jvxlColorData, 164 true, jvxlData.isJvxlPrecisionColor, jvxlData.valueMappedToRed, 165 jvxlData.valueMappedToBlue); 166 } 167 appendEncodedBitSetTag(sb, "jvxlInvalidatedVertexData", jvxlData.jvxlExcluded[1], -1, null); 168 if (jvxlData.excludedVertexCount > 0) { 169 appendEncodedBitSetTag(sb, "jvxlExcludedVertexData", jvxlData.jvxlExcluded[0], jvxlData.excludedVertexCount, null); 170 appendEncodedBitSetTag(sb, "jvxlExcludedPlaneData", jvxlData.jvxlExcluded[2], -1, null); 171 } 172 appendEncodedBitSetTag(sb, "jvxlExcludedTriangleData", jvxlData.jvxlExcluded[3], jvxlData.excludedTriangleCount, null); 173 XmlUtil.closeTag(sb, "jvxlSurfaceData"); 174 int len = sb.length(); 175 data.appendSB(sb); 176 if (jvxlData.vContours != null && jvxlData.vContours.length > 0) { 177 jvxlEncodeContourData(jvxlData.vContours, data); 178 } 179 if (jvxlData.vertexColorMap != null) { 180 if (jvxlData.baseColor == null) 181 XmlUtil.openTag(data, "jvxlVertexColorData"); 182 else 183 XmlUtil.openTagAttr(data, "jvxlVertexColorData", new String[] {"baseColor", jvxlData.baseColor}); 184 for (Map.Entry<String, BS> entry : jvxlData.vertexColorMap.entrySet()) 185 appendEncodedBitSetTag(data, "jvxlColorMap", entry.getValue(), -1, new Object[] { "color", entry.getKey() }); 186 jvxlData.vertexColorMap = null; 187 XmlUtil.closeTag(data, "jvxlVertexColorData"); 188 } 189 XmlUtil.closeTag(data, "jvxlSurface"); 190 if (includeHeader) { 191 XmlUtil.closeTag(data, "jvxlSurfaceSet"); 192 XmlUtil.closeTag(data, "jvxl"); 193 } 194 return jvxlSetCompressionRatio(data, jvxlData, len); 195 } 196 checkHaveXMLUtil()197 private static void checkHaveXMLUtil() { 198 if (!haveXMLUtil) { 199 // creating an instance prevents pre-loading by JavaScript 200 if (Viewer.isJS) 201 Interface.getInterface("javajs.util.XmlUtil", null, "show"); 202 haveXMLUtil = true; 203 } 204 } 205 appendEncodedBitSetTag(SB sb, String name, BS bs, int count, Object[] attribs)206 private static void appendEncodedBitSetTag(SB sb, String name, BS bs, int count, Object[] attribs) { 207 if (count < 0) 208 count = BSUtil.cardinalityOf(bs); 209 if (count == 0) 210 return; 211 SB sb1 = new SB(); 212 sb1.append("\n "); 213 jvxlEncodeBitSetBuffer(bs, -1, sb1); 214 XmlUtil.appendTagObj(sb, name, new Object[] { 215 attribs, 216 "bsEncoding", "base90+35", 217 "count", "" + count, 218 "len", "" + bs.length() }, 219 jvxlCompressString(sb1.toString(), true)); 220 } 221 jvxlSetCompressionRatio(SB data, JvxlData jvxlData, int len)222 private static String jvxlSetCompressionRatio(SB data, 223 JvxlData jvxlData, int len) { 224 String s = data.toString(); 225 int r = (int) (jvxlData.nBytes > 0 ? ((float) jvxlData.nBytes) / len 226 : ((float) (jvxlData.nPointsX 227 * jvxlData.nPointsY * jvxlData.nPointsZ * 13)) / len); 228 return PT.rep(s, "\"not calculated\"", (r > 0 ? "\"" + r +":1\"": "\"?\"")); 229 } 230 appendXmlEdgeData(SB sb, JvxlData jvxlData)231 private static void appendXmlEdgeData(SB sb, JvxlData jvxlData) { 232 XmlUtil.appendTagObj(sb, "jvxlEdgeData", new String[] { 233 "count", "" + (jvxlData.jvxlEdgeData.length() - 1), 234 "encoding", "base90f1", 235 "bsEncoding", "base90+35c", 236 "isXLowToHigh", "" + jvxlData.isXLowToHigh, 237 "data", jvxlCompressString(jvxlData.jvxlEdgeData, true) }, "\n" 238 + jvxlCompressString(jvxlData.jvxlSurfaceData, true)); 239 } 240 jvxlAppendCommandState(SB data, String cmd, String state)241 private static void jvxlAppendCommandState(SB data, String cmd, 242 String state) { 243 if (cmd != null) 244 XmlUtil.appendCdata(data, "jvxlIsosurfaceCommand", null, 245 "\n" + (cmd.indexOf("#") < 0 ? cmd : cmd.substring(0, cmd.indexOf("#"))) + "\n"); 246 if (state != null) { 247 if (state.indexOf("** XML ** ") >=0) { 248 state = PT.split(state, "** XML **")[1].trim(); 249 XmlUtil.appendTag(data, "jvxlIsosurfaceState", "\n" + state + "\n"); 250 } else { 251 XmlUtil.appendCdata(data, "jvxlIsosurfaceState", null, "\n" + state); 252 } 253 } 254 } 255 appendXmlColorData(SB sb, String data, boolean isEncoded, boolean isPrecisionColor, float value1, float value2)256 private static void appendXmlColorData(SB sb, 257 String data, 258 boolean isEncoded, 259 boolean isPrecisionColor, 260 float value1, 261 float value2) { 262 int n; 263 if (data == null || (n = data.length() - 1) < 0) 264 return; 265 if (isPrecisionColor) 266 n /= 2; 267 XmlUtil.appendTagObj(sb, "jvxlColorData", new String[] { 268 "count", "" + n, 269 "encoding", (isEncoded ? "base90f" + (isPrecisionColor ? "2" : "1") : "none"), 270 "min", "" + value1, 271 "max", "" + value2, 272 "data", jvxlCompressString(data, true) }, null); 273 } 274 275 jvxlGetInfo(JvxlData jvxlData)276 public static String jvxlGetInfo(JvxlData jvxlData) { 277 return jvxlGetInfoData(jvxlData, jvxlData.vertexDataOnly); 278 } 279 jvxlGetInfoData(JvxlData jvxlData, boolean vertexDataOnly)280 public static String jvxlGetInfoData(JvxlData jvxlData, boolean vertexDataOnly) { 281 if (jvxlData.jvxlSurfaceData == null) 282 return ""; 283 checkHaveXMLUtil(); 284 Lst<String[]> attribs = new Lst<String[]>(); 285 286 int nSurfaceInts = jvxlData.nSurfaceInts;// jvxlData.jvxlSurfaceData.length(); 287 int bytesUncompressedEdgeData = (vertexDataOnly ? 0 288 : jvxlData.jvxlEdgeData.length() - 1); 289 int nColorData = (jvxlData.jvxlColorData == null ? -1 : (jvxlData.jvxlColorData.length() - 1)); 290 addAttrib(attribs, "\n isModelConnected", "" + jvxlData.isModelConnected); 291 if (!vertexDataOnly) { 292 // informational only: 293 addAttrib(attribs, "\n cutoff", "" + jvxlData.cutoff); 294 addAttrib(attribs, "\n isCutoffAbsolute", "" + jvxlData.isCutoffAbsolute); 295 addAttrib(attribs, "\n pointsPerAngstrom", "" + jvxlData.pointsPerAngstrom); 296 int n = jvxlData.jvxlSurfaceData.length() 297 + bytesUncompressedEdgeData + nColorData + 1; 298 if (n > 0) 299 addAttrib(attribs, "\n nBytesData", "" + n); 300 301 //TODO: these should only be for information purposes, but are not: 302 addAttrib(attribs, "\n isXLowToHigh", "" + jvxlData.isXLowToHigh); 303 if (jvxlData.jvxlPlane == null) { 304 addAttrib(attribs, "\n nSurfaceInts", "" + nSurfaceInts); 305 addAttrib(attribs, "\n nBytesUncompressedEdgeData", "" + bytesUncompressedEdgeData); 306 } 307 if (nColorData > 0) 308 addAttrib(attribs, "\n nBytesUncompressedColorData", "" + nColorData); // TODO: later? 309 } 310 jvxlData.excludedVertexCount = BSUtil.cardinalityOf(jvxlData.jvxlExcluded[0]); 311 jvxlData.excludedTriangleCount = BSUtil.cardinalityOf(jvxlData.jvxlExcluded[3]); 312 if (jvxlData.excludedVertexCount > 0) 313 addAttrib(attribs, "\n nExcludedVertexes", "" + jvxlData.excludedVertexCount); 314 if (jvxlData.excludedTriangleCount > 0) 315 addAttrib(attribs, "\n nExcludedTriangles", "" + jvxlData.excludedTriangleCount); 316 int n = BSUtil.cardinalityOf(jvxlData.jvxlExcluded[1]); 317 if (n > 0) 318 addAttrib(attribs, "\n nInvalidatedVertexes", "" + n); 319 if (jvxlData.slabInfo != null) 320 addAttrib(attribs, "\n slabInfo", jvxlData.slabInfo); 321 //next is for information only -- will be superceded by "encoding" attribute of jvxlColorData 322 if (jvxlData.isJvxlPrecisionColor) 323 addAttrib(attribs, "\n precisionColor", "true"); 324 if (jvxlData.colorDensity) 325 addAttrib(attribs, "\n colorDensity", "true"); 326 if (!Float.isNaN(jvxlData.pointSize)) 327 addAttrib(attribs, "\n pointSize", "" + jvxlData.pointSize); 328 else if (jvxlData.diameter != 0) 329 addAttrib(attribs, "\n diameter", "" + jvxlData.diameter); 330 if (!jvxlData.allowVolumeRender) 331 addAttrib(attribs, "\n allowVolumeRender", "false"); 332 if (jvxlData.jvxlPlane == null || vertexDataOnly) { 333 if (jvxlData.fixedLattice != null && !vertexDataOnly) 334 addAttrib(attribs, "\n fixedLattice", "" + jvxlData.fixedLattice); 335 if (jvxlData.isContoured) { 336 addAttrib(attribs, "\n contoured", "true"); 337 addAttrib(attribs, "\n colorMapped", "true"); 338 } else if (jvxlData.isBicolorMap) { 339 addAttrib(attribs, "\n bicolorMap", "true"); 340 addAttrib(attribs, "\n colorNegative", C.getHexCode(jvxlData.minColorIndex)); 341 addAttrib(attribs, "\n colorPositive", C.getHexCode(jvxlData.maxColorIndex)); 342 } else if (nColorData > 0) { 343 addAttrib(attribs, "\n colorMapped", "true"); 344 } 345 if (jvxlData.vContours != null && jvxlData.vContours.length > 0) 346 addAttrib(attribs, "\n nContourData", "" + jvxlData.vContours.length); 347 } else { 348 if (jvxlData.mapLattice != null) 349 addAttrib(attribs, "\n mapLattice", "" + jvxlData.mapLattice); 350 if (jvxlData.scale3d != 0) 351 addAttrib(attribs, "\n scale3d", "" + jvxlData.scale3d); 352 if (nColorData > 0) 353 addAttrib(attribs, "\n colorMapped", "true"); 354 addAttrib(attribs, "\n plane", Escape.eP4(jvxlData.jvxlPlane)); 355 } 356 if (jvxlData.color != null && jvxlData.color.indexOf("null") < 0) 357 addAttrib(attribs, "\n color", jvxlData.color); 358 addAttrib(attribs, "\n translucency", "" + jvxlData.translucency); 359 if (jvxlData.meshColor != null) 360 addAttrib(attribs, "\n meshColor", jvxlData.meshColor); 361 if (jvxlData.colorScheme != null) 362 addAttrib(attribs, "\n colorScheme", jvxlData.colorScheme); 363 if (jvxlData.rendering != null) 364 addAttrib(attribs, "\n rendering", jvxlData.rendering); 365 if (jvxlData.thisSet != null) { 366 String s = subsetString(jvxlData.thisSet); 367 if (s.startsWith("[")) 368 addAttrib(attribs, "\n subset", s); 369 else 370 addAttrib(attribs, "\n set", s); 371 } 372 if (jvxlData.slabValue != Integer.MIN_VALUE) 373 addAttrib(attribs, "\n slabValue", "" + jvxlData.slabValue); 374 if (jvxlData.isSlabbable) 375 addAttrib(attribs, "\n slabbable", "true"); 376 if (jvxlData.nVertexColors > 0) 377 addAttrib(attribs, "\n nVertexColors", "" + jvxlData.nVertexColors); 378 379 float min = (jvxlData.mappedDataMin == Float.MAX_VALUE ? 0f 380 : jvxlData.mappedDataMin); 381 float blue = (jvxlData.isColorReversed ? jvxlData.valueMappedToRed : jvxlData.valueMappedToBlue); 382 float red = (jvxlData.isColorReversed ? jvxlData.valueMappedToBlue : jvxlData.valueMappedToRed); 383 384 if (jvxlData.jvxlColorData != null && jvxlData.jvxlColorData.length() > 0 && !jvxlData.isBicolorMap) { 385 addAttrib(attribs, "\n dataMinimum", "" + min); 386 addAttrib(attribs, "\n dataMaximum", "" + jvxlData.mappedDataMax); 387 addAttrib(attribs, "\n valueMappedToRed", "" + red); 388 addAttrib(attribs, "\n valueMappedToBlue", "" + blue); 389 } 390 if (jvxlData.isContoured) { 391 if (jvxlData.contourValues == null || jvxlData.contourColixes == null) { 392 if (jvxlData.vContours == null) 393 addAttrib(attribs, "\n nContours", "" + Math.abs(jvxlData.nContours)); 394 } else { 395 if (jvxlData.jvxlPlane != null) 396 addAttrib(attribs, "\n contoured", "true"); 397 addAttrib(attribs, "\n nContours", "" + jvxlData.contourValues.length); 398 addAttrib(attribs, "\n contourValues", Escape.eAF(jvxlData.contourValuesUsed == null ? jvxlData.contourValues : jvxlData.contourValuesUsed)); 399 addAttrib(attribs, "\n contourColors", jvxlData.contourColors); 400 } 401 if (jvxlData.thisContour > 0) 402 addAttrib(attribs, "\n thisContour", "" + jvxlData.thisContour); 403 } 404 //TODO: confusing flag insideOut: 405 if (jvxlData.insideOut) 406 addAttrib(attribs, "\n insideOut", "true"); 407 408 // rest is information only: 409 if (jvxlData.vertexDataOnly) 410 addAttrib(attribs, "\n note", "vertex/face data only"); 411 else if (jvxlData.isXLowToHigh) 412 addAttrib(attribs, "\n note", "progressive JVXL+ -- X values read from low(0) to high(" 413 + (jvxlData.nPointsX - 1) + ")"); 414 addAttrib(attribs, "\n xyzMin", Escape.eP(jvxlData.boundingBox[0])); 415 addAttrib(attribs, "\n xyzMax", Escape.eP(jvxlData.boundingBox[1])); 416 addAttrib(attribs, "\n approximateCompressionRatio", "not calculated"); 417 addAttrib(attribs, "\n jmolVersion", jvxlData.version); 418 419 SB info = new SB(); 420 XmlUtil.openTagAttr(info, "jvxlSurfaceInfo", attribs.toArray(new Object[attribs.size()])); 421 XmlUtil.closeTag(info, "jvxlSurfaceInfo"); 422 return info.toString(); 423 } 424 subsetString(BS bs)425 private static String subsetString(BS bs) { 426 int n = bs.cardinality(); 427 if (n > 1) { 428 String a = "[ "; 429 for (int ia = bs.nextSetBit(0); ia >= 0; ia = bs.nextSetBit(ia)) 430 a += (++ia) + " "; 431 return a + "]"; 432 } 433 return "" + (bs.nextSetBit(0) + 1); 434 } 435 addAttrib(Lst<String[]> attribs, String name, String value)436 private static void addAttrib(Lst<String[]> attribs, String name, String value) { 437 attribs.addLast(new String[] { name, value }); 438 } 439 440 public static final int CONTOUR_NPOLYGONS = 0; 441 public static final int CONTOUR_BITSET = 1; 442 public static final int CONTOUR_VALUE = 2; 443 public static final int CONTOUR_COLIX = 3; 444 public static final int CONTOUR_COLOR = 4; 445 public static final int CONTOUR_FDATA = 5; 446 public static final int CONTOUR_POINTS = 6; // must be last 447 448 /** 449 * contour data are appended to a string buffer in the form of a 450 * <jmolContourData count="[nContours]"> 451 * <jmolContour index="0" value="-0.033" color="[xff0000]" encoding="base90iff1" data="fractional data">triangle bitset data</jmolContour> 452 * <jmolContour index="1" value=" 0.000" color="[xffff00]" encoding="base90iff1" data="fractional data">triangle bitset data</jmolContour> 453 * <jmolContour index="2" value=" 0.033" color="[x00ffff]" encoding="base90iff1" data="fractional data">triangle bitset data</jmolContour> 454 * ... 455 * </jmolContourData> 456 * 457 * One presumes an ordered set of triangles. 458 * The contour intersects these triangles along two edges or at two vertices. 459 * (see IsosurfaceMesh for details) 460 * Each contour is a Vector containing: 461 * 0 Integer number of polygons (length of BitSet) 462 * 1 BitSet of critical triangles 463 * 2 Float value 464 * 3 int[] [colorArgb] 465 * 4 StringXBuilder containing encoded data for each segment: 466 * char type ('3', '6', '5') indicating which two edges 467 * of the triangle are connected: 468 * '3' 0x011 AB-BC 469 * '5' 0x101 AB-CA 470 * '6' 0x110 BC-CA 471 * char fraction along first edge (jvxlFractionToCharacter) 472 * char fraction along second edge (jvxlFractionToCharacter) 473 * 5- stream of pairs of points for rendering (created 474 * 475 * 476 * @param contours 477 * @param sb 478 */ jvxlEncodeContourData(Lst<Object>[] contours, SB sb)479 private static void jvxlEncodeContourData(Lst<Object>[] contours, SB sb) { 480 XmlUtil.openTagAttr(sb, "jvxlContourData", new String[] { "count", "" + contours.length }); 481 for (int i = 0; i < contours.length; i++) { 482 if (contours[i].size() < CONTOUR_POINTS) { 483 continue; 484 } 485 int nPolygons = ((Integer) contours[i].get(CONTOUR_NPOLYGONS)).intValue(); 486 SB sb1 = new SB(); 487 sb1.append("\n"); 488 BS bs = (BS) contours[i].get(CONTOUR_BITSET); 489 jvxlEncodeBitSetBuffer(bs, nPolygons, sb1); 490 XmlUtil.appendTagObj(sb, "jvxlContour", new String[] { 491 "index", "" + i, 492 "value", "" + contours[i].get(CONTOUR_VALUE), 493 "color", Escape.escapeColor(((int[]) contours[i] 494 .get(CONTOUR_COLOR))[0]), 495 "count", "" + bs.length(), 496 "encoding", "base90iff1", 497 "bsEncoding", "base90+35c", 498 "data", jvxlCompressString(contours[i].get(CONTOUR_FDATA).toString(), true) }, 499 jvxlCompressString(sb1.toString(), true)); 500 } 501 XmlUtil.closeTag(sb, "jvxlContourData"); 502 } 503 504 /** 505 * Interpret fractional data in terms of actual vertex positions and 506 * create the elements of a Vector in Vector[] vContours starting at 507 * the CONTOUR_POINTS position. 508 * 509 * @param v 510 * @param polygonIndexes 511 * @param vertices 512 */ set3dContourVector(Lst<Object> v, int[][] polygonIndexes, T3[] vertices)513 public static void set3dContourVector(Lst<Object> v, int[][] polygonIndexes, T3[] vertices) { 514 // we must add points only after the MarchingCubes process has completed. 515 if (v.size() < CONTOUR_POINTS) 516 return; 517 SB fData = (SB) v.get(CONTOUR_FDATA); 518 BS bs = (BS) v.get(CONTOUR_BITSET); 519 //int nPolygons = ((Integer)v.get(CONTOUR_NPOLYGONS)).intValue(); 520 int pt = 0; 521 int nBuf = fData.length(); 522 int type = 0; 523 char c1 = ' '; 524 char c2 = ' '; 525 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 526 int[] vertexIndexes = polygonIndexes[i]; 527 while (pt < nBuf && !PT.isDigit(c1 = fData.charAt(pt++))) { 528 // skip non-digit data 529 } 530 type = c1 - 48; 531 while (pt < nBuf && PT.isWhitespace(c1 = fData.charAt(pt++))) { 532 // skip whitespace 533 } 534 while (pt < nBuf && PT.isWhitespace(c2 = fData.charAt(pt++))) { 535 // skip whitespace 536 } 537 float f1 = jvxlFractionFromCharacter(c1, defaultEdgeFractionBase, defaultEdgeFractionRange, 0); 538 float f2 = jvxlFractionFromCharacter(c2, defaultEdgeFractionBase, defaultEdgeFractionRange, 0); 539 int i1, i2, i3, i4; 540 /* 541 * char type ('3', '6', '5') indicating which two edges 542 * of the triangle are connected: 543 * '3' 0x011 AB-BC 544 * '5' 0x101 AB-CA 545 * '6' 0x110 BC-CA 546 */ 547 if ((type & 1) == 0) { //BC-CA 548 i1 = vertexIndexes[1]; 549 i2 = i3 = vertexIndexes[2]; 550 i4 = vertexIndexes[0]; 551 } else { //AB-BC or //AB-CA 552 i1 = vertexIndexes[0]; 553 i2 = vertexIndexes[1]; 554 if ((type & 2) != 0) { 555 i3 = i2; 556 i4 = vertexIndexes[2]; 557 } else { 558 i3 = vertexIndexes[2]; 559 i4 = i1; 560 } 561 } 562 v.addLast(getContourPoint(vertices, i1, i2, f1)); 563 v.addLast(getContourPoint(vertices, i3, i4, f2)); 564 } 565 } 566 getContourPoint(T3[] vertices, int i, int j, float f)567 private static T3 getContourPoint(T3[] vertices, int i, int j, float f) { 568 P3 pt = new P3(); 569 pt.sub2(vertices[j], vertices[i]); 570 pt.scaleAdd2(f, pt, vertices[i]); 571 return pt; 572 } 573 574 /** 575 * appends an integer (3, 5, or 6) representing two sides of a triangle ABC -- 576 * AB/BC(3), AB/CA(5), or BC/CA(6) -- along with two fractions along the edges 577 * for the intersection point base-90-encoded. This version is single precision. 578 * 579 * type f1 f2 580 * 3 AB BC 581 * 5 AB CA 582 * 6 BC CA 583 * 584 * @param type 585 * @param f1 -- character-encoded fraction 586 * @param f2 -- character-encoded fraction 587 * @param fData 588 */ appendContourTriangleIntersection(int type, float f1, float f2, SB fData)589 public static void appendContourTriangleIntersection(int type, float f1, float f2, SB fData) { 590 fData.appendI(type); 591 fData.appendC(jvxlFractionAsCharacter(f1)); 592 fData.appendC(jvxlFractionAsCharacter(f2)); 593 } 594 595 /** 596 * 597 * @param jvxlData 598 * @param vertexValues 599 */ jvxlCreateColorData(JvxlData jvxlData, float[] vertexValues)600 public static void jvxlCreateColorData(JvxlData jvxlData, float[] vertexValues) { 601 if (vertexValues == null) { 602 jvxlData.jvxlColorData = ""; 603 return; 604 } 605 boolean writePrecisionColor = jvxlData.isJvxlPrecisionColor; 606 boolean doTruncate = jvxlData.isTruncated; 607 int colorFractionBase = jvxlData.colorFractionBase; 608 int colorFractionRange = jvxlData.colorFractionRange; 609 float valueBlue = jvxlData.valueMappedToBlue; 610 float valueRed = jvxlData.valueMappedToRed; 611 int vertexCount = (jvxlData.saveVertexCount > 0 ? jvxlData.saveVertexCount 612 : jvxlData.vertexCount); 613 if(vertexCount > vertexValues.length) 614 System.out.println("JVXLCODER ERROR"); 615 float min = jvxlData.mappedDataMin; 616 float max = jvxlData.mappedDataMax; 617 SB list1 = new SB(); 618 SB list2 = new SB(); 619 if (vertexValues.length < vertexCount) 620 System.out.println("JVXLCOLOR OHOHO"); 621 for (int i = 0; i < vertexCount; i++) { 622 float value = vertexValues[i]; 623 if (Float.isNaN(value)) 624 value = min; 625 if (doTruncate) 626 value = (value > 0 ? 0.999f : -0.999f); 627 if (writePrecisionColor) 628 jvxlAppendCharacter2(value, min, max, colorFractionBase, 629 colorFractionRange, list1, list2); 630 else 631 list1.appendC(jvxlValueAsCharacter(value, valueRed, valueBlue, 632 colorFractionBase, colorFractionRange)); 633 } 634 jvxlData.jvxlColorData = list1.appendSB(list2).appendC('\n').toString(); 635 } 636 637 /* ****************************************************************** 638 * 639 * JVXL 2.0 encoding of vertices, triangles, and vertex values: 640 * 641 * <jvxlSurfaceData> 642 * <jvxlTriangleData data="!]][[_]]Y`WbVa^]]] ... cZ_T^ZdUdTc!^[Dv][Bx-43,+44,]-55,f+43,_W`Z^X`Z ..."> 643 * </jvxlTriangleData> 644 * <jvxlVertexData min="(15.218472, -28.304049, 34.71112)" max="(97.8228, 54.011948, 109.95208)" data=0HY0HZ0HZ0HY0H[0GZ0IZ0IZ0H[0FZ..."> 645 * </jvxlVertexData> 646 * <jvxlColorData type="range|discrete" data="015.86++1@<?<D~4 CD2BDDCD*D?BCB?~6 @@.=??CAAC@?~4 A@A?CCD@?@?ABA?>B=<=~4 <====???>>>???,0<<<0/5;:;=><;=<<;,8:;:;=><BAA=?<;+,)*0+/<=<<<<==<~7 =<=<=<====<??<<>>>?=>>??>~5 ?>=>>>===<<<<;<<;;<<<=<<<===><====<==<=~4 <=<9::<<;;;::;;:;;<:;>~4 ;;==<=;=~4 <====>??>==>>>==<=<==<==>=~4 >>>>=>>==?==><~7 ;;;<;<<<;;;;/..0/<;316268<<<;;22:~18 ;:;:<<<=<~9 ;;<;~4 <~6 =<;;<;~4 <<<;<<;<<<;~5 <~16 ;;;;<;:;;:~4 ;:;;;<;;;:;<<<;::;;:;:99;;;:?@>@<<<;==<;::<<;=;<>;:<==>;<;@@>===<<;=AAAA;=~4 ;:=<::><::9::::9:;;;;::::;~4 :;;:;~7 <<;;;<:;::;~5 <;<;~5 ::;9~7 :999;:::;:9~4 ;:;~6 :;;:~4 ;;;:::9;~4 <;<<::999:999:~7 ;;;:::;:<<<:<;<::<;<:::;:~5 9:::99:999::999<<<=<===>~4 ?@?A@A?BABA===>>>==<A>><><>???B>>>BBB?~6 >>BBBB>@AA>~4 ?AB~4 <~5 9~16 :~4 9:~5 9:::9~7 8999:::9:::999:99::9::9~11 ;::::;;99:9::99::9999:9~6 :~5 ;;;988889~5 8889889998:989989~4 8~5 9==>==;<;=>;<====<;>>>=<<<<;;?A?AB<~4 ;=<;ABB<;<~6 ==<=<~4 ;;;;9~7 8989~4 88898~4 989~11 8999989889:::998888::7788789999:8989888898988988988989~31 ;:;<:9888999:;;;;<~6 ;::<<;<:~4 9;;::8887777556878887666787867757775~6 6~4 8789889:99:998999:999899::99:9~23 8898~4 99998~4 989998989767788876776696668766667899777889989999898~4 987778~4 9998989~5 898~4 78668777788767555655688786668998666967888668898~11 66687778~8 78~16 7766686655667688786~14 7766778898899:9:7899995554454~5 5544655456655568~9 9998889899998~4 99888777887~4 8889998766999896859988986666558865886695~4 8888998~5 9887776787~4 878~4 788445444554436666776~6 76~4 7778867788778666886667663~10 433223334444338~14 998~6 99899988898~16 66545888776787865777883333445456343~10 8~10 98~4 989~7 88993~11 878~5 9867766676776~10 333343~7 443~9 76776776633357776554755888878~6 787788877676666765999988878877766668866557563335564554555656577657755756655665664554434564465544467778878~4 7777898798989998889~5 5~5 6~13 776445565756675446766565566446~5 7~5 56665556666565644765588775767686676878~5 78787777886667~5 6~8 78~4 7777887678887869996~7 76~5 7667~6 8~5 78~5 98778887787887~7 ::886828::88988:9::9:88:98888:::88777769768987978889:96777788:::;::;:87789~13 8999777766665~7 6666566555599888898998988:::7787:::99897:889787~4 88887778887998898999-)**,+)*)*()*(+++(***7878889788989998999898777677776777876~4 7665652231~5 4/24656657677<<;<<<<5665656555665~5 4456565~11 6665~4 6655656556665657~17 6655777677554~6 33;4444;<;;4555;;5<;<<;;449;;;<7~7 67776777767~5 6656677657<<<;~4 <<<=<;;<;<~6 =<;5~14 =~16 <===8889999899998~4 99997887877878~7 998888987888798989999;;;9:~6 ;:::989;;;988887788665589886577887778877767~4 6655565789899998787878788788998999:9:~4 988766676~10 565<<<<=~7 <===<<=<====>>=>=:;~4 <<;;;:<::78878777677767~4 8877888787787~5 8~7 7788878878887~5 8777787~4 66788776767667~15 877887988988778978876~6 565~4 66656656;<;;;<<:;:~4 ;;;;<:~5 9:99:9~6 7~10 8~6 7~6 887~10 88878~4 7878866678898~6 6787768668778887777888788878778~21 6~4 5676~4 56878878~8 99888999::9:::9~7 :4~8 54~7 54446458~7 9888898889~14 8998989898~6 9889~4 88999898779889889969899687869969867866556989~7 89888898889~8 8894556568~19 98989~9 4~5 333434~5 55455454445~5 88889988899898988989~7 8~5 99998~8 98~4 988878656787888645~4 675455546778~8 988998884~4 34~17 9~10 889899989~5 89~5 8999989:9::9~7 :9~8 787899989~5 88799989889~4 :9~10 :9:9~4 :9:5598898769~4 688899:566645477767774644;;;;:::;;;;9:::6~4 777::::6~12 ::;:::4456~4 447~5 66664557776669~7 :::9:9~5 :;;:;;:~16 99::9::98:7:999988778988::::9:::99::999:~8 ;777:::8989:~4 98:7:8:;:8;~7 :7778<;<<<;<;~7 <<:<<::;<;;;;<;;<<;~4 <;;<~4 78;;:;:;;9;;:;<;~6 :;:;;:;~11 :::;:;:;~8 :~7 ;;::::9998~4 :::899888:;;::978;:;9999:9;;:<<;::;::::;<:::9<<<:;<<;<;;<;;;;:;;;;:9;;:;;;::;~5 :;;::;~5 ::9;::9:~5 ;::::;;:::;;9:~5 ;:~4 ;~20 :;;::;~6 :::;:;;::;~16 :;;;9::::;:;;;;:;~4 :;;;;:~4 ;~4 :;~6 :~8 ;;;;8988998889:~4 99:9:~7 99:9997789~5 889898899879878899889:;;;:~7 ;:~15 889999:9:9:89779~5 8~4 ::9:::9::9::9:~19 9:999989~5 ::;9~5 ::9::;:9::99:998888;~6 88;;;:9:9:::98;;::9:;9:9999::;;:::;;:~5 ;:99:~4 ;<;;<<:;:<;;<;::::<<<<::<;:::<~4 =:::9<;;<<<;<<<;:;<:;<;~6 ::999989:9:99::9998898:9~17 8887778767668~4 98:~8 ;<~4 ;<<<;<;:;:;;:;;:::99::::98:~7 ;:~5 ;:9;;:;9::9;:;8:9:9::98988899::9888878:~12 9999:~8 7677787676669~24 54~8 5656559:9:9:9:9:::9::;99::9;;;::9999::::;:;~5 :;:::9;::9~8 897798~5 999886667766678::9999898~5 7~4 88:;::99:99:;:5566456654~8 5449~9 ::::;:::;~6 ::;;;888989~7 88899988989989~12 89~7 667767755888776487888855666675644545555664~4 5~5 45~5 ;::;;;;<<<<;<~5 ==<~4 99::;;<<:;;:77998989989898979~4 :~5 9:9:;;::;;;;:<;<66699796999:767668888978998454566655;;;:::;;;;99:9::;;9;;;;8899899998<<<<;;;=<=:;;<<5556555=~8 <=<<====<666656776~6 55664446688998~10 98::9~5 :9:::99:988::;;;;:98889986666788889988669688677789978~5 776778~15 9889~8 ::::88666766766:::;:;;:;65~5 665556~4 56~9 8~18 98988998998899998~8 9999889888988878~5 6666777888688877778~15 998989998889955566555:~5 9999::;;:;:~4 ;;;;<<;;5~4 666565~4 7~8 88877878~15 7~5 87888778~10 7~6 87787766777677788677665567766667755675557~9 87787777566665~8 9::;::::;888899888989878~10 78787878778887778~6 7~10 8~6 7~4 8887888777876667768787666555665~9 787877887787788787~6 875~4 4457888778887~4 878778~4 5~8 4554559~11 8988898888798898~4 9877788889988877789876786::9:~5 7::::9889~4 8:788766999855775~4 9~5 889998998887978889988878~14 756667676577877776677767756666778776785667~4 577675759~13 :~9 99:99::9:9~6 ::::99::999898998889988997998897899889987888879~5 8979899879889~5 8899988989899998988899889~7 78~5 778978~4 76~4 56~8 999897~6 877889:::99978879:99:9999899:99987998889889~5 ::99998:::99:99:~20 7~8 6768787777676776554554664677677766989::::8899::999::99888:::9:~15 9999:99989998~6 :898~4 97887878988898888::9:::99:~16 8~4 :::99998:99:778566786998666:::9:~5 9:99:::98897996678;;;:;::;;:::56545644333343~4 4534:9:9::999:~11 ;;;:;899898999;<;99:99<<<;;:;;<877;<::99:::;:~8 =~4 <<=>====:=~9 <~4 66766559:;<<6;=46789:3334333435633=>~5 ==><;=>~4 ==>>>?=:<;:<;=:;54~12 55455534~12 9:9:;;::9;:::;;<;;<~4 ;;;;>==>==<<:;><~8 :=<<<<===>~7 7~4 87884555764577658799::;9:;988999::9::::668987=><89;;<;::95555657779986887955<==<<89;<;::;97778~5 9?>>???>>?>=>=56556666>>?@A<???@?>???<==<>;~6 <<>>;;;<;;=;?>?>@<;<<;666656~12 566668888:99:999;;:98~4 ;<::9::999::=>=<;;;:8~6 777677878~6 77878776677776777788;:99:;:~6 9:99:8>>>=;<=?>;>~5 ;<;?>?>7~8 666?~9 >?~5 >;;;;<;;?<?<<><<;~4 ?>;;;??@????;;<;;<9~4 889998~6 997878987786:999:999::9998889898889998898:999:9::99::9::99:~5 9:::888:99:::9::88889998899989~7 :9:~4 9:9~7 ::::9:~5 ;;:;;:<;8~5 ::::>><><==?;;:;::::;;<<;7978878889~20 89~6 89999899:99:9:::999:9::99988998889~4 ::999888878888779~5 :99:9~4 ::::9:9998:9:~17 9:::9::;9::;~4 ::88989898~8 9:~4 9:9:~9 99:999::9::::9:;;;:;::;:::;::::;::<;<~4 ;<;<;;;9::99988;;::98<~4 ;;<~4 ::9;9<;;:::99<<<;<<<;;;:;:<<<<;:899;;<<<;:;::<<;;<;;;;::<:::<<;;<<;<;<;;<<;<<<;:99<;:;;;:9:;;;;<;;:;;;;9<9;==>==>~5 =<<=~7 9999===:::<<<;;;9::=<;~4 <::>==>??>?~8 >?>>>>=>?>>?>~6 ==>~6 =>88788878799888>>>>====>>>====>?>>==?:586649568;88967878~8 78889:7:6786777766577:898:=~9 <<=<;;<::::;:<<<<;:;:9;7979::984655796:97877<~4 ====::<<=<<;=<<<<;:::989897778887788867;;:;998:;=~5 ;<~4 ====<<===<~16 =<>~4 ?>>=>?>=<;;;:;<;<=~5 ><>~6 ==>>==>=;<<;:;<<:;=:::?~4 >~6 ?>????>~5 ?>~6 =>~8 =<=<<;=;=><<>~6 =<>><<=>?=<?~5 >>?>?>>>>A@@@?@???>?>@==@>>?@@?>>>>??=<=<<>>====>==><?<=?>>>?<;;<;<<;<<<==<=<==<=<<<=~5 <====<>=~5 <~4 ;<~5 ;;<;~5 :;;;<<=<~5 ;;<~12 ==;<>====>=>=>~8 ??=>>>=~7 ???>>==>==>==????>>>>?====>=>=>>>=~19 <<=<=<<<====<~8 =<==<<<<====>==>=>===<<==>=~4 <=~4 <<=<~4 =<~4 ;<;~7 ::;;:;;<;<;<~5 ===<>=>=><<<<==>>>=>==>~9 ==>====>>=>~5 =>=~14 <=~9 <=~22 >~11 <<<<==>=<<====>====>~7 <~4 ;<<=~4 >>==<<<<=~4 <~5 ==<~12 =<~4 =~4 <<==<=<~12 =~5 ><>===<=<~8 =;;;<<;<;<~16 ===<<<;~8 =~5 ;==;;;<=<<<<=~6 >>>=>===>>=<=<====>~6 ?>>><====<>=~10 <===<~9 =<<<==<=>~12 ?>~4 ===<~5 =~5 <====>>=>=>~4 ;~6 <;;<<<<;;;<<;;<<<DFEDEFFFFGFFE~8 FFE~5 FFFEEFE~6 DDD=~50 <~11 =<=<=~8 <;;;;<<;<;<;~4 <~5 ;;<;;;;<<<;;;==<=<<=<===<=<===<~36 ;<<<===<====<=>>=<<<;<<=>=>>>?>>>>:~7 ;::;:::;<::;::A?@AA@?>A?@@@?@>???@A@?@?C???>>=>=;;:?<<>9=<7:>>>====<===<~14 =DBAC<<B===<:;<<;:?<<?=>8:8<;;<=<9<=<<=<>==<;>=>@@@<<=<~9 ?<>??<?A@?<;>@B9<=?=@>:@B@<<<=<===<~6 ;;<;<;<<<<;9:999::;;<:9;;:=<<<<=>>==>>?<==<=>@>==<=<=<<<====@AA@B@@AAAB@AAAA@<~6 ??>??>?~4 ===<=<<===<~5 ==>>==<<===>>@=<====>?===>==@=>=@>@~4 ?>>?@?@@@?<;<<;;<<=<<<;;<;;=>><<<;<??@>==:<:;;=~4 <=<====>=>===>>>=>=~4 >=>??====??>>?>>===>89<===>~4 :899<>=9989;9;;:>>?A???ABBABB@???>?~11 @A?>?>???>??>~5 ???>~9 ??>?@@????>~7 =>@>~9 ??==>=>=~6 ???@~4 ?AAAA@@AAB@BB@A???====>~5 ?>=>>??@@====@A@???AA??@@@?~4 >???>~4 =>>>=>~4 =~5 <=<==>=<<==>==<<<<==>>???>???>>>>????@~4 ?@@@?@@@AABAB@AA@@?BB@~5 AA@@@?@???AA@~7 A@~6 A@@?@~5 A@?~4 @~6 ?@@@?@@@?@~5 >?~4 @~5 ??@?@??@??>>>===>====>=~12 >=~8 <=<<===>==>==<<>><<=>><>>>==>>>==>>>=>?==?>~8 ?~8 >@???@@=>===>===?@>@@?=>>>>??=>??>==<<=?<~5 ==>????@?>==>???>>>>???>?=>>>@@???@@?>>;9?>>>=:9<>>>>?>>>??>>?><>9::?>?=?=>>>:<<<><>?;7999:8=?<;<?>66;==<==?~5 >A@@A?>@@>@?@@?@@@@???>~4 ?<>>?@CA?@??@@??@@?@@@@?@@>?>>>=>>>>====<<==<<<;<<<;;<;;;<<<;<<;~4 <~5 ;;;::;:9::9~4 ;:>>====<===<<=<<<<?@>?>?>>?@>=?=~6 ?>>?>?===???@?>==?<=~4 <~7 :;:;999:99887789~4 8777899976669988<;<<<:::;;<9998898798768776~4 7:;:;:9888989889~6 8~5 9889888898899988898~8 787~4 66687776776665889:9~5 8999;;::;:~5 9999::;~7 :~4 ;:;:~7 ;<<::::<<<8~5 98~5 98?>?>~6 ====?===?>>>>=>::;;;:9:99:8<<==;:>96=<=~7 <<=~4 >>=>=~4 <==>>><=<~8 =<~8 ==<=<<<=<~4 ==<~4 ==>~5 =~5 <~5 =~15 >=>~5 =>====>==>>>====>~7 =~5 >>>=~4 >>>====;~4 <;;====:;;:;;==<=<<<<;<=<;<=~18 @@@?@?@@?@?<=<<=?===>==>>?=?>>=~4 >=>=>?<?=;<?<>=>==<==>>?>?>??>>>====>=>==>>=~6 >=~7 <<;;;>;;<=<<;=;;===<<=<=~7 >=<=;:7>@?@?<<;<<;<~10 =>==?==?>>?>>>???=99;998~10 :8998;::9;;98<;:=9=:<;8;664687787574325289:<66FFFGFGGGFGF~5 EFFFFEFEF~4 EFCCCEBDGEEFCC@DDBF=~5 <=<<<=<~7 =<~7 ;<<;~6 :;;::<~8 ;;;:9:899;<<:;:<;;;;<;<<<;;<<<;:<<:::;~4 =?>887;<=>;:99::::;:;~10 :;::;~4 79777878E~6 DEE8EEEED;=;9;<<;;<;;67;~5 <<6;<EDDDEDEDEEEED~7 ;;::;::;<;~4 <~7 ;<:;;:;~9 <;~48 <~7 ===<=<~12 =<<<<===;<====<==<<<=<~20 >~8 =>?>=><==>=><<<<=<<<=~4 <<=<>=~4 <~10 >>><<<<==>===><<==<=~5 <<<=<==<~7 =~9 >>>>=>~4 ==>>=>>>=<<===<~4 ===<=<==<=~11 <~5 ===>??>==>>=~10 >=>===<<<===<~6 =<=<<=<<<<>>>=~14 >=~9 <====<====>>?>~4 ?>>??>?>?>>=>>>>=>>>>==>~4 ?>====>>=>~24 ?>???>???>>?>~5 ?>=~4 >=<=<~8 =<=<=<====<<=<<<=<~4 ;=>=>==<==<<=<<<<===<;?=<>=<;;;<=<<==>>=>=>>>><C?C@C@=BABCD@?@@??@???@??@@@@??@???>===><>;<@@@??=>>?~4 =>????<>=??@@?><<<<==<=<==><;:;;<>=~5 >====^__^`_]]]^^]]_^__^^]]]^^^_^~4 babadffcgddfffcdeb^^^```????@?~10 >?~8 !!![!^_^][!]!^!![![[???>?~5 >@??=?=?~4 ><<<>>><;<=<=>>=>=<=>~4 ?>=>~6 kkjkkhhhg!^!_^Y^!Yhfd_`!]gbbeeY[![[!ZYZ!Z[[_!`a`^Y_dfZWWX[kkjjjkhjgjjdjjedkkkk_[a[aXXWWWX[cdicXVXVYYVXrrrsposlkkkkjkkkikilkmknlh_^^]lgmhb`eaoonqlYZ[XVYY[Z[Y[[[[Z]^][[]!^!]YYYXXXYXYYYWXXVWXWXZXSSVRSRRRSRSRRVSVZXV<~7 ;~7 <;<;;<<;<~4 ;<~14 99::9::<<;;<;;<:~6 <<<<;<;~4 <<:9:9:9:;;;:::98899<~22 ;;<;;<<<8887~4 877877;:9999:<<<<;<<<;<;>~5 ?>????9889????:=:>>899788<?>????>?;<<<<>>>>=<<==<<=>>?>>>>=<=<>>;<<;==<=;<====;==ECEC???BB;=<HIJ@EE88:9878:3443333654545444455432553:845545~4 :89955588798554544456<<B?89=56=?=<<<<:<<<<;<~4 ;<~6 ;~5 <;<4636.333387867767741354655623665564044547~6 8777865=>>>??>?=;:;;<<=<=;;;<;EGFHGHELLKKAGENK7679HDI86NONDC567::;::::;::<9:?~8 <GHIGGHIIHGGGHHIEIGH204D364=HIIJI3<H./KFGFFFIGGG--//0;:;:;;;;:::;:~4 ^_^a]cd`alllkleeflkihli;::99:aagg9f``b^]]]][^!::9999fffc]a_a_`zyyzrr{twwzy{|zzkklkklkjkikwqppvtli^^iWWVVX`Wj[[]Z[[[[Z[f`WXvxWWfbZYY![]]]!]!]![~5 Z[[[ZZ]^~9 _[[^^^__^^ZWYXXYYZXYWYWXXYX[:;;;:;;;:;;9:;~4 :;::;;:;;::::=>=:;::<==>;:;>=<=<=;====<>>==>>>??>=??>A~5 @AAAA@~4 AAAA@@A@AAAA@@AA@@A????>?>>>=>>>>?>>>A@@A@@??A===>>A@?@A@@?A?~4 @?>?@???@@??A~5 @@@A@?A@??@@@A~5 @A@@@@???>>>?~6 ;<<;<~5 ;<<>=<=<;>?@??@?@@?@?@@??@@??>??@???>~6 ?>?>>?=~4 <<===>>???>>=>>=?~5 =>===<=<<<>=>=>=<<=>>>==<<=~4 >>=~8 >>==>>>>?>??@@????@?>===<~13 ;<<<;~8 <<<=<=<<<===<<<===<=<=<~16 =<=<=<~5 =~4 <=>=>?>;;<~4 =<<;;;;<<<<;;;<~4 =;~4 <<<;;;;<~9 ==<=<<;=>=?==>>=<<==<==<====>>>=>>=>~4 ??>>??>~7 ====?>>>>??>>>>??@@?~4 @????>=~4 <<=<;~6 <;<<:;;;;<<>;=9<<<?=<<<<;=~14 <=<<=~11 <===<=;===>>>==<=~5 <=>=>====<<<<==<<=<<<===<<<=~6 <=~6 <=>=<<<=;===<=~7 <~12 =<====<==>=~6 <=~5 DA@DC<=?FDCEDHJJH=~11 <==CEEBGIBH<~19 =<=<=~4 <=>BC=~4 ><<===<E<CJKIGHBJ====<=<==<<<===<<<==;;<~11 =<~9 ;~7 <;~12 <;<<<=>====;<>>>?=::9:;;;;:::9<<<9=;;;<~6 =<=<<<<;;<;;<;<;~7 <;~6 <<;~5 <<;;;<;~53 :;~10 <;;;<~6 ;;<;;<;;;;:::<:~4 <~4 ;<<;~5 <<<;~8 :~5 ;<;;;<<<;;;;<~17 =<<;;9::;;:;;;<;;;::9998;:;99889:98888;;:::9<;;;;GGIFJHLLBCLFHI<CA==<===<<<<===<=><=<>>=<=~12 <====<<<=~7 <;<<==;<;:=:::;~4 <<:;:~4 8:9988977===<;<;hggjhrnotvnsiqvfhffeefjyxyhghxyxtyzxy|xtmpxxxefcccdecbcbccddgffbabccabadcccd|zz{~7 zz{{zz{wz|zzz{{zyyyzwywwwsttrrnzxwssssnllmmvqpR~13 QRRQRQRQRRPRQQQRQQrwnvxxruuolsjihivgebaa```gb```cdl```bbb`bi`^_`elfnahae`p^_^^_^skoressnajbga`b_e?>>>??>~5 ?>>=IMIK:;:~7 ;:~4 ;;;9~5 :999:9:~9 ;<~5 ;;;<;;:9:~13 9999888899998899889~4 ;~7 <;;<~4 ;;<<;~10 :~5 ;<<;;;:::;:::;~10 <<<<;;<;<<<<;;:;:9<=<;<~4 =<<<===9:9:889::;;<;<99=;98:<<===<<;<;;;;:<=:<~8 ;;;9~5 :99:;;;;:;99<~5 ;<;<;;<9988977778788865767::8998:89==<=<<=<==<==<==<=<~8 ;;<<<<:;:;;;;<<<;;;<;:::=~11 <===<~12 =<=<<<<=<=<~14 =<=<;<;<;~7 =~6 <<=;;=<<=<==;<<=;=~4 >=>><<===<<=~10 >=>>=~6 >=>>=;<<<=<<<====>>==>??@?>>>??>>?@?>><~5 >==>??>=>>>>?>?>::;~6 <;~10 <~8 ;<;~5 <<;<<<<;;<;~5 :::;::;~13 <;;<;;<==;::;<;::<~6 ;99998899889;;:;:;;<:;:;99;:;;9:;:;:;;<;<<;;;;<<;<;~4 88898899;;<<;~4 <<<<;<;<~5 =<<=<;<<<==<=<<==@>??;==<??<<<<>==>>>;;>>=<=<;<=><9;;:9:;;;;<~4 ;~5 ::::;;:::9::9898::::999;898878989;9:9988::87887878778888::::;:89::::9:<==<<<=<9::999:99::;::=<>>=>>><;>>><~4 :::;;<<;::::;<;;;:~5 ;::<;<=>==<<;<;:==<<;;<<<=~4 ;;<<;<<<;;:<=<==<;>=>>;;;==<==<>~5 ====>==<=~4 <=~4 <<<=<~5 ;=~10 <<=~6 <===>>>==>=~15 >~5 =?>===>==>>>=>>=>===>>>=~10 >:;~9 :;~4 ::;~5 <<<<=<;<<<<;<;<==;;<<<<;;>>>>?>>>><<<>=<=<<<;>>>=<>>:<>>=9::;;::;9=;<<;::;==9:::<;;::=::::>=>~4 8998999899:88787889999:9999:999:~12 ;~5 ::::;;::;:~5 ;<==<<=~5 <;~5 =<<<=~11 <;<<;;;]aa]_a_ba^eeakljlihkllkkkgffeed<<>>>=;<<;~4 <::Y!Z!Z_]ZYX^`db^!!ff[cccbbababcbcb_`bc[[Wdb^[]Z[]`dXW[eaYXVYehgdextsdccccnm{xystuw{wsf[XeXW_Wjk_XZmk7~4 :;::::88::9:999acb_`_`^^a_accba__]bca````a``ab``<=<@@@```_``_^_`]^^==<==5657989<6>:>:=443444756><<=D?>??>>>>???>>>??>~4 ==>=>=>>>===BBADCG====>=>?>>====>~18 EEDFEGGE~19 DDEDEDE>~8 5453552256;5986A:<;<<77767;::;99665569797;::7656<<;<:;=>====:9;9:66:967577888989766555656687677768978<;99;;<:;9::;~9 :787;;99;77;:977;;;<~8 ===<<==;;==>=>=>=>====<=<;==>=>=;;;<~5 ;<<;;<<<;;;<;~4 <<<;;;<;~13 <;;<<;:;9;9:::;<74;;22487;<;<<;<<;<;<~5 ;:;;::;~5 :;;9:::9~7 ::;999:9:;;998;;:99:9999778788789889::99898~10 778777688758877887675656777<~6 ===<=<~10 ===<~5 ;~4 :;::;:;;:9===<<<=~5 <~6 =<<=~7 <=<~5 ;<;;<~4 ==<=<====<<<::<<<;;<=<~6 :<;:9~6 <<<;;;<<;<<<;:;;::;;;;:::99;99888;;::9:<<;~8 <<;~9 :;;9~5 8887~4 677667678898:;;;:;~13 :<:?;:~5 ;9::;;;;<;;;999;9:::877887898978:~5 9::98:966677887777668777A@;<BF8~7 56679887~4 889877998998:::89~4 77;;;9:;97878~5 ;;;;99:999:999987::;>989:;::::9>?@@A9~17 <<<::;<::;<:9~6 =<<<;<<<;::;:;9<;;:9;:;:;;<<>==>><<<>===><QQQQRQQRRQPQQQP~8 ==>>==>=~7 @@@A@A@A@@@AA>>>>?@@?~4 @?>~8 ?=>>>=>?>???@@@?@???>?@DDDCDDDD?@?@CCCADDD@@???AA?@AAACABDDEEEDECAAA@@????C???GGGEFHHHFHEFGFFFGFHFHGHHHGG?~4 @@>~4 ?>??BBDB>??>~8 =>~4 ?===>>>>==>~5 AA??@>>@ABBA@@B?@?@??>A@?A?>>@@???A~5 >@?~4 @?>>@??@@@@?@@??@~5 A??@~4 >>?>~9 ==>@@@@>???>?@>?>>>====>=>=<=<~5 ===>>=>>==>>><<>;>=><<<;;==<=<<===<~5 ====;;;:::;;;::;<<;:=<;::;<;=~4 >=~8 ??@@===>>>@=@@@==?==A~4 BA][]XXZZVVXYVUUWUVVUZ[Z![]^_^^_^_^^_^^ZVTSRSTSSTSSSR<~8 ;;RROOQOKHHLJFRQOQOPOQFGGGFFGGHGFHFFFFHFHLKL8~13 77877878~6 <<;<;<;;;;8~4 <<;;<899::;;:::;:98888998;;<;:998:;?@@@>?>>??>>?>?>>?888?>>>8~6 =>>===9:;8:8~6 ;=:89;98~4 ?==<9;<<;98?@???>><>~4 =~4 <<;<>>>===<8888;;<;88989:::9<9:99:~4 ;:;:<:::;<:8:9::::8~6 >~6 =>>>887888877779899878778:7;99:::9998~4 77676~5 :;::;:::>~8 =~4 <<===<<<<;;<:~4 ;:;;99::9<=;:89889ONNPNQQPOPPQPQPOOIHHJJIPOPPLLLMNLKOHGHLFHEFL:~7 ;~6 :~5 9::9;<~6 ??@?~8 >?~32 >?~10 @@@?==<>;<;;<<<;>=;;;<=>=?E~11 D~4 ==<=<;::<;::;;<=;;;;:;;;<;<~9 =<<<<==<<<;<<<<;~4 <<;<~21 =<<=<;;<;<;;<;<<<<;<~9 ===<====<==<<;;<<;<====<~21 ;;;;<;<<<;~4 <;;<;;;===<<====<<<<==;<<;==<=<~13 ;~19 <~5 ;;;;=;;<~4 ==<<=;===<~8 ===<~4 =<~11 ;;<=;<~4 ====<<====<==<~6 =<<===>=<<=~5 >=~4 >>=>?>==>>??>??=>>>==>==?>@?>@>~11 =>==<<==<????@??>????@@@@>>????@???><~5 ;;<~5 ;;;;<;<<;<;~6 :~7 <<<<;:~10 ;:;<<;:~10 9~5 8~4 9989988:;<;:::HHIHIIIGFHIIIHIGFHGIFFF>?JI?>?JJJGG?>FFFH?>=OPOOOOKMMKJLNONKPPOPILIJ???>>?>????@>=~5 >@==@<A>=<~4 ===>>=>=?>=>><<=<>>>?>>A@A@CC?~4 @@@?@?ABC@>>?A@BACDEAAB~5 ADQQPRRPPOPMKKMNORPRRRIIJIHPQPPONMMLHKHHHHA@@A~4 ?AA=>>>=>@@@B@@@?@?BA@???@@>@@@>@>>===>>>=>>=~10 <<<<=~5 >=>??>@@@=>=>>?>>>?>>@@@@????@>=>??=>???@?~5 @=?==<<<@?>?>?@@<@@>>>??>???>?~7 >A@@@?~4 @??@~8 ?@@@??@?@?@@??>?~6 >?>@~9 ?@?@@?@?~5 >?~7 >~6 ?>?>????>>??>~4 =>>====>??>=~5 ????>~5 ?>>?=>>?~8 >>>??>AAA@?A@AAA@=@@>=><=~4 >?====<===>=>>;<;;<;=<<<=;;;=~14 ;;;<<;<;~6 :~5 ??>?>=@@@>==>=@===?@>>>=>=<<====>~5 @~4 ??>>@@>@>?~7 >>>?>??@@??@????@BB?@?>?>@B@~4 A@??>??@=~6 ;<~5 >>>>=<=<=;;<===<===<:;;;<;9;9;=<;=89:9:9;:;7776667755668568778888=<<;<;::999:9:;9:999;88788;<<;:~4 ;::;:98:~6 7877878:::;;;:::99:885799<:<<<;:;:===<=<=;;<;<<<<;~4 :~4 898~4 ::9:99:::89:9999899<===<<<;;<~5 ;;:<:9:<::9998998~5 98878778877<<<;<;99::;;;;::98~5 96~6 99777766887798978787688878~4 7878998888989:9:;88:9898877768778~6 78876677677767666868~4 9~6 ::99:9;9;;:::;;99:~5 ;:9::::99:;;;@~9 ?@?@A~8 @B~4 ABB?@@ABBAA>A@AAAA=~5 >>A=>AA===@@==><=~5 <<>>?>>=~4 ?@??>====>>?>>>@A????@A?><@??@AAA<BAB@?@AA@?;?<=B<BBBB<<<BABAAA@AAAAB@@>?=><<<<==>?@<<<<@?@<<<<>><~5 ;<<;~4 <~5 =<=;==<;=~4 <;::;:<~13 ?@~4 ?AA@;:;::<<<::<<;:;:~6 99@AA@~6 AA@~5 A@@@@A@@@B~4 ABDCAAABABBCBA@>>AAA@>@AAA<=<@99::999:::9:@~4 A@~5 AA>?>?CBBCABB@A@AABB:;;:::<<<;;:~4 ;;;<;=;<=~8 <>>>=>>===>>>=>>==>>>=>>????>>>>????>=>?<;<<<=;==;<;;<<<<;;;;=;;;:;:~4 ?>?<<<?~7 =>=<=>??<?==>>><>~4 A~7 BAAAA<<;;<<=;=BABA==AAA==BB=~4 AAA@A==BCBB:;;BBBCBB:::;BBBB;<;AA=<B<;=AA@@A@@???>=>A>>>>?>>?=<===>=?B@@@?AA>??@??@???>~7 ====@~5 ??>==@@=>@>>>=~10 >>>=>>=>=~37 >>=>??>~5 ?>?>>??>?>>=~4 >==>>>==>=~6 A~5 @A~6 @????@@?>?>>?=@@A??@@A=~5 >>?===>=>>===>~5 =>>=>~11 ==>==>~5 =>>=~7 >=>>=~15 <=~4 <=<===<<==<==<<<=~7 <=<=~15 <===<~5 =<<<=<<==<<=~8 <=<<<<=<<<<====<==>>=~6 <~8 =<<>>>=~4 <<<<=~5 ;<<;;;<;;;<~15 =<<<<;<;;=~6 <>>===<=~6 >~19 ==>>;~11 <~34 >~7 <=~4 <==<<<>>=<<====><<;==<=<;<=~29 >=~5 <<====>=<=<>=>=<~4 ;;<;<=~21 <=<<<<===<<<=<=<<<=~5 >===>>=~12 >=~7 <<>~22 =~17 <<=~11 <=<<==<====<===<<<<=<<=<====<=<<<<==LMLLLLKIJLLLJK=>=~6 >=~5 >>===IHKJGJHKLLLLM===>~7 KFJKJJHFJJ>=~10 <=<<=<==EFFFFHFHFIHFHE?DCA<===?<<=CDCC<=~6 FGGBD;;;;DGFE;<;;=H;=>>CH<=<~4 FHHIEIG=<==<~4 ==<=<>=~4 <<<<==>~8 ====>==<=~6 <=EE>===E@;<~5 ;~4 <<==<;<<<;;<<<==<=<==<=<==<<=<=<~6 ====<<=<====A?@@@C??=>?>?>=?<<==<=<===>>=~4 <=~4 >>?>>??<<<<=~4 <<=???>>???===<=<EEDEEDDDDEDEDDCD;~7 <<<<;;<;;;;::;;:;;::;;;::;~4 <;=FBFBHHHG=>=>>=<<<=IKID;<=GJJJ?A@CB?>>@?C@?><;<;<<<<====>;=<==>;;;>;~7 ====<=<=~6 <<<=<<<===<<>=~10 >=<====>=<<><~5 ;=<=<=~4 <<<;;;;<;~5 <<;9999:::9::;<<<=<<<;=<<<===<~5 >>=>~4 :::<:;:;:9~11 ;<<=:<;====:<=~9 <<=~6 >>=~5 >>>=::8:999;;;999;:;;<~7 =;;:::;;:<<:~4 ;~4 <~4 :<<<:::;::;<==>==<<>=>;=>>>==<<<<=<=<=<<<<=<~4 =<<<==<=~4 >DFFDEHEKJGKIIJIGILKKKMCKKKLJKKKII?AA><<?B=<=<ACD==<=<=KLKLKMJJ=~11 >=>~4 =>>=>~6 ==>==>==>>==>>>=~4 >~4 =~4 <==<=<=<=~4 <<<<==<=<<=;<;;=~18 >==>=~10 >>=~10 >=~4 <=<==<====<<<;;;;<;=;9~10 ::::;;9999::9;~8 :9::;;:<=999899:;:::;::;<<;=;<<<;:~8 ;~4 ::;9:999:98889:;;;;::;;:;8787788997~4 99::9877888968867776788898899989997798887;<;~7 <;;<<<===<<==<<===<<=<<=~4 <===<<<==<<<===<===>=~8 :<9<;<:<<<<==<;;;;::899:;9998~4 JGGLD>F9;=>?@46<@E>>=F>===>=~4 ::<<;<;<<=>>>>=>>>=<==;=>>=CC;6@8=6DA7:98798;98?~5 @CAJDG@CLD?8?::?55<6@A6675@95553434558C9C;74755566665~7 DQ77:9NNOFM::9:99<?~9 >~4 =~4 ????>???>>=>====HLKJ=~5 AB<<<=<<<=<<====<===<====<==;;<;=:;;;:<<=<==<<=<;<<GEEEGDDED<=<<==>==<=>>==<~5 =<<=~5 <==CF>FCF<=<<=<~8 =<<<>>=<==<<?<<<<=<<<@?B@??@??@?@~4 =~4 <<<==<~6 =<~6 ===<~6 :;;;<~5 ;;<;;<==::::<~4 ;;<~5 ;;<<;~4 <;;<;~7 <<;~10 :;:;;;;:~4 ;:;<;;<;~9 :;~4 A>?;;;;@?;~7 ?>??@<;<;~4 <;~8 <;;;<;;<~4 ;<;<;~10 <;;<;~26 <;~5 <~4 ;~4 <~5 ==<==<<<<=<=<<<==;<~4 =<<<<;;<<;;=~4 <~4 =<~20 ===<====<=~7 <<<;;<<;;==;~4 <<<<===<~4 =;~10 <<<;<~10 =<<<=<==;<;<;;<<;;<;~11 <;:::;<<;;<<<==<;<=:;=<:<;<~4 ;;=<~4 ==<<<=>>=<<=<=<~6 ====<<<<===;;:;<<;;;:;:<:::<;:=>=~8 <=<=~7 <===<==<<<=<<==<>==<<<>>>=~8 >=<<>=>==>>=>=>>>>=~10 >>;<<;<;;==>=~7 >=<<;<=<;~6 >~13 ====<<====<=~12 <=~26 >>?>?>===<===>??>=>>>=~5 >>>>=>==EEEDEDDDC~5 DDCCCDCCDDDDCDCD~7 EBAABBABA~4 BA~12 @?@@A@AA?@AAAA@AA@?@A?@>?>>???@@?A@?@??>?>>?>>>??>~6 b~26 acaabcbbaaabbbabbbbaA~7 @A@A~6 WWWWVWXVWYXXWWXWWTUWUXWXWY@A@@@@AA@AABAAA?A??@A~5 @@@AXXXYXWZYhhgih[]!]eefcdeefcdca`dde`bcT[T^^XZUWZXZ[Y[Xcdd^]_ZYWWZmlkffmmhjeWVWW!!]bb`UUTUWZTTVV[^!]ZZ!Zcc`ccdddffihi[!jllkikkjkic`b_Zj9==:?<<@<?:<::;::<::?>~6 =>~5 <=<<=>=>><<==>>>=<???>==<>~5 ???>>>>???9:99=<====;;<==<:999==<99:;8<=<=;::;=>;:>>>???>=<<><=>?<<=?>;>~10 =>~10 =>====<<=>==<<<=<<<<;<;~6 >====;:;====<<<;~5 <<;:<;===>>=>====>~4 =~6 >====>?~5 >>=???==?~10 =>~5 ?>~10 ??>A??A?>>?>?~5 ==>=>~5 =>>>=;~6 <<;<~5 =>?~4 A@@@?@????@@?@A~4 BA@SSU?BBWSVZPPP?BEKXQPNNONNPQP>ONNNJOMMMJKQQPN~4 B>@@>>>=~4 >C==?PQ>=F>====HDLC?>=>>>>???@B@=@<<<==<<=<<==<===>>====<?>>><~8 >>>>@==??<==???>==<<<=<<====<>>>=????=<<<?>>=~11 <~4 ;<=;===<<;:::;~9 ::;:;<=<=<<<;<>>>>=<==>;<=;<=>?:~6 ;~11 <;<~4 =;~5 =<=<;<;;;<~6 ;:;<~9 ;<~8 ;<~9 :;::;:;;::::;:<<;;:~5 ;;9:;<<===<<<==<<<;;;:::;<;9;:;::=~5 <=~6 :::====>>====chbh_``bcmnmnhlnl]]]]b]^!]]bklhklkglll=~6 >>>==?>???>==bb_fg[^[T]mmgpmlm]mngbebdcfebaaVTVTSYTUX!!Y!W]VV!`[YYTXa^_aVU_ZZZgfefeebRUQURUWWUT^baWUUU]bdcTTY]WVVVbbbaddecdeecdcd@=<A?=<=<=<=>><<<;;:;;<<<;;;:;;;<=<~5 ===<<===<===>>>=~8 ;<~5 =<=<~4 =<~5 =<==<<<<=>=>=<=<==<~6 ;<~16 JJLJHKLLLLKLMMLLKLLKHKNNNPOLI>?>????;<<>>?===;~7 <~14 ===<~16 ;?>??>~5 ???>>>><~4 =~8 <>~4 ?>><==>===<=<<<==>>>?==<=>>=<<?>???<~4 ???>?>?>>A@A@???@~4 ;=<<<==>>?=;>=<?;<;;=;;BA@>=AABBAA<<<A87666989::;:8;<;:;:9:KGIIEFGLGHKNKJ>3HL1BE<6CO47657999:;;5699986897:660116575224<;;:~6 ;;<;~5 :::;:;<~6 ;;;<<;;;<<<;<;;<;;;<<<<;~4 :;::<;~5 <;;;<<;;=<=<<===:;=;:;:::;::=;::>><===>>>==>>>?>??A?>?AAA>?>A>>>?>?AAA;;:;HFEG[!YWZ!XWUYUWVWUYXWWVWUY!XWWWWRRRSSQSRSS^~8 99:~17 ;::;::9:9786658666;596857996<8<7989~4 :97899778876997=~13 :~10 ;:;~13 :;;::99;:::778;8~4 788:;8989~9 89:78~4 586885:5698;6677888766588>>>><<<;==<;><;<=><;=~4 <;<;<=;;<=>>===<<<<=<<<<;<~20 ===<~28 ;~8 <;;;9:9898999::999:~5 9~4 :9:::;<;<<;<<<<;;;<<;;<;<<;<<=<=<<=~5 <<<<=<===<==<<<<=<~8 ;;;:;::;:;:;::;:;;;<<;:;~5 <;<<;<<=<<;;;<~15 ;<<<;;<;<;<;=<<<;;<<<:<:;:<<;<<nopllkjkhikjlmlprrpppqnqoorppmkknnmghjhhjfffgh~4 ileefddeh~4 ei:~9 srsrptmrptqqpowwtejflllhmunlffdhfjsvvrlrkknmnvvlehfdckgfmmdljfjmllkmqpqlmkmussutturihjffigfgffikleffefjkefedccdddcghflpelmkjkngkbbccbcbcbbccbbbbcifdcjffe77888878:9:;97:<;858768949~7 59999859795=~4 <<==<=~8 E~16 DDEDE~11 99:98868:7;;<;<<;~9 <;<=<<;;;;<888799989;~4 ::;~8 :::;:;;;;:;:~4 <;~4 ::;;:;::;;:;:<<<;<<;;<<<;<<<;<<<<=<<==<<<;~9 <<;<;;;<;;=:::9999<;;9;<<<=<<;<<::;9;;;999<==<;;;;=;<;;;<;;<~6 =<<<=<~4 ==<;=;;:;;::9;~4 :<9:=;<;;:;;9;;<<<<====<<<;;=;;===;~10 <<<;;;=<~11 ;<<==<~6 =~7 <~6 ;<<;;<~16 ;;<<<;<<<:;<:<<===<;;;<~4 ;<;~9 <<<=<<<==;<==;<=<=<<=<<==<==<==<=~9 <=~7 <====>><=<<=<=~8 <=>>>=~4 >=~4 >====>===????=<<=>>=><===>=><==<====;==;<==>~5 ?>~9 ?>;<~4 ;;;;<;;;<;;;<<====<=<<<=<~11 =<<<<=<<<;;;;<;;<;;;:;~7 <~6 ;<<==;<<<>==::;;;:==;;;;>>=;=<==<<=;:::;~7 :;~7 <:<;;<;;;<~5 ===<<;;;<~5 ;;;<;<>???@@@?@@@@?AA??>@<~5 >>>>=<<=><<<<=>?=>=><~5 :::;;;::<;~7 <<<<;;;:;;;;<~6 ;::;<;<;;<<<;;;;<<<<;~4 <<<<==<<<;:<;=<<<>>?@>??A@AA@?>??==<<?>??=???<=<=~4 <=<;<~4 =><<<=<<<<====>?>>=~34 >>>>=>>>=>>===>>>==>>>==>=~4 <<==<;==<=~7 ;~4 >~5 ====>>==>=>=>~10 ===>==>>=>~11 ==>~5 =>~7 =>>==>~4 =>==>=>=~8 >~4 =A?A@@@???>?=@A@@?@@>>>?@?>=>>?==>?><>=~4 >=~5 >===<<<=~8 <<===>~8 =>==>~4 ?>>?>~6 =~4 >>>=>??A@@AABAB@@@?>>CABBA@B?BB??B~4 =<==<<<===<=<=<~8 ;<;;;<;;<<<=>=>>>==<><=<<=~7 <=~12 <=~6 A@AAB?B^h]gfBf^_fbXXZ!YXZYYBBkkjj!C?@????efhnnkmkmlnlkllk??>^d]VZ[WVX_eXZ[kjkUYVTTTRQcddddecccddddcd`cacc^^VWaaVTWacca!ccbbU!VVTTUTYYXUWWXbXWecRc`TUVUafj_XVkiffdblXnmoUTTUh`befmXompoek]k<=>=ebcbceecdbbbfabhhhghfhgddA~4 DDFEEDDCCDDDDCCDDDEDE~4 DDhfececfcbdbbchgfd<<<<==<<<==<E~4 FE~11 DEEEDDDE~6 ::;:~4 99989989:979::9:988;<<>;B?;>>:<:;>>=>>>>=>>=~12 ><=>>====<==<;;====<~6 ;;<;<;;;<<<;;;<;~5 @<AAEEADDAAA<C::99:8998:<999889~4 :9;:;;==:9:8:9<<<<=<<:::<<<=:~5 ;:;<;::;;;:99;;<;;9999<:9;:::9:~5 9~4 ;:;<<<:;:;;<;99:999::9:9999:~5 999:;~10 9:9;;;=<<==<~8 =<=<;<<<<;<~4 ;<<<;<<:;;:;::<;~6 <<;;<<;~10 <<;;;;<<;~21 =><;?;~6 >;?;;<<<;<::<<<<;<<<;;;<<;:<~9 ;;;<;;<;~4 <;;;;898;:;;<<<<;:;;9898:::;9;9;;;::;99::;;;::;;9:;<<;;;;:~5 ;:~4 ;::;:::;::;;:::9:~6 99:;:~9 ;;;;<~12 ===<<<=:;9:9::;::;:9;;;999;<;<~8 ===;;;<<<<=<~5 ==<<=<~5 =<~9 =<;<;<<::;<;~5 :;<<<<:;;:9999;::9:;;:~9 ;::;;:~5 ;:~4 9:::;;<;;;::;~7 :;;;:;;:~6 <<<<;~4 <;;<;;;;<~4 ;;;:9;~4 :::99;<<;<<;<;:~5 ;::::>>;;?;:~7 <;~5 :;;;;:;~9 :~9 ;;;;:::;::;:::;~4 ::;;<<<:;~4 :;~15 <;;;;<<<<;<;<;~4 :;:~4 9:9999F<?:;=;<9999:::C=99::BECDB:;~5 <<<;;;::;~5 <<;:<;;;9:::;;;;<~4 ==;<>><<=<;;<~5 ==>====<<=<=<=~5 <<<::;:;;>??@C=~5 ;~4 :;:;;:;;;==<;<;<;~5 <<<<;;<;;<~4 ;;<<;;<~4 D~8 CDEDDEDDDC~4 DCCDDDDCDD67657776676669~13 4633300-..10/31.769955566715157599555342:0812.:;;-,12,;;;;<;;-6,;;9;<=>=>::>><=>;:<>><<<>~6 ==>.0-9~10 :9::9999::99:~5 ;;:::17/73:9~5 <<:<<99;:;;9::9<<<;;;::<~10 =<=>>=>=<==<==<;<;::;<;:<::;:<<9:98;99<98<9;<9<9:9~4 :99:9:9~4 :<<<<=<<====<=~8 <<<=~4 <<=<==<=<<<;;<;;;;<<<;:;:<<;;;<;<::<~4 ;==<<=9::98999:999::;9=~8 99::;:;998:999;<===;:<<;=;::<<===<=~4 <<<<::;:99:99:::99;;;:::98899;:;::9999:;<998~4 9999877988778799977:98979:;;;::::;;;;<:;;=<<;;<<<<=<<==<=<=<=~5 <=<>==;<;;<;<<999::::<:::;:;<<<9999:;:;;::<:<99<:<>?~4 >?=~7 >>>>?=~5 >?A~13 @AA@A@~6 AA@~5 A~5 @AAA@A~7 @AAA?>?>><=?===>><<<>>>====<=<==<~6 ===<;<<;<=>=><>>><<=<<;=<><<>;:;:;:;;;:;=~8 <<==<<=<<<=<==<<<<=<<<==<~12 =~12 <~13 =<<<<=<<====<=~4 <<<<=<<=<<<<==<<<=<=<~10 =<<==>=>===>=>>=<?<=?~4 =~4 <==<~9 =<=~8 ><=>><<==>>=>=>>>?>>==>?>>>====>>===>>=>>=~11 <<<=<<==<<====>>>=>==>~9 ===<===<==>=~10 >==>???>>@?>?>@A@~4 AA@@AAA??@?>>>A>~6 =<>=>>>>==>>=>A~10 BA@A@AABBACCABCC?~5 >~4 ?>>>?>>?>=~6 <===<===>===<<=?>~6 ?>=~5 >=>=~9 >=>~4 =>~4 =>>=~9 <<<<;;;<:77788788:;889889;:9789777=><;<>>=>==>===>><<<;<;<777;:7~6 12:;;85+..98889:87988872/*0..7~5 17~9 337789899978,.))(672655===34<<<9<22<4=2-==>===<6===>=>>>>=~5 ;<<;<<;<<;;<;;:;::;;;:<<=~4 <=99:9<9:;8~5 9999:8;:;;;<:::;<;:676~8 7~12 879888978777787778777789<<<;;<=<;?>?AAB>>?~4 BD>>>?>?==>?=>>==>=?==<<>;<;:;~4 :;~5 :~6 9:9:;;:~14 ;;;:::;;9<;<=<<;<;;;;<;;<;<;;<=<==<=;~7 <~4 =<;;;<;<<;;;<=9~7 88898:987:88988877788798899464767~4 676654778777755644445664556~7 44546~9 767~4 6~8 766676666877787888778787888878787~5 8~4 999899888998:~11 9989:::9:::9:9:9:~6 9:~5 ;;:;;:;::;;:;~6 :::<;<<<;:~9 ;;:;;;:~4 9778~4 :::88::9899:9::9::9:9777789899989766678877877588887547777556676645778~4 77778~9 98888989~5 7787777886566756678668545556666455676776889899998~5 798~5 99::::97~4 8889~4 ::88998888778779898999:;~6 ::;9::99;~7 ::;;;:;:::;~7 A@A~4 @~5 AAA@AA@A~6 @@AA@ABBA@A@@@A@~4 AA@A@@@>~18 BBBCCBBBCBBAAABBBADDDEDB@~4 BB@BAA@BBBB@@@AA@@CC@@@?~6 @~7 ??>~4 =>=>~8 @>~18 ????>>?>~20 ?>????>@~6 >>>?=>==@???>?>=~4 >>=~4 >>===>>==>=~17 @ABBBA@B~32 ?BA@??AB>B~4 >===>>?>?=?~4 >??>??B~9 @?@??@A~4 BA?A@B@???@@ABBBB????@@BBBA?~9 >?>?>~4 ????>==>=<=<=~4 >><~4 ===>~8 ==>>>?>?>>=>===>??>>===>==<=~6 <=?~8 >?AB?@@AA???A????@@?@?@@?@?@@A@@A@@@@????@BB@B???@@??@@?~11 @@?~4 @@?@???@?~11 >@=?~8 @@@@?~13 @@?@@>?~5 >?>?<<<<>===<<<>=>=<=>>>>==<=>~8 ??>??>?@@?~4 >???@????@??@@@@A@~5 ?~4 @????@??@???@????@?>?>?@??>>????>>?~7 >>>=>=>~16 ?>~9 ?>~9 =>>===>~7 =>~7 @?@?~4 >>>?==<<=<<<>==<<<???>>>===<=>>>=><<<<;==<;=<=>;?~6 >~5 ?>~12 =>=>>>>==>>>==>=~4 <~11 >~15 <==><==<~15 =<~19 >>>=<=>>>=~4 <=~5 >>>>=>>=>====<<<====<~14 =<<<==<~5 ===<=<=>~7 =<<==>>=>>==>====<===<~8 ;<<;~7 ?~12 <~14 =<==>>??<<<<>=><~4 =~4 <?>~4 =>>>===>><~9 ;=<;;;<<;;;<=<=<<;?~9 >=~5 >=>>><<<>=<<<==<<=>???>???>?~11 ===;<;<<=<~5 ;<<;;===<~5 ;;;<~7 ;<<<=;;;<<<;;<;<;<=;;;;<;<;;;TQRRSSRRSPS==<<==<<==KNONNOOOQOPSS=~5 >>>==???>?>????>>?>SPRRQRSQNNQR===<>=>=KKLKLKKLKLLMOLQMMKFJGPNQONOHEHKMOLFEEEIEI>=>==>><==<<<==<<<<==<<<=<<;<<<;LKLJLMLNPPNPKPPNOQNIJNKPKMMJMKJO??>~5 ????>>?~5 @???@?@@>=>===>>====POPPNOOOOPOONMLNMMMNM?M?~6 >~5 ?>?>==?=>>>=>===>>=>??>??>=~14 >===>=<<===<=<=<<<<=~6 <=<<<===<~5 =<<=~5 <=<==<<<<=<~5 ;<~4 ;<<==<=<;~4 ONMNOQOOOFGIHJ>=HJ>~9 =~17 >=>=>=>>===>=@??@AGDEHC?@?@>>>>DH>>>FA?NFNGILMMMMKJIIL?>IHLL?MO>KO?>===>=~5 <=~5 <==<===<<<<===<====<==<~9 =<<<<;<~6 >?>??@@??=>?>=@@@?<<<=<~5 ;<<;<<;;:::;<<;;<::<<:9<;<<===;;;<>;:<<;;;;::;::<==;<<=~6 ?~5 :~8 ;;:~16 ;~4 :===>;=~4 >>>??@?@@??@@A@A;=~4 <~6 =<>?<?<<<?=?<=<=<<<=>AB<<B=<<?~6 >BBBB<B@>>BB<<<>><~5 ;@AAAA<<<<@A>>A<<@>@>ABBBAA<~4 =;<=<?@@@<@~7 A~10 @@@A;~10 :;~5 :;=>==DFCF=>=;<<<<;==<<=<===>A;<>;<=A====<;::999;;::;;::;<;<;<=<?LNDQO??FO>PVI>PJG@K@===?>==IPQFUSVVTYJDVVU>~6 @>>?>??@>==AB???=?>>??@?<<;;::;@@><?::::<;:::@>??>?@?@@@@?@@A@ZXQ[QQOMMKJJQMNLMMLKJKHIIJILIMNJMMONOPPPPNKOPMMNLNMNOMMKKHLMNMPPOOMLKJONPONMNMNLNONNMNOPPPPOJMMPOOONGDFMN=<<===GHF>JFE>>=<<<=<<=OOOQONOPPO=<<=<=<<<<=<<<=~5 >=>>===>~6 ==>>>=>>>==>=>>==>>=>>>>==>=<~8 ===<<<<=<<<<;<<;<===<<>==<<<<=<=~5 <=<=<<<====<<;;;;=~5 <<<;=;<>=>=<<=<<;;;;<~10 ;;<~8 ;~5 <~6 ;<;<<<;::9;;;9:9:;;:9;;;<<;;9<<<;<~14 ;~6 :;;;;:::<<<;;;;<:;<;~8 <;<;~6 <~10 ;~7 :;~6 :;~4 <;~4 <~5 ;<<<==<=~5 <==<;;;<<;<~4 ==>>=;<???;~16 ECCFGGF@@@?FFEFG~6 BC@@?@DA>?>=MMMKLORTSRRRRQRSRSPONMPMPOLMLNQPOOQOTORSNNNOSQORQQQRQSPOONOPOPQNOMNMLMLOMKMKLKKK>~4 ?>>>?>>=~5 >=>=>=>=~7 :;:~6 ;;:::>~4 ===<===<;=<<==<====>>>=~23 >~4 <<=<==<===@>?>=@A=<=>??CACACCC=~4 >=>=<=~7 <=<~5 ;<;;<<<:;;<<<;<;=C??A===<D@BD<====>=~4 >>?=<=;<=>==;;<;:;OMQQNPPPQQONNNOOONMQPQOLJKKNM?@?>>>@?===>=???>=?==?~4 >>>>==>==>~5 ==>=<====><=?@=@<<>><<?;;;:;;;;::PNPOPPNOMKKLONRRQNRSRMLLMMLLMNNP???@@????@~4 ??PPQPNOPOMP@???>=>=?@?>>=><=~6 ><~7 ;~7 <<<<;;<<;;@?>??@>@=?@=?>@@@@<~8 ;<<;<;:;:9~5 :;;88:;:;<<<;;;;<;:;~4 :;:;;<<<;<;~15 <<;;;<<;<;;;;<;;;:~7 9:~9 99989:9~4 :::99::::8:::;:99:8<;;;<:;:::;;;;<;;;<<<;;::;;::;::;;;;:;~5 ::;;<;<<;~6 :;~5 <;;<<<;<<<<;;;;<<;~7 <;:;~7 :9;;;:;;;;<=<<<==<=~9 <<=<===<<<<==;<==<~6 ;<;;=<;;=~6 ;;<~18 =<=<<<=~5 ;====<=~4 <;;;<<<<==<;;<<=;;<;<;<~5 =~5 <=<~4 ==<=~6 <~11 ;<~16 ><<<=~4 <=~4 :::=@?<<::@?@>@?@=<:>::@::<;:@<;<;<<;:<=~5 <=<<=<<;<:;<<===<=~5 <;===<~6 ==<<<==<>?==>=<<<=<=~12 <<<;<<;;<<;;;;<~4 ==;;:::=<<<<=~11 <=~9 <=~5 >=~4 >??<=<@?=?=>?=~4 <<=;;=~7 <===;<;====;;;===<:;;;;<<=;==<;;;<<::;:?;;@=~6 >=:~4 <:;===<~5 =<<<<=<<;=<<?>??@@@B?>?==>>=<<><<><~6 :;:<==<~6 =<~7 ====>><<@>????>=<<<==<=<?>><>===><===<<<<><?:9::999;:;98989~7 898998999BBBAAAABABBBA~4 B~6 AAABA@B?@@ABBAABAA@@?~4 BBA?>??>===>~7 @??>>>?@@????>==>!~5 [![!~11 [!!!B~4 ABAB~5 AB~16 A~8 B~11 AAAAB~5 !_]_[^[^[X][Xhiihiihhhg~4 hhfeehfegdehmnfiX^Yab[]XWXXttr!ZXY[YZ[Z!Yxvvxzvyqsuvnhp![[[!![[]Z!_!!c_chkXWWZZX[jo!ZX^`_`^iij[^[e~4 aedfhfhfjlkjkikadf?>>?=>>>>??>?=>~7 ?~10 >?>=>====>>====?=~4 >~11 @~9 ?~10 ====>?>=>><<>>>=<<?>??>>===><<=<?>>?>===>>?~9 >?>??>>>??>>>>?>>?~4 @@???>=>==>>????>???>?>~7 ??>>>>?~9 >>?==?==>=>==>>===>>>=~18 <==<~4 ==?>~4 =>>>>=?>>>>=~14 >=>????>>>>?>=~5 >=~5 <<<<=<=~11 <=<<=<=?==>~6 ==>===>>=>~4 =>=~4 >>=>?>~6 ===>=>~7 =~4 <=~6 <<=~9 >>>=~4 >>=>>==>===>>>=~24 <=~24 >>==>==>=>==>~13 =>>><===<<====>>===<<=<<=~4 >~4 =~5 >??>=>>>=>>==<=<===<===<=>>>>===>=>====<~16 =<=<=~7 <<=<<<<=<=<=<~6 =<<<?~4 >~4 =>><<<<=~4 >><=djbioojc`rmru`^~6 aa_!!ecdffcuuwxwyxwxvvr]lr?=>>=>~4 ?>???==>~4 choio]^!Y`cb^ruvwwwxwyxXZ[][!WWYWXZYY[!`[bedhi!lnlmlllhhYWWY!!XXpgegglkZXabkeaeedffceYXa!]YY>~4 ?>?>?~4 =~7 >>>=>>>>=~6 >===>>>=~7 >>>=~4 >====<===>>>?>??>??>~7 ?>>><;<:89>>>=>=>::9:9;9<<=<=~4 <~6 ====<<====68576:8687787;;85:ED~4 @@BBB@AEECCABD>?A>@A@AA@~5 A@~8 AAA@~5 A@@A~6 @A:;;;:::;:;;:<~10 >===?~7 >=<<;<;;:~9 ;<<<<@???<<=>=<;;<;<===>===<>=~4 ?@?@>>>=~4 >=?@@????AA@===@<===?@@@?~5 @?~5 @~7 >???@??@?>>>??>>>>=>=@>>>>??>?<~11 ;<;<<>=~8 >=>=<====>=>====>>><<<>>=~8 <~4 =~6 >==?>@?===>=<=>@==@@@<<>=>><<>===?<=?=<=<=99:9~18 :9999:~24 ;:::;:::<<=<;;<;;;:;;<:9~4 ;::;:~8 ;;;::::;~7 99::=~4 <;<<=<<<=<<>==<<<;<=;<==:::;<;=<<===;<:<~5 ;<;<<<<==>???=>>=>>>====>====>~7 ====>>><=<>>?>>???>~4 ===>==>~7 99:999:::9<<:<<;<;:::<~12 ::;::;;;<;<~5 ::;;==<==<<<===<<==<>=~6 <~6 .10,54+.--+48731/0::;,0---*-/-+-//./0/0-0/0.32561-,,,,-165?=@@?9=BA,,,,<<=~5 >==@??CAACCAC===>>>D?=?>?@>=>)+*,++*'*'(&('&&#$#*+:~7 ;:~6 9~4 79<;::9;887777;~4 77867:9~4 888879~6 :::9999::9999:::9:~6 999:~12 ;~6 ====<<<=<*))&%-,++'(($$%#&%*##&#,-.---,,===;<<=<=<<<<;;:;<==<<<;=~5 ;;;:;;=<<=~5 >==<=~12 <====;<====<====<=>===>===;:<::::;;<;<<==;=~4 9:8=<<<:;<<;===<;<<=<~5 77778898698;;:;;::9:::9:;;<:<;~5 98999::::<;;::;;:;<;;<;<;<;;;;<;~5 =~13 <<=~5 <===<<<<;===<=~9 >==>=~10 8987889899887*+*777,,+---.-0,-.-,,-,((*'(&*-#(%(+(0178736546678777#1449~4 :;:;;:::30./2460/664567567665676464-455;~6 9999:::999:9~6 :~6 8:::7887788779997878::9~6 ::;;:;~5 ::;::;;9;;;;:;::;~4 ::8:9:98987878:;~5 8778<::=~4 <=<<8779;>B?B<8878896787>;=;9>=?;95Arpnnmpsqrrrnmmfghfdgfihlfkihkijfldea~4 bb`^_``a`a``_a`a`agggebbdbab9899998897~8 rrpstrtwwuuwuoonooppqporquuvvsurssvotswtklhoolggpmmmheeflkoqvwwmhhkfhirsieipddhe_`]]_]_]bc]!!]!``^_]]!]!]!!d]^]c`]^]^]]]!!]eqqgghdfahfa__gjhfaplmmii_]^ghlhfg_afdeh]^^]]!]!]]h]^]!~7 97978887::8;?><<.(,//1-'.CAA??@===::A7@7<;;;==<;<<;<~10 >>>><><=>=<=<==>==>~4 =>~6 =;==;=;=<>::;;<<;:;<;;;<;<;;::;;<<;;<;<<;<<<<::::9:;<:;;;====;;>=>~7 =<<<=;<==<<===<?=<=<<=;<<;=<;;<;;;;<=<;:::;;:;;:;<;:;:;;:~4 >=<<<>>>?>>@?~7 <=?>>=~6 <===A~5 >=>=?@<<<<?=>?><~4 >>>>?>>>>@AA?A@??>>=>~4 ===>===>>=~5 >~8 ?>?>>?>>?>??>?@?@??@??>=>>>===>>?>>>>?>?==>>==>AAA@@=~4 <===>=~9 >=~5 ;<;<;;<;<;<=<===;;;=>>>>?@@@==??>>@>=>=>=~6 >>A@@ABB?>?>?@A>===>>>=>?>;=<~4 ;<==;<;;<<;<;<<=<=<==>=>>>???>?A==>>===>~4 ==>~7 ?>??>?>~4 ??>>>>=>=>>>>?>?>>>>=>>=>==><=<>>>>=>====>==>=>>>==>?==>==>~10 <~4 ===<<;<;~13 ==<;<;<;<~8 =<:;;:::;;<;<<<<;<;~10 <<<<;<<<<:~8 ;;:;;;:;;<:;<88889988987888:~7 9:~6 88:;:;9;<<:9:;;:878::78::87~5 @??@A???AAAA?A;;;<=<====;;@@@A;@@@==>~4 @==<<=;?A>>@?@;<=;>=>=::;~8 <<;<<==;;<=:::;::9:::88::9::;:;::;988:~8 777899978:::9888787789~4 8988?@@A@AA=~7 @ABAAAA@AAA??@BB==>====>=~13 >?>@>??AAA>>==>?~4 BB?B====;:;;:::9:::;:=~12 <~8 ====<~10 ===<<<<>=~7 ;=<<<<=;==<<;==>===;=<<====<><==>><>>=>~4 ==<<>=>><==>=><<>~6 =>>>====>==>>===>>>>==>=><~10 ==<<===<<<====>===>>>=~6 >==>>??=>=?===>==>=><=<==<<==<<<<=<=<==<>>@?@@?@?@@@???>~5 =>=>~13 =>=>>>=>~5 CBB@@>@?@>>?>~11 =~4 ::;9:::===:<<<:;;>=~6 <=<<===;<=<=<====<<====<<==AAAA@caadc_ae]^^`outuqtwpv!]!!``![!ilcllc>~4 yxwxuyyywyywy>>a`XYZ[Y^_]_]a^c[[Ydbdca```acbb^`__Y[W!]fffed]!]!!XZfe][^[![Z[!!!![[[!aZcXXXZffeec`hcYXce`eednqmmfeYYkienoilkYWWYW!!bdqrmlZfj777a_^`_^]]]]^!]![!!!]_!]^``]]]^A~4 BBA]!]~4 ::99;;:89;<;<;<;9::]!!]]!!!!?D?@??:;;::;<9;9:;~5 :;;:>>=>=~7 >>>====>===<===???>>===A>>>>=>=~13 >~7 ==>=<=?><<<=<<<==>??<?==<<?@@=??<=<<==<<=~7 <~4 ;<<<==<<==<<=<<====<~12 =<~10 =<<;<~6 >=<==>===<~11 =<~11 =<~4 ==<=<~4 ===<~5 =<~5 =<=~7 <=<<=<~6 =~6 <===<~5 ;~5 <<;~5 <;;:::;;;::;:;::;:;::;~4 :;:~5 ;;<;<~4 =~8 <===<>=>==>=>><<;<===<=<==<=????>AA@AAA@A??>>??=>>?A:A:A:~8 <=;<;;;:;;A;::B:BBA::::???=<<>?>===<<<<==;<=<====>>>;;:<;;>==<=<;~5 ?@A???@@@ABA??=>=>@@B?>>>>==>?>==>==>>=><<>=>;;<=::;;:~4 ;~9 <<=<;~9 <;<<<;~4 <~4 ;<<;<;~12 ::;~9 <~8 ===::;;;<:<~4 ;<~4 ;;:;:::9;:~4 9::9998:9988;~10 9;;;:;;;;::;;;;:;;;:;;:9::;::8=~5 <~4 =<=<<<===<~5 ===<~6 ;<====<====<<<<=~9 >=<~4 ==<<=~5 <====;<<==<;<~5 ==<==<?@?>>===??==@~5 ?@?;=<~5 ==<<==;<<<==>=>=~4 >===>===>>>=>?=?>~4 ===>>>>====<~4 ===<<;<>>?=~5 ??==?=<<;;;;::899:889:~4 ;<;<;<;:;;;;RRSRSTSQQSSTSSPQQQRQPPRTRBCDBDBDDFCDBDBBD??@DCCC==-1<=CD1484:0<?A?C-BD;===:../0=<~14 =<>==>>=<====<=<==<~6 ==>><@>?@DD<?@B?DBD~4 EEGEGDDED?=DHGFDEEFEGHHHGGGFHHHEH<3<<<72>~4 =>>>>====>~4 ====>~5 ====>><=>~5 <<====1052==>=~7 >~6 @A@@@?@@?A??>A@AAA@>>>>?>>@~4 ??>@???@@@??@~5 ??@>~13 =>>===>~5 ?>>?>==>>>>?>~6 ?>>=~4 >=>=~8 ??>>>==???==>~9 ?>=~4 >>>??>><<=<<<>=>>=~4 <~8 ====>==<====><>>>>==>>=>=><=<~8 ?>?>>=>=>=>~16 ?~9 ===>>>>=>====<<=<>===<<<=<=????>~16 ?>>>D~4 CD>~9 D~8 B@A@A??CD?>?>>>?>>DDCD??A???>??>?~4 >>>>?>???>~11 =>~14 ?~12 >>=>?=?==>>==>>?>>>EDEDDD>~6 ===>>=>>>>====<<<<==<<<<==DCDFEDGFGDFGCEBAC?@@CB@??@??@?>>>???A??<=<===<<===<~5 =<~5 =<<>~7 A~10 B~11 AAB~9 AAA@AAA@?@@@?BA~5 BBBCCBB?>>@?>~10 ??><<==<<;:;::;<;;:;;;:;;:~5 ;=:;<~9 ====<=;<<<<=<<=<~7 ;~20 <~9 ;<~16 =<<<==<~11 ;<~19 ===<<=<<<<=<==<<=<=<<=<=<<==<<<=<~10 =~18 <=<=~4 <===<=<<<==<~11 =>>=;:;==>==>>=~6 >>?>>>???>~4 ?>?>?>=?~5 =>???>>??<<<=>><=<>=><~4 =<=~6 <~4 =<<=;;==>>>>=~4 >>????>?>=>~6 <<=~8 >==>>==?>@~4 A>??>@?>?@BB>>??AA@AB@@A@??>?@@===>=~4 >~4 =~6 <<<<=~6 BBCCBCCB~4 A~6 @ABAA@AAA@A@@@@>~5 ?>>????>????>?>>>??>=><=>?;;;<<=<=>>??;<==<<<<=<~14 ;<;<<<;;<<;;;;<;;<~4 ;~4 ?>><<=>=G~15 C~4 DECBDDBEEDDCDCCCBBBBCBBDCC@@@BB@@?>?>@??=>=?>?>@?@=?<?>?<<??<;<?>>?=:>=>>====>===87;A9;>>;<~6 >>==<===:~5 @:~7 @@A::::<=~25 >>;<=;:~4 ??>??=>=:<??=::=@=;=<;<<;;<~8 ::<=~6 <@?>==<>>>?@?>=~4 ;=;<<<;<;;;<<<??@~8 A@?@~19 =~5 <><==>=@>>><=>~11 =<=>>AAA@><<<<A@ABB;;<<;<?@=@@@<<???=??>=??>??>??@@=>~4 ?>BBB<=;;;;B;@>=>~4 ==>>=~12 ;=<====<:;<;<::<<==>~5 :~5 <;<;;;;<>>>I>><;<==>;;<;;<<=>==><<<:~4 ;99:99:<;<;<;~11 <;<<<;<;;:;;;<<<::<???<<==><<<==><@???@>=<~6 @@<<<<@>>==<>=>==<~25 >~10 <<=<<>=>>>=~5 <=>===<==>~5 ====<<<<=~4 <~5 =<=<===<=<=<=<;~9 =>>==><<=;;;=>;<<??=>=>?=><<<<;=887788878~4 7~4 88777999:99889988989899998999::99:~6 ;;::;::;<<<;~7 <;::::9998878898:9:87778787778<<<<;<;<;;:;;;:;;:;;;:~4 99::::8::99::999::899897899:788:9:9<~7 ;<<<;<:;<~6 ;;;:::9999;:;8:9<<==<===<<<=<<=~4 <==<<<<=<=<<<;;<<===<<<<===;<;=<;;:;;;;:;<::;89::8:::8:::8787:::79:9:99989:9:;:;;;:;;<;;;;<~7 ;<99;;:"> 647 * </jvxlColorData> 648 * </jvxlSurfaceData> 649 * 650 * 651 **********************************************************/ 652 appendXmlVertexOnlyData(SB sb, JvxlData jvxlData, MeshData meshData, boolean escapeXml)653 private static void appendXmlVertexOnlyData(SB sb, 654 JvxlData jvxlData, MeshData meshData, boolean escapeXml) { 655 int[] vertexIdNew = new int[meshData.vc]; 656 if (appendXmlTriangleData(sb, meshData.pis, 657 meshData.pc, meshData.bsSlabDisplay, 658 vertexIdNew, escapeXml)) 659 appendXmlVertexData(sb, jvxlData, vertexIdNew, 660 meshData.vs, meshData.vvs, meshData.vc, 661 meshData.polygonColorData, meshData.pc, 662 meshData.bsSlabDisplay, 663 jvxlData.vertexColors, 664 jvxlData.jvxlColorData.length() > 0, escapeXml); 665 } 666 667 /** 668 * encode triangle data -- [ia ib ic] [ia ib ic] [ia ib ic] ... 669 * algorithm written by Bob Hanson, 11/2008. The principle is that 670 * not all vertices may be represented -- we only need the 671 * used vertices here. Capitalizing on the fact that triangle sets 672 * tend to have common edges and similar numbers for sequential triangles. 673 * 674 * a) Renumbering vertices as they appear in the triangle set 675 * 676 * [2456 2457 2458] [2456 2459 2458] 677 * 678 * becomes 679 * 680 * [ 1 2 3] [ 1 4 3] 681 * 682 * b) This allows efficient encoding of differences, not absolute numbers. 683 * 684 * 0 1 2 -2 3 -1 685 * 686 * c) Which can then be represented often using a single ASCII character. 687 * I chose \ to be 0, and replace that with !. 688 * 689 * ASCII: 690 * -30 -20 -10 0 +10 +20 +30 691 * <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{| 692 * 693 * So the above sequence would simply be: 694 * 695 * !]^Z_[ 696 * 697 * When the range falls outside of +/-32, we simply use a number. 698 * When a positive number follows another number, we add a "+" to it. 699 * 700 * !]^Z_[-33+250]230-210]] 701 * 702 * Preliminary trials indicated that on average a triangle 703 * can be encoded in about 7 bytes, or roughly half the 12 bytes 704 * necessary for standard binary encoding of integers. The advantage 705 * here is that we have an ASCII-readable file and no little-/big-endian issue. 706 * 707 * @param sb 708 * @param triangles 709 * @param nData 710 * @param bsSlabDisplay 711 * @param vertexIdNew 712 * @param escapeXml 713 * @return (triangles are present) 714 */ appendXmlTriangleData(SB sb, int[][] triangles, int nData, BS bsSlabDisplay, int[] vertexIdNew, boolean escapeXml)715 private static boolean appendXmlTriangleData(SB sb, int[][] triangles, int nData, 716 BS bsSlabDisplay, 717 int[] vertexIdNew, boolean escapeXml) { 718 SB list1 = new SB(); 719 SB list2 = new SB(); 720 int ilast = 1; 721 int p = 0; 722 int inew = 0; 723 boolean addPlus = false; 724 int nTri = 0; 725 726 // note that the slabbing present becomes irreversible if there is no ghosting. 727 boolean removeSlabbed = (bsSlabDisplay != null); 728 729 for (int i = 0; i < nData;) { 730 if (triangles[i] == null || (removeSlabbed && !bsSlabDisplay.get(i))) { 731 i++; 732 continue; 733 } 734 int idata = triangles[i][p]; 735 if (vertexIdNew[idata] > 0) { 736 idata = vertexIdNew[idata]; 737 } else { 738 idata = vertexIdNew[idata] = ++inew; 739 } 740 int diff = idata - ilast; 741 ilast = idata; 742 if (diff == 0) { 743 list1.appendC('!'); 744 addPlus = false; 745 } else if (diff > 32) { 746 if (addPlus) 747 list1.appendC('+'); 748 list1.appendI(diff); 749 addPlus = true; 750 } else if (diff < -32) { 751 list1.appendI(diff); 752 addPlus = true; 753 } else { 754 list1.appendC((char) ('\\' + diff)); 755 addPlus = false; 756 } 757 if (++p % 3 == 0) { 758 list2.appendI(triangles[i][3]); 759 p = 0; 760 i++; 761 nTri++; 762 } 763 } 764 if (list1.length() == 0) 765 return true; 766 XmlUtil.appendTagObj(sb, "jvxlTriangleData", new String[] { 767 "count", "" + nTri, 768 "encoding", "jvxltdiff", 769 "data" , jvxlCompressString(list1.toString(), escapeXml), 770 }, null); 771 XmlUtil.appendTagObj(sb, "jvxlTriangleEdgeData", new String[] { // Jmol 12.1.50 772 "count", "" + nTri, 773 "encoding", "jvxlsc", 774 "data" , jvxlCompressString(list2.toString(), escapeXml) }, null); 775 return true; 776 } 777 778 /** 779 * encode the vertex data. This must be done AFTER encoding the triangles, 780 * because the triangles redefine the order of vertices. 781 * 782 * Bob Hanson 11/2008 783 * 784 * If another program has created the triangles, we probably do not know the 785 * grid that was used for Marching Cubes, or quite possibly no grid was used. 786 * In that case, we just save the vertex/triangle/value data in a compact 787 * form. 788 * 789 * For the we use an extension of the way edge points are encoded. We simply 790 * identify the minimum and maximum x, y, and z coordinates and then express 791 * the point as a fraction along each of those directions. Thus, the x, y, and 792 * z coordinate are within the interval [0,1]. 793 * 794 * We opt for the two-byte double-precision JVXL character compression. This 795 * allows a 1 part in 8100 resolution, which is plenty for these purposes. 796 * 797 * The tag will indicate the minimum and maximum values: 798 * 799 * <jvxlVertexData count="150" min="(15.218472, -28.304049, 34.71112)" 800 * max="(97.8228, 54.011948, 109.95208)" data="...."> </jvxlVertexData> 801 * 802 * The resultant string is really two strings of length nData where the first 803 * string lists the "high" part of the positions, and the second string lists 804 * the "low" part of the positions. 805 * 806 * @param sb 807 * @param jvxlData 808 * @param vertexIdNew 809 * @param vertices 810 * @param vertexValues 811 * @param vertexCount 812 * @param polygonColorData 813 * @param polygonCount 814 * @param bsSlabDisplay 815 * @param vertexColors 816 * @param addColorData 817 * @param escapeXml 818 */ appendXmlVertexData(SB sb, JvxlData jvxlData, int[] vertexIdNew, T3[] vertices, float[] vertexValues, int vertexCount, String polygonColorData, int polygonCount, BS bsSlabDisplay, int[] vertexColors, boolean addColorData, boolean escapeXml)819 private static void appendXmlVertexData(SB sb, JvxlData jvxlData, 820 int[] vertexIdNew, T3[] vertices, 821 float[] vertexValues, 822 int vertexCount, 823 String polygonColorData, 824 int polygonCount, BS bsSlabDisplay, 825 int[] vertexColors, 826 boolean addColorData, 827 boolean escapeXml) { 828 int colorFractionBase = jvxlData.colorFractionBase; 829 int colorFractionRange = jvxlData.colorFractionRange; 830 T3 p; 831 P3 min = jvxlData.boundingBox[0]; 832 P3 max = jvxlData.boundingBox[1]; 833 SB list1 = new SB(); 834 SB list2 = new SB(); 835 int[] vertexIdOld = null; 836 boolean removeSlabbed = (bsSlabDisplay != null); 837 if (polygonCount > 0) { 838 if (removeSlabbed) 839 polygonCount = bsSlabDisplay.cardinality(); 840 removeSlabbed = false; 841 vertexIdOld = new int[vertexCount]; 842 for (int i = 0; i < vertexCount; i++) 843 if (vertexIdNew[i] > 0) // not all vertices may be in triangle -- that's OK 844 vertexIdOld[vertexIdNew[i] - 1] = i; 845 } 846 int n = 0; 847 for (int i = 0; i < vertexCount; i++) 848 if (!removeSlabbed || bsSlabDisplay.get(i)) { 849 n++; 850 p = vertices[(polygonCount == 0 ? i : vertexIdOld[i])]; 851 jvxlAppendCharacter2(p.x, min.x, max.x, colorFractionBase, 852 colorFractionRange, list1, list2); 853 jvxlAppendCharacter2(p.y, min.y, max.y, colorFractionBase, 854 colorFractionRange, list1, list2); 855 jvxlAppendCharacter2(p.z, min.z, max.z, colorFractionBase, 856 colorFractionRange, list1, list2); 857 } 858 list1.appendSB(list2); 859 XmlUtil.appendTagObj(sb, "jvxlVertexData", new String[] { "count", "" + n, 860 "min", Escape.eP(min), "max", Escape.eP(max), "encoding", "base90xyz2", 861 "data", jvxlCompressString(list1.toString(), escapeXml), }, null); 862 if (polygonColorData != null) 863 XmlUtil.appendTagObj(sb, "jvxlPolygonColorData", new String[] { 864 "encoding", "jvxlnc", "count", "" + polygonCount }, "\n" 865 + polygonColorData); 866 if (!addColorData) 867 return; 868 869 // now add the color data, again as a double-precision value. 870 871 list1 = new SB(); 872 list2 = new SB(); 873 if (vertexColors == null) { 874 for (int i = 0; i < vertexCount; i++) 875 if (!removeSlabbed || bsSlabDisplay.get(i)) { 876 float value = vertexValues[polygonCount == 0 ? i : vertexIdOld[i]]; 877 jvxlAppendCharacter2(value, jvxlData.mappedDataMin, 878 jvxlData.mappedDataMax, colorFractionBase, colorFractionRange, 879 list1, list2); 880 } 881 } else { 882 int lastColor = 0; 883 list1.appendI(n).append(" "); 884 for (int i = 0; i < vertexCount; i++) 885 if (!removeSlabbed || bsSlabDisplay.get(i)) { 886 int c = vertexColors[polygonCount == 0 ? i : vertexIdOld[i]]; 887 if (c == lastColor) 888 c = 0; 889 else 890 lastColor = c; 891 list1.appendI(c); 892 list1.append(" "); 893 } 894 } 895 appendXmlColorData(sb, list1.appendSB(list2).append("\n") 896 .toString(), (vertexColors == null), true, jvxlData.valueMappedToRed, 897 jvxlData.valueMappedToBlue); 898 } 899 900 ////////// character - fraction encoding and decoding 901 902 // NEVER change the numbers for these next defaults 903 904 final public static int defaultEdgeFractionBase = 35; //#$%....... 905 final public static int defaultEdgeFractionRange = 90; 906 final public static int defaultColorFractionBase = 35; 907 final public static int defaultColorFractionRange = 90; 908 909 /* character-encoding of factions in base 90: 910 * 911 * characters ASC(35) - ASC(124) are used for this encoding with the 912 * exception of ASC(92)'\\', which is encoded as ASC(33)'!'. 913 * ASC(125)'}' is reserved for "NaN". 914 * Double-quote is not in this range, but '<' and '>' are, so this 915 * is only XML-safe when quoted as an attribute. 916 * 917 */ jvxlFractionAsCharacter(float fraction)918 public static char jvxlFractionAsCharacter(float fraction) { 919 return jvxlFractionAsCharacterRange(fraction, defaultEdgeFractionBase, defaultEdgeFractionRange); 920 } 921 jvxlFractionAsCharacterRange(float fraction, int base, int range)922 public static char jvxlFractionAsCharacterRange(float fraction, int base, int range) { 923 if (fraction > 0.9999f) 924 fraction = 0.9999f; 925 else if (Float.isNaN(fraction)) 926 fraction = 1.0001f; 927 int ich = (int) Math.floor(fraction * range + base); 928 if (ich < base) 929 return (char) base; 930 if (ich == 92) 931 return '!'; // \ --> ! 932 //if (logCompression) 933 //Logger.info("fac: " + fraction + " --> " + ich + " " + (char) ich); 934 return (char) ich; 935 } 936 jvxlAppendCharacter2(float value, float min, float max, int base, int range, SB list1, SB list2)937 private static void jvxlAppendCharacter2(float value, float min, float max, 938 int base, int range, 939 SB list1, 940 SB list2) { 941 float fraction = (min == max ? value : (value - min) / (max - min)); 942 char ch1 = jvxlFractionAsCharacterRange(fraction, base, range); 943 list1.appendC(ch1); 944 fraction -= jvxlFractionFromCharacter(ch1, base, range, 0); 945 list2.appendC(jvxlFractionAsCharacterRange(fraction * range, base, range)); 946 } 947 jvxlFractionFromCharacter(int ich, int base, int range, float fracOffset)948 public static float jvxlFractionFromCharacter(int ich, int base, int range, 949 float fracOffset) { 950 if (ich == base + range) 951 return Float.NaN; 952 if (ich < base) 953 ich = 92; // ! --> \ 954 float fraction = (ich - base + fracOffset) / range; 955 if (fraction < 0f) 956 return 0f; 957 if (fraction > 1f) 958 return 0.999999f; 959 //System.out.println("ffc: " + fraction + " <-- " + ich + " " + (char) 960 // ich); 961 return fraction; 962 } 963 jvxlFractionFromCharacter2(int ich1, int ich2, int base, int range)964 public static float jvxlFractionFromCharacter2(int ich1, int ich2, int base, 965 int range) { 966 float fraction = jvxlFractionFromCharacter(ich1, base, range, 0); 967 float remains = jvxlFractionFromCharacter(ich2, base, range, 0.5f); 968 return fraction + remains / range; 969 } 970 jvxlValueAsCharacter(float value, float min, float max, int base, int range)971 public static char jvxlValueAsCharacter(float value, float min, float max, int base, 972 int range) { 973 float fraction = (min == max ? value : (value - min) / (max - min)); 974 return jvxlFractionAsCharacterRange(fraction, base, range); 975 } 976 jvxlValueFromCharacter2(int ich, int ich2, float min, float max, int base, int range)977 protected static float jvxlValueFromCharacter2(int ich, int ich2, float min, 978 float max, int base, int range) { 979 float fraction = jvxlFractionFromCharacter2(ich, ich2, base, range); 980 return (max == min ? fraction : min + fraction * (max - min)); 981 } 982 983 // /// differential bitset encoding and decoding (Bob Hanson hansonr@stolaf.edu for Jmol) 984 jvxlEncodeBitSet0(BS bs, int nPoints, SB sb)985 public static int jvxlEncodeBitSet0(BS bs, int nPoints, SB sb) { 986 // nunset nset nunset ... 987 // for repeated numbers: 988 // 3 3 3 3 3 3 3 becomes 3 -6 989 int dataCount = 0; 990 int prevCount = -1; 991 int nPrev = 0; 992 if (nPoints < 0) 993 nPoints = bs.length(); 994 int n = 0; 995 boolean isset = false; 996 int lastPoint = nPoints - 1; 997 998 for (int i = 0; i < nPoints; ++i) { 999 if (isset == bs.get(i)) { 1000 dataCount++; 1001 } else { 1002 if (dataCount == prevCount && i != lastPoint) { 1003 nPrev++; 1004 } else { 1005 if (nPrev > 0) { 1006 sb.appendC(' ').appendI(-nPrev); 1007 nPrev = 0; 1008 n++; 1009 } 1010 sb.appendC(' ').appendI(dataCount); 1011 n++; 1012 prevCount = dataCount; 1013 } 1014 dataCount = 1; 1015 isset = !isset; 1016 } 1017 } 1018 sb.appendC(' ').appendI(dataCount).appendC('\n'); 1019 return n; 1020 } 1021 jvxlEncodeBitSet(BS bs)1022 public static String jvxlEncodeBitSet(BS bs) { 1023 SB sb = new SB(); 1024 jvxlEncodeBitSetBuffer(bs, -1, sb); 1025 return sb.toString(); 1026 } 1027 jvxlEncodeBitSetBuffer(BS bs, int nPoints, SB sb)1028 public static int jvxlEncodeBitSetBuffer(BS bs, int nPoints, SB sb) { 1029 //System.out.println("jvxlcoder " + Escape.escape(bs)); 1030 int dataCount = 0; 1031 int n = 0; 1032 boolean isset = false; 1033 if (nPoints < 0) 1034 nPoints = bs.length(); 1035 if (nPoints == 0) 1036 return 0; 1037 sb.append("-"); 1038 for (int i = 0; i < nPoints; ++i) { 1039 if (isset == bs.get(i)) { 1040 dataCount++; 1041 } else { 1042 jvxlAppendEncodedNumber(sb, dataCount, defaultEdgeFractionBase, defaultEdgeFractionRange); 1043 n++; 1044 dataCount = 1; 1045 isset = !isset; 1046 } 1047 } 1048 jvxlAppendEncodedNumber(sb, dataCount, defaultEdgeFractionBase, defaultEdgeFractionRange); 1049 sb.appendC('\n'); 1050 return n; 1051 } 1052 jvxlAppendEncodedNumber(SB sb, int n, int base, int range)1053 public static void jvxlAppendEncodedNumber(SB sb, int n, int base, int range) { 1054 boolean isInRange = (n < range); 1055 if (n == 0) 1056 sb.appendC((char) base); 1057 else if (!isInRange) 1058 sb.appendC((char)(base + range)); 1059 while (n > 0) { 1060 int n1 = n / range; 1061 int x = base + n - n1 * range; 1062 if (x == 92) 1063 x = 33; // \ --> ! 1064 sb.appendC((char) x); 1065 n = n1; 1066 } 1067 if (!isInRange) 1068 sb.append(" "); 1069 } 1070 jvxlDecodeBitSetRange(String data, int base, int range)1071 public static BS jvxlDecodeBitSetRange(String data, int base, int range) { 1072 BS bs = new BS(); 1073 int dataCount = 0; 1074 int ptr = 0; 1075 boolean isset = false; 1076 int[] next = new int[1]; 1077 while ((dataCount = jvxlParseEncodedInt(data, base, range, next)) != Integer.MIN_VALUE) { 1078 if (isset) 1079 bs.setBits(ptr, ptr + dataCount); 1080 ptr += dataCount; 1081 isset = !isset; 1082 } 1083 return bs; 1084 } 1085 jvxlParseEncodedInt(String str, int offset, int base, int[] next)1086 public static int jvxlParseEncodedInt(String str, int offset, int base, int[] next) { 1087 boolean digitSeen = false; 1088 int value = 0; 1089 int ich = next[0]; 1090 int ichMax = str.length(); 1091 if (ich < 0) 1092 return Integer.MIN_VALUE; 1093 while (ich < ichMax && PT.isWhitespace(str.charAt(ich))) 1094 ++ich; 1095 if (ich >= ichMax) 1096 return Integer.MIN_VALUE; 1097 int factor = 1; 1098 boolean isLong = (str.charAt(ich) == (offset + base)); 1099 if (isLong) 1100 ich++; 1101 while (ich < ichMax && !PT.isWhitespace(str.charAt(ich))) { 1102 int i = str.charAt(ich); 1103 if (i < offset) 1104 i = 92; // ! --> \ 1105 value += (i - offset) * factor; 1106 digitSeen = true; 1107 ++ich; 1108 if (!isLong) 1109 break; 1110 factor *= base; 1111 } 1112 if (!digitSeen) 1113 value = Integer.MIN_VALUE; 1114 next[0] = ich; 1115 return value; 1116 } 1117 jvxlDecodeBitSet(String data)1118 public static BS jvxlDecodeBitSet(String data) { 1119 if (data.startsWith("-")) 1120 return jvxlDecodeBitSetRange(jvxlDecompressString(data.substring(1)), defaultEdgeFractionBase, defaultEdgeFractionRange); 1121 // nunset nset nunset ... 1122 BS bs = new BS(); 1123 int dataCount = 0; 1124 int lastCount = 0; 1125 int nPrev = 0; 1126 int ptr = 0; 1127 boolean isset = false; 1128 int[] next = new int[1]; 1129 while (true) { 1130 dataCount = (nPrev++ < 0 ? dataCount : PT.parseIntNext(data, next)); 1131 if (dataCount == Integer.MIN_VALUE) 1132 break; 1133 if (dataCount < 0) { 1134 nPrev = dataCount; 1135 dataCount = lastCount; 1136 continue; 1137 } 1138 if (isset) 1139 bs.setBits(ptr, ptr + dataCount); 1140 ptr += dataCount; 1141 lastCount = dataCount; 1142 isset = !isset; 1143 } 1144 return bs; 1145 } 1146 1147 /////// string data compression/decompression 1148 jvxlCompressString(String data, boolean escapeXml)1149 public static String jvxlCompressString(String data, boolean escapeXml) { 1150 1151 1152 /* just a simple compression, but allows 2000-6000:1 CUBE:JVXL for planes! 1153 * 1154 * "X~nnn " means "nnn copies of character X" 1155 * 1156 * ########## becomes "#~10 " 1157 * 1158 * ~ is not encoded, as it is ASC(126), outside the range of 33--125. 1159 * 1160 * for escaping XML, we also do: 1161 * 1162 * < becomes "~;0 " 1163 * & becomes "~%0 " 1164 * 1165 * and repeats of those become: 1166 * 1167 * "~;nnn " 1168 * "~%nnn " 1169 * 1170 */ 1171 if (data.indexOf("~") >= 0) 1172 return data; 1173 SB dataOut = new SB(); 1174 char chLast = '\0'; 1175 boolean escaped = false; 1176 boolean lastEscaped = false; 1177 int nLast = 0; 1178 int n = data.length(); 1179 for (int i = 0; i <= n; i++) { 1180 char ch = (i == n ? '\0' : data.charAt(i)); 1181 switch (ch) { 1182 case '\n': 1183 case '\r': 1184 continue; 1185 case '&': 1186 case '<': 1187 escaped = escapeXml; 1188 break; 1189 default: 1190 escaped = false; 1191 } 1192 if (ch == chLast) { 1193 ++nLast; 1194 ch = '\0'; 1195 } else if (nLast > 0 || lastEscaped) { 1196 if (nLast < 4 && !lastEscaped || chLast == ' ' 1197 || chLast == '\t') { 1198 while (--nLast >= 0) 1199 dataOut.appendC(chLast); 1200 } else { 1201 if (lastEscaped) 1202 lastEscaped = false; 1203 else 1204 dataOut.appendC('~'); 1205 dataOut.appendI(nLast); 1206 dataOut.appendC(' '); 1207 } 1208 nLast = 0; 1209 } 1210 if (ch != '\0') { 1211 if (escaped) { 1212 lastEscaped = true; 1213 escaped = false; 1214 dataOut.appendC('~'); 1215 chLast = ch; 1216 --ch; 1217 } else { 1218 chLast = ch; 1219 } 1220 dataOut.appendC(ch); 1221 } 1222 } 1223 1224 return dataOut.toString(); 1225 } 1226 jvxlDecompressString(String data)1227 public static String jvxlDecompressString(String data) { 1228 if (data.indexOf("~") < 0) 1229 return data; 1230 SB dataOut = new SB(); 1231 char chLast = '\0'; 1232 int[] next = new int[1]; 1233 for (int i = 0; i < data.length(); i++) { 1234 char ch = data.charAt(i); 1235 if (ch == '~') { 1236 next[0] = ++i; 1237 switch (ch = data.charAt(i)) { 1238 case ';': 1239 case '%': 1240 next[0]++; 1241 dataOut.appendC(chLast = ++ch); 1242 //$FALL-THROUGH$ 1243 case '1': 1244 case '2': 1245 case '3': 1246 case '4': 1247 case '5': 1248 case '6': 1249 case '7': 1250 case '8': 1251 case '9': 1252 int nChar = PT.parseIntNext(data, next); 1253 for (int c = 0; c < nChar; c++) 1254 dataOut.appendC(chLast); 1255 i = next[0]; 1256 continue; 1257 case '~': 1258 --i; 1259 break; 1260 default: 1261 Logger.error("Error uncompressing string " + data.substring(0, i) + "?"); 1262 } 1263 } 1264 dataOut.appendC(ch); 1265 chLast = ch; 1266 } 1267 return dataOut.toString(); 1268 } 1269 1270 // VERSION 1 methods -- deprecated but still available through Jmol 11.9.18 1271 jvxlCreateHeaderWithoutTitleOrAtoms(VolumeData v, SB bs)1272 public static void jvxlCreateHeaderWithoutTitleOrAtoms(VolumeData v, SB bs) { 1273 jvxlCreateHeader(v, bs); 1274 } 1275 1276 /** 1277 * Creates a two-line header for the XJVXL file. It is no longer necessary 1278 * to create the atom set or generate the vectors here. Please leave the 1279 * commented code for posterity. 1280 * 1281 * @param v 1282 * @param sb 1283 */ jvxlCreateHeader(VolumeData v, SB sb)1284 public static void jvxlCreateHeader(VolumeData v, SB sb) { 1285 // if the StringXBuilder comes in non-empty, it should have two lines 1286 // that do not start with # already present. 1287 v.setVolumetricXml(); 1288 if (sb.length() == 0) 1289 sb.append("Line 1\nLine 2\n"); 1290 /* no longer necessary 1291 sb.append(nAtoms == Integer.MIN_VALUE ? "+2" 1292 : nAtoms == Integer.MAX_VALUE ? "-2" : "" + (-nAtoms)) 1293 .append(' ') 1294 .append(v.volumetricOrigin.x).append(' ') 1295 .append(v.volumetricOrigin.y).append(' ') 1296 .append(v.volumetricOrigin.z).append(" ANGSTROMS\n"); 1297 for (int i = 0; i < 3; i++) 1298 sb.append(v.voxelCounts[i]).append(' ') 1299 .append(v.volumetricVectors[i].x).append(' ') 1300 .append(v.volumetricVectors[i].y).append(' ') 1301 .append(v.volumetricVectors[i].z).append('\n'); 1302 if (nAtoms != Integer.MAX_VALUE && nAtoms != Integer.MIN_VALUE) { 1303 nAtoms = Math.abs(nAtoms); 1304 for (int i = 0, n = 0; i < nAtoms; i++) 1305 sb.append((n = Math.abs(atomNo[i])) + " " + n + ".0 " 1306 + atomXyz[i].x + " " + atomXyz[i].y + " " + atomXyz[i].z + "\n"); 1307 return; 1308 } 1309 Point3f pt = Point3f.new3(v.volumetricOrigin); 1310 sb.append("1 1.0 ").append(pt.x).append(' ').append(pt.y).append(' ') 1311 .append(pt.z).append(" //BOGUS H ATOM ADDED FOR JVXL FORMAT\n"); 1312 for (int i = 0; i < 3; i++) 1313 pt.scaleAdd(v.voxelCounts[i] - 1, v.volumetricVectors[i], pt); 1314 sb.append("2 2.0 ").append(pt.x).append(' ').append(pt.y).append(' ') 1315 .append(pt.z).append(" //BOGUS He ATOM ADDED FOR JVXL FORMAT\n"); 1316 */ 1317 } 1318 1319 /* 1320 private static String jvxlGetFileVersion1(JvxlData jvxlData, 1321 MeshData meshData, String[] title, 1322 String msg, boolean includeHeader, 1323 int nSurfaces, String state, 1324 String comment) { 1325 // pre-XML 1326 if ("TRAILERONLY".equals(msg)) 1327 return ""; 1328 StringXBuilder data = new StringXBuilder(); 1329 if (includeHeader) { 1330 String s = jvxlData.jvxlFileHeader 1331 + (nSurfaces > 0 ? -nSurfaces : -1) +" " + jvxlData.edgeFractionBase + " " 1332 + jvxlData.edgeFractionRange + " " + jvxlData.colorFractionBase + " " 1333 + jvxlData.colorFractionRange + " Jmol voxel format version " + JVXL_VERSION1 + "\n"; 1334 if (s.indexOf("#JVXL") != 0) 1335 data.append("#JVXL").append(jvxlData.isXLowToHigh ? "+" : "").append( 1336 " VERSION ").append(JVXL_VERSION1).append("\n"); 1337 data.append(s); 1338 } 1339 if ("HEADERONLY".equals(msg)) 1340 return data.toString(); 1341 data.append("# ").append(msg).append('\n'); 1342 if (title != null) 1343 for (int i = 0; i < title.length; i++) 1344 data.append("# ").append(title[i]).append('\n'); 1345 state = (state == null ? "" : " rendering:" + state); 1346 String definitionLine = jvxlGetDefinitionLineVersion1(jvxlData); 1347 data.append(definitionLine).append(state).append('\n'); 1348 StringXBuilder sb = new StringXBuilder(); 1349 String colorData = (jvxlData.jvxlColorData == null ? "" : jvxlData.jvxlColorData); 1350 // if (jvxlData.vertexDataOnly) { // see XML version 1351 // sb.append("<jvxlSurfaceData>\n"); 1352 // jvxlAppendMeshXml(sb, jvxlData, meshData, false); 1353 // sb.append("</jvxlSurfaceData>\n"); 1354 //} else 1355 if (jvxlData.jvxlPlane == null) { 1356 if (jvxlData.jvxlEdgeData == null) 1357 return ""; 1358 //no real point in compressing this unless it's a sign-based coloring 1359 sb.append(jvxlData.jvxlSurfaceData); 1360 sb.append(jvxlCompressString(jvxlData.jvxlEdgeData, false)).append('\n').append( 1361 jvxlCompressString(colorData, false)).append('\n'); 1362 } else if (colorData != null) { 1363 sb.append(jvxlCompressString(colorData, false)).append('\n'); 1364 } 1365 int len = sb.length(); 1366 data.append(sb); 1367 if (includeHeader) { 1368 if (msg != null && !jvxlData.vertexDataOnly) 1369 data.append("#-------end of jvxl file data-------\n"); 1370 data.append(jvxlGetInfo(jvxlData, false)).append('\n'); 1371 jvxlAppendCommandState(data, comment, state, false); 1372 if (includeHeader) 1373 XmlUtil.appendTag(data, "jvxlFileTitle", null, null, jvxlData.jvxlFileTitle, false, true); 1374 } 1375 return jvxlSetCompressionRatio(data, jvxlData, len); 1376 } 1377 1378 private static String jvxlGetDefinitionLineVersion1(JvxlData jvxlData) { 1379 String definitionLine = 1380 //(jvxlData.vContours == null ? "" : "#+contourlines\n")+ 1381 jvxlData.cutoff + " "; 1382 1383 // optional comment line for compatibility with earlier Jmol versions: 1384 // #+contourlines (no longer used -- see XML version) 1385 // cutoff nInts (+/-)bytesEdgeData (+/-)bytesColorData 1386 // param1 param2 param3 1387 // | | | 1388 // when | | > 0 ==> jvxlDataIsColorMapped 1389 // when | | == -1 ==> not color mapped 1390 // when | | < -1 ==> jvxlDataIsPrecisionColor 1391 // when == -1 && == -1 ==> noncontoured plane 1392 // when == -1 && == -2 ==> contourable plane 1393 // when < -1* && > 0 ==> contourable functionXY 1394 // when > 0 && < 0 ==> jvxlDataisBicolorMap 1395 1396 // nInts saved as -1 - nInts 1397 1398 if (jvxlData.jvxlSurfaceData == null) 1399 return ""; 1400 int nSurfaceInts = jvxlData.nSurfaceInts;// jvxlData.jvxlSurfaceData.length(); 1401 int bytesUncompressedEdgeData = (jvxlData.vertexDataOnly ? 0 1402 : jvxlData.jvxlEdgeData.length() - 1); 1403 int nColorData = (jvxlData.jvxlColorData == null ? -1 : (jvxlData.jvxlColorData.length() - 1)); 1404 if (jvxlData.jvxlPlane == null) { 1405 if (jvxlData.isContoured) { 1406 definitionLine += (-1 - nSurfaceInts) + " " + bytesUncompressedEdgeData; 1407 } else if (jvxlData.isBicolorMap) { 1408 definitionLine += (nSurfaceInts) + " " + (-bytesUncompressedEdgeData); 1409 } else { 1410 definitionLine += nSurfaceInts + " " + bytesUncompressedEdgeData; 1411 } 1412 definitionLine += " " 1413 + (jvxlData.isJvxlPrecisionColor && nColorData != -1 ? -nColorData 1414 : nColorData); 1415 } else { 1416 String s = " " + jvxlData.jvxlPlane.x + " " + jvxlData.jvxlPlane.y + " " 1417 + jvxlData.jvxlPlane.z + " " + jvxlData.jvxlPlane.w; 1418 definitionLine += (jvxlData.isContoured ? "-1 -2 " + (-nColorData) 1419 : "-1 -1 " + nColorData) 1420 + s; 1421 } 1422 if (jvxlData.isContoured) { 1423 if (jvxlData.contourValues == null || jvxlData.contourColixes == null) { 1424 definitionLine += " " + jvxlData.nContours; 1425 } else { 1426 definitionLine += " " + Escape.escapeArray(jvxlData.contourValues) 1427 + " \"" + jvxlData.contourColors + "\""; 1428 } 1429 } 1430 // ... mappedDataMin mappedDataMax valueMappedToRed valueMappedToBlue ... 1431 float min = (jvxlData.mappedDataMin == Float.MAX_VALUE ? 0f 1432 : jvxlData.mappedDataMin); 1433 definitionLine += " " + min + " " + jvxlData.mappedDataMax + " " 1434 + jvxlData.valueMappedToRed + " " + jvxlData.valueMappedToBlue; 1435 if (jvxlData.insideOut) { 1436 definitionLine += " insideOut"; 1437 } 1438 return definitionLine; 1439 } 1440 1441 */ 1442 1443 } 1444