/* * This file is part of MoleculeViewer. * * MoleculeViewer is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MoleculeViewer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with MoleculeViewer. If not, see <http://www.gnu.org/licenses/>. */ package astex; import java.util.List; /** * Class for generating various sorts of texture coordinates. */ public class Texgen { /** * Measure distance to nearest point in point list. * Texture coordinates are normalised by dividing by max. * This will make points further away than max invisible. * * If max is less than zero, then the tex coords are * normalised by the longest distance measured. * This has the effect that the tex coords will max at 1.0. */ public static void distance(Tmesh tm, List<Atom> points, int uv){ int tnp = tm.np; float tlocal[] = null; double dmax = 0.0; if(uv == Tmesh.UTexture){ tlocal = tm.u; }else if(uv == Tmesh.VTexture){ tlocal = tm.v; }else{ System.out.println("Texgen.distance: " + "invalid texture coordinate " + uv); return; } for(int i = 0; i < tnp; i++){ double tx = tm.x[i]; double ty = tm.y[i]; double tz = tm.z[i]; double dmin = 1.e10; for(Point3d p : points){ double dx = tx - p.x; double dy = ty - p.y; double dz = tz - p.z; double d2 = dx*dx + dy*dy + dz*dz; if(d2 < dmin){ dmin = d2; } } double d = Math.sqrt(dmin); if(d > dmax){ dmax = d; } tlocal[i] = (float)d; } if(Math.abs(dmax) > 1.e-3){ if(uv == Tmesh.UTexture){ tm.setUOffset(0.0); tm.setUScale(1./dmax); }else if(uv == Tmesh.VTexture){ tm.setVOffset(0.0); tm.setVScale(1./dmax); } }else{ Log.error("dmax was zero"); } } /** Calculate pseudo curvature. */ public static void curvature(Tmesh tm, List<Atom> points, int uv, double maxd){ int tnp = tm.np; float tlocal[] = null; double maxd2 = maxd*maxd; double min = 1.e10; double max = 0.0; if(uv == Tmesh.UTexture){ tlocal = tm.u; }else if(uv == Tmesh.VTexture){ tlocal = tm.v; }else{ System.out.println("Texgen.distance: " + "invalid texture coordinate " + uv); return; } for(int i = 0; i < tnp; i++){ double tx = tm.x[i]; double ty = tm.y[i]; double tz = tm.z[i]; double dtotal = 0.0; for(Point3d p : points){ double dx = tx - p.x; double dy = ty - p.y; double dz = tz - p.z; double d2 = dx*dx + dy*dy + dz*dz; if(d2 < maxd2){ d2 = Math.sqrt(d2); dtotal += (maxd - d2); } } tlocal[i] = (float)dtotal; if(dtotal > max){ max = dtotal; } if(dtotal < min){ min = dtotal; } } for(int i = 0; i < tnp; i++){ tlocal[i] = (float)((tlocal[i] - min)/(max - min)); } } /** Create rectangular texture coordinates. */ public static void rectangular(Tmesh tm){ int tnp = tm.np; double xmin = 1.e10; double xmax = -1.e10; double ymin = 1.e10; double ymax = -1.e10; for(int i = 0; i < tnp; i++){ if(tm.x[i] < xmin) xmin = tm.x[i]; if(tm.x[i] > xmax) xmax = tm.x[i]; if(tm.y[i] < ymin) ymin = tm.y[i]; if(tm.y[i] > ymax) ymax = tm.y[i]; } double dx = xmax - xmin; double dy = ymax - ymin; for(int i = 0; i < tnp; i++){ tm.u[i] = (float)((tm.x[i] - xmin)/dx); tm.v[i] = (float)((ymax - tm.y[i])/dy); } } private static double x[] = null; private static double y[] = null; private static double z[] = null; private static double q[] = null; public enum MapFunc { Electrostatic, Lipophilicity } /** Generate potential. */ public static synchronized void property_map(Tmesh tm, List<Atom> atoms, int uv, double maxd, boolean absolute, MapFunc func){ int atomCount = atoms.size(); float tlocal[] = null; double min = 1.0e10; double max = -1.0e10; double maxd2 = maxd * maxd; double halfWidth = 1.; double dCutoff = 3.0; double topPart = Math.exp(-halfWidth * dCutoff) + 1.0; if(uv == Tmesh.UTexture){ tlocal = tm.u; }else if(uv == Tmesh.VTexture){ tlocal = tm.v; } int arraySize = atomCount * 2; if(x == null || x.length < arraySize){ x = new double[arraySize]; y = new double[arraySize]; z = new double[arraySize]; q = new double[arraySize]; } int na = 0; int amideProtons = 0; for(Atom a : atoms){ String name = a.getAtomLabel(); if(func == MapFunc.Electrostatic && "N".equals(name)){ Point3d nh = getAmideHydrogen(a); // nh will be null if we already had an nh if(nh != null){ x[na] = nh.x; y[na] = nh.y; z[na] = nh.z; // this is the charmm19 value of // the amide proton charge. // should be customisable somehow... q[na] = +0.25; na++; amideProtons++; } } // get the property value... double qa = a.getPartialCharge(); // scale charge by occupancy // to allow for multiple positions. if(func == MapFunc.Electrostatic){ qa *= a.getOccupancy(); } // only considering atoms with non-zero charge if(Math.abs(qa) > 1.e-3){ x[na] = a.x; y[na] = a.y; z[na] = a.z; q[na] = qa; na++; } } // build the lattice Lattice l = new Lattice(maxd); for(int ia = 0; ia < na; ia++){ l.add(ia, x[ia], y[ia], z[ia]); } if(func == MapFunc.Electrostatic){ System.out.println("added " + amideProtons + " amide protons"); } double totalCharge = 0.0; for(int i = 0; i < na; i++){ totalCharge += q[i]; } int tnp = tm.np; for(int i = 0; i < tnp; i++){ double tx = tm.x[i]; double ty = tm.y[i]; double tz = tm.z[i]; double dtotal = 0.0; double norm = 0.0; for(int j = 0; j < na; j++){ double dx = tx - x[j]; double dy = ty - y[j]; double dz = tz - z[j]; double d2 = dx*dx + dy*dy + dz*dz; if(d2 < maxd2){ if(func == MapFunc.Electrostatic){ dtotal += q[j]/d2; }else if(func == MapFunc.Lipophilicity){ double d = Math.sqrt(d2); double gd = topPart / (Math.exp(halfWidth * (d - dCutoff)) + 1.0); dtotal += q[j] * gd; norm += gd; } } } if(func == MapFunc.Lipophilicity){ dtotal /= norm; } tlocal[i] = (float)dtotal; if(dtotal > max){ max = dtotal; } if(dtotal < min){ min = dtotal; } } FILE.out.print("property min %.3f ", min); FILE.out.print("max %.3f\n", max); if(uv == Tmesh.UTexture){ if(func == MapFunc.Lipophilicity){ tm.setUOffset(min); tm.setUScale(1.0/(max - min)); }else{ tm.setUOffset(-0.5); } }else{ if(func == MapFunc.Lipophilicity){ tm.setVOffset(min); tm.setVScale(1.0/(max - min)); }else{ tm.setVOffset(-0.5); } } } /** Generate an amide hydrogen position. */ private static Point3d getAmideHydrogen(Atom N){ if(N == null){ return null; } Atom H = N.getBondedAtom("H"); if(H != null){ return null; } Atom CA = N.getBondedAtom("CA"); Atom C = N.getBondedAtom("C"); if(N == null || CA == null || C == null){ return null; } Point3d hpos = new Point3d(); hpos.set(N); hpos.sub(C); hpos.add(N); hpos.sub(CA); hpos.normalize(); hpos.scale(1.04); hpos.add(N); return hpos; } }