Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: joelib/io/types/POVRay.java


1   ///////////////////////////////////////////////////////////////////////////////
2   //  Filename: $RCSfile: POVRay.java,v $
3   //  Purpose:  Reader/Writer for SDF files.
4   //  Language: Java
5   //  Compiler: JDK 1.4
6   //  Authors:  Joerg K. Wegner
7   //  Version:  $Revision: 1.19 $
8   //            $Date: 2003/08/22 15:56:18 $
9   //            $Author: wegner $
10  //
11  //  Copyright (c) Dept. Computer Architecture, University of Tuebingen, Germany
12  //
13  //  This program is free software; you can redistribute it and/or modify
14  //  it under the terms of the GNU General Public License as published by
15  //  the Free Software Foundation version 2 of the License.
16  //
17  //  This program is distributed in the hope that it will be useful,
18  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  //  GNU General Public License for more details.
21  ///////////////////////////////////////////////////////////////////////////////
22  package joelib.io.types;
23  
24  import cformat.PrintfStream;
25  
26  import joelib.data.JOEElementTable;
27  
28  import joelib.desc.DescResult;
29  import joelib.desc.DescriptorException;
30  import joelib.desc.DescriptorHelper;
31  
32  import joelib.io.MoleculeFileType;
33  
34  import joelib.math.XYZVector;
35  
36  import joelib.molecule.JOEAtom;
37  import joelib.molecule.JOEBond;
38  import joelib.molecule.JOEMol;
39  
40  import joelib.molecule.types.AtomProperties;
41  import joelib.molecule.types.AtomPropertyColoring;
42  
43  import joelib.ring.JOERing;
44  
45  import joelib.util.JHM;
46  import joelib.util.JOEHelper;
47  
48  import joelib.util.iterator.AtomIterator;
49  import joelib.util.iterator.NbrAtomIterator;
50  
51  import wsi.ra.tool.PropertyHolder;
52  
53  /*==========================================================================*
54   * IMPORTS
55   *==========================================================================        */
56  import java.awt.Color;
57  
58  import java.io.IOException;
59  import java.io.InputStream;
60  import java.io.OutputStream;
61  
62  import java.util.Vector;
63  
64  import org.apache.log4j.Category;
65  
66  
67  /*==========================================================================*
68   * CLASS DECLARATION
69   *==========================================================================        */
70  
71  /**
72   * Reader/Writer for Persitance Of Vision Raytracer (POVRay) files.
73   *
74   * @author     wegnerj
75   * @license GPL
76   * @cvsversion    $Revision: 1.19 $, $Date: 2003/08/22 15:56:18 $
77   * @cite povray
78   */
79  public class POVRay implements MoleculeFileType
80  {
81      //~ Static fields/initializers /////////////////////////////////////////////
82  
83      /*-------------------------------------------------------------------------*
84       * public static member variables
85       *-------------------------------------------------------------------------        */
86  
87      /**
88       * Description of the Field
89       */
90      public final static int BALL_AND_STICK = 0;
91      public final static String BALL_AND_STICK_S = "ball_and_stick";
92  
93      /**
94       * Description of the Field
95       */
96      public final static int SPHERE = 1;
97      public final static String SPHERE_S = "sphere";
98  
99      /**
100      * Description of the Field
101      */
102     public final static int STICK = 2;
103     public final static String STICK_S = "stick";
104 
105     /**
106      * Description of the Field
107      */
108     public final static int DEFAULT_OUTPUT_TYPE = BALL_AND_STICK;
109 
110     /*-------------------------------------------------------------------------*
111      * private static member variables
112      *-------------------------------------------------------------------------        */
113 
114     /**
115      * Obtain a suitable logger.
116      */
117     private static Category logger = Category.getInstance(
118             "joelib.io.types.POVRay");
119     private final static String version = "$Revision: 1.19 $";
120 
121     /**
122      *  Description of the Field
123      */
124     private final static String description = new String(
125             "Persistence Of Vision (POV) Ray Tracer");
126     private final static String[] extensions = new String[]{"pov"};
127 
128     //~ Instance fields ////////////////////////////////////////////////////////
129 
130     // variables for property coloring
131     private AtomPropertyColoring aPropColoring = new AtomPropertyColoring();
132     private JOEElementTable etab = JOEElementTable.instance();
133 
134     /*-------------------------------------------------------------------------*
135      * private member variables
136      *-------------------------------------------------------------------------        */
137 
138     //    private LineNumberReader lnr;
139     private PrintfStream ps;
140     private String atomProperty2Use = null;
141 
142     //    private AtomProperties data=null;
143     //    private boolean dataInitialised=false;
144     //    private double minDataValue;
145     //    private double maxDataValue;
146     //    private Color minColor = new Color(0.0f,0.0f,1.0f);
147     //    private Color maxColor = new Color(1.0f,0.0f,0.0f);
148     private boolean usePropertyColoring = false;
149     private boolean writeAromaticRings = true;
150     private boolean writePorbitals = false;
151     private double atomResizeFactor = 0.25;
152     private double biggerBondRadius = 0.3;
153     private double maxX;
154     private double maxY;
155     private double maxZ;
156     private double minX;
157     private double minY;
158     private double minZ;
159     private double mx;
160     private double my;
161     private double mz;
162     private double smallerBondRadius = 0.175;
163     private int moleculeCounter = 1;
164     private int outputType = DEFAULT_OUTPUT_TYPE;
165 
166     //~ Methods ////////////////////////////////////////////////////////////////
167 
168     /*-------------------------------------------------------------------------*
169      * constructor
170      *-------------------------------------------------------------------------        */
171     /*-------------------------------------------------------------------------*
172      * public  methods
173      *-------------------------------------------------------------------------        */
174 
175     /**
176      * Sets the outputType attribute of the POVRay object
177      *
178      * @param _outputType  The new outputType value
179      */
180     public void setOutputType(int _outputType)
181     {
182         outputType = _outputType;
183     }
184 
185     /**
186      * Gets the outputType attribute of the POVRay object
187      *
188      * @return   The outputType value
189      */
190     public int getOutputType()
191     {
192         return outputType;
193     }
194 
195     /**
196      * Description of the Method
197      *
198      * @exception IOException  Description of the Exception
199      */
200     public void closeReader() throws IOException
201     {
202     }
203 
204     /**
205      * Description of the Method
206      *
207      * @exception IOException  Description of the Exception
208      */
209     public void closeWriter() throws IOException
210     {
211         ps.close();
212     }
213 
214     /**
215      *  Description of the Method
216      *
217      * @param is               Description of the Parameter
218      * @exception IOException  Description of the Exception
219      */
220     public void initReader(InputStream is) throws IOException
221     {
222         //        lnr = new LineNumberReader(new InputStreamReader(is));
223     }
224 
225     /**
226      *  Description of the Method
227      *
228      * @param os               Description of the Parameter
229      * @exception IOException  Description of the Exception
230      */
231     public void initWriter(OutputStream os) throws IOException
232     {
233         ps = new PrintfStream(os);
234 
235         ps.println("// Creator: " + this.getClass().getName() + " " + version);
236         ps.println("// Author: Joerg K. Wegner");
237         ps.println("// Version: POV-Ray 3.1" + JHM.eol);
238 
239         ps.println("#include \"shapes.inc\"");
240         ps.println("#include \"colors.inc\"");
241         ps.println("#include \"textures.inc\"" + JHM.eol);
242 
243         ps.println("// brighten up colors");
244         ps.println("global_settings {assumed_gamma 1.4}");
245         ps.println("// set background color");
246         ps.println("background {colour<0.0, 0.0, 0.3>}" + JHM.eol);
247 
248         initProperties();
249     }
250 
251     /**
252      * Description of the Method
253      *
254      * @return   Description of the Return Value
255      */
256     public String inputDescription()
257     {
258         return description;
259     }
260 
261     /**
262      *  Description of the Method
263      *
264      * @return   Description of the Return Value
265      */
266     public String[] inputFileExtensions()
267     {
268         return extensions;
269     }
270 
271     /**
272      *  Description of the Method
273      *
274      * @return   Description of the Return Value
275      */
276     public String outputDescription()
277     {
278         return description;
279     }
280 
281     /**
282      *  Description of the Method
283      *
284      * @return   Description of the Return Value
285      */
286     public String[] outputFileExtensions()
287     {
288         return extensions;
289     }
290 
291     /**
292      *  Reads an molecule entry as (unparsed) <tt>String</tt> representation.
293      *
294      * @return                  <tt>null</tt> if the reader contains no more
295      *      relevant data. Otherwise the <tt>String</tt> representation of the
296      *      whole molecule entry is returned.
297      * @exception  IOException  typical IOException
298      */
299     public String read() throws IOException
300     {
301         logger.error(
302             "Reading POVRay data as String representation is not implemented yet !!!");
303 
304         return null;
305     }
306 
307     /**
308      *  Description of the Method
309      *
310      * @param mol              Description of the Parameter
311      * @return                 Description of the Return Value
312      * @exception IOException  Description of the Exception
313      */
314     public synchronized boolean read(JOEMol mol) throws IOException
315     {
316         return read(mol, null);
317     }
318 
319     /**
320      * Loads an molecule in MDL SD-MOL format and sets the title.
321      * If <tt>title</tt> is <tt>null</tt> the title line in
322      * the molecule file is used.
323      *
324      * @param mol              Description of the Parameter
325      * @param title            Description of the Parameter
326      * @return                 Description of the Return Value
327      * @exception IOException  Description of the Exception
328      */
329     public synchronized boolean read(JOEMol mol, String title)
330         throws IOException
331     {
332         return false;
333     }
334 
335     /**
336      *  Description of the Method
337      *
338      * @return   Description of the Return Value
339      */
340     public boolean readable()
341     {
342         return false;
343     }
344 
345     public boolean skipReaderEntry() throws IOException
346     {
347         return true;
348     }
349 
350     /**
351      *  Description of the Method
352      *
353      * @param mol              Description of the Parameter
354      * @return                 Description of the Return Value
355      * @exception IOException  Description of the Exception
356      */
357     public boolean write(JOEMol mol) throws IOException
358     {
359         return write(mol, null);
360     }
361 
362     /**
363      *  Description of the Method
364      *
365      * @param mol              Description of the Parameter
366      * @param title            Description of the Parameter
367      * @return                 Description of the Return Value
368      * @exception IOException  Description of the Exception
369      */
370     public boolean write(JOEMol mol, String title) throws IOException
371     {
372         if ((atomProperty2Use != null) && usePropertyColoring)
373         {
374             //useAtomPropertyColoring(mol, atomProperty2Use);
375             aPropColoring.useAtomPropertyColoring(mol, atomProperty2Use);
376         }
377         else
378         {
379             aPropColoring.usePlainColoring();
380         }
381 
382         //        useAtomPropertyColoring(mol, "A_QTOT");
383         //        useAtomPropertyColoring(mol, "A_POLARIZABILITY");
384         StringBuffer povMolecule = new StringBuffer((mol.numAtoms() * 100) +
385                 (mol.numBonds() * 100));
386 
387         // calculate molecule centrum new everytime
388         mx = my = mz = 0.0;
389         minX = minY = minZ = Double.MAX_VALUE;
390         maxX = maxY = maxZ = -Double.MAX_VALUE;
391 
392         // get molecule information
393         write2Buffer(mol, povMolecule);
394 
395         // write moelcule informations
396         ps.println("// minimum values");
397         ps.println("#declare minX = " + minX + ";");
398         ps.println("#declare minY = " + minY + ";");
399         ps.println("#declare minZ = " + minZ + ";");
400         ps.println("// maximum values");
401         ps.println("#declare maxX = " + maxX + ";");
402         ps.println("#declare maxY = " + maxY + ";");
403         ps.println("#declare maxZ = " + maxZ + ";");
404         ps.println("// delta values");
405         ps.println("#declare deltaX = " + Math.abs(maxX - minX) + ";");
406         ps.println("#declare deltaY = " + Math.abs(maxY - minY) + ";");
407         ps.println("#declare deltaZ = " + Math.abs(maxZ - minZ) + ";");
408         ps.println("// average values");
409         ps.println("#declare mx = " + mx + ";");
410         ps.println("#declare my = " + my + ";");
411         ps.println("#declare mz = " + mz + ";");
412         ps.println();
413 
414         if (outputType == BALL_AND_STICK)
415         {
416             ps.println("// atom resize factor");
417             ps.println("#declare atomResizeFactor = " + atomResizeFactor + ";");
418         }
419 
420         // use camera and light only for the first molecule
421         String isComment = "";
422 
423         if (moleculeCounter > 1)
424         {
425             isComment = "//";
426         }
427 
428         ps.println("// Camera" + JHM.eol + "camera {");
429         ps.println(isComment +
430             "    location <mx, my, mz-(max(deltaX,deltaY)*1.4)> // use maximum window with a resize factor of 1.4");
431         ps.println(isComment + "    direction <0.0, 0.0, 1.0>");
432         ps.println(isComment + "    look_at <mx, my, 1.0>" + JHM.eol + "}" +
433             JHM.eol);
434 
435         ps.println("// Light");
436         ps.println(isComment + " light_source {<" + ((mx < 0.0) ? "-" : "") +
437             "mx*2, " + ((my < 0.0) ? "-" : "") +
438             "my*2, mz-max(deltaX,deltaY)>");
439         ps.println(isComment + " colour White");
440         ps.println(isComment + "}" + JHM.eol);
441 
442         // define molecule in povray
443         ps.println("// Molecule " + moleculeCounter + ":" + mol.getTitle());
444         ps.println("#declare");
445         ps.println("Molecule" + moleculeCounter + " = union{");
446         ps.println(povMolecule.toString());
447         ps.println("}");
448 
449         // draw molecule in povray
450         ps.println();
451         ps.println("object { Molecule" + moleculeCounter + JHM.eol);
452 
453         //        ps.println("  translate <-mx,-my,-mz>"+JHM.eol);
454         //        ps.println("  rotate y*clock*10"+JHM.eol);
455         //        ps.println("  translate <mx,my,mz>"+JHM.eol);
456         ps.println("}" + JHM.eol);
457 
458         moleculeCounter++;
459 
460         return (true);
461     }
462 
463     /**
464      *  Description of the Method
465      *
466      * @return   Description of the Return Value
467      */
468     public boolean writeable()
469     {
470         return true;
471     }
472 
473     //public void useAtomPropertyColoring(JOEMol mol, String property)
474     //{
475     //  aPropColoring.useAtomPropertyColoring(mol, property);
476 
477     /*      DescResult result=null;
478           try
479             {
480                     result= DescriptorHelper.instance().descFromMol(mol,property);
481             }
482             catch (DescriptorException e)
483             {
484                     logger.error(e.toString());
485                     usePropertyColoring=false;
486             }
487 
488 
489           if(result==null)logger.error("Can't get atom property "+property+" for atom coloring in "+this.getClass().getName());
490           if(JOEHelper.hasInterface(result, "AtomProperties"))
491           {
492             dataInitialised=true;
493             data = (AtomProperties)result;
494             minDataValue=Double.MAX_VALUE;
495             maxDataValue=-Double.MAX_VALUE;
496             double value;
497             for(int i=1;i<=mol.numAtoms();i++)
498             {
499               value = data.getDoubleValue(i);
500               if(value>maxDataValue)maxDataValue=value;
501               if(value<minDataValue)minDataValue=value;
502     //          System.out.println(""+i+": "+value);
503             }
504 
505             usePropertyColoring=true;
506           }
507           else
508           {
509             logger.error("Data for atom coloring has wrong format in "+this.getClass().getName());
510           }*/
511 
512     //}
513     //private Color getAtomColor(JOEAtom atom)
514     //{
515     //  return aPropColoring.getAtomColor(atom);
516 
517     /*      if(usePropertyColoring)
518           {
519             double delta = maxDataValue-minDataValue;
520             //System.out.println("data:"+data);
521 
522             float val = (float) ((data.getDoubleValue(atom.getIdx())-minDataValue)/delta);
523             float r= ((maxColor.getRed()-minColor.getRed())*val +minColor.getRed())/255.0f;
524             float g=((maxColor.getGreen()-minColor.getGreen())*val +minColor.getGreen())/255.0f;
525             float b=((maxColor.getBlue()-minColor.getBlue())*val +minColor.getBlue())/255.0f;
526     //        System.out.println(""+atom.getIdx()+": "+data.getDoubleValue(atom.getIdx())+": "+val);
527     //        System.out.println("rgb:"+r+" "+g+" "+b);
528             return new Color(r,g,b);
529           }
530           else
531           {
532             int atomNum = atom.getAtomicNum();
533             return etab.getColor(atomNum);
534           }*/
535 
536     //}
537 
538     /**
539      *  Description of the Method
540      *
541      * @exception  IOException  Description of the Exception
542      */
543     private void initProperties()
544     {
545         String value;
546 
547         value = PropertyHolder.instance().getProperty(this, "output");
548 
549         if (value == null)
550         {
551             outputType = DEFAULT_OUTPUT_TYPE;
552         }
553         else if (value.equalsIgnoreCase(STICK_S))
554         {
555             outputType = STICK;
556         }
557         else if (value.equalsIgnoreCase(SPHERE_S))
558         {
559             outputType = SPHERE;
560         }
561         else if (value.equalsIgnoreCase(BALL_AND_STICK_S))
562         {
563             outputType = BALL_AND_STICK;
564         }
565         else
566         {
567             logger.error("Use output type :" + STICK_S + ", " + SPHERE_S +
568                 " and " + BALL_AND_STICK_S);
569             outputType = DEFAULT_OUTPUT_TYPE;
570         }
571 
572         value = PropertyHolder.instance().getProperty(this,
573                 "atomPropertyColoring");
574 
575         if (((value != null) && value.equalsIgnoreCase("true")))
576         {
577             usePropertyColoring = true;
578         }
579         else
580         {
581             usePropertyColoring = false;
582         }
583 
584         atomProperty2Use = null;
585         value = PropertyHolder.instance().getProperty(this, "atomProperty");
586 
587         Vector atomPropDescs = DescriptorHelper.instance().getAtomPropDescs();
588         int s = atomPropDescs.size();
589 
590         for (int ii = 0; ii < s; ii++)
591         {
592             if (value == null)
593             {
594                 break;
595             }
596 
597             if (value.equalsIgnoreCase((String) atomPropDescs.get(ii)))
598             {
599                 atomProperty2Use = value;
600             }
601 
602             //System.out.println(atomPropDescs.get(ii));
603         }
604 
605         if ((atomProperty2Use == null) && usePropertyColoring)
606         {
607             logger.warn("atomProperty=" + value +
608                 " is not a valid atom property. Setting to Gasteiger_Marsili");
609 
610             StringBuffer sb = new StringBuffer();
611             sb.append("Or use:");
612 
613             for (int ii = 0; ii < s; ii++)
614             {
615                 sb.append(atomPropDescs.get(ii));
616                 sb.append(" ");
617             }
618 
619             logger.warn(sb.toString());
620             atomProperty2Use = "Gasteiger_Marsili";
621         }
622     }
623 
624     /**
625      * Description of the Method
626      *
627      * @param mol  Description of the Parameter
628      * @param sb   Description of the Parameter
629      */
630     private void write2Buffer(JOEMol mol, StringBuffer sb)
631     {
632         // write atoms
633         writeAtoms(mol, sb);
634 
635         if (outputType != SPHERE)
636         {
637             // write bonds
638             writeBonds(mol, sb);
639 
640             if (writeAromaticRings)
641             {
642                 // write rings
643                 writeRings(mol, sb);
644             }
645         }
646     }
647 
648     /**
649      * Description of the Method
650      *
651      * @param mol  Description of the Parameter
652      * @param sb   Description of the Parameter
653      */
654     private void writeAtoms(JOEMol mol, StringBuffer sb)
655     {
656         JOEAtom atom;
657         AtomIterator ait = mol.atomIterator();
658         double x;
659         double y;
660         double z;
661         double radius;
662         Color color;
663 
664         while (ait.hasNext())
665         {
666             atom = ait.nextAtom();
667 
668             int atomNum = atom.getAtomicNum();
669 
670             x = atom.getX();
671             y = atom.getY();
672             z = atom.getZ();
673             mx += x;
674             my += y;
675             mz += z;
676 
677             if (x > maxX)
678             {
679                 maxX = x;
680             }
681 
682             if (x < minX)
683             {
684                 minX = x;
685             }
686 
687             if (y > maxY)
688             {
689                 maxY = y;
690             }
691 
692             if (y < minY)
693             {
694                 minY = y;
695             }
696 
697             if (z > maxZ)
698             {
699                 maxZ = z;
700             }
701 
702             if (z < minZ)
703             {
704                 minZ = z;
705             }
706 
707             if (outputType != STICK)
708             {
709                 radius = etab.correctedVdwRad(atomNum);
710             }
711             else
712             {
713                 radius = smallerBondRadius;
714             }
715 
716             sb.append("  // atom " + atom.getIdx() + ": " +
717                 etab.getSymbol(atom.getAtomicNum()) + JHM.eol);
718             sb.append("  sphere {" + JHM.eol);
719 
720             if (outputType != BALL_AND_STICK)
721             {
722                 sb.append("    <" + x + ", " + y + ", " + z + "> " + radius +
723                     JHM.eol);
724             }
725             else
726             {
727                 sb.append("    <" + x + ", " + y + ", " + z + "> " + radius +
728                     "*atomResizeFactor" + JHM.eol);
729             }
730 
731             sb.append("    texture {" + JHM.eol);
732 
733             //color = getAtomColor(atom);
734             color = aPropColoring.getAtomColor(atom);
735             sb.append("      pigment {color rgb <" + (color.getRed() / 255.0f) +
736                 ", " + (color.getGreen() / 255.0f) + ", " +
737                 (color.getBlue() / 255.0f) + ">}" + JHM.eol);
738             sb.append("      finish {Shiny}" + JHM.eol);
739             sb.append("    }" + JHM.eol);
740             sb.append("  }" + JHM.eol);
741         }
742 
743         mx = mx / (double) mol.numAtoms();
744         my = my / (double) mol.numAtoms();
745         mz = mz / (double) mol.numAtoms();
746     }
747 
748     /**
749      * Description of the Method
750      *
751      * @param mol  Description of the Parameter
752      * @param sb   Description of the Parameter
753      */
754     private void writeBonds(JOEMol mol, StringBuffer sb)
755     {
756         JOEBond bond;
757         double x;
758         double y;
759         double z;
760         Color color;
761         double middleX;
762         double middleY;
763         double middleZ;
764         double r1;
765         double r2;
766         double l;
767         double s;
768         JOEAtom atom1;
769         JOEAtom atom2;
770         double smallerR;
771         double biggerR;
772         double middleR;
773 
774         JOEAtom nbr;
775         JOEAtom atom;
776         AtomIterator ait = mol.atomIterator();
777 
778         while (ait.hasNext())
779         {
780             atom = ait.nextAtom();
781 
782             NbrAtomIterator nait = atom.nbrAtomIterator();
783 
784             while (nait.hasNext())
785             {
786                 nbr = nait.nextNbrAtom();
787 
788                 if (atom.getIdx() < nbr.getIdx())
789                 {
790                     bond = nait.actualBond();
791 
792                     //            while (bit.hasNext())
793                     //            {
794                     //                bond = bit.nextBond();
795                     atom1 = atom;
796                     atom2 = nbr;
797 
798                     if (atom1.getIdx() < atom2.getIdx())
799                     {
800                         sb.append("  // bond " + bond.getIdx() + ": " +
801                             etab.getSymbol(atom1.getAtomicNum()) + "(" +
802                             atom1.getIdx() + ")");
803                         sb.append(bond.toString());
804                         sb.append(etab.getSymbol(atom2.getAtomicNum()) + "(" +
805                             atom2.getIdx() + ")" + JHM.eol);
806                         sb.append("  union {" + JHM.eol);
807 
808                         r1 = JOEElementTable.instance().correctedVdwRad(atom1.getAtomicNum()) * atomResizeFactor;
809                         r2 = JOEElementTable.instance().correctedVdwRad(atom2.getAtomicNum()) * atomResizeFactor;
810                         x = atom2.getX() - atom1.getX();
811                         y = atom2.getY() - atom1.getY();
812                         z = atom2.getZ() - atom1.getZ();
813                         l = Math.sqrt((x * x) + (y * y) + (z * z));
814 
815                         // if atom radius of atom to big, cones not visible !!!!
816                         if (l < (r1 + r2))
817                         {
818                             s = 0.5;
819                         }
820                         else
821                         {
822                             s = (((l - r1 - r2) / 2) + r1) / l;
823                         }
824 
825                         middleX = atom1.getX() + (x * s);
826                         middleY = atom1.getY() + (y * s);
827                         middleZ = atom1.getZ() + (z * s);
828 
829                         // getting bond radii
830                         if ((bond.isUp() || bond.isDown()) &&
831                                 (outputType != STICK))
832                         {
833                             smallerR = smallerBondRadius;
834                             biggerR = biggerBondRadius;
835                         }
836                         else
837                         {
838                             smallerR = smallerBondRadius;
839                             biggerR = smallerBondRadius;
840                         }
841 
842                         middleR = smallerR + ((biggerR - smallerR) * s);
843 
844                         // write bond
845                         sb.append("    cone {" + JHM.eol);
846                         sb.append("       <" + atom1.getX() + ", " +
847                             atom1.getY() + ", " + atom1.getZ() + "> " +
848                             smallerR + JHM.eol);
849                         sb.append("       <" + middleX + ", " + middleY + ", " +
850                             middleZ + "> " + middleR + JHM.eol);
851                         sb.append("       open" + JHM.eol);
852                         sb.append("       texture {" + JHM.eol);
853 
854                         //color = getAtomColor(atom1);
855                         color = aPropColoring.getAtomColor(atom1);
856                         sb.append("         pigment {color rgb <" +
857                             (color.getRed() / 255.0f) + ", " +
858                             (color.getGreen() / 255.0f) + ", " +
859                             (color.getBlue() / 255.0f) + ">}" + JHM.eol);
860                         sb.append("         finish {Shiny}" + JHM.eol);
861                         sb.append("       }" + JHM.eol);
862                         sb.append("    }" + JHM.eol);
863 
864                         sb.append("    cone {" + JHM.eol);
865                         sb.append("       <" + middleX + ", " + middleY + ", " +
866                             middleZ + "> " + middleR + JHM.eol);
867                         sb.append("       <" + atom2.getX() + ", " +
868                             atom2.getY() + ", " + atom2.getZ() + "> " +
869                             biggerR + JHM.eol);
870                         sb.append("       open" + JHM.eol);
871                         sb.append("       texture {" + JHM.eol);
872 
873                         //color = getAtomColor(atom2);
874                         color = aPropColoring.getAtomColor(atom2);
875                         sb.append("         pigment {color rgb <" +
876                             (color.getRed() / 255.0f) + ", " +
877                             (color.getGreen() / 255.0f) + ", " +
878                             (color.getBlue() / 255.0f) + ">}" + JHM.eol);
879                         sb.append("         finish {Shiny}" + JHM.eol);
880                         sb.append("       }" + JHM.eol);
881                         sb.append("    }" + JHM.eol);
882 
883                         sb.append("  }" + JHM.eol);
884                     }
885                 }
886             }
887         }
888     }
889 
890     /**
891      * Description of the Method
892      *
893      * @param mol  Description of the Parameter
894      * @param sb   Description of the Parameter
895      */
896     private void writeRings(JOEMol mol, StringBuffer sb)
897     {
898         JOEAtom atom;
899         Color color;
900         JOEAtom atom1;
901         JOEAtom atom2;
902         double l;
903         double x;
904         double y;
905         double z;
906 
907         // write rings
908         Vector sssRings = mol.getSSSR();
909         JOERing ring;
910         XYZVector center = new XYZVector();
911         XYZVector r1v = new XYZVector();
912         XYZVector r2v = new XYZVector();
913         int[] itmp;
914         boolean allAromatic;
915         double rgb_r;
916         double rgb_g;
917         double rgb_b;
918 
919         //sb.append("  // rings:" + JHM.eol);
920         for (int i = 0; i < sssRings.size(); i++)
921         {
922             ring = (JOERing) sssRings.get(i);
923 
924             // is ring aromatic ?
925             // if yes, get the color of this ring
926             allAromatic = true;
927             itmp = ring.getAtoms();
928 
929             for (int n = 0; n < itmp.length; n++)
930             {
931                 atom = mol.getAtom(itmp[n]);
932 
933                 if (!atom.isAromatic())
934                 {
935                     allAromatic = false;
936 
937                     break;
938                 }
939             }
940 
941             if (!allAromatic)
942             {
943                 continue;
944             }
945 
946             // show ring atoms in command line
947             sb.append("  // ring " + i + ":");
948 
949             for (int n = 0; n < itmp.length; n++)
950             {
951                 sb.append(" " + itmp[n]);
952             }
953 
954             sb.append(JHM.eol);
955 
956             // calculate color and write p orbitals
957             ring.findCenterAndNormal(center, r1v, r2v);
958             r1v.normalize();
959             itmp = ring.getAtoms();
960             rgb_r = 0.0;
961             rgb_g = 0.0;
962             rgb_b = 0.0;
963 
964             for (int n = 0; n < itmp.length; n++)
965             {
966                 atom = mol.getAtom(itmp[n]);
967 
968                 //color = getAtomColor(atom);
969                 color = aPropColoring.getAtomColor(atom);
970                 rgb_r += (color.getRed() / 255.0f);
971                 rgb_g += (color.getGreen() / 255.0f);
972                 rgb_b += (color.getBlue() / 255.0f);
973 
974                 if (writePorbitals)
975                 {
976                     sb.append("  cylinder {" + JHM.eol);
977                     sb.append("    <" + r1v._vx + ",  " + r1v._vy + ",  " +
978                         r1v._vz + ">" + JHM.eol);
979                     sb.append("    <" + r2v._vx + ",  " + r2v._vy + ",  " +
980                         r2v._vz + ">, 0.05" + JHM.eol);
981                     sb.append("    pigment { color rgbt<0, 0.5, 0, 0.7>}" +
982                         JHM.eol);
983                     sb.append("    finish { ambient 1 diffuse 0 }" + JHM.eol);
984                     sb.append("    no_shadow" + JHM.eol);
985                     sb.append("    translate <" + atom.getX() + ",  " +
986                         atom.getY() + ",  " + atom.getZ() + ">" + JHM.eol);
987                     sb.append("  }" + JHM.eol);
988                 }
989             }
990 
991             rgb_r /= itmp.length;
992             rgb_g /= itmp.length;
993             rgb_b /= itmp.length;
994 
995             // calculate radius
996             atom1 = mol.getAtom(itmp[0]);
997             atom2 = mol.getAtom(itmp[0]);
998             x = ((atom1.getX() + atom2.getX()) / 2) - center._vx;
999             y = ((atom1.getY() + atom2.getY()) / 2) - center._vy;
1000            z = ((atom1.getZ() + atom2.getZ()) / 2) - center._vz;
1001            l = Math.sqrt((x * x) + (y * y) + (z * z)) * 0.45;
1002
1003            // calculate rotation vector
1004            double rrx = -XYZVector.angle(XYZVector.vX, r1v);
1005
1006            if (r1v._vz < 0.0)
1007            {
1008                rrx *= -1.0;
1009            }
1010
1011            double rry = -XYZVector.angle(XYZVector.vY, r1v);
1012
1013            // write ring
1014            sb.append("  torus {" + JHM.eol);
1015            sb.append("    " + l + ", 0.075" + JHM.eol);
1016            sb.append("    rotate z*" + rry + JHM.eol);
1017            sb.append("    rotate y*" + rrx + JHM.eol);
1018            sb.append("    translate <" + center._vx + ",  " + center._vy +
1019                ",  " + center._vz + ">" + JHM.eol);
1020            sb.append("    pigment {color rgb <" + rgb_r + ", " + rgb_g + ", " +
1021                rgb_b + ">}" + JHM.eol);
1022            sb.append("    finish {Shiny}" + JHM.eol);
1023            sb.append("  }" + JHM.eol);
1024        }
1025    }
1026}
1027///////////////////////////////////////////////////////////////////////////////
1028//  END OF FILE.
1029///////////////////////////////////////////////////////////////////////////////