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 Public 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 25 /* 26 27 * The JVXL file format 28 * -------------------- 29 * 30 * as of 3/29/07 this code is COMPLETELY untested. It was hacked out of the 31 * Jmol code, so there is probably more here than is needed. 32 * 33 * 34 * 35 * see http://www.stolaf.edu/academics/chemapps/jmol/docs/misc/JVXL-format.pdf 36 * 37 * The JVXL (Jmol VoXeL) format is a file format specifically designed 38 * to encode an isosurface or planar slice through a set of 3D scalar values 39 * in lieu of a that set. A JVXL file can contain coordinates, and in fact 40 * it must contain at least one coordinate, but additional coordinates are 41 * optional. The file can contain any finite number of encoded surfaces. 42 * However, the compression of 300-500:1 is based on the reduction of the 43 * data to a SINGLE surface. 44 * 45 * 46 * The original Marching Cubes code was written by Miguel Howard in 2005. 47 * The classes Parser, ArrayUtil, and TextFormat are condensed versions 48 * of the classes found in org.jmol.util. 49 * 50 * All code relating to JVXL format is copyrighted 2006/2007 and invented by 51 * Robert M. Hanson, 52 * Professor of Chemistry, 53 * St. Olaf College, 54 * 1520 St. Olaf Ave. 55 * Northfield, MN. 55057. 56 * 57 * Implementations of the JVXL format should reference 58 * "Robert M. Hanson, St. Olaf College" and the opensource Jmol project. 59 * 60 * 61 * implementing marching squares; see 62 * http://www.secam.ex.ac.uk/teaching/ug/studyres/COM3404/COM3404-2006-Lecture15.pdf 63 * 64 * lines through coordinates are identical to CUBE files 65 * after that, we have a line that starts with a negative number to indicate this 66 * is a JVXL file: 67 * 68 * line1: (int)-nSurfaces (int)edgeFractionBase (int)edgeFractionRange 69 * (nSurface lines): (float)cutoff (int)nBytesData (int)nBytesFractions 70 * 71 * definition1 72 * edgedata1 73 * fractions1 74 * colordata1 75 * .... 76 * definition2 77 * edgedata2 78 * fractions2 79 * colordata2 80 * .... 81 * 82 * definitions: a line with detail about what sort of compression follows 83 * 84 * edgedata: a list of the count of vertices ouside and inside the cutoff, whatever 85 * that may be, ordered by nested for loops for(x){for(y){for(z)}}}. 86 * 87 * nOutside nInside nOutside nInside... 88 * 89 * fractions: an ascii list of characters representing the fraction of distance each 90 * encountered surface point is along each voxel cube edge found to straddle the 91 * surface. The order written is dictated by the reader algorithm and is not trivial 92 * to describe. Each ascii character is constructed by taking a base character and 93 * adding onto it the fraction times a range. This gives a character that can be 94 * quoted EXCEPT for backslash, which MAY be substituted for by '!'. Jmol uses the 95 * range # - | (35 - 124), reserving ! and } for special meanings. 96 * 97 * colordata: same deal here, but with possibility of "double precision" using two bytes. 98 * 99 * 100 * 101 * THIS READER 102 * ----------- 103 * 104 * This is a first attempt at a generic JVXL file reader and writer class. 105 * It is an extraction of Jmol org.jmol.viewer.Isosurface.Java and related pieces. 106 * 107 * The goal of the reader is to be able to read CUBE-like data and 108 * convert that data to JVXL file data. 109 * 110 * 111 */ 112 113 package org.jmol.jvxl.readers; 114 115 116 import java.io.BufferedInputStream; 117 import java.io.BufferedReader; 118 import java.util.Map; 119 120 121 import org.jmol.atomdata.AtomData; 122 import org.jmol.atomdata.AtomDataServer; 123 import org.jmol.atomdata.RadiusData; 124 import javajs.util.BS; 125 import org.jmol.jvxl.data.JvxlCoder; 126 import org.jmol.jvxl.data.JvxlData; 127 import org.jmol.jvxl.data.VolumeData; 128 import org.jmol.jvxl.data.MeshData; 129 import org.jmol.jvxl.api.MeshDataServer; 130 import org.jmol.jvxl.calc.MarchingSquares; 131 132 import javajs.api.GenericBinaryDocument; 133 import javajs.util.AU; 134 import javajs.util.Lst; 135 import org.jmol.util.Logger; 136 import org.jmol.viewer.FileManager; 137 import org.jmol.viewer.Viewer; 138 139 import javajs.util.M4; 140 import javajs.util.Measure; 141 import javajs.util.Rdr; 142 import javajs.util.SB; 143 import javajs.util.OC; 144 import javajs.util.PT; 145 import javajs.util.P3; 146 import javajs.util.P4; 147 import javajs.util.V3; 148 149 public class SurfaceGenerator { 150 151 public Parameters params; 152 public JvxlData jvxlData; 153 public MeshData meshData; 154 public VolumeData volumeDataTemp; 155 public MeshDataServer meshDataServer; 156 public AtomDataServer atomDataServer; 157 public MarchingSquares marchingSquares; 158 public String version; 159 public boolean isValid = true; 160 public String fileType; 161 public BS bsVdw; 162 163 private int colorPtr; 164 private SurfaceReader surfaceReader; 165 private OC out; 166 SurfaceGenerator(AtomDataServer atomDataServer, MeshDataServer meshDataServer, MeshData meshData, JvxlData jvxlData)167 public SurfaceGenerator(AtomDataServer atomDataServer, MeshDataServer meshDataServer, 168 MeshData meshData, JvxlData jvxlData) { 169 this.atomDataServer = atomDataServer; 170 this.meshDataServer = meshDataServer; 171 params = new Parameters(); 172 this.meshData = (meshData == null ? new MeshData() : meshData); 173 this.jvxlData = (jvxlData == null ? new JvxlData() : jvxlData); 174 volumeDataTemp = new VolumeData(); 175 // volumeDataTemp is used for some initial work, but it is sometimes 176 // replaced in surfaceReader by other sources of volume data. 177 // Contact will re-use it. 178 initializeIsosurface(); 179 } 180 setJvxlData(JvxlData jvxlData)181 public void setJvxlData(JvxlData jvxlData) { 182 this.jvxlData = jvxlData; 183 if (jvxlData != null) 184 jvxlData.version = version; 185 } 186 187 ////////////////////////////////////////////////////////////// 188 189 /** 190 * 191 * @param propertyName 192 * @param value 193 * @param bs 194 * @return TRUE if handled 195 */ 196 @SuppressWarnings("unchecked") setProp(String propertyName, Object value, BS bs)197 public boolean setProp(String propertyName, Object value, BS bs) { 198 199 if ("debug" == propertyName) { 200 boolean TF = ((Boolean) value).booleanValue(); 201 params.logMessages = TF; 202 // logCompression = TF; 203 params.logCube = TF; 204 return true; 205 } 206 207 if ("init" == propertyName) { 208 initializeIsosurface(); 209 if (value instanceof Parameters) { 210 params = (Parameters) value; 211 } else { 212 params.script = (String) value; 213 if (params.script != null && params.script.indexOf(";#") >= 0) { 214 // crude hack for ScriptEvaluator messing up 215 params.script = PT.rep(params.script, ";#", "; #"); 216 } 217 } 218 return false; // more to do 219 } 220 221 if ("silent" == propertyName) { 222 params.isSilent = true; 223 return true; 224 } 225 226 if ("map" == propertyName) { 227 params.resetForMapping(((Boolean) value).booleanValue()); 228 if (surfaceReader != null) 229 surfaceReader.minMax = null; 230 return true; 231 } 232 if ("finalize" == propertyName) { 233 initializeIsosurface(); 234 return true; 235 } 236 237 if ("clear" == propertyName) { 238 if (surfaceReader != null) 239 surfaceReader.discardTempData(true); 240 return false; 241 } 242 243 if ("fileIndex" == propertyName) { 244 params.fileIndex = ((Integer) value).intValue(); 245 if (params.fileIndex < 0) 246 params.fileIndex = 0;// 0 used in efvet reader for "current color" 247 params.readAllData = false; 248 return true; 249 } 250 251 if ("blockData" == propertyName) { 252 params.blockCubeData = ((Boolean) value).booleanValue(); 253 return true; 254 } 255 256 if ("withinPoints" == propertyName) { 257 params.boundingBox = (P3[]) ((Object[]) value)[1]; 258 return true; 259 } 260 261 if ("boundingBox" == propertyName) { 262 P3[] pts = (P3[]) value; 263 params.boundingBox = new P3[] { P3.newP(pts[0]), 264 P3.newP(pts[pts.length - 1]) }; 265 return true; 266 } 267 268 if ("func" == propertyName) { 269 params.func = value; 270 return true; 271 } 272 273 if ("intersection" == propertyName) { 274 params.intersection = (BS[]) value; 275 return true; 276 } 277 278 if ("bsSolvent" == propertyName) { 279 params.bsSolvent = (BS) value; 280 return true; 281 } 282 283 if ("select" == propertyName) { 284 params.bsSelected = (BS) value; 285 return true; 286 } 287 288 if ("ignore" == propertyName) { 289 params.bsIgnore = (BS) value; 290 return true; 291 } 292 293 if ("propertySmoothing" == propertyName) { 294 params.propertySmoothing = ((Boolean) value).booleanValue(); 295 return true; 296 } 297 298 if ("propertyDistanceMax" == propertyName) { 299 params.propertyDistanceMax = ((Float) value).floatValue(); 300 return true; 301 } 302 303 if ("propertySmoothingPower" == propertyName) { 304 params.propertySmoothingPower = ((Integer) value).intValue(); 305 return true; 306 } 307 308 if ("title" == propertyName) { 309 if (value == null) { 310 params.title = null; 311 return true; 312 } else if (AU.isAS(value)) { 313 params.title = (String[]) value; 314 if (Logger.debugging) 315 for (int i = 0; i < params.title.length; i++) 316 if (params.title[i].length() > 0) 317 Logger.info(params.title[i]); 318 } 319 return true; 320 } 321 322 if ("sigma" == propertyName) { 323 // not all readers will take this, so we assign 324 // cutoff to the value as well. 325 params.cutoff = params.sigma = ((Float) value).floatValue(); 326 //params.isPositiveOnly = false; 327 params.cutoffAutomatic = false; 328 return true; 329 } 330 331 if ("cutoff" == propertyName) { 332 params.cutoff = ((Float) value).floatValue(); 333 params.isPositiveOnly = false; 334 params.cutoffAutomatic = false; 335 return true; 336 } 337 338 if ("parameters" == propertyName) { 339 params.parameters = AU.ensureLengthA((float[]) value, 2); 340 if (params.parameters.length > 0 && params.parameters[0] != 0) 341 params.cutoff = params.parameters[0]; 342 return true; 343 } 344 345 if ("cutoffPositive" == propertyName) { 346 params.cutoff = ((Float) value).floatValue(); 347 params.isPositiveOnly = true; 348 params.isCutoffAbsolute = false; 349 return true; 350 } 351 352 if ("cap" == propertyName || "slab" == propertyName) { 353 if (value != null) 354 params.addSlabInfo((Object[]) value); 355 return true; 356 } 357 358 if ("scale" == propertyName) { 359 params.scale = ((Float) value).floatValue(); 360 return true; 361 } 362 363 if ("scale3d" == propertyName) { 364 params.scale3d = ((Float) value).floatValue(); 365 return true; 366 } 367 368 if ("angstroms" == propertyName) { 369 params.isAngstroms = true; 370 return true; 371 } 372 373 if ("resolution" == propertyName) { 374 float resolution = ((Float) value).floatValue(); 375 params.resolution = (resolution > 0 ? resolution : Float.MAX_VALUE); 376 return true; 377 } 378 379 if ("downsample" == propertyName) { 380 int rate = ((Integer) value).intValue(); 381 params.downsampleFactor = (rate >= 0 ? rate : 0); 382 return true; 383 } 384 385 if ("anisotropy" == propertyName) { 386 if ((params.dataType & Parameters.NO_ANISOTROPY) == 0) 387 params.setAnisotropy((P3) value); 388 return true; 389 } 390 391 if ("eccentricity" == propertyName) { 392 params.setEccentricity((P4) value); 393 return true; 394 } 395 396 if ("addHydrogens" == propertyName) { 397 params.addHydrogens = ((Boolean) value).booleanValue(); 398 return true; 399 } 400 401 if ("squareData" == propertyName) { 402 params.isSquared = (value == null ? false : ((Boolean) value) 403 .booleanValue()); 404 return true; 405 } 406 407 if ("squareLinear" == propertyName) { 408 params.isSquaredLinear = (value == null ? false : ((Boolean) value) 409 .booleanValue()); 410 return true; 411 } 412 413 if ("gridPoints" == propertyName) { 414 params.iAddGridPoints = true; 415 return true; 416 } 417 418 if ("atomIndex" == propertyName) { 419 params.atomIndex = ((Integer) value).intValue(); 420 return true; 421 } 422 423 // / color options 424 425 if ("insideOut" == propertyName) { 426 params.insideOut = true; 427 return true; 428 } 429 430 if ("sign" == propertyName) { 431 params.isCutoffAbsolute = !params.isPositiveOnly; 432 params.colorBySign = true; 433 colorPtr = 0; 434 return true; 435 } 436 437 if ("colorRGB" == propertyName) { 438 int rgb = ((Integer) value).intValue(); 439 params.colorRgb = params.colorPos = params.colorPosLCAO = rgb; 440 if (colorPtr++ == 0) { 441 params.colorNeg = params.colorNegLCAO = rgb; 442 } else { 443 params.colorRgb = Integer.MAX_VALUE; 444 } 445 return true; 446 } 447 448 if ("monteCarloCount" == propertyName) { 449 params.psi_monteCarloCount = ((Integer) value).intValue(); 450 return true; 451 } 452 if ("rangeAll" == propertyName) { 453 params.rangeAll = true; 454 return true; 455 } 456 457 if ("rangeSelected" == propertyName) { 458 params.rangeSelected = true; 459 return true; 460 } 461 462 if ("red" == propertyName) { 463 params.valueMappedToRed = ((Float) value).floatValue(); 464 return true; 465 } 466 467 if ("blue" == propertyName) { 468 params.valueMappedToBlue = ((Float) value).floatValue(); 469 if (params.valueMappedToRed > params.valueMappedToBlue) { 470 float f = params.valueMappedToRed; 471 params.valueMappedToRed = params.valueMappedToBlue; 472 params.valueMappedToBlue = f; 473 params.isColorReversed = !params.isColorReversed; 474 } 475 params.rangeDefined = true; 476 params.rangeAll = false; 477 return true; 478 } 479 480 if ("reverseColor" == propertyName) { 481 params.isColorReversed = true; 482 return true; 483 } 484 485 if ("setColorScheme" == propertyName) { 486 getSurfaceSets(); 487 params.colorBySets = true; 488 mapSurface(); 489 return true; 490 } 491 492 if ("center" == propertyName) { 493 params.center.setT((P3) value); 494 return true; 495 } 496 497 // if ("volumeData" == propertyName) { 498 // params.volumeData = (VolumeData) value; 499 // return true; 500 // } 501 502 if ("origin" == propertyName) { 503 params.origin = (P3) value; 504 return true; 505 } 506 507 if ("step" == propertyName) { 508 params.steps = (P3) value; 509 return true; 510 } 511 512 if ("modelInvRotation" == propertyName) { 513 params.modelInvRotation = (M4) value; 514 return true; 515 } 516 517 if ("point" == propertyName) { 518 params.points = (P3) value; 519 return true; 520 } 521 522 if ("withinDistance" == propertyName) { 523 params.distance = ((Float) value).floatValue(); 524 return true; 525 } 526 527 if ("withinPoint" == propertyName) { 528 params.point = (P3) value; 529 return true; 530 } 531 532 if ("progressive" == propertyName) { 533 // an option for JVXL.java 534 params.isXLowToHigh = true; 535 return true; 536 } 537 538 if ("phase" == propertyName) { 539 String color = (String) value; 540 params.isCutoffAbsolute = true; 541 params.colorBySign = true; 542 params.colorByPhase = true; 543 params.colorPhase = SurfaceReader.getColorPhaseIndex(color); 544 if (params.colorPhase < 0) { 545 Logger.warn(" invalid color phase: " + color); 546 params.colorPhase = 0; 547 } 548 params.colorByPhase = params.colorPhase != 0; 549 if (params.state >= Parameters.STATE_DATA_READ) { 550 params.dataType = params.surfaceType; 551 params.state = Parameters.STATE_DATA_COLORED; 552 params.isBicolorMap = true; 553 surfaceReader.applyColorScale(); 554 } 555 return true; 556 } 557 558 /* 559 * Based on the form of the parameters, returns and encoded radius as 560 * follows: 561 * 562 * script meaning range encoded 563 * 564 * +1.2 offset [0 - 10] x -1.2 offset 0) x 1.2 absolute (0 - 10] x + 10 -30% 565 * 70% (-100 - 0) x + 200 +30% 130% (0 x + 200 80% percent (0 x + 100 566 * 567 * in each case, numbers can be integer or float 568 */ 569 570 if ("radius" == propertyName) { 571 Logger.info("solvent probe radius set to " + value); 572 params.atomRadiusData = (RadiusData) value; 573 return true; 574 } 575 576 if ("envelopeRadius" == propertyName) { 577 params.envelopeRadius = ((Float) value).floatValue(); 578 return true; 579 } 580 581 if ("cavityRadius" == propertyName) { 582 params.cavityRadius = ((Float) value).floatValue(); 583 return true; 584 } 585 586 if ("cavity" == propertyName) { 587 params.isCavity = true; 588 return true; 589 } 590 591 if ("doFullMolecular" == propertyName) { 592 params.doFullMolecular = true; 593 return true; 594 } 595 596 if ("pocket" == propertyName) { 597 params.pocket = (Boolean) value; 598 params.fullyLit = params.pocket.booleanValue(); 599 return true; 600 } 601 602 if ("minset" == propertyName) { 603 params.minSet = ((Integer) value).intValue(); 604 return true; 605 } 606 607 if ("maxset" == propertyName) { 608 params.maxSet = ((Integer) value).intValue(); 609 return true; 610 } 611 612 if ("plane" == propertyName) { 613 params.setPlane((P4) value); 614 return true; 615 } 616 617 if ("contour" == propertyName) { 618 params.isContoured = true; 619 int n; 620 if (AU.isAF(value)) { 621 // discrete values 622 params.contoursDiscrete = (float[]) value; 623 params.nContours = params.contoursDiscrete.length; 624 } else if (value instanceof P3) { 625 P3 pt = params.contourIncrements = (P3) value; 626 float from = pt.x; 627 float to = pt.y; 628 float step = pt.z; 629 if (step <= 0) 630 step = 1; 631 n = 0; 632 for (float p = from; p <= to + step / 10; p += step, n++) { 633 } 634 params.contoursDiscrete = new float[n]; 635 float p = from; 636 for (int i = 0; i < n; i++, p += step) { 637 params.contoursDiscrete[i] = p; 638 } 639 params.nContours = n; 640 } else { 641 n = ((Integer) value).intValue(); 642 params.thisContour = 0; // flags as marked for JVXL reader 643 if (n == 0) 644 params.nContours = MarchingSquares.defaultContourCount; 645 else if (n > 0) 646 params.nContours = n; 647 else 648 params.thisContour = -n; 649 } 650 return true; 651 } 652 653 if ("colorDiscrete" == propertyName) { 654 params.contourColixes = (short[]) value; 655 return true; 656 } 657 658 if ("colorDensity" == propertyName) { 659 params.colorDensity = true; 660 if (value != null) 661 params.pointSize = ((Float) value).floatValue(); 662 return false; 663 } 664 if ("fullPlane" == propertyName) { 665 // fullPlane == true --> params.contourFromZero is false 666 // fullPlane == false --> params.contourFromZero is true 667 // this only relates to projections onto a plane 668 // the default is contourFromZero TRUE 669 // but MEP default is contourFromZero FALSE 670 // the setting is ignored when discrete contours 671 // are specified, because in that case we just 672 // define the triangle color by their centers 673 674 params.contourFromZero = !((Boolean) value).booleanValue(); 675 return true; 676 } 677 678 if ("mapLattice" == propertyName) { 679 params.mapLattice = (P3) value; 680 return true; 681 } 682 683 if ("extendGrid" == propertyName) { 684 params.extendGrid = ((Float) value).floatValue(); 685 return true; 686 } 687 688 // / final actions /// 689 690 if ("property" == propertyName) { 691 params.dataType = Parameters.SURFACE_PROPERTY; 692 params.theProperty = (float[]) value; 693 mapSurface(); 694 return true; 695 } 696 697 // these next four set the reader themselves. 698 if ("sphere" == propertyName) { 699 params.setSphere(((Float) value).floatValue(), false); 700 readerData = Float.valueOf(params.distance); 701 surfaceReader = newReader("IsoShapeReader"); 702 generateSurface(); 703 return true; 704 } 705 706 // these next four set the reader themselves. 707 if ("geodesic" == propertyName) { 708 params.setSphere(((Float) value).floatValue(), true); 709 readerData = Float.valueOf(params.distance); 710 surfaceReader = newReader("IsoShapeReader"); 711 generateSurface(); 712 return true; 713 } 714 715 if ("ellipsoid" == propertyName) { 716 if (value instanceof P4) 717 params.setEllipsoidP4((P4) value); 718 else if (AU.isAF(value)) 719 params.setEllipsoidAF((float[]) value); 720 else 721 return true; 722 readerData = Float.valueOf(params.distance); 723 surfaceReader = newReader("IsoShapeReader"); 724 generateSurface(); 725 return true; 726 } 727 728 if ("ellipsoid3" == propertyName) { 729 params.setEllipsoidAF((float[]) value); 730 readerData = Float.valueOf(params.distance); 731 surfaceReader = newReader("IsoShapeReader"); 732 generateSurface(); 733 return true; 734 } 735 736 if ("lp" == propertyName) { 737 params.setLp((P4) value); 738 readerData = new float[] { 3, 2, 0, 15, 0 }; 739 surfaceReader = newReader("IsoShapeReader"); 740 generateSurface(); 741 return true; 742 } 743 744 if ("rad" == propertyName) { 745 params.setRadical((P4) value); 746 readerData = new float[] { 3, 2, 0, 15, 0 }; 747 surfaceReader = newReader("IsoShapeReader"); 748 generateSurface(); 749 return true; 750 } 751 752 if ("lobe" == propertyName) { 753 params.setLobe((P4) value); 754 readerData = new float[] { 3, 2, 0, 15, 0 }; 755 surfaceReader = newReader("IsoShapeReader"); 756 generateSurface(); 757 return true; 758 } 759 760 if ("hydrogenOrbital" == propertyName) { 761 if (!params.setAtomicOrbital((float[]) value)) { 762 isValid = false; 763 return true; 764 } 765 readerData = new float[] { params.psi_n, params.psi_l, params.psi_m, 766 params.psi_Znuc, params.psi_monteCarloCount }; 767 surfaceReader = newReader("IsoShapeReader"); 768 processState(); 769 return true; 770 } 771 772 if ("functionXY" == propertyName) { 773 params.setFunctionXY((Lst<Object>) value); 774 if (params.isContoured) // xy plane through origin 775 volumeDataTemp.setPlaneParameters( 776 params.thePlane == null ? params.thePlane = P4.new4(0, 0, 1, 0) 777 : params.thePlane); 778 if (((String) params.functionInfo.get(0)).indexOf("_xyz") >= 0) 779 getFunctionZfromXY(); 780 processState(); 781 return true; 782 } 783 784 if ("functionXYZ" == propertyName) { 785 params.setFunctionXYZ((Lst<Object>) value); 786 processState(); 787 return true; 788 } 789 790 if ("lcaoType" == propertyName) { 791 params.setLcao((String) value, colorPtr); 792 return true; 793 } 794 795 if ("lcaoCartoonCenter" == propertyName) { 796 if (++params.state != Parameters.STATE_DATA_READ) 797 return true; 798 if (Float.isNaN(params.center.x)) 799 params.center.setT((V3) value); 800 return false; 801 } 802 803 if ("molecular" == propertyName || "solvent" == propertyName 804 || "sasurface" == propertyName || "nomap" == propertyName) { 805 params.setSolvent(propertyName, ((Float) value).floatValue()); 806 if (!params.isSilent) 807 Logger.info(params.calculationType); 808 processState(); 809 return true; 810 } 811 812 if ("moData" == propertyName) { 813 params.moData = (Map<String, Object>) value; 814 return true; 815 } 816 817 if ("mepCalcType" == propertyName) { 818 params.mep_calcType = ((Integer) value).intValue(); 819 return true; 820 } 821 822 if ("mep" == propertyName) { 823 params.setMep((float[]) value, false); // mep charges 824 processState(); 825 return true; 826 } 827 828 if ("mlp" == propertyName) { 829 params.setMep((float[]) value, true); // mlp charges 830 processState(); 831 return true; 832 } 833 834 if ("nci" == propertyName) { 835 boolean isPromolecular = ((Boolean) value).booleanValue(); 836 params.setNci(isPromolecular); 837 if (isPromolecular) 838 processState(); 839 return true; 840 } 841 842 if ("calculationType" == propertyName) { 843 params.calculationType = (String) value; 844 return true; 845 } 846 847 if ("charges" == propertyName) { 848 params.theProperty = (float[]) value; 849 return true; 850 } 851 852 if ("randomSeed" == propertyName) { 853 // for any object requiring reproduction in the state 854 // and using random numbers -- AO and MO 855 params.randomSeed = ((Integer) value).intValue(); 856 return true; 857 } 858 859 if ("molecularOrbital" == propertyName) { 860 int iMo = 0; 861 float[] linearCombination = null; 862 if (value instanceof Integer) { 863 iMo = ((Integer) value).intValue(); 864 } else { 865 linearCombination = (float[]) value; 866 } 867 params.setMO(iMo, linearCombination); 868 Logger.info(params.calculationType); 869 processState(); 870 return true; 871 } 872 873 if ("fileType" == propertyName) { 874 fileType = (String) value; 875 return true; 876 } 877 878 if ("fileName" == propertyName) { 879 params.fileName = (String) value; 880 return true; 881 } 882 883 if ("filesData" == propertyName) { 884 params.filesData = (Object[]) value; 885 return true; 886 } 887 888 if ("outputChannel" == propertyName) { 889 out = (OC) value; 890 return true; 891 } 892 893 if ("readFile" == propertyName) { 894 if ((surfaceReader = setFileData((Viewer) atomDataServer, value)) == null) { 895 Logger.error("Could not set the surface data"); 896 return true; 897 } 898 surfaceReader.setOutputChannel(out); 899 generateSurface(); 900 return true; 901 } 902 903 if ("mapColor" == propertyName) { 904 if ((surfaceReader = setFileData((Viewer) atomDataServer, value)) == null) { 905 Logger.error("Could not set the mapping data"); 906 return true; 907 } 908 surfaceReader.setOutputChannel(out); 909 mapSurface(); 910 return true; 911 } 912 913 if ("getSurfaceSets" == propertyName) { 914 getSurfaceSets(); 915 return true; 916 } 917 918 if ("periodic" == propertyName) { 919 params.isPeriodic = true; 920 } 921 922 // continue with operations in calling class... 923 return false; 924 } 925 newReader(String name)926 private SurfaceReader newReader(String name) { 927 SurfaceReader sr = (SurfaceReader) getInterface(name); 928 if (sr != null) 929 sr.init(this); 930 return sr; 931 } 932 newReaderBr(String name, BufferedReader br)933 private SurfaceReader newReaderBr(String name, BufferedReader br) { 934 SurfaceFileReader sr = (SurfaceFileReader) getInterface(name); 935 if (sr != null) 936 sr.init2(this, br); 937 return sr; 938 } 939 getInterface(String name)940 private static Object getInterface(String name) { 941 try { 942 Class<?> x = Class.forName("org.jmol.jvxl.readers." + name); 943 return (x == null ? null : x.newInstance()); 944 } catch (Exception e) { 945 Logger.error("Interface.java Error creating instance for " + name + ": \n" + e.toString()); 946 return null; 947 } 948 } 949 getSurfaceSets()950 private void getSurfaceSets() { 951 if (meshDataServer == null) { 952 meshData.getSurfaceSet(); 953 } else { 954 meshDataServer.fillMeshData(meshData, MeshData.MODE_GET_VERTICES, null); 955 meshData.getSurfaceSet(); 956 meshDataServer.fillMeshData(meshData, MeshData.MODE_PUT_SETS, null); 957 } 958 } 959 processState()960 private void processState() { 961 if (params.state == Parameters.STATE_INITIALIZED && params.thePlane != null) 962 params.state++; 963 if (params.state >= Parameters.STATE_DATA_READ) { 964 mapSurface(); 965 } else { 966 generateSurface(); 967 } 968 } 969 setReader()970 private boolean setReader() { 971 readerData = null; 972 if (surfaceReader != null) 973 return !surfaceReader.vertexDataOnly; 974 switch (params.dataType) { 975 case Parameters.SURFACE_NOMAP: 976 surfaceReader = newReader("IsoPlaneReader"); 977 break; 978 case Parameters.SURFACE_PROPERTY: 979 surfaceReader = newReader("AtomPropertyMapper"); 980 break; 981 case Parameters.SURFACE_MEP: 982 case Parameters.SURFACE_MLP: 983 readerData = (params.dataType == Parameters.SURFACE_MEP ? "Mep" : "Mlp"); 984 if (params.state == Parameters.STATE_DATA_COLORED) { 985 surfaceReader = newReader("AtomPropertyMapper"); 986 } else { 987 surfaceReader = newReader("Iso" + readerData + "Reader"); 988 } 989 break; 990 case Parameters.SURFACE_INTERSECT_FILE: 991 surfaceReader = newReader("IsoIntersectFileReader"); 992 break; 993 case Parameters.SURFACE_INTERSECT_ATOM: 994 surfaceReader = newReader("IsoIntersectAtomReader"); 995 break; 996 case Parameters.SURFACE_SOLVENT: 997 case Parameters.SURFACE_MOLECULAR: 998 case Parameters.SURFACE_SASURFACE: 999 surfaceReader = newReader("IsoSolventReader"); 1000 break; 1001 case Parameters.SURFACE_NCI: 1002 case Parameters.SURFACE_MOLECULARORBITAL: 1003 surfaceReader = newReader("IsoMOReader"); 1004 break; 1005 case Parameters.SURFACE_FUNCTIONXY: 1006 surfaceReader = newReader("IsoFxyReader"); 1007 break; 1008 case Parameters.SURFACE_FUNCTIONXYZ: 1009 surfaceReader = newReader("IsoFxyzReader"); 1010 break; 1011 } 1012 if (Logger.debugging) 1013 Logger.info("Using surface reader " + surfaceReader); 1014 if (params.isSilent && surfaceReader != null) 1015 surfaceReader.isQuiet = true; 1016 return true; 1017 } 1018 generateSurface()1019 private void generateSurface() { 1020 if (++params.state != Parameters.STATE_DATA_READ) 1021 return; 1022 setReader(); 1023 if (params.sbOut == null) 1024 params.sbOut = new SB(); 1025 jvxlData.sbOut = params.sbOut; 1026 boolean haveMeshDataServer = (meshDataServer != null); 1027 if (params.colorBySign) 1028 params.isBicolorMap = true; 1029 if (surfaceReader == null) { 1030 Logger.error("surfaceReader is null for " + params.dataType); 1031 return; 1032 } 1033 if (!surfaceReader.createIsosurface(false)) { 1034 Logger.error("Could not create isosurface"); 1035 params.cutoff = Float.NaN; 1036 surfaceReader.closeReader(); 1037 return; 1038 } 1039 1040 if (params.probes != null) { 1041 for (int i = params.probeValues.length; --i >= 0;) { 1042 params.probeValues[i] = surfaceReader.getValueAtPoint(params.probes[i], false); 1043 } 1044 } 1045 1046 if (params.pocket != null && haveMeshDataServer) 1047 surfaceReader.selectPocket(!params.pocket.booleanValue()); 1048 1049 if (params.minSet > 0) 1050 surfaceReader.excludeMinimumSet(); 1051 1052 if (params.maxSet > 0) 1053 surfaceReader.excludeMaximumSet(); 1054 1055 if (params.slabInfo != null) 1056 surfaceReader.slabIsosurface(params.slabInfo); 1057 1058 if (haveMeshDataServer && meshDataServer.notifySurfaceGenerationCompleted()) 1059 surfaceReader.hasColorData = false; 1060 1061 if (jvxlData.thisSet != null) 1062 getSurfaceSets(); 1063 if (jvxlData.jvxlDataIs2dContour) { 1064 surfaceReader.colorIsosurface(); 1065 params.state = Parameters.STATE_DATA_COLORED; 1066 } 1067 if (jvxlData.jvxlDataIsColorDensity) { 1068 params.state = Parameters.STATE_DATA_COLORED; 1069 } 1070 if (params.colorBySign || params.isBicolorMap) { 1071 params.state = Parameters.STATE_DATA_COLORED; 1072 surfaceReader.applyColorScale(); 1073 } 1074 if (jvxlData.vertexColorMap != null) { 1075 jvxlData.vertexColorMap = null; 1076 surfaceReader.hasColorData = false; 1077 } 1078 surfaceReader.jvxlUpdateInfo(); 1079 marchingSquares = surfaceReader.marchingSquares; 1080 surfaceReader.discardTempData(false); 1081 params.mappedDataMin = Float.MAX_VALUE; 1082 surfaceReader.closeReader(); 1083 if (params.state != Parameters.STATE_DATA_COLORED && 1084 (surfaceReader.hasColorData || params.colorDensity)) { 1085 params.state = Parameters.STATE_DATA_COLORED; 1086 colorIsosurface(); 1087 } 1088 surfaceReader = null; 1089 } 1090 mapSurface()1091 private void mapSurface() { 1092 if (params.state == Parameters.STATE_INITIALIZED && params.thePlane != null) 1093 params.state++; 1094 if (++params.state < Parameters.STATE_DATA_COLORED) 1095 return; 1096 if (!setReader()) 1097 return; 1098 //if (params.dataType == Parameters.SURFACE_FUNCTIONXY) 1099 //params.thePlane = new Point4f(0, 0, 1, 0); 1100 if (params.isPeriodic) 1101 surfaceReader.volumeData.isPeriodic = true; 1102 if (params.thePlane != null) { 1103 boolean isSquared = params.isSquared; 1104 params.isSquared = false; 1105 params.cutoff = 0; 1106 surfaceReader.volumeData.setMappingPlane(params.thePlane); 1107 surfaceReader.createIsosurface(!params.isPeriodic);//but don't read volume data yet 1108 surfaceReader.volumeData.setMappingPlane(null); 1109 if (meshDataServer != null) 1110 meshDataServer.notifySurfaceGenerationCompleted(); 1111 if (params.dataType == Parameters.SURFACE_NOMAP) { 1112 // just a simple plane 1113 surfaceReader.discardTempData(true); 1114 return; 1115 } 1116 params.isSquared = isSquared; 1117 params.mappedDataMin = Float.MAX_VALUE; 1118 surfaceReader.readVolumeData(true); 1119 if (params.mapLattice != null) 1120 surfaceReader.volumeData.isPeriodic = true; 1121 } else if (!params.colorBySets && !params.colorDensity) { 1122 surfaceReader.readAndSetVolumeParameters(true); 1123 params.mappedDataMin = Float.MAX_VALUE; 1124 surfaceReader.readVolumeData(true); 1125 } 1126 colorIsosurface(); 1127 surfaceReader.closeReader(); 1128 surfaceReader = null; 1129 } 1130 colorIsosurface()1131 void colorIsosurface() { 1132 surfaceReader.colorIsosurface(); 1133 surfaceReader.jvxlUpdateInfo(); 1134 surfaceReader.updateTriangles(); 1135 surfaceReader.discardTempData(true); 1136 if (meshDataServer != null) 1137 meshDataServer.notifySurfaceMappingCompleted(); 1138 } 1139 1140 /** 1141 * only called from org.openscience.jvxl.Jvxl.main 1142 * 1143 * @param property 1144 * @param index 1145 * @return Object 1146 */ getProperty(String property, int index)1147 public Object getProperty(String property, int index) { 1148 if (property == "jvxlFileData") 1149 return JvxlCoder.jvxlGetFile(jvxlData, null, params.title, "", true, 1150 index, null, null); // for Jvxl.java 1151 if (property == "jvxlFileInfo") 1152 return JvxlCoder.jvxlGetInfo(jvxlData); // for Jvxl.java 1153 return null; 1154 } 1155 1156 /** 1157 * @param vwr 1158 * @param value 1159 * @return SurfaceReader 1160 */ 1161 @SuppressWarnings("unchecked") setFileData(Viewer vwr, Object value)1162 private SurfaceReader setFileData(Viewer vwr, Object value) { 1163 // comes from "readFile" or "mapColors" 1164 String fileType = this.fileType; 1165 this.fileType = null; 1166 if (value instanceof Map) { 1167 Map<String, Object> map = (Map<String, Object>) value; 1168 if (map.containsKey("__pymolSurfaceData__")) { 1169 readerData = map; 1170 return newReaderBr("PyMOLMeshReader", null); 1171 } 1172 value = map.get("volumeData"); 1173 } 1174 if (value instanceof VolumeData) { 1175 // never implemented? 1176 volumeDataTemp = (VolumeData) value; 1177 return newReader("VolumeDataReader"); 1178 } 1179 String data = null; 1180 if (value instanceof String) { 1181 // inline string data 1182 data = (String) value; 1183 // this will be OK, because any string will be a simple string, 1184 // not a binary file. 1185 value = Rdr.getBR((String) value); 1186 } 1187 if (value instanceof Object[]) { 1188 // [BufferedFileReader[], float[]] -> [VolumeFileReader[], float[]] 1189 Object[] a = (Object[]) ((Object[]) value)[0]; 1190 VolumeFileReader[] b = new VolumeFileReader[a.length]; 1191 for (int i = 0; i < a.length; i++) 1192 b[i] = (VolumeFileReader) setFileData(vwr, a[i]); 1193 ((Object[]) value)[0] = b; 1194 readerData = value; 1195 return newReader("IsoIntersectGridReader"); 1196 } 1197 BufferedReader br = (BufferedReader) value; 1198 if (fileType == null) 1199 fileType = FileManager.determineSurfaceFileType(br); 1200 if (fileType != null && fileType.startsWith("UPPSALA")) { 1201 //"http://eds.bmc.uu.se/cgi-bin/eds/gen_maps_zip.pl?POST?pdbCode=1blu&mapformat=ccp4&maptype=2fofc&page=generate" 1202 // -- ah, but this does not work, because it is asynchronous! 1203 // -- first a message is sent back that suggests you might have to wait, 1204 // then a message that says, "Here is your map" is sent. 1205 1206 String fname = params.fileName; 1207 fname = fname.substring(0, fname.indexOf("/", 10)); 1208 fname += PT.getQuotedStringAt(fileType, 1209 fileType.indexOf("A HREF") + 1); 1210 params.fileName = fname; 1211 value = atomDataServer.getBufferedInputStream(fname); 1212 if (value == null) { 1213 Logger.error("Isosurface: could not open file " + fname); 1214 return null; 1215 } 1216 try { 1217 br = Rdr.getBufferedReader((BufferedInputStream) value, null); 1218 } catch (Exception e) { 1219 // TODO 1220 } 1221 fileType = FileManager.determineSurfaceFileType(br); 1222 } 1223 if (fileType == null) 1224 fileType = "UNKNOWN"; 1225 Logger.info("data file type was determined to be " + fileType); 1226 if (fileType.equals("Jvxl+")) 1227 return newReaderBr("JvxlReader", br); 1228 1229 readerData = new Object[] { params.fileName, data }; 1230 1231 if ("MRC DELPHI DSN6".indexOf(fileType.toUpperCase()) >= 0) { 1232 fileType += "Binary"; 1233 } 1234 return newReaderBr(fileType + "Reader", br); 1235 } 1236 1237 private Object readerData; 1238 getReaderData()1239 Object getReaderData() { 1240 // needed by DelPhiBinary, Dsn6Binary, IsoShape, MrcBinary, Msms, Pmesh, CifDensity 1241 Object o = readerData; 1242 readerData = null; 1243 return o; 1244 } 1245 initializeIsosurface()1246 void initializeIsosurface() { 1247 params.initialize(); 1248 colorPtr = 0; 1249 surfaceReader = null; 1250 marchingSquares = null; 1251 initState(); 1252 } 1253 initState()1254 public void initState() { 1255 params.state = Parameters.STATE_INITIALIZED; 1256 params.dataType = params.surfaceType = Parameters.SURFACE_NONE; 1257 } 1258 setLcao()1259 public String setLcao() { 1260 params.colorPos = params.colorPosLCAO; 1261 params.colorNeg = params.colorNegLCAO; 1262 return params.lcaoType; 1263 1264 } 1265 getFunctionZfromXY()1266 private void getFunctionZfromXY() { 1267 P3 origin = (P3) params.functionInfo.get(1); 1268 int[] counts = new int[3]; 1269 int[] nearest = new int[3]; 1270 V3[] vectors = new V3[3]; 1271 for (int i = 0; i < 3; i++) { 1272 P4 info = (P4) params.functionInfo.get(i + 2); 1273 counts[i] = Math.abs((int) info.x); 1274 vectors[i] = V3.new3(info.y, info.z, info.w); 1275 } 1276 int nx = counts[0]; 1277 int ny = counts[1]; 1278 P3 pt = new P3(); 1279 P3 pta = new P3(); 1280 P3 ptb = new P3(); 1281 P3 ptc = new P3(); 1282 1283 float[][] data = (float[][]) params.functionInfo.get(5); 1284 float[][] data2 = new float[nx][ny]; 1285 float[] d; 1286 //int n = 0; 1287 //for (int i = 0; i < data.length; i++) 1288 //System.out.println("draw pt"+(++n)+" {" + data[i][0] + " " + data[i][1] + " " + data[i][2] + "} color yellow"); 1289 for (int i = 0; i < nx; i++) 1290 for (int j = 0; j < ny; j++) { 1291 pt.scaleAdd2(i, vectors[0], origin); 1292 pt.scaleAdd2(j, vectors[1], pt); 1293 float dist = findNearestThreePoints(pt.x, pt.y, data, nearest); 1294 pta.set((d = data[nearest[0]])[0], d[1], d[2]); 1295 if (dist < 0.00001) { 1296 pt.z = d[2]; 1297 } else { 1298 ptb.set((d = data[nearest[1]])[0], d[1], d[2]); 1299 ptc.set((d = data[nearest[2]])[0], d[1], d[2]); 1300 pt.z = distanceVerticalToPlane(pt.x, pt.y, pta, ptb, ptc); 1301 } 1302 data2[i][j] = pt.z; 1303 //System.out.println("draw pt"+(++n)+" " + Escape.escape(pt) + " color red"); 1304 } 1305 params.functionInfo.set(5, data2); 1306 } 1307 1308 private final V3 vAB = new V3(); 1309 private final V3 vNorm = new V3(); 1310 private final P3 ptRef = P3.new3(0, 0, 1e15f); 1311 distanceVerticalToPlane(float x, float y, P3 pta, P3 ptb, P3 ptc)1312 private float distanceVerticalToPlane(float x, float y, P3 pta, 1313 P3 ptb, P3 ptc) { 1314 // ax + by + cz + d = 0 1315 1316 float d = Measure.getDirectedNormalThroughPoints(pta, ptb, ptc, ptRef, vNorm, vAB); 1317 return (vNorm.x * x + vNorm.y * y + d) / -vNorm.z; 1318 } 1319 findNearestThreePoints(float x, float y, float[][] xyz, int[] result)1320 private static float findNearestThreePoints(float x, float y, float[][] xyz, int[] result) { 1321 //result should be int[3]; 1322 float d, dist1, dist2, dist3; 1323 int i1, i2, i3; 1324 i1 = i2 = i3 = -1; 1325 dist1 = dist2 = dist3 = Float.MAX_VALUE; 1326 for (int i = xyz.length; --i >= 0;) { 1327 d = (d = xyz[i][0] - x) * d + (d = xyz[i][1] - y) * d; 1328 if (d < dist1) { 1329 dist3 = dist2; 1330 dist2 = dist1; 1331 dist1 = d; 1332 i3 = i2; 1333 i2 = i1; 1334 i1 = i; 1335 } else if (d < dist2) { 1336 dist3 = dist2; 1337 dist2 = d; 1338 i3 = i2; 1339 i2 = i; 1340 } else if (d < dist3) { 1341 dist3 = d; 1342 i3 = i; 1343 } 1344 } 1345 //System.out.println("findnearest " + dist1); 1346 result[0] = i1; 1347 result[1] = i2; 1348 result[2] = i3; 1349 return dist1; 1350 } 1351 addRequiredFile(String fileName)1352 public void addRequiredFile(String fileName) { 1353 if (meshDataServer == null) 1354 return; 1355 meshDataServer.addRequiredFile(fileName); 1356 } 1357 setRequiredFile(String oldName, String fileName)1358 public void setRequiredFile(String oldName, String fileName) { 1359 if (meshDataServer == null) 1360 return; 1361 meshDataServer.setRequiredFile(oldName, fileName); 1362 } 1363 log(String msg)1364 void log(String msg) { 1365 if (atomDataServer == null) 1366 System.out.println(msg); 1367 else 1368 atomDataServer.log(msg); 1369 } 1370 setOutputChannel(GenericBinaryDocument binaryDoc, OC out)1371 void setOutputChannel(GenericBinaryDocument binaryDoc, OC out) { 1372 if (meshDataServer == null) 1373 return; 1374 meshDataServer.setOutputChannel(binaryDoc, out); 1375 } 1376 fillAtomData(AtomData atomData, int mode)1377 void fillAtomData(AtomData atomData, int mode) { 1378 if ((mode & AtomData.MODE_FILL_RADII) != 0 1379 && atomData.bsSelected != null) { 1380 if (bsVdw == null) 1381 bsVdw = new BS(); 1382 bsVdw.or(atomData.bsSelected); 1383 } 1384 atomDataServer.fillAtomData(atomData, mode); 1385 } 1386 getOriginVaVbVc()1387 public V3[] getOriginVaVbVc() { 1388 return (surfaceReader.volumeData == null ? null : surfaceReader.volumeData.oabc); 1389 } 1390 1391 } 1392