1 /****************************************************************************
2 * MeshLab                                                           o o     *
3 * An extendible mesh processor                                    o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2005, 2006                                          \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program is free software; you can redistribute it and/or modify      *
12 * it under the terms of the GNU General Public License as published by      *
13 * the Free Software Foundation; either version 2 of the License, or         *
14 * (at your option) any later version.                                       *
15 *                                                                           *
16 * This program is distributed in the hope that it will be useful,           *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 
24 #include <Qt>
25 
26 #include "io_pdb.h"
27 
28 #include <wrap/io_trimesh/import_ply.h>
29 
30 #include <wrap/io_trimesh/export_ply.h>
31 #include <wrap/io_trimesh/export.h>
32 
33 
34 #include <vcg/complex/append.h>
35 #include <vcg/complex/algorithms/create/platonic.h>
36 #include <vcg/complex/algorithms/create/marching_cubes.h>
37 #include <vcg/complex/algorithms/create/mc_trivial_walker.h>
38 
39 #include <QMessageBox>
40 #include <QFileDialog>
41 
42 using namespace std;
43 using namespace vcg;
44 typedef vcg::SimpleVoxel<MESHLAB_SCALAR> SimpleVoxelm;
45 // initialize importing parameters
initPreOpenParameter(const QString & formatName,const QString &,RichParameterSet & parlst)46 void PDBIOPlugin::initPreOpenParameter(const QString &formatName, const QString &/*filename*/, RichParameterSet &parlst)
47 {
48 	if (formatName.toUpper() == tr("PDB"))
49 	{
50 		parlst.addParam(new RichBool("usecolors",true,"Use Atoms colors","Atoms are colored according to atomic type"));
51 		parlst.addParam(new RichBool("justpoints",false,"SURFACE: Atoms as Points","Atoms are created as points, no surface is built. Overrides all subsequential surface parameters"));
52 		parlst.addParam(new RichBool("justspheres",true,"SURFACE: Atoms as Spheres","Atoms are created as intersecting spheres, no interpolation surface is built. Overrides all subsequential surface parameters"));
53 		parlst.addParam(new RichBool("interpspheres",false,"SURFACE: Atoms as Jointed Spheres","Atoms are created as spheres, joining surface is built. Overrides all subsequential surface parameters"));
54 		parlst.addParam(new RichBool("metaballs",false,"SURFACE: Atoms as Metaballs","Atoms are created as blobby interpolation surface, refer to BLINN Metaballs article. Overrides all subsequential surface parameters"));
55 		parlst.addParam(new RichFloat("voxelsize",0.25,"Surface Resolution","is used by Jointed Spheres and Metaball"));
56 		parlst.addParam(new RichFloat("blobby",2.0,"Blobbyness factor","is used by Metaball"));
57 		/*
58 		parlst.addParam(new RichInt("meshindex",0,"Index of Range Map to be Imported","PTX files may contain more than one range map. 0 is the first range map. If the number if higher than the actual mesh number, the import will fail");
59 		parlst.addParam(new RichBool("anglecull",true,"Cull faces by angle","short");
60 		parlst.addParam(new RichFloat("angle",85.0,"Angle limit for face culling","short");
61 		parlst.addParam(new RichBool("usecolor",true,"import color","Read color from PTX, if color is not present, uses reflectance instead");
62 		parlst.addParam(new RichBool("pointcull",true,"delete unsampled points","Deletes unsampled points in the grid that are normally located in [0,0,0]");
63 		parlst.addParam(new RichBool("pointsonly",false,"Keep only points","Just import points, without triangulation");
64 		parlst.addParam(new RichBool("switchside",false,"Swap rows/columns","On some PTX, the rows and columns number are switched over");
65 		parlst.addParam(new RichBool("flipfaces",false,"Flip all faces","Flip the orientation of all the triangles");
66 		*/
67 	}
68 }
69 
open(const QString & formatName,const QString & fileName,MeshModel & m,int & mask,const RichParameterSet & parlst,CallBackPos * cb,QWidget *)70 bool PDBIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterSet &parlst, CallBackPos *cb, QWidget * /*parent*/)
71 {
72 	//bool normalsUpdated = false;
73 
74 	// initializing mask
75 	mask = 0;
76 
77 	// initializing progress bar status
78 	if (cb != NULL)		(*cb)(0, "Loading...");
79 
80 	QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2";
81 
82 	//string filename = fileName.toUtf8().data();
83 	string filename = QFile::encodeName(fileName).constData ();
84 
85   if (formatName.toUpper() == tr("PDB"))
86 	{
87 
88 		mask |= vcg::tri::io::Mask::IOM_VERTCOLOR;
89 		m.Enable(mask);
90 
91 		return parsePDB(qUtf8Printable(fileName), m.cm, parlst, cb);
92 
93 
94 		/*
95 		tri::io::ImporterPTX<CMeshO>::Info importparams;
96 
97 		importparams.meshnum = parlst.getInt("meshindex");
98 		importparams.anglecull =parlst.getBool("anglecull");
99 		importparams.angle = parlst.getFloat("angle");
100 		importparams.savecolor = parlst.getBool("usecolor");
101 		importparams.pointcull = parlst.getBool("pointcull");
102 		importparams.pointsonly = parlst.getBool("pointsonly");
103 		importparams.switchside = parlst.getBool("switchside");
104 		importparams.flipfaces = parlst.getBool("flipfaces");
105 
106 		// if color, add to mesh
107 		if(importparams.savecolor)
108 			importparams.mask |= tri::io::Mask::IOM_VERTCOLOR;
109 
110 		// reflectance is stored in quality
111 		importparams.mask |= tri::io::Mask::IOM_VERTQUALITY;
112 
113 		m.Enable(importparams.mask);
114 
115 		int result = tri::io::ImporterPTX<CMeshO>::Open(m.cm, filename.c_str(), importparams, cb);
116 		if (result == 1)
117 		{
118 			errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterPTX<CMeshO>::ErrorMsg(result));
119 			return false;
120 		}
121 
122 		// update mask
123 		mask = importparams.mask;
124 		*/
125 	}
126 	else
127 	{
128 		assert(0); // Unknown File type
129 		return false;
130 	}
131 
132 	if (cb != NULL)	(*cb)(99, "Done");
133 
134 	return true;
135 }
136 
save(const QString &,const QString &,MeshModel &,const int,const RichParameterSet &,CallBackPos *,QWidget *)137 bool PDBIOPlugin::save(const QString & /*formatName*/,const QString & /*fileName*/, MeshModel & /*m*/, const int /*mask*/, const RichParameterSet & /*par*/, CallBackPos * /*cb*/, QWidget * /*parent*/)
138 {
139   assert(0);
140 	return false;
141 }
142 
143 /*
144 	returns the list of the file's type which can be imported
145 */
importFormats() const146 QList<MeshIOInterface::Format> PDBIOPlugin::importFormats() const
147 {
148 	QList<Format> formatList;
149 	formatList << Format("Protein Data Bank"	, tr("PDB"));
150 
151 	return formatList;
152 }
153 
154 /*
155 	returns the list of the file's type which can be exported
156 */
exportFormats() const157 QList<MeshIOInterface::Format> PDBIOPlugin::exportFormats() const
158 {
159 	QList<Format> formatList;
160 //	formatList << Format("Stanford Polygon File Format"	, tr("PLY"));
161 
162 	return formatList;
163 }
164 
165 /*
166 	returns the mask on the basis of the file's type.
167 	otherwise it returns 0 if the file format is unknown
168 */
GetExportMaskCapability(QString &,int & capability,int & defaultBits) const169 void PDBIOPlugin::GetExportMaskCapability(QString & /*format*/, int &capability, int &defaultBits) const
170 {
171   capability=defaultBits=0;
172 	return;
173 }
174 
initOpenParameter(const QString &,MeshModel &,RichParameterSet &)175 void PDBIOPlugin::initOpenParameter(const QString & /*format*/, MeshModel &/*m*/, RichParameterSet & /*par*/)
176 {
177 	/*
178 	if(format.toUpper() == tr("STL"))
179 		par.addBool("Unify",true, "Unify Duplicated Vertices",
180 								"The STL format is not an vertex-indexed format. Each triangle is composed by independent vertices, so, usually, duplicated vertices should be unified");
181 	*/
182 }
initSaveParameter(const QString &,MeshModel &,RichParameterSet &)183 void PDBIOPlugin::initSaveParameter(const QString & /*format*/, MeshModel &/*m*/, RichParameterSet & /*par*/)
184 {
185 	/*
186 	if(format.toUpper() == tr("STL") || format.toUpper() == tr("PLY"))
187 		par.addBool("Binary",true, "Binary encoding",
188 								"Save the mesh using a binary encoding. If false the mesh is saved in a plain, readable ascii format");
189   */
190 }
applyOpenParameter(const QString &,MeshModel &,const RichParameterSet &)191 void PDBIOPlugin::applyOpenParameter(const QString & /*format*/, MeshModel & /*m*/, const RichParameterSet & /*par*/)
192 {
193   /*
194 	if(format.toUpper() == tr("STL"))
195 		if(par.getBool("Unify"))
196 			tri::Clean<CMeshO>::RemoveDuplicateVertex(m.cm);
197 	*/
198 }
199 
MESHLAB_PLUGIN_NAME_EXPORTER(PDBIOPlugin)200 MESHLAB_PLUGIN_NAME_EXPORTER(PDBIOPlugin)
201 
202 
203 //---------- PDB READER -----------//
204 bool PDBIOPlugin::parsePDB(const std::string &filename, CMeshO &m, const RichParameterSet &parlst, CallBackPos *cb)
205 {
206 	size_t atomNumber=0;
207 	bool surfacecreated = false;
208 
209   FILE *fp = fopen(filename.c_str(), "rb");
210   if (!fp) {
211 		return false;
212   }
213 
214 	//-- clear all molecule data
215 	atomDetails.clear();
216 	atomPos.clear();
217 	atomCol.clear();
218 	atomRad.clear();
219 
220 	//-- read all lines, if the line contains  ATOM, then store the details for parsing
221 	char buf[82];
222   buf[81]=0;
223 
224 	while(1)
225 	{
226 		if(! fgets(buf,81,fp)) break;
227 		string st(buf);
228 		if (strcmp( st.substr(0,6).c_str(), "ATOM  ") == 0 )
229 		{
230 			atomDetails.push_back(st);
231 			atomNumber++;
232 		}
233   }
234 
235 	// updating progress bar status
236 	char msgbuf[256];
237 	sprintf(msgbuf,"Read %zu atoms...",atomNumber);
238 	if (cb != NULL)		(*cb)(10, "Loading...");
239 
240 	//-- atoms parsing
241 	for(size_t atomIndex=0; atomIndex<atomDetails.size(); atomIndex++)
242 	{
243 		Point3m currAtomPos;
244 		Color4b currAtomCol;
245 		float   currAtomRad;
246 
247 		// position
248 		mysscanf(atomDetails[atomIndex].substr( 31, 38).c_str(), &(currAtomPos.X()));
249 		mysscanf(atomDetails[atomIndex].substr( 39, 46).c_str(), &(currAtomPos.Y()));
250 		mysscanf(atomDetails[atomIndex].substr( 47, 54).c_str(), &(currAtomPos.Z()));
251 		atomPos.push_back(currAtomPos);
252 
253 		// color
254 		currAtomCol=getAtomColor(atomDetails[atomIndex].substr(13, 4).c_str());
255 		atomCol.push_back(currAtomCol);
256 
257 		// radius
258 		currAtomRad=getAtomRadius(atomDetails[atomIndex].substr(13, 4).c_str()); //  Van der Waals radii
259 		atomRad.push_back(currAtomRad);
260 	}
261 
262 	// build mesh
263 
264 	if(parlst.getBool("justpoints") && !surfacecreated)  	// pointcloud
265 	{
266 		tri::Allocator<CMeshO>::AddVertices(m,atomNumber);
267 
268 		for (size_t atomIndex = 0; atomIndex < atomNumber; ++atomIndex)
269 		{
270 			m.vert[atomIndex].P()=atomPos[atomIndex];
271 			m.vert[atomIndex].C()=atomCol[atomIndex];
272 		}
273 
274 		surfacecreated = true;
275 	}
276 
277 	if(parlst.getBool("justspheres") && !surfacecreated)  	// spheres
278 	{
279 		CMeshO tmpmesh;
280 		tmpmesh.face.EnableFFAdjacency();
281 		vcg::tri::UpdateTopology<CMeshO>::FaceFace(tmpmesh);
282 
283 		for (size_t atomIndex = 0; atomIndex < atomNumber; ++atomIndex)
284 		{
285 				tmpmesh.Clear();
286 				vcg::tri::Sphere<CMeshO>(tmpmesh,1);
287 
288 				// scale, move and apply color
289 				for(int vi=0; vi<tmpmesh.vn; vi++)
290 				{
291 					tmpmesh.vert[vi].P().X() = (tmpmesh.vert[vi].P().X() * atomRad[atomIndex]) + atomPos[atomIndex].X();
292 					tmpmesh.vert[vi].P().Y() = (tmpmesh.vert[vi].P().Y() * atomRad[atomIndex]) + atomPos[atomIndex].Y();
293 					tmpmesh.vert[vi].P().Z() = (tmpmesh.vert[vi].P().Z() * atomRad[atomIndex]) + atomPos[atomIndex].Z();
294 
295 					tmpmesh.vert[vi].C() = atomCol[atomIndex];
296 				}
297 
298 				tri::Append<CMeshO,CMeshO>::Mesh(m,tmpmesh);
299 		}
300 		tmpmesh.Clear();
301 
302 		surfacecreated = true;
303 	}
304 
305 	if(parlst.getBool("interpspheres") && !surfacecreated)  	// jointed spheres marching cube
306 	{
307 		SimpleVolume<SimpleVoxelm> 	volume;
308 
309 		typedef vcg::tri::TrivialWalker<CMeshO, SimpleVolume<SimpleVoxelm> >	MyWalker;
310 		typedef vcg::tri::MarchingCubes<CMeshO, MyWalker>	MyMarchingCubes;
311 		MyWalker walker;
312 
313 		Box3m rbb;
314 		// calculating an enlarged bbox
315 		rbb.min[0]=rbb.min[1]=rbb.min[2]= 100000;
316 		rbb.max[0]=rbb.max[1]=rbb.max[2]=-100000;
317 		for (size_t atomIndex = 0; atomIndex < atomNumber; ++atomIndex)
318 		{
319 			if(atomPos[atomIndex].X() < rbb.min[0])			rbb.min[0]=atomPos[atomIndex].X();
320 			if(atomPos[atomIndex].X() > rbb.max[0])			rbb.max[0]=atomPos[atomIndex].X();
321 			if(atomPos[atomIndex].Y() < rbb.min[1])			rbb.min[1]=atomPos[atomIndex].Y();
322 			if(atomPos[atomIndex].Y() > rbb.max[1])			rbb.max[1]=atomPos[atomIndex].Y();
323 			if(atomPos[atomIndex].Z() < rbb.min[2])			rbb.min[2]=atomPos[atomIndex].Z();
324 			if(atomPos[atomIndex].Z() > rbb.max[2])			rbb.max[2]=atomPos[atomIndex].Z();
325 		}
326 		rbb.min[0]-=5;		rbb.min[1]-=5;		rbb.min[2]-=5;
327 		rbb.max[0]+=5;		rbb.max[1]+=5;		rbb.max[2]+=5;
328 
329 		// defining resolution
330 		double step = parlst.getFloat("voxelsize");
331 		Point3i siz= Point3i::Construct((rbb.max-rbb.min)*(1.0/step));
332 
333 		volume.Init(siz,rbb);
334 		float xpos,ypos,zpos;
335 		for(double i=0;i<siz[0];i++)
336 			for(double j=0;j<siz[1];j++)
337 				for(double k=0;k<siz[2];k++)
338 				{
339 					xpos = rbb.min[0]+step*i;
340 					ypos = rbb.min[1]+step*j;
341 					zpos = rbb.min[2]+step*k;
342 
343 					volume.Val(i,j,k)=10000;
344 					for (size_t atomIndex = 0; atomIndex < atomNumber; ++atomIndex)
345 					{
346 						if(! (fabs(xpos-atomPos[atomIndex].X())>3.0f) )
347 							if(! (fabs(ypos-atomPos[atomIndex].Y())>3.0f) )
348 								if(! (fabs(zpos-atomPos[atomIndex].Z())>3.0f) )
349 								{
350 									float val = pow((double)(xpos-atomPos[atomIndex].X()),2.0) +
351 															pow((double)(ypos-atomPos[atomIndex].Y()),2.0) +
352 														pow((double)(zpos-atomPos[atomIndex].Z()),2.0) - atomRad[atomIndex];
353 									if(val < volume.Val(i,j,k))
354 										volume.Val(i,j,k) = val;
355 								}
356 					}
357 				}
358 
359 		// MARCHING CUBES
360 		MyMarchingCubes	mc(m, walker);
361 		walker.BuildMesh<MyMarchingCubes>(m, volume, mc, 0);
362 		Matrix44m tr; tr.SetIdentity(); tr.SetTranslate(rbb.min[0],rbb.min[1],rbb.min[2]);
363 		Matrix44m sc; sc.SetIdentity(); sc.SetScale(step,step,step);
364 		tr=tr*sc;
365 
366 		tri::UpdatePosition<CMeshO>::Matrix(m,tr);
367 		tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m);
368 		tri::UpdateBounding<CMeshO>::Box(m);					// updates bounding box
369 
370 		surfacecreated = true;
371 	}
372 
373 
374 	if(parlst.getBool("metaballs") && !surfacecreated)  	// metaballs marching cube
375 	{
376 		SimpleVolume<SimpleVoxelm> 	volume;
377 
378 		typedef vcg::tri::TrivialWalker<CMeshO, SimpleVolume<SimpleVoxelm> >	MyWalker;
379 		typedef vcg::tri::MarchingCubes<CMeshO, MyWalker>	MyMarchingCubes;
380 		MyWalker walker;
381 
382 		Box3m rbb;
383 		// calculating an enlarged bbox
384 		rbb.min[0]=rbb.min[1]=rbb.min[2]= 100000;
385 		rbb.max[0]=rbb.max[1]=rbb.max[2]=-100000;
386 		for (size_t atomIndex = 0; atomIndex < atomNumber; ++atomIndex)
387 		{
388 			if(atomPos[atomIndex].X() < rbb.min[0])			rbb.min[0]=atomPos[atomIndex].X();
389 			if(atomPos[atomIndex].X() > rbb.max[0])			rbb.max[0]=atomPos[atomIndex].X();
390 			if(atomPos[atomIndex].Y() < rbb.min[1])			rbb.min[1]=atomPos[atomIndex].Y();
391 			if(atomPos[atomIndex].Y() > rbb.max[1])			rbb.max[1]=atomPos[atomIndex].Y();
392 			if(atomPos[atomIndex].Z() < rbb.min[2])			rbb.min[2]=atomPos[atomIndex].Z();
393 			if(atomPos[atomIndex].Z() > rbb.max[2])			rbb.max[2]=atomPos[atomIndex].Z();
394 		}
395 		rbb.min[0]-=5;		rbb.min[1]-=5;		rbb.min[2]-=5;
396 		rbb.max[0]+=5;		rbb.max[1]+=5;		rbb.max[2]+=5;
397 
398 		// defining resolution
399 		double step = parlst.getFloat("voxelsize");
400 		float blobby = -parlst.getFloat("blobby");
401 		Point3i siz= Point3i::Construct((rbb.max-rbb.min)*(1.0/step));
402 
403 
404 //	Log("Filling a Volume of %i %i %i",siz[0],siz[1],siz[2]);
405 		volume.Init(siz,rbb);
406 		float xpos,ypos,zpos;
407 		for(double i=0;i<siz[0];i++)
408 			for(double j=0;j<siz[1];j++)
409 				for(double k=0;k<siz[2];k++)
410 				{
411 					xpos = rbb.min[0]+step*i;
412 					ypos = rbb.min[1]+step*j;
413 					zpos = rbb.min[2]+step*k;
414 
415 					volume.Val(i,j,k)=0.0;
416 					for (size_t atomIndex = 0; atomIndex < atomNumber; ++atomIndex)
417 					{
418 						if(! (fabs(xpos-atomPos[atomIndex].X())>5.0f) )
419 							if(! (fabs(ypos-atomPos[atomIndex].Y())>5.0f) )
420 								if(! (fabs(zpos-atomPos[atomIndex].Z())>5.0f) )
421 								{
422 									float r2 = (pow((double)(xpos-atomPos[atomIndex].X()),2.0) +
423 														  pow((double)(ypos-atomPos[atomIndex].Y()),2.0) +
424 													  pow((double)(zpos-atomPos[atomIndex].Z()),2.0));
425 									float val = exp((blobby/atomRad[atomIndex])*r2 - blobby);
426 
427 									volume.Val(i,j,k) += val;
428 								}
429 					}
430 				}
431 
432 		// MARCHING CUBES
433 		MyMarchingCubes	mc(m, walker);
434 		walker.BuildMesh<MyMarchingCubes>(m, volume, mc, 1);
435 		Matrix44m tr; tr.SetIdentity(); tr.SetTranslate(rbb.min[0],rbb.min[1],rbb.min[2]);
436 		Matrix44m sc; sc.SetIdentity(); sc.SetScale(step,step,step);
437 		tr=tr*sc;
438 
439 		//tri::io::ExporterPLY<CMeshO>::Save(m,"./pippo.ply");
440 
441 		tri::UpdatePosition<CMeshO>::Matrix(m,tr);
442 		tri::Clean<CMeshO>::FlipMesh(m);
443 		tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m);
444 		tri::UpdateBounding<CMeshO>::Box(m);					// updates bounding box
445 
446 		//------------------------------------------------
447 
448 		double ww;
449 		double rr;
450 		double gg;
451 		double bb;
452 		for(int vind=0; vind<m.vn ; vind++)
453 		{
454 			xpos = m.vert[vind].P().X();
455 			ypos = m.vert[vind].P().Y();
456 			zpos = m.vert[vind].P().Z();
457 			ww=rr=gg=bb=0;
458 
459 			for (size_t atomIndex = 0; atomIndex < atomNumber; ++atomIndex)
460 			{
461 				if(! (fabs(xpos-atomPos[atomIndex].X())>5.0f) )
462 				{
463 					if(! (fabs(ypos-atomPos[atomIndex].Y())>5.0f) )
464 					{
465 						if(! (fabs(zpos-atomPos[atomIndex].Z())>5.0f) )
466 						{
467 							float r2 = (pow((double)(xpos-atomPos[atomIndex].X()),2.0) +
468 												  pow((double)(ypos-atomPos[atomIndex].Y()),2.0) +
469 								    		  pow((double)(zpos-atomPos[atomIndex].Z()),2.0));
470 							r2 = r2 / atomRad[atomIndex];
471 							r2 = min(2.0f,r2);
472 
473 							ww += r2;
474 							rr += r2 * atomCol[atomIndex].X();
475 							gg += r2 * atomCol[atomIndex].Y();
476 							bb += r2 * atomCol[atomIndex].Z();
477 
478 						}
479 					}
480 				}
481 
482 				m.vert[vind].C().X() = rr/ww;
483 				m.vert[vind].C().Y() = gg/ww;
484 				m.vert[vind].C().Z() = bb/ww;
485 			}
486 
487 
488 		}
489 
490 		//------------------------------------------------
491 
492 		surfacecreated = true;
493 	}
494 
495 
496 	//-- ending all
497 	if (cb != NULL)	(*cb)(99, "Done");
498 
499 	//-- finish by clearing all molecule data
500 	atomDetails.clear();
501 	atomPos.clear();
502 	atomCol.clear();
503 	atomRad.clear();
504 
505 	// closing file
506 	fclose(fp);
507 
508 	return surfacecreated;
509 }
510 
511 
512 //-- helper function... parses + and - values with space
mysscanf(const char * st,float * f)513 void PDBIOPlugin::mysscanf(const char* st, float *f)
514 {
515   if (!sscanf( st, "%f", f)) {
516     if (sscanf( st, " - %f", f))
517     *f=-*f;
518     else  *f=0.0;
519   };
520 }
521 
mysscanf(const char * st,double * f)522 void PDBIOPlugin::mysscanf(const char* st, double *f)
523 {
524     if (!sscanf( st, "%lf", f)) {
525         if (sscanf( st, " - %lf", f))
526             *f=-*f;
527         else  *f=0.0;
528     };
529 }
530 
531 
532 //-- returns the correct radius for each atom type
getAtomRadius(const char * atomicElementCharP)533 float PDBIOPlugin::getAtomRadius(const char* atomicElementCharP)
534 {
535   static std::map<std::string,float> E2R;
536   if(E2R.size()==0)
537   {
538     // according to http://www.imb-jena.de/ImgLibDoc/glossary/IMAGE_VDWR.html
539     //E2R["H"]=  	1.20f;
540     //E2R["C"]= 	1.70f;
541     //E2R["N"]= 	1.55f;
542     //E2R["O"]= 	1.52f;
543     //E2R["F"]= 	1.47f;
544     //E2R["P"]= 	1.80f;
545     //E2R["S"]= 	1.80f;
546     //E2R["CL"]= 	1.89f;
547 
548     /// according to http://www.umass.edu/microbio/rasmol/rasbonds.htm
549     E2R["H"]=   1.100f;
550     E2R["C"]=   1.400f;//1.548f;
551     E2R["N"]=   1.400f;
552     E2R["O"]=   1.348f;
553     E2R["P"]=   1.880f;
554     E2R["S"]= 	1.808f;
555     E2R["CA"]= 	1.948f;
556     E2R["FE"]= 	1.948f;
557     E2R["ZN"]= 	1.148f;
558     E2R["CD"]= 	1.748f;
559     E2R["I"]= 	1.748f;
560   }
561   std::string ss0,ss1;
562   string atomicElement(atomicElementCharP);
563   ss0=atomicElement.substr(0,1);
564   ss1=atomicElement.substr(0,2);
565   float rad=E2R[ss1];
566   if(rad==0) rad = E2R[ss0];
567   if(rad==0) rad=1;
568   return rad;
569 }
570 
getAtomColor(const char * atomicElementCharP)571 vcg::Color4b PDBIOPlugin::getAtomColor(const char* atomicElementCharP)
572 {
573 	string atomicElement(atomicElementCharP);
574   static std::map<std::string,vcg::Color4b> E2C;
575 
576 	if(E2C.size()==0)
577 	{
578 		E2C["H"] = vcg::Color4b(255,255,255,255)  	/* 0xFFFFFF			*/  	;
579 		E2C["HE"]= vcg::Color4b(217,255,255,255)   	/* 0xD9FFFF			*/  	;
580 		E2C["LI"]= vcg::Color4b(204,128,255,255)   	/* 0xCC80FF			*/  	;
581 		E2C["BE"]= vcg::Color4b(194,255,  0,255)   	/* 0xC2FF00			*/  	;
582 		E2C["B"] = vcg::Color4b(255,181,181,255)   	/* 0xFFB5B5			*/  	;
583 		E2C["C"] = vcg::Color4b(144,144,144,255)   	/* 0x909090			*/  	;
584 		E2C["N"] = vcg::Color4b( 48, 80,248,255)   	/* 0x3050F8			*/  	;
585 		E2C["O"] = vcg::Color4b(255, 13, 13,255)   	/* 0xFF0D0D			*/  	;
586 		E2C["F"] = vcg::Color4b(144,224, 80,255)   	/* 0x90E050			*/  	;
587 		E2C["NE"]= vcg::Color4b(179,227,245,255)   	/* 0xB3E3F5			*/  	;
588 		E2C["NA"]= vcg::Color4b(171, 92,242,255)   	/* 0xAB5CF2			*/  	;
589 		E2C["MG"]= vcg::Color4b(138,255,  0,255)   	/* 0x8AFF00			*/  	;
590 		E2C["AL"]= vcg::Color4b(191,166,166,255)   	/* 0xBFA6A6			*/  	;
591 		E2C["SI"]= vcg::Color4b(240,200,160,255)   	/* 0xF0C8A0			*/  	;
592 		E2C["P"] = vcg::Color4b(255,128,  0,255)   	/* 0xFF8000			*/  	;
593 		E2C["S"] = vcg::Color4b(255,255, 48,255)   	/* 0xFFFF30			*/  	;
594 		E2C["CL"]= vcg::Color4b( 31,240, 31,255)   	/* 0x1FF01F			*/  	;
595 		E2C["AR"]= vcg::Color4b(128,209,227,255)   	/* 0x80D1E3			*/  	;
596 		E2C["K"] = vcg::Color4b(143, 64,212,255)   	/* 0x8F40D4			*/  	;
597 		E2C["CA"]= vcg::Color4b( 61,255,  0,255)   	/* 0x3DFF00			*/  	;
598 		E2C["SC"]= vcg::Color4b(230,230,230,255)   	/* 0xE6E6E6			*/  	;
599 		E2C["TI"]= vcg::Color4b(191,194,199,255)   	/* 0xBFC2C7			*/  	;
600 		E2C["V"] = vcg::Color4b(166,166,171,255)   	/* 0xA6A6AB			*/  	;
601 		E2C["CR"]= vcg::Color4b(138,153,199,255)   	/* 0x8A99C7			*/  	;
602 		E2C["MN"]= vcg::Color4b(156,122,199,255)   	/* 0x9C7AC7			*/  	;
603 		E2C["FE"]= vcg::Color4b(224,102, 51,255)   	/* 0xE06633			*/  	;
604 		E2C["CO"]= vcg::Color4b(240,144,160,255)   	/* 0xF090A0			*/  	;
605 		E2C["NI"]= vcg::Color4b( 80,208, 80,255)   	/* 0x50D050			*/  	;
606 		E2C["CU"]= vcg::Color4b(200,128, 51,255)   	/* 0xC88033			*/  	;
607 		E2C["ZN"]= vcg::Color4b(125,128,176,255)   	/* 0x7D80B0			*/  	;
608 		E2C["GA"]= vcg::Color4b(194,143,143,255)   	/* 0xC28F8F			*/  	;
609 		E2C["GE"]= vcg::Color4b(102,143,143,255)   	/* 0x668F8F			*/  	;
610 		E2C["AS"]= vcg::Color4b(189,128,227,255)   	/* 0xBD80E3			*/  	;
611 		E2C["SE"]= vcg::Color4b(255,161,  0,255)   	/* 0xFFA100			*/  	;
612 		E2C["BR"]= vcg::Color4b(166, 41, 41,255)   	/* 0xA62929			*/  	;
613 		E2C["KR"]= vcg::Color4b( 92,184,209,255)   	/* 0x5CB8D1			*/  	;
614 		E2C["RB"]= vcg::Color4b(112, 46,176,255)   	/* 0x702EB0			*/  	;
615 		E2C["SR"]= vcg::Color4b(  0,255,  0,255)   	/* 0x00FF00			*/  	;
616 		E2C["Y"] = vcg::Color4b(148,255,255,255)   	/* 0x94FFFF			*/  	;
617 		E2C["ZR"]= vcg::Color4b(148,224,224,255)   	/* 0x94E0E0			*/  	;
618 		E2C["NB"]= vcg::Color4b(115,194,201,255)   	/* 0x73C2C9			*/  	;
619 		E2C["MO"]= vcg::Color4b( 84,181,181,255)   	/* 0x54B5B5			*/  	;
620 		E2C["TC"]= vcg::Color4b( 59,158,158,255)   	/* 0x3B9E9E			*/  	;
621 		E2C["RU"]= vcg::Color4b( 36,143,143,255)   	/* 0x248F8F			*/  	;
622 		E2C["RH"]= vcg::Color4b( 10,125,140,255)   	/* 0x0A7D8C			*/  	;
623 		E2C["PD"]= vcg::Color4b(  0,105,133,255)   	/* 0x006985			*/  	;
624 		E2C["AG"]= vcg::Color4b(192,192,192,255)   	/* 0xC0C0C0			*/  	;
625 		E2C["CD"]= vcg::Color4b(255,217,143,255)   	/* 0xFFD98F			*/  	;
626 		E2C["IN"]= vcg::Color4b(166,117,115,255)   	/* 0xA67573			*/  	;
627 		E2C["SN"]= vcg::Color4b(102,128,128,255)   	/* 0x668080			*/  	;
628 		E2C["SB"]= vcg::Color4b(158, 99,181,255)   	/* 0x9E63B5			*/  	;
629 		E2C["TE"]= vcg::Color4b(212,122,  0,255)   	/* 0xD47A00			*/  	;
630 		E2C["I"] = vcg::Color4b(148,  0,148,255)   	/* 0x940094			*/  	;
631 		E2C["XE"]= vcg::Color4b( 66,158,176,255)   	/* 0x429EB0			*/  	;
632 		E2C["CS"]= vcg::Color4b( 87, 23,143,255)   	/* 0x57178F			*/  	;
633 		E2C["BA"]= vcg::Color4b(  0,201,  0,255)   	/* 0x00C900			*/  	;
634 		E2C["LA"]= vcg::Color4b(112,212,255,255)   	/* 0x70D4FF			*/  	;
635 		E2C["CE"]= vcg::Color4b(255,255,199,255)   	/* 0xFFFFC7			*/  	;
636 		E2C["PR"]= vcg::Color4b(217,255,199,255)   	/* 0xD9FFC7			*/  	;
637 		E2C["ND"]= vcg::Color4b(199,255,199,255)   	/* 0xC7FFC7			*/  	;
638 		E2C["PM"]= vcg::Color4b(163,255,199,255)   	/* 0xA3FFC7			*/  	;
639 		E2C["SM"]= vcg::Color4b(143,255,199,255)   	/* 0x8FFFC7			*/  	;
640 		E2C["EU"]= vcg::Color4b( 97,255,199,255)   	/* 0x61FFC7			*/  	;
641 		E2C["GD"]= vcg::Color4b( 69,255,199,255)   	/* 0x45FFC7			*/  	;
642 		E2C["TB"]= vcg::Color4b( 48,255,199,255)   	/* 0x30FFC7			*/  	;
643 		E2C["DY"]= vcg::Color4b( 31,255,199,255)   	/* 0x1FFFC7			*/  	;
644 		E2C["HO"]= vcg::Color4b(  0,255,156,255)   	/* 0x00FF9C			*/  	;
645 		E2C["ER"]= vcg::Color4b(  0,230,117,255)   	/* 0x00E675			*/  	;
646 		E2C["TM"]= vcg::Color4b(  0,212, 82,255)   	/* 0x00D452			*/  	;
647 		E2C["YB"]= vcg::Color4b(  0,191, 56,255)   	/* 0x00BF38			*/  	;
648 		E2C["LU"]= vcg::Color4b(  0,171, 36,255)   	/* 0x00AB24			*/  	;
649 		E2C["HF"]= vcg::Color4b( 77,194,255,255)   	/* 0x4DC2FF			*/  	;
650 		E2C["TA"]= vcg::Color4b( 77,166,255,255)   	/* 0x4DA6FF			*/  	;
651 		E2C["W"] = vcg::Color4b( 33,148,214,255)   	/* 0x2194D6			*/  	;
652 		E2C["RE"]= vcg::Color4b( 38,125,171,255)   	/* 0x267DAB			*/  	;
653 		E2C["OS"]= vcg::Color4b( 38,102,150,255)   	/* 0x266696			*/  	;
654 		E2C["IR"]= vcg::Color4b( 23, 84,135,255)   	/* 0x175487			*/  	;
655 		E2C["PT"]= vcg::Color4b(208,208,224,255)   	/* 0xD0D0E0			*/  	;
656 		E2C["AU"]= vcg::Color4b(255,209, 35,255)   	/* 0xFFD123			*/  	;
657 		E2C["HG"]= vcg::Color4b(184,184,208,255)   	/* 0xB8B8D0			*/  	;
658 		E2C["TL"]= vcg::Color4b(166, 84, 77,255)   	/* 0xA6544D			*/  	;
659 		E2C["PB"]= vcg::Color4b( 87, 89, 97,255)   	/* 0x575961			*/  	;
660 		E2C["BI"]= vcg::Color4b(158, 79,181,255)   	/* 0x9E4FB5			*/  	;
661 		E2C["PO"]= vcg::Color4b(171, 92,  0,255)   	/* 0xAB5C00			*/  	;
662 		E2C["AT"]= vcg::Color4b(117, 79, 69,255)   	/* 0x754F45			*/  	;
663 		E2C["RN"]= vcg::Color4b( 66,130,150,255)   	/* 0x428296			*/  	;
664 		E2C["FR"]= vcg::Color4b( 66,  0,102,255)   	/* 0x420066			*/  	;
665 		E2C["RA"]= vcg::Color4b(  0,125,  0,255)   	/* 0x007D00			*/  	;
666 		E2C["AC"]= vcg::Color4b(112,171,250,255)   	/* 0x70ABFA			*/  	;
667 		E2C["TH"]= vcg::Color4b(  0,186,255,255)   	/* 0x00BAFF			*/  	;
668 		E2C["PA"]= vcg::Color4b(  0,161,255,255)   	/* 0x00A1FF			*/  	;
669 		E2C["U"] = vcg::Color4b(  0,143,255,255)   	/* 0x008FFF			*/  	;
670 		E2C["NP"]= vcg::Color4b(  0,128,255,255)   	/* 0x0080FF			*/  	;
671 		E2C["PU"]= vcg::Color4b(  0,107,255,255)   	/* 0x006BFF			*/  	;
672 		E2C["AM"]= vcg::Color4b( 84, 92,242,255)   	/* 0x545CF2			*/  	;
673 		E2C["CM"]= vcg::Color4b(120, 92,227,255)   	/* 0x785CE3			*/  	;
674 		E2C["BK"]= vcg::Color4b(138, 79,227,255)   	/* 0x8A4FE3			*/  	;
675 		E2C["CF"]= vcg::Color4b(161, 54,212,255)   	/* 0xA136D4			*/  	;
676 		E2C["ES"]= vcg::Color4b(179, 31,212,255)   	/* 0xB31FD4			*/  	;
677 		E2C["FM"]= vcg::Color4b(179, 31,186,255)   	/* 0xB31FBA			*/  	;
678 		E2C["MD"]= vcg::Color4b(179, 13,166,255)   	/* 0xB30DA6			*/  	;
679 		E2C["NO"]= vcg::Color4b(189, 13,135,255)   	/* 0xBD0D87			*/  	;
680 		E2C["LR"]= vcg::Color4b(199,  0,102,255)   	/* 0xC70066			*/  	;
681 		E2C["RF"]= vcg::Color4b(204,  0, 89,255)   	/* 0xCC0059			*/  	;
682 		E2C["DB"]= vcg::Color4b(209,  0, 79,255)   	/* 0xD1004F			*/  	;
683 		E2C["SG"]= vcg::Color4b(217,  0, 69,255)   	/* 0xD90045			*/  	;
684 		E2C["BH"]= vcg::Color4b(224,  0, 56,255)   	/* 0xE00038			*/  	;
685 		E2C["HS"]= vcg::Color4b(230,  0, 46,255)   	/* 0xE6002E			*/  	;
686 		E2C["MT"]= vcg::Color4b(235,  0, 38,255)   	/* 0xEB0026			*/  	;
687 	}
688 
689   std::string ss0,ss1,ss2;
690   std::min(atomicElement.length(),atomicElement.find_first_of(' '));
691   ss0=atomicElement.substr(0,1);
692 	vcg::Color4b color=vcg::Color4b::Black;
693 	color=E2C[ss0];
694 	if((color.Red==0) && (color.Green==0) && (color.Blue==0))
695   {
696     ss1=atomicElement.substr(0,2);
697     color = E2C[ss1];
698   }
699 
700   return color;
701 }
702