protected void readVoxelVector(int voxelVectorIndex) throws Exception { readLine(); V3 voxelVector = volumetricVectors[voxelVectorIndex]; if ((voxelCounts[voxelVectorIndex] = parseIntStr(line)) == Integer.MIN_VALUE) // unreadable next[0] = line.indexOf(" "); voxelVector.set(parseFloat(), parseFloat(), parseFloat()); if (isAnisotropic) setVectorAnisotropy(voxelVector); }
/** * Matches normals for adjacent mesh sections to create a seamless overall mesh. We use temporary * normals here. We will convert normals to normixes later. * * @param i * @param nPer */ void adjustCartoonSeamNormals(int i, int nPer) { if (bsTemp == null) bsTemp = Normix.newVertexBitSet(); if (i == iNext - 1 && iNext < monomerCount && monomers[i].getStrucNo() == monomers[iNext].getStrucNo() && meshReady[i] && meshReady[iNext]) { try { V3[] normals2 = meshes[iNext].getNormalsTemp(); V3[] normals = meshes[i].getNormalsTemp(); int normixCount = normals.length; if (doCap0) normixCount -= nPer; for (int j = 1; j <= nPer; ++j) { norml.add2(normals[normixCount - j], normals2[nPer - j]); norml.normalize(); meshes[i].normalsTemp[normixCount - j].setT(norml); meshes[iNext].normalsTemp[nPer - j].setT(norml); } } catch (Exception e) { } } }
private void getStateID(SB sb) { V3 v1 = new V3(); for (Ellipsoid ellipsoid : simpleEllipsoids.values()) { Tensor t = ellipsoid.tensor; if (!ellipsoid.isValid || t == null) continue; sb.append(" Ellipsoid ID ") .append(ellipsoid.id) .append(" modelIndex ") .appendI(t.modelIndex) .append(" center ") .append(Escape.eP(ellipsoid.center)) .append(" axes"); for (int i = 0; i < 3; i++) { v1.setT(t.eigenVectors[i]); v1.scale(ellipsoid.lengths[i]); sb.append(" ").append(Escape.eP(v1)); } sb.append(" " + getColorCommandUnk("", ellipsoid.colix, translucentAllowed)); if (ellipsoid.options != null) sb.append(" options ").append(PT.esc(ellipsoid.options)); if (!ellipsoid.isOn) sb.append(" off"); sb.append(";\n"); } }
private void setSymmetry(boolean setOperators) { double[][] a; // Part 1: Get sigma_nu // van Smaalen, p. 92. Logger.info("[subsystem " + code + "]"); Matrix winv = w.inverse(); Logger.info("w=" + w); Logger.info("w_inv=" + winv); // w33 w3d van Smaalen, p. 94, Eqn. 4.15 // w = // wd3 wdd Matrix w33 = w.getSubmatrix(0, 0, 3, 3); Matrix wd3 = w.getSubmatrix(3, 0, d, 3); Matrix w3d = w.getSubmatrix(0, 3, 3, d); Matrix wdd = w.getSubmatrix(3, 3, d, d); Matrix sigma = msRdr.getSigma(); // Eqn. 4.16 Matrix sigma_nu = wdd.mul(sigma).add(wd3).mul(w3d.mul(sigma).add(w33).inverse()); Matrix tFactor = wdd.sub(sigma_nu.mul(w3d)); Logger.info("sigma_nu = " + sigma_nu); // Part 2: Get the new unit cell and symmetry operators SymmetryInterface s0 = msRdr.cr.asc.getSymmetry(); V3[] vu43 = s0.getUnitCellVectors(); V3[] vr43 = reciprocalsOf(vu43); // using full matrix math here: // // mar3 = just 3x3 matrix of ai* (a*, b*, c*) // mard3 = full (3+d)x3 matrix of ai* (a*, b*, c*, x4*, x5*,....) // = [ mard3 | sigma * mard3 ] // Matrix mard3 = new Matrix(null, 3 + d, 3); Matrix mar3 = new Matrix(null, 3, 3); double[][] mard3a = mard3.getArray(); double[][] mar3a = mar3.getArray(); for (int i = 0; i < 3; i++) mard3a[i] = mar3a[i] = new double[] {vr43[i + 1].x, vr43[i + 1].y, vr43[i + 1].z}; Matrix sx = sigma.mul(mar3); a = sx.getArray(); for (int i = 0; i < d; i++) mard3a[i + 3] = a[i]; a = w.mul(mard3).getArray(); // back to vector notation and direct lattice V3[] uc_nu = new V3[4]; uc_nu[0] = vu43[0]; // origin for (int i = 0; i < 3; i++) uc_nu[i + 1] = V3.new3((float) a[i][0], (float) a[i][1], (float) a[i][2]); uc_nu = reciprocalsOf(uc_nu); symmetry = ((Symmetry) msRdr.cr.getInterface("org.jmol.symmetry.Symmetry")) .getUnitCell(uc_nu, false, null); modMatrices = new Matrix[] {sigma_nu, tFactor}; if (!setOperators) return; isFinalized = true; // Part 3: Transform the operators // Logger.info("unit cell parameters: " + symmetry.getUnitCellInfo()); symmetry.createSpaceGroup(-1, "[subsystem " + code + "]", new Lst<M4>()); int nOps = s0.getSpaceGroupOperationCount(); for (int iop = 0; iop < nOps; iop++) { Matrix rv = s0.getOperationRsVs(iop); Matrix r0 = rv.getRotation(); Matrix v0 = rv.getTranslation(); Matrix r = w.mul(r0).mul(winv); Matrix v = w.mul(v0); String code = this.code; if (isMixed(r)) { // This operator mixes x4,x5... into x1,x2,x3. // It is not a pure operation. Instead, it correlates one // subsystem with another. Our job is to find the other // subsystem "j" that will satisfy the following condition: // // (Wj R Wi_inv).submatrix(0,3,3,d) == all_zeros // for (Entry<String, Subsystem> e : msRdr.htSubsystems.entrySet()) { Subsystem ss = e.getValue(); if (ss == this) continue; Matrix rj = ss.w.mul(r0).mul(winv); if (!isMixed(rj)) { // We have found the corresponding subsystem. // The result of this operation will be in other system, // and the operation itself will be used to rotate the modulation. // ss.code will be used to mark any atom created by this operation as // part of the other system. r = rj; v = ss.w.mul(v0); code = ss.code; break; } } } String jf = symmetry.addOp(code, r, v, sigma_nu); Logger.info( this.code + "." + (iop + 1) + (this.code.equals(code) ? " " : ">" + code + " ") + jf); } }
/** * Cartoon meshes are triangulated objects. * * @param i * @param madBeg * @param madMid * @param madEnd * @param aspectRatio * @param tension * @return true if deferred rendering is required due to normals averaging */ private boolean createMesh( int i, int madBeg, int madMid, int madEnd, float aspectRatio, int tension) { setNeighbors(i); if (controlPoints[i].distanceSquared(controlPoints[iNext]) == 0) return false; // options: // isEccentric == not just a tube boolean isEccentric = (aspectRatio != 1 && wingVectors != null); // isFlatMesh == using mesh even for hermiteLevel = 0 (for exporters) boolean isFlatMesh = (aspectRatio == 0); // isElliptical == newer cartoonFancy business boolean isElliptical = (cartoonsFancy || hermiteLevel >= 6); // parameters: int nHermites = (hermiteLevel + 1) * 2 + 1; // 5 for hermiteLevel = 1; 13 for hermitelevel 5 int nPer = (isFlatMesh ? 4 : (hermiteLevel + 1) * 4 - 2); // 6 for hermiteLevel 1; 22 for hermiteLevel 5 float angle = (float) ((isFlatMesh ? Math.PI / (nPer - 1) : 2 * Math.PI / nPer)); Mesh mesh = meshes[i] = new Mesh().mesh1("mesh_" + shapeID + "_" + i, (short) 0, i); boolean variableRadius = (madBeg != madMid || madMid != madEnd); // control points and vectors: if (controlHermites == null || controlHermites.length < nHermites + 1) { controlHermites = new P3[nHermites + 1]; } GData.getHermiteList( tension, controlPoints[iPrev], controlPoints[i], controlPoints[iNext], controlPoints[iNext2], controlPoints[iNext3], controlHermites, 0, nHermites, true); // wing hermites determine the orientation of the cartoon if (wingHermites == null || wingHermites.length < nHermites + 1) { wingHermites = new V3[nHermites + 1]; } wing.setT(wingVectors[iPrev]); if (madEnd == 0) wing.scale(2.0f); // adds a flair to an arrow GData.getHermiteList( tension, wing, wingVectors[i], wingVectors[iNext], wingVectors[iNext2], wingVectors[iNext3], wingHermites, 0, nHermites, false); // } // radius hermites determine the thickness of the cartoon float radius1 = madBeg / 2000f; float radius2 = madMid / 2000f; float radius3 = madEnd / 2000f; if (variableRadius) { if (radiusHermites == null || radiusHermites.length < ((nHermites + 1) >> 1) + 1) { radiusHermites = new P3[((nHermites + 1) >> 1) + 1]; } ptPrev.set(radius1, radius1, 0); pt.set(radius1, radius2, 0); pt1.set(radius2, radius3, 0); ptNext.set(radius3, radius3, 0); // two for the price of one! GData.getHermiteList( 4, ptPrev, pt, pt1, ptNext, ptNext, radiusHermites, 0, (nHermites + 1) >> 1, true); } // now create the cartoon polygon int nPoints = 0; int iMid = nHermites >> 1; int kpt1 = (nPer + 2) / 4; int kpt2 = (3 * nPer + 2) / 4; int mode = (!isEccentric ? MODE_TUBE : isFlatMesh ? MODE_FLAT : isElliptical ? MODE_ELLIPTICAL : MODE_NONELLIPTICAL); boolean useMat = (mode == MODE_TUBE || mode == MODE_NONELLIPTICAL); for (int p = 0; p < nHermites; p++) { norm.sub2(controlHermites[p + 1], controlHermites[p]); float scale = (!variableRadius ? radius1 : p < iMid ? radiusHermites[p].x : radiusHermites[p - iMid].y); wing.setT(wingHermites[p]); wing1.setT(wing); switch (mode) { case MODE_FLAT: // hermiteLevel = 0 and not exporting break; case MODE_ELLIPTICAL: // cartoonFancy wing1.cross(norm, wing); wing1.normalize(); wing1.scale(wing.length() / aspectRatio); break; case MODE_NONELLIPTICAL: // older nonelliptical hermiteLevel > 0 wing.scale(2 / aspectRatio); wing1.sub(wing); break; case MODE_TUBE: // not helix or sheet wing.cross(wing, norm); wing.normalize(); break; } wing.scale(scale); wing1.scale(scale); if (useMat) { aa.setVA(norm, angle); mat.setAA(aa); } pt1.setT(controlHermites[p]); float theta = (isFlatMesh ? 0 : angle); for (int k = 0; k < nPer; k++, theta += angle) { if (useMat && k > 0) mat.rotate(wing); switch (mode) { case MODE_FLAT: wingT.setT(wing1); wingT.scale((float) Math.cos(theta)); break; case MODE_ELLIPTICAL: wingT.setT(wing1); wingT.scale((float) Math.sin(theta)); wingT.scaleAdd2((float) Math.cos(theta), wing, wingT); break; case MODE_NONELLIPTICAL: wingT.setT(wing); if (k == kpt1 || k == kpt2) wing1.scale(-1); wingT.add(wing1); break; case MODE_TUBE: wingT.setT(wing); break; } pt.add2(pt1, wingT); mesh.addV(pt, true); } if (p > 0) { int nLast = (isFlatMesh ? nPer - 1 : nPer); for (int k = 0; k < nLast; k++) { // draw the triangles of opposing quads congruent, so they won't clip // esp. for high ribbonAspectRatio values int a = nPoints - nPer + k; int b = nPoints - nPer + ((k + 1) % nPer); int c = nPoints + ((k + 1) % nPer); int d = nPoints + k; if (k < nLast / 2) mesh.addQuad(a, b, c, d); else mesh.addQuad(b, c, d, a); } } nPoints += nPer; } if (!isFlatMesh) { int nPointsPreCap = nPoints; // copying vertices here so that the caps are not connected to the rest of // the mesh preventing light leaking around the sharp edges if (doCap0) { for (int l = 0; l < nPer; l++) mesh.addV(mesh.vs[l], true); nPoints += nPer; for (int k = hermiteLevel * 2; --k >= 0; ) mesh.addQuad( nPoints - nPer + k + 2, nPoints - nPer + k + 1, nPoints - nPer + (nPer - k) % nPer, nPoints - k - 1); } if (doCap1) { for (int l = 0; l < nPer; l++) mesh.addV(mesh.vs[nPointsPreCap - nPer + l], true); nPoints += nPer; for (int k = hermiteLevel * 2; --k >= 0; ) mesh.addQuad( nPoints - k - 1, nPoints - nPer + (nPer - k) % nPer, nPoints - nPer + k + 1, nPoints - nPer + k + 2); } } meshReady[i] = true; adjustCartoonSeamNormals(i, nPer); mesh.setVisibilityFlags(1); return true; }