Esempio n. 1
0
bool PainterFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
  OBMol* pmol = dynamic_cast<OBMol*>(pOb);
  if(pmol==NULL)
      return false;

  ostream& ofs = *pConv->GetOutStream();

  OBMol workingmol(*pmol); // Copy the molecule

  //*** Coordinate generation ***
  //Generate coordinates only if no existing 2D coordinates
  if(!workingmol.Has2D(true))
  {
    OBOp* pOp = OBOp::FindType("gen2D");
    if(!pOp)
    {
      obErrorLog.ThrowError("PainterFormat", "gen2D not found", obError, onceOnly);
      return false;
    }
    if(!pOp->Do(&workingmol))
    {
      obErrorLog.ThrowError("PainterFormat", string(workingmol.GetTitle()) + "- Coordinate generation unsuccessful", obError);
      return false;
    }
  }
  if(!workingmol.Has2D() && workingmol.NumAtoms()>1)
  {
    string mes("Molecule ");
    mes += workingmol.GetTitle();
    mes += " needs 2D coordinates to display in PNG2format";
    obErrorLog.ThrowError("PainterFormat", mes, obError);
    return false;
  }

  CommandPainter painter(*pConv->GetOutStream());
  OBDepict depictor(&painter);
  if(pConv->IsOption("M"))
    depictor.SetOption(OBDepict::noMargin);
  depictor.DrawMolecule(&workingmol);

  return true; //or false to stop converting
}
Esempio n. 2
0
  bool FastSearchFormat::ReadChemObject(OBConversion* pConv)
  {
    //Searches index file for structural matches
    //This function is called only once per search

    std::string auditMsg = "OpenBabel::Read fastsearch index ";
    std::string description(Description());
    auditMsg += description.substr(0,description.find('\n'));
    obErrorLog.ThrowError(__FUNCTION__,
                          auditMsg,
                          obAuditMsg);

    //Derive index name
    string indexname = pConv->GetInFilename();
    string::size_type pos=indexname.find_last_of('.');
    if(pos!=string::npos)
      {
        indexname.erase(pos);
        indexname += ".fs";
      }

    //Have to open input stream again because needs to be in binary mode
    ifstream ifs;
    stringstream errorMsg;
    if(!indexname.empty())
      ifs.open(indexname.c_str(),ios::binary);
    if(!ifs)
      {
        errorMsg << "Couldn't open " << indexname << endl;
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
        return false;
      }

    string datafilename = fs.ReadIndex(&ifs);
    if(datafilename.empty())
      {
        errorMsg << "Difficulty reading from index " << indexname << endl;
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
        return false;
      }

    vector<OBMol> patternMols;
    if(!ObtainTarget(pConv, patternMols, indexname))
      return false;

    bool exactmatch = pConv->IsOption("e",OBConversion::INOPTIONS)!=NULL;// -ae option

    //Open the datafile and put it in pConv
    //datafile name derived from index file probably won't have a file path
    //but indexname may. Derive a full datafile name
    string path;
    pos = indexname.find_last_of("/\\");
    if(pos==string::npos)
      path = datafilename;
    else
      path = indexname.substr(0,pos+1) + datafilename;

    ifstream datastream(path.c_str());
    if(!datastream)
      {
        errorMsg << "Difficulty opening " << path << endl;
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
        return false;
      }
    pConv->SetInStream(&datastream);

    //Input format is currently fs; set it appropriately
    if(!pConv->SetInAndOutFormats(pConv->FormatFromExt(datafilename.c_str()),pConv->GetOutFormat()))
      return false;

    // If target has dative bonds like -[N+](=O)[O-] convert it to the uncharged form
    // (-N(=O)=O and add uncharged form to vector of mols which are sent to
    // the -s (SMARTS)filter.
    // Also check whether the target has dative bonds in the uncharged form and supply
    // the charged form to the -s filter.
    // Together with the automatic conversion to the uncharged form when the fs index is made,
    // this ensures that both forms are found however they occur in the datafile or the taget.
    vector<OBBase*> extraSMARTSMols;
    vector<OBMol>extraUnchargedMols;
    for(unsigned i=0;i<patternMols.size();++i)
    {
      if(patternMols[i].ConvertDativeBonds())
        extraSMARTSMols.push_back(&patternMols[i]);
      else 
      {
        // If target has uncharged dative bonds, still use it for fastsearching,
        // but add the charged form for -s filter.
        extraUnchargedMols.push_back(patternMols[i]);
        if(extraUnchargedMols.back().MakeDativeBonds())
          extraSMARTSMols.push_back(&extraUnchargedMols.back());
      }
    }
    OBOp* sFilter = OBOp::FindType("s");
    if(sFilter)
      sFilter->ProcessVec(extraSMARTSMols);

    //Now do searching
    const char* p = pConv->IsOption("t",OBConversion::INOPTIONS);
    if(p)
      {
        //Do a similarity search
        multimap<double, unsigned int> SeekposMap;
        string txt=p;
        if(txt.find('.')==string::npos)
          {
            //Finds n molecules with largest Tanimoto
            int n = atoi(p);
            fs.FindSimilar(&patternMols[0], SeekposMap, n);
          }
        else
          {
            //Finds molecules with Tanimoto > MinTani
            double MaxTani = 1.1;
            size_t pos = txt.find(',');
            if( pos != string::npos ) {
              MaxTani = atof( txt.substr( pos + 1 ).c_str() );
            }
            double MinTani = atof( txt.substr( 0, pos ).c_str() );
            fs.FindSimilar(&patternMols[0], SeekposMap, MinTani, MaxTani);
          }

        //Don't want to filter through SMARTS filter
        pConv->RemoveOption("s", OBConversion::GENOPTIONS);
        //also because op names are case independent
        pConv->RemoveOption("S", OBConversion::GENOPTIONS);

        multimap<double, unsigned int>::reverse_iterator itr;
        for(itr=SeekposMap.rbegin();itr!=SeekposMap.rend();++itr)
          {
            datastream.seekg(itr->second);

            if(pConv->IsOption("a", OBConversion::INOPTIONS))
              {
                //Adds Tanimoto coeff to title
                //First remove any previous value
                pConv->RemoveOption("addtotitle", OBConversion::GENOPTIONS);
                stringstream ss;
                ss << " " << itr->first;
                pConv->AddOption("addtotitle",OBConversion::GENOPTIONS, ss.str().c_str());

              }
            pConv->SetOneObjectOnly();
            if(itr != --SeekposMap.rend())
              pConv->SetMoreFilesToCome();//so that not seen as last on output
            pConv->Convert(NULL,NULL);
          }
      }

    else
    {
      //Structure search
      int MaxCandidates = 4000;
      p = pConv->IsOption("l",OBConversion::INOPTIONS);
      if(p && atoi(p))
        MaxCandidates = atoi(p);

      vector<unsigned int> SeekPositions;

      if(exactmatch)
      {
        //Find mols where all fingerprint bits are the same as the target
        fs.FindMatch(&patternMols[0], SeekPositions, MaxCandidates);
        // ensure that SMARTS filter in transform.cpp looks only for an exact match
        // by setting an option with the number of heavy atoms in the pattern mol included.
        stringstream ss;
        ss << patternMols[0].NumHvyAtoms();
        pConv->AddOption("exactmatch", OBConversion::GENOPTIONS, ss.str().c_str());
      }

      else
      {
        //Do a substructure search for each target
        vector<OBMol>::iterator iter;
        for(iter=patternMols.begin();iter!=patternMols.end();++iter)
          fs.Find(&*iter, SeekPositions, MaxCandidates);
        clog << SeekPositions.size() << " candidates from fingerprint search phase" << endl;
      }

      vector<unsigned int>::iterator seekitr,
          begin = SeekPositions.begin(), end = SeekPositions.end();

      if(patternMols.size()>1)//only sort and eliminate duplicates if necessary
      {
        sort(begin, end);
        end = unique(begin, end); //removed duplicates are after new end
      }

      //Output the candidate molecules, filtering through s filter, unless it was not requested
      if(pConv->IsOption("n", OBConversion::INOPTIONS) )
        pConv->RemoveOption("s",OBConversion::GENOPTIONS);

      pConv->SetLast(false);
      for(seekitr=begin; seekitr!=end; ++seekitr)
      {
        datastream.seekg(*seekitr);
        if(!pConv->GetInFormat()->ReadChemObject(pConv))
          return false;
        pConv->SetFirstInput(false); //needed for OpSort
      }
    }
    return false;	//To finish
  }
Esempio n. 3
0
bool OpAlign::Do(OBBase* pOb, const char* OptionText, OpMap* pmap, OBConversion* pConv)
{
  OBMol* pmol = dynamic_cast<OBMol*>(pOb);
  if(!pmol)
    return false;

  map<string,string>::const_iterator itr;

  // Is there an -s option?
  if(pConv->IsFirstInput())
  {
    _pOpIsoM = NULL; //assume no -s option
    itr = pmap->find("s");
    if(itr!=pmap->end())
    {
      //There is an -s option; check it is ok
      _pOpIsoM = static_cast<OpNewS*>(OBOp::FindType("s"));
      _stext = itr->second; //get its parameter(s)
      if(!_pOpIsoM || _stext.empty())
      {
        obErrorLog.ThrowError(__FUNCTION__,
        "No parameter on -s option, or its OBOp version is not loaded", obError);
        pConv->SetOneObjectOnly(); //to finish
        return false;
      }
    }
  }

  // If the output format is a 2D depiction format, then we should align
  // on the 2D coordinates and not the 3D coordinates (if present). This
  //means we need to generate the 2D coordinates at this point.
  if(pmol->GetDimension()==3 && (pConv->GetOutFormat()->Flags() & DEPICTION2D))
  {
    OBOp* pgen = OBOp::FindType("gen2D");
    if(pgen)
      pgen->Do(pmol);
  }

  // All molecules must have coordinates, so add them if 0D
  // They may be added again later when gen2D or gen3D is called, but they will be the same.
  // It would be better if this op was called after them, which would happen
  // if its name was alphabetically after "gen" (and before "s").
  if(pmol->GetDimension()==0)
  {
    //Will the coordinates be 2D or 3D?
    itr = pmap->find("gen3D");
    OBOp* pgen = (itr==pmap->end()) ? OBOp::FindType("gen2D") : OBOp::FindType("gen3D");
    if(pgen)
      pgen->Do(pmol);
  }

  //Do the alignment in 2D if the output format is svg, png etc. and there is no -xn option
  if(pmol->GetDimension()==3 && pConv && !pConv->IsOption("n"))
  {
    OBFormat* pOutFormat = pConv->GetOutFormat();
    if(pOutFormat->Flags() & DEPICTION2D)
    {
      OBOp* pgen = OBOp::FindType("gen2D");
      if(pgen)
        pgen->Do(pmol);
    }
  }

  if(pConv->IsFirstInput() || _refMol.NumAtoms()==0)
  {
    _refvec.clear();
    // Reference molecule is basically the first molecule
    _refMol = *pmol;
    if(!_pOpIsoM)
     //no -s option. Use a molecule reference.
     _align.SetRefMol(_refMol);
    else
    {
      //If there is a -s option, reference molecule has only those atoms that are matched
      //Call the -s option from here
      bool ret = _pOpIsoM->Do(pmol, _stext.c_str(), pmap, pConv);
      // Get the atoms that were matched
      vector<int> ats = _pOpIsoM->GetMatchAtoms();
      if(!ats.empty())
      {
        // Make a vector of the matching atom coordinates...
        for(vector<int>::iterator iter=ats.begin(); iter!=ats.end(); ++iter)
          _refvec.push_back((pmol->GetAtom(*iter))->GetVector());
        // ...and use a vector reference
        _align.SetRef(_refvec);
      }
      // Stop -s option being called normally, although it will still be called once
      //  in the DoOps loop already started for the current (first) molecule.
      pConv->RemoveOption("s",OBConversion::GENOPTIONS);
      if(!ret)
      {
        // the first molecule did not match the -s option so a reference molecule
        // could not be made. Keep trying.
        _refMol.Clear();
        //obErrorLog.ThrowError(__FUNCTION__, "The first molecule did not match the -s option\n"
        //  "so the reference structure was not derived from it", obWarning, onceOnly);
        return false; //not matched
      }
    }
  }

  //All molecules
  if(pmol->GetDimension()!= _refMol.GetDimension())
  {
    stringstream ss;
    ss << "The molecule" << pmol->GetTitle()
       << " does not have the same dimensions as the reference molecule "
       << _refMol.GetTitle() << " and is ignored.";
       obErrorLog.ThrowError(__FUNCTION__, ss.str().c_str(), obError);
    return false;
  }

  if(_pOpIsoM) //Using -s option
  {
    //Ignore mol if it does not pass -s option
    if(!_pOpIsoM->Do(pmol, "", pmap, pConv)) // "" means will use existing parameters
      return false;

    // Get the atoms equivalent to those in ref molecule
    vector<int> ats = _pOpIsoM->GetMatchAtoms();

    // Make a vector of their coordinates and get the centroid
    vector<vector3> vec;
    vector3 centroid;
    for(vector<int>::iterator iter=ats.begin(); iter!=ats.end(); ++iter) {
      vector3 v = pmol->GetAtom(*iter)->GetVector();
      centroid += v;
      vec.push_back(v);
    }
    centroid /= vec.size();

    // Do the alignment
    _align.SetTarget(vec);
    if(!_align.Align())
      return false;

    // Get the centroid of the reference atoms
    vector3 ref_centroid;
    for(vector<vector3>::iterator iter=_refvec.begin(); iter!=_refvec.end(); ++iter)
      ref_centroid += *iter;
    ref_centroid /= _refvec.size();

    //subtract the centroid, rotate the target molecule, then add the centroid
    matrix3x3 rotmatrix = _align.GetRotMatrix();
    for (unsigned int i = 1; i <= pmol->NumAtoms(); ++i)
    {
      vector3 tmpvec = pmol->GetAtom(i)->GetVector();
      tmpvec -= centroid;
      tmpvec *= rotmatrix; //apply the rotation
      tmpvec += ref_centroid;
      pmol->GetAtom(i)->SetVector(tmpvec);
    }
  }
  else //Not using -s option)
  {
    _align.SetTargetMol(*pmol);
    if(!_align.Align())
      return false;
    _align.UpdateCoords(pmol);
  }

  //Save rmsd as a property
  OBPairData* dp = new OBPairData;
  dp->SetAttribute("rmsd");
  double val = _align.GetRMSD();
  if(val<1e-12)
    val = 0.0;
  dp->SetValue(toString(val));
  dp->SetOrigin(local);
  pmol->SetData(dp);

  return true;
}
Esempio n. 4
0
bool SVGFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
  OBMol* pmol = dynamic_cast<OBMol*>(pOb);
  if(!pmol)
    return false;
  ostream &ofs = *pConv->GetOutStream();

  //Check for option for single mol in fixed size image
  const char* fixedpx = pConv->IsOption("P");
  if(!fixedpx)
    fixedpx= pConv->IsOption("px", OBConversion::GENOPTIONS);
  //If WriteMolecule called directly, e.g. from OBConversion::Write()
  //the default mode is a fixed image size of 200px square
  if(!fixedpx && !pConv->IsOption("svgwritechemobject"))
    fixedpx = "200";
  if(fixedpx)
  {
    _nmax = _nrows = _ncols = 1;
    pConv->AddOption("j");
    pConv->SetLast(true);
    pConv->SetOutputIndex(1);
  }

  //*** Coordinate generation ***
  //Generate coordinates only if no existing 2D coordinates
  if( (pConv->IsOption("y") || !pmol->Has2D(true)) && !pConv->IsOption("n") )
  {
    OBOp* pOp = OBOp::FindType("gen2D");
    if(!pOp)
    {
      obErrorLog.ThrowError("SVGFormat", "gen2D not found", obError, onceOnly);
      return false;
    }
    if(!pOp->Do(pmol))
    {
      obErrorLog.ThrowError("SVGFormat", string(pmol->GetTitle()) + "- Coordinate generation unsuccessful", obError);
      return false;
    }
  }
  if(!pmol->Has2D() && pmol->NumAtoms()>1)//allows 3D coordinates (if passed by -xn above)
  {
    string mes("Molecule ");
    mes += pmol->GetTitle();
    mes += " needs 2D coordinates to display in SVGformat";
    obErrorLog.ThrowError("SVGFormat", mes, obError);
    return false;
  }
  
  bool hasTable = (_nrows || _ncols);

  bool transparent=false;
  string background, bondcolor;
  const char* bg = pConv->IsOption("b");
  background = bg ? "black" : "white";
  bondcolor  = bg ? "white" : "black";
  if(bg && (!strcmp(bg, "none") || bg[0]=='0'))
  {
    transparent = true;
    bondcolor = "gray";
  }
  const char* bcol = pConv->IsOption("B");
  if(bcol && *bcol)
    bondcolor = bcol;
  if(bg && *bg)
    background = bg;
  
  if(pConv->GetOutputIndex()==1 || fixedpx)
  {
    //For the first molecule...
    if(hasTable)
    {
      //multiple molecules - use a table
      //Outer svg has viewbox for 0 0 100 100 or adjusted for table shape,
      //and no width or height - it uses the whole of its containing element.
      //Inner svg with width, height, x, y of table cell,
      //and viewbox to match molecule min and max x and y
      if(!pConv->IsOption("x"))
        ofs << "<?xml version=\"1.0\"?>\n";

      ofs << "<svg version=\"1.1\" id=\"topsvg\"\n"
             "xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
             "xmlns:cml=\"http://www.xml-cml.org/schema\" ";

      //*** Outer viewbox ***
      double vbwidth=100, vbheight=100;
      if (_nrows>_ncols)
        vbwidth = (100*_ncols)/_nrows;
      else if(_ncols>_nrows)
        vbheight = (100*_nrows)/_ncols;

      if(fixedpx)//fixed size image
        ofs << "x=\"0\" y=\"0\" width=\"" << fixedpx << "px\" height=\"" << fixedpx <<"px\" ";
      else
        ofs << "x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" ";
      
      ofs << "viewBox=\"0 0 " << vbwidth << ' ' << vbheight << "\">\n";

      ofs << "<title>OBDepict</title>\n";
      // Draw the background unless transparent
      if(!transparent)
        ofs << "<rect x=\"0\" y=\"0\" width=\"" << vbwidth << "\" height=\"" << vbheight
            << "\" fill=\"" << background << "\"/>\n";
    }
  }

  //All mols
  double cellsize;
  if(hasTable)
  {
    //*** Parameter for inner svg ***
    int nc = _ncols ? _ncols : 1;
    int nr = (_nrows ? _nrows : 1);
    cellsize = 100. / std::max(nc, nr);
    int indx = pConv->GetOutputIndex() - 1;
    double innerX  = (indx % nc) * cellsize;
    double innerY  = (indx / nc) * cellsize;

    // Change the background in this cell if the condition in the first
    // parameter of  the -xh option is met. Use a default color if
    // the highlight color is not specified in the second parameter.
    const char* htxt = pConv->IsOption("h");
    if(htxt)
    {
      vector<string> vec;
      tokenize(vec, htxt);
      string highlight(vec.size()>1 ? vec[1] : "#f4f0ff");
      std::istringstream conditionText(vec[0]);
      if(OBDescriptor::FilterCompare(pOb, conditionText, false))
        //Still in outer <svg>, unfortunately
        ofs << "<rect x=\"" << innerX << "\" y=\"" << innerY
            << "\" width=\"" << cellsize << "\" height=\"" << cellsize
            << "\" fill=\"" << highlight << "\"/>\n";
    }

    //*** Write molecule name ***
    if(!pConv->IsOption("d"))
      ofs << "<text text-anchor=\"middle\" font-size=\"" << 0.06*cellsize << "\""
      << " fill =\"" << bondcolor << "\" font-family=\"sans-serif\"\n"
      << "x=\"" << innerX + cellsize * 0.5 << "\" y=\"" << innerY + cellsize - 2.0/nr << "\" >"
      << pmol->GetTitle() << "</text>\n";

    SVGPainter painter(*pConv->GetOutStream(), true, cellsize,cellsize,innerX,innerY);
    OBDepict depictor(&painter);

    if(!pConv->IsOption("C"))
      depictor.SetOption(OBDepict::drawTermC);// on by default
    if(pConv->IsOption("a"))
      depictor.SetOption(OBDepict::drawAllC);

    if(pConv->IsOption("A"))
    {
      AliasData::RevertToAliasForm(*pmol);
      depictor.SetAliasMode();
    }
    painter.SetFontFamily("sans-serif");
    painter.SetPenColor(OBColor(bondcolor));
    depictor.SetBondColor(bondcolor);
    if(pConv->IsOption("t"))
      painter.SetPenWidth(4);
    else
      painter.SetPenWidth(2);

    //No element-specific atom coloring if requested
    if(pConv->IsOption("u"))
      depictor.SetOption(OBDepict::bwAtoms);
    if(!pConv->IsOption("U"))
      depictor.SetOption(OBDepict::internalColor);
    if(pConv->IsOption("s"))
      depictor.SetOption(OBDepict::asymmetricDoubleBond);

    depictor.DrawMolecule(pmol);

    //Draw atom indices if requested
    if(pConv->IsOption("i"))
      depictor.AddAtomLabels(OBDepict::AtomIndex);

    //Embed CML of molecule if requested
    if(pConv->IsOption("e"))
      EmbedCML(pmol,pConv);
  }
  else //single molecule
  {
    //Nothing written until DrawMolecule call
    //Final </svg> written at the end of this block (painter destructor)
    //This leads to some code duplication.
    double factor = 1.0;
    SVGPainter painter(*pConv->GetOutStream(), false);
    OBDepict depictor(&painter);

    //Scale image by specifying the average bond length in pixels.
    const char* ppx = pConv->IsOption("p");
    if(!ppx)
      ppx= pConv->IsOption("px", OBConversion::GENOPTIONS);
    if(ppx)
    {
      double oldblen = depictor.GetBondLength();
      double newblen = atof(ppx);
      depictor.SetBondLength(newblen);
      factor = newblen / oldblen;
      //Scale bondspacing and font size by same factor
      depictor.SetBondSpacing(depictor.GetBondSpacing() * factor);
      depictor.SetFontSize((int)(depictor.GetFontSize() * factor));
    }

    if(pConv->IsOption("W"))
      depictor.SetOption(OBDepict::noWedgeHashGen);
    if(!pConv->IsOption("C"))
      depictor.SetOption(OBDepict::drawTermC);// on by default
    if(pConv->IsOption("a"))
      depictor.SetOption(OBDepict::drawAllC);

    if(pConv->IsOption("A"))
    {
      AliasData::RevertToAliasForm(*pmol);
      depictor.SetAliasMode();
    }

    painter.SetFontFamily("sans-serif");
    painter.SetPenColor(OBColor(bondcolor));
    depictor.SetBondColor(bondcolor);
    painter.SetFillColor(OBColor(background));
    if(pConv->IsOption("t"))
      painter.SetPenWidth(4);
    else
      painter.SetPenWidth(1);

    //No element-specific atom coloring if requested
    if(pConv->IsOption("u"))
      depictor.SetOption(OBDepict::bwAtoms);
    if(!pConv->IsOption("U"))
      depictor.SetOption(OBDepict::internalColor);
    if(pConv->IsOption("s"))
      depictor.SetOption(OBDepict::asymmetricDoubleBond);

    depictor.DrawMolecule(pmol);

    //Draw atom indices if requested
    if(pConv->IsOption("i"))
      depictor.AddAtomLabels(OBDepict::AtomIndex);


    //*** Write molecule name ***
    if(!pConv->IsOption("d"))
      ofs << "<text font-size=\"" << 18 * factor  << "\""
      << " fill =\"" << bondcolor << "\" font-family=\"sans-serif\"\n"
      << "x=\"" << 10 * factor << "\" y=\"" << 20 * factor << "\" >"
      << pmol->GetTitle() << "</text>\n";

    //*** Write page title name ***
    ofs << "<title>" << pmol->GetTitle() << " - OBDepict</title>\n";

    //Embed CML of molecule if requested
    if(pConv->IsOption("e"))
      EmbedCML(pmol,pConv);
  }

  if(hasTable && pConv->IsLast())
  {
    //Draw grid lines
    if(_nrows && _ncols && pConv->IsOption("l"))
    {
      for(int i=1; i<_nrows; ++i)
        ofs << " <line  stroke=\"gray\" stroke-width=\"0.1\" x1=\"0\" x2=\"100\""
            << " y1=\""  << i*cellsize << "\" y2=\""  << i*cellsize << "\"/>\n";
      for(int i=1; i<_ncols; ++i)
        ofs << " <line  stroke=\"gray\" stroke-width=\"0.1\" y1=\"0\" y2=\"100\""
            << " x1=\""  << i*cellsize << "\" x2=\""  << i*cellsize << "\"/>\n";
    }

    //Insert javascript for zooming and panning
    if(!pConv->IsOption("j"))
      EmbedScript(ofs);

    ofs << "</svg>\n" << endl;//Outer svg
  }
  return !fixedpx; // return false with fixed size image because only 1 mol
}
Esempio n. 5
0
bool SVGFormat::WriteSVG(OBConversion* pConv, vector<OBBase*>& molecules)
{

  bool ret=true;

  //Check for option for single mol in fixed size image
  const char* fixedpx = pConv->IsOption("P");
  if(!fixedpx)
    fixedpx= pConv->IsOption("px", OBConversion::GENOPTIONS);
  //If WriteMolecule called directly, e.g. from OBConversion::Write()
  //the default mode is a fixed image size of 200px square
  if(!fixedpx && molecules.size()==1)
    fixedpx = "200";
  if(fixedpx)
  {
    _nmax = _nrows = _ncols = 1;
    pConv->AddOption("j");
  }

  ostream &ofs = *pConv->GetOutStream();

  bool hasTable = (_nrows>1) || (_ncols>1);

  bool transparent=false;
  string background, bondcolor;
  const char* bg = pConv->IsOption("b");
  background = bg ? "black" : "white";
  bondcolor  = bg ? "white" : "black";
  if(bg && (!strcmp(bg, "none") || bg[0]=='0'))
  {
    transparent = true;
    bondcolor = "gray";
  }
  const char* bcol = pConv->IsOption("B");
  if(bcol && *bcol)
    bondcolor = bcol;
  if(bg && *bg)
    background = bg;

  if(!pConv->IsOption("x"))
  ofs << "<?xml version=\"1.0\"?>\n";

  ofs << "<svg version=\"1.1\" id=\"topsvg\"\n"
         "xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
         "xmlns:cml=\"http://www.xml-cml.org/schema\" ";
  double vbwidth=100, vbheight=100;
  if (_nrows>_ncols)
    vbwidth = (100*_ncols)/_nrows;
  else if(_ncols>_nrows)
    vbheight = (100*_nrows)/_ncols;

  if(fixedpx)//fixed size image
    ofs << "x=\"0\" y=\"0\" width=\"" << fixedpx << "px\" height=\"" << fixedpx <<"px\" ";
  else
    ofs << "x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" ";

  ofs << "viewBox=\"0 0 " << vbwidth << ' ' << vbheight << "\">\n";

  if (hasTable)
    ofs << "<title>Multiple Molecules - Open Babel Depiction</title>\n";
  else if(molecules.size() == 1)
    ofs << "<title>" << molecules[0]->GetTitle() << " - Open Babel Depiction</title>\n";

  // Draw the background unless transparent
  if(!transparent)
    ofs << "<rect x=\"0\" y=\"0\" width=\"" << vbwidth << "\" height=\"" << vbheight
        << "\" fill=\"" << background << "\"/>\n";

  unsigned opts = 0;
  if(pConv->IsOption("u"))
    opts |= OBDepict::bwAtoms;
  if(!pConv->IsOption("U"))
   opts |= OBDepict::internalColor;
  if(!pConv->IsOption("C"))
    opts |= OBDepict::drawTermC;// on by default
  if(pConv->IsOption("a"))
    opts |= OBDepict::drawAllC;
  if(pConv->IsOption("W"))
    opts |= OBDepict::noWedgeHashGen;
  if(pConv->IsOption("s"))
   opts |= OBDepict::asymmetricDoubleBond;
  if(pConv->IsOption("X"))
    opts |= OBDepict::allExplicit;

  bool balldepict = false;
  if(pConv->IsOption("S"))
    balldepict = true;

  double factor = 1.0;
  int nc = _ncols ? _ncols : 1;
  int nr = (_nrows ? _nrows : 1);
  double cellsize = 100. / std::max(nc, nr);

  stringstream molfs;
  std::set<ColorGradient> gradients;

  OBOp* pOp = OBOp::FindType("gen2D");
  if(!pOp)
  {
    obErrorLog.ThrowError("SVGFormat", "gen2D not found", obError, onceOnly);
    return false;
  }

  vector<OBBase*>::iterator iter;
  int indx = 0;
  for(iter=_objects.begin(); ret && iter!=_objects.end(); ++iter,++indx)
  {
    OBMol* pmol = dynamic_cast<OBMol*>(*iter);

    if (!pmol)
      continue;
    //*** Coordinate generation ***
    //Generate coordinates only if no existing 2D coordinates
    if( (pConv->IsOption("y") || !pmol->Has2D(true)) && !pConv->IsOption("n") )
    {
      if(!pOp->Do(pmol))
      {
        obErrorLog.ThrowError("SVGFormat", string(pmol->GetTitle()) + "- Coordinate generation unsuccessful", obError);
        return false;
      }
    }
    if(!pmol->Has2D() && pmol->NumAtoms()>1)//allows 3D coordinates (if passed by -xn above)
    {
      string mes("Molecule ");
      mes += pmol->GetTitle();
      mes += " needs 2D coordinates to display in SVGformat";
      obErrorLog.ThrowError("SVGFormat", mes, obError);
      return false;
    }
    double innerX = 0.0;
    double innerY = 0.0;
    if(hasTable)
    {
      //*** Parameter for inner svg ***
      innerX  = (indx % nc) * cellsize;
      innerY  = (indx / nc) * cellsize;

      // Change the background in this cell if the condition in the first
      // parameter of  the -xh option is met. Use a default color if
      // the highlight color is not specified in the second parameter.
      const char* htxt = pConv->IsOption("h");
      if(htxt)
      {
        vector<string> vec;
        tokenize(vec, htxt);
        string highlight(vec.size()>1 ? vec[1] : "#f4f0ff");
        std::istringstream conditionText(vec[0]);
        if(OBDescriptor::FilterCompare(*iter, conditionText, false))
          //Still in outer <svg>, unfortunately
          molfs << "<rect x=\"" << innerX << "\" y=\"" << innerY
              << "\" width=\"" << cellsize << "\" height=\"" << cellsize
              << "\" fill=\"" << highlight << "\"/>\n";
      }
    }

    SVGPainter painter(molfs, &gradients, true, cellsize, cellsize);
    OBDepict depictor(&painter, balldepict);

    depictor.SetOption(opts);

    if(pConv->IsOption("A"))
    {
      AliasData::RevertToAliasForm(*pmol);
      depictor.SetAliasMode();
    }
    painter.SetFontFamily("sans-serif");
    painter.SetPenColor(OBColor(bondcolor));
    depictor.SetBondColor(bondcolor);
    if(pConv->IsOption("t"))
      painter.SetPenWidth(4);
    else
      painter.SetPenWidth(2);

    molfs << "<g transform=\"translate(" << innerX << "," << innerY << ")\">\n";

    ret = depictor.DrawMolecule(pmol);


    //Draw atom indices if requested
    if(pConv->IsOption("i"))
      depictor.AddAtomLabels(OBDepict::AtomIndex);

    painter.EndCanvas();


    //Embed CML of molecule if requested
    if(pConv->IsOption("e"))
      EmbedCML(pmol, pConv, &molfs);

    molfs <<"</g>\n";

    //*** Write molecule name ***
    if(!pConv->IsOption("d"))
      if(hasTable)
        molfs << "<text text-anchor=\"middle\" font-size=\"" << 0.06*cellsize << "\""
        << " fill =\"" << bondcolor << "\" font-family=\"sans-serif\"\n"
        << "x=\"" << innerX + cellsize * 0.5 << "\" y=\"" << innerY + cellsize - 2.0/nr << "\" >"
        << pmol->GetTitle() << "</text>\n";
      else
        molfs << "<text font-size=\"" << 18 * factor  << "\""
        << " fill =\"" << bondcolor << "\" font-family=\"sans-serif\"\n"
        << "x=\"" << 10 * factor << "\" y=\"" << 20 * factor << "\" >"
        << pmol->GetTitle() << "</text>\n";
  }

  // finally write svg defs
  SVGPainter painter(ofs, &gradients, true, cellsize,cellsize);
  painter.WriteDefs();

  // and stream back all molecule data
  ofs << molfs.str();

  //Draw grid lines
  if(hasTable && pConv->IsOption("l"))
  {
    for(int i=1; i<_nrows; ++i)
      ofs << " <line  stroke=\"gray\" stroke-width=\"0.1\" x1=\"0\" x2=\"100\""
          << " y1=\""  << i*cellsize << "\" y2=\""  << i*cellsize << "\"/>\n";
    for(int i=1; i<_ncols; ++i)
      ofs << " <line  stroke=\"gray\" stroke-width=\"0.1\" y1=\"0\" y2=\"100\""
          << " x1=\""  << i*cellsize << "\" x2=\""  << i*cellsize << "\"/>\n";
  }

  //Insert javascript for zooming and panning
  if(!pConv->IsOption("j"))
    EmbedScript(ofs);

  ofs << "</svg>\n";
return ret;
}
Esempio n. 6
0
bool SVGFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
    if(!pmol)
        return false;
    ostream &ofs = *pConv->GetOutStream();

    //*** Coordinate generation ***
    //Generate coordinates only if no existing 2D coordinates
    if( (pConv->IsOption("y") || !pmol->Has2D(true)) && !pConv->IsOption("n") )
    {
        OBOp* pOp = OBOp::FindType("gen2D");
        if(!pOp)
        {
            obErrorLog.ThrowError("SVGFormat", "gen2D not found", obError, onceOnly);
            return false;
        }
        if(!pOp->Do(pmol))
        {
            obErrorLog.ThrowError("SVGFormat", string(pmol->GetTitle()) + "- Coordinate generation unsuccessful", obError);
            return false;
        }
    }
    if(!pmol->Has2D() && pmol->NumAtoms()>1)//allows 3D coordinates (if passed by -xn above)
    {
        string mes("Molecule ");
        mes += pmol->GetTitle();
        mes += " needs 2D coordinates to display in SVGformat";
        obErrorLog.ThrowError("SVGFormat", mes, obError);
        return false;
    }

    bool hasTable = (_nrows || _ncols);

    string background = pConv->IsOption("b") ? "black" : "white";
    string bondcolor  = pConv->IsOption("b") ? "white" : "black";

    if(pConv->GetOutputIndex()==1)
    {
        //For the first molecule...
        if(hasTable)
        {
            //multiple molecules - use a table
            //Outer svg has viewbox for 0 0 100 100 or adjusted for table shape,
            //and no width or height - it uses the whole of its containing element.
            //Inner svg with width, height, x, y of table cell,
            //and viewbox to match molecule min and max x and y
            if(!pConv->IsOption("x"))
                ofs << "<?xml version=\"1.0\"?>\n";

            ofs << "<svg version=\"1.1\" id=\"topsvg\"\n"
                "xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
                "xmlns:cml=\"http://www.xml-cml.org/schema\" ";

            //*** Outer viewbox ***
            double vbwidth=100, vbheight=100;
            if (_nrows>_ncols)
                vbwidth = (100*_ncols)/_nrows;
            else if(_ncols>_nrows)
                vbheight = (100*_nrows)/_ncols;
            ofs << "viewBox=\"0 0 " << vbwidth << ' ' << vbheight << "\">\n";

            ofs << "<title>OBDepict</title>\n";
            // Draw the background
            ofs << "<rect x=\"0\" y=\"0\" width=\"" << vbwidth << "\" height=\"" << vbheight
                << "\" fill=\"" << background << "\"/>\n";
        }
    }

    //All mols
    double cellsize;
    if(hasTable)
    {
        //*** Parameter for inner svg ***
        int nc = _ncols ? _ncols : 1;
        int nr = (_nrows ? _nrows : 1);
        cellsize = 100. / std::max(nc, nr);
        int indx = pConv->GetOutputIndex() - 1;
        double innerX  = (indx % nc) * cellsize;
        double innerY  = (indx / nc) * cellsize;

        //*** Write molecule name ***
        if(!pConv->IsOption("d"))
            ofs << "<text text-anchor=\"middle\" font-size=\"" << 0.06*cellsize << "\""
                << " fill =\"" << bondcolor << "\" font-family=\"sans-serif\"\n"
                << "x=\"" << innerX + cellsize * 0.5 << "\" y=\"" << innerY + cellsize - 2.0/nr << "\" >"
                << pmol->GetTitle() << "</text>\n";

        SVGPainter painter(*pConv->GetOutStream(), true, cellsize,cellsize,innerX,innerY);
        OBDepict depictor(&painter);

        if(pConv->IsOption("w"))
            depictor.SetOption(OBDepict::genWedgeHash);
        if(!pConv->IsOption("C"))
            depictor.SetOption(OBDepict::drawTermC);// on by default
        if(pConv->IsOption("a"))
            depictor.SetOption(OBDepict::drawAllC);

        if(pConv->IsOption("A"))
        {
            AliasData::RevertToAliasForm(*pmol);
            depictor.SetAliasMode();
        }
        painter.SetFontFamily("sans-serif");
        painter.SetPenColor(OBColor(bondcolor));
        depictor.SetBondColor(bondcolor);
        painter.SetPenWidth(2);

        //No element-specific atom coloring if requested
        if(pConv->IsOption("u"))
            depictor.SetOption(OBDepict::bwAtoms);
        if(!pConv->IsOption("U"))
            depictor.SetOption(OBDepict::internalColor);

        depictor.DrawMolecule(pmol);

        //Draw atom indices if requested
        if(pConv->IsOption("i"))
            depictor.AddAtomLabels(OBDepict::AtomIndex);

        //Embed CML of molecule if requested
        if(pConv->IsOption("e"))
            EmbedCML(pmol,pConv);
    }
    else //single molecule
    {
        //Nothing written until DrawMolecule call
        //Final </svg> written at the end of this block (painter destructor)
        //This leads to some code duplication.
        double factor = 1.0;
        SVGPainter painter(*pConv->GetOutStream());
        OBDepict depictor(&painter);

        //Scale image by specifying the average bond length in pixels.
        if(pConv->IsOption("p"))
        {
            double oldblen = depictor.GetBondLength();
            double newblen = atof(pConv->IsOption("p"));
            depictor.SetBondLength(newblen);
            factor = newblen / oldblen;
            //Scale bondspacing and font size by same factor
            depictor.SetBondSpacing(depictor.GetBondSpacing() * factor);
            depictor.SetFontSize((int)(depictor.GetFontSize() * factor));
        }

        if(!pConv->IsOption("w"))
            depictor.SetOption(OBDepict::genWedgeHash);
        if(!pConv->IsOption("C"))
            depictor.SetOption(OBDepict::drawTermC);// on by default
        if(pConv->IsOption("a"))
            depictor.SetOption(OBDepict::drawAllC);

        if(pConv->IsOption("A"))
        {
            AliasData::RevertToAliasForm(*pmol);
            depictor.SetAliasMode();
        }

        painter.SetFontFamily("sans-serif");
        painter.SetPenColor(OBColor(bondcolor));
        depictor.SetBondColor(bondcolor);
        painter.SetFillColor(OBColor(background));
        painter.SetPenWidth(1);

        //No element-specific atom coloring if requested
        if(pConv->IsOption("u"))
            depictor.SetOption(OBDepict::bwAtoms);
        if(!pConv->IsOption("U"))
            depictor.SetOption(OBDepict::internalColor);

        depictor.DrawMolecule(pmol);

        //Draw atom indices if requested
        if(pConv->IsOption("i"))
            depictor.AddAtomLabels(OBDepict::AtomIndex);


        //*** Write molecule name ***
        if(!pConv->IsOption("d"))
            ofs << "<text font-size=\"" << 18 * factor  << "\""
                << " fill =\"" << bondcolor << "\"\n"
                << "x=\"" << 140 * factor << "\" y=\"" << 20 * factor << "\" >"
                << pmol->GetTitle() << "</text>\n";

        //*** Write page title name ***
        ofs << "<title>" << pmol->GetTitle() << " - OBDepict</title>\n";

        //Embed CML of molecule if requested
        if(pConv->IsOption("e"))
            EmbedCML(pmol,pConv);
    }

    if(hasTable && pConv->IsLast())
    {
        //Draw grid lines
        if(_nrows && _ncols && pConv->IsOption("l"))
        {
            for(int i=1; i<_nrows; ++i)
                ofs << " <line  stroke=\"gray\" stroke-width=\"0.1\" x1=\"0\" x2=\"100\""
                    << " y1=\""  << i*cellsize << "\" y2=\""  << i*cellsize << "\"/>\n";
            for(int i=1; i<_ncols; ++i)
                ofs << " <line  stroke=\"gray\" stroke-width=\"0.1\" y1=\"0\" y2=\"100\""
                    << " x1=\""  << i*cellsize << "\" x2=\""  << i*cellsize << "\"/>\n";
        }

        //Insert javascript for zooming and panning
        if(!pConv->IsOption("j"))
            EmbedScript(ofs);

        ofs << "</svg>\n" << endl;//Outer svg
    }

    return true;
}