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; }
int main(int argc,char *argv[]) { OBConversion Conv(&cin, &cout); //default input and output are console OBFormat* pInFormat = NULL; OBFormat* pOutFormat = NULL; vector<string> FileList, OutputFileList; string OutputFileName; // Parse commandline bool gotInType = false, gotOutType = false; bool SplitOrBatch=false; char *oext = NULL; char *iext = NULL; //Save name of program without its path (and .exe) string pn(argv[0]); string::size_type pos; #ifdef _WIN32 pos = pn.find(".exe"); if(pos!=string::npos) argv[0][pos]='\0'; #endif pos = pn.find_last_of("/\\"); if(pos==string::npos) program_name=argv[0]; else program_name=argv[0]+pos+1; const char* p; int arg; for (arg = 1; arg < argc; ++arg) { if (argv[arg]) { if (argv[arg][0] == '-') { char opchar[2]="?"; opchar[0]=argv[arg][1]; switch (opchar[0]) { case 'V': { cout << "Open Babel " << BABEL_VERSION << " -- " << __DATE__ << " -- " << __TIME__ << endl; exit(0); } case 'i': //Parameter is the input format which overrides any file extensions gotInType = true; iext = argv[arg] + 2; if(!*iext) iext = argv[++arg]; //space left after -i: use next argument if (strncasecmp(iext, "MIME", 4) == 0) { // get the MIME type from the next argument iext = argv[++arg]; pInFormat = Conv.FormatFromMIME(iext); } else pInFormat = Conv.FindFormat(iext); if(pInFormat==NULL) { cerr << program_name << ": cannot read input format!" << endl; usage(); } break; case 'o': //Parameter is the output format which overrides any file extension gotOutType = true; oext = argv[arg] + 2; if(!*oext) oext = argv[++arg]; //space left after -i: use next argument if (strncasecmp(oext, "MIME", 4) == 0) { // get the MIME type from the next argument oext = argv[++arg]; pOutFormat = Conv.FormatFromMIME(oext); } else pOutFormat = Conv.FindFormat(oext); if(pOutFormat==NULL) { cerr << program_name << ": cannot write output format!" << endl; usage(); } break; case 'O': OutputFileName = argv[arg] + 2; if(OutputFileName.size()<3) OutputFileName = argv[++arg]; //space left after -O: use next argument break; case 'L': //display a list of plugin type or classes { const char* param=NULL; if(argc>arg+1) param = argv[arg+2]; // First assume first arg is a plugin type and // param is a subtype, like babel -L ops gen3D // or first arg is a plugin ID, like babel -L cml OBPlugin* plugin; if(OBPlugin::GetPlugin("plugins", argv[arg+1]) && (plugin = OBPlugin::GetPlugin(argv[arg+1], param)) || (plugin = OBPlugin::GetPlugin(NULL, argv[arg+1]))) { //Output details of subtype string txt; plugin->Display(txt, "verbose", argv[arg+1]); cout << "One of the " << plugin->TypeID() << '\n' << txt << endl; return 0; } //...otherwise assume it is a plugin type, like babel -L forcefields //Output list of subtypes OBPlugin::List(argv[arg+1], param); return 0; } case '?': case 'H': if(isalnum(argv[arg][2]) || arg==argc-2) { if(strncasecmp(argv[arg]+2,"all",3)) { OBFormat* pFormat = (arg==argc-2) ? Conv.FindFormat(argv[arg+1]) : Conv.FindFormat(argv[arg]+2); if(pFormat) { cout << argv[arg]+2 << " " << pFormat->Description() << endl; if(pFormat->Flags() & NOTWRITABLE) cout << " This format is Read-only" << endl; if(pFormat->Flags() & NOTREADABLE) cout << " This format is Write-only" << endl; if(strlen(pFormat->SpecificationURL())) cout << "Specification at: " << pFormat->SpecificationURL() << endl; } else cout << "Format type: " << argv[arg]+2 << " was not recognized" <<endl; } else { OBPlugin::List("formats","verbose"); } } else help(); return 0; case '-': //long option --name text { //Option's text is in the next and subsequent args, until one starts with - char* nam = argv[arg]+2; if(!strcasecmp(nam, "help")) //special case handled here { help(); return 0; } if(*nam != '\0') //Do nothing if name is empty { string txt; while(arg<argc-1 && *argv[arg+1]!='-') { //use text from subsequent args if(!txt.empty())txt += ' '; //..space separated if more than one txt += argv[++arg]; } // If a API directive, e.g.---errorlevel // send to the pseudoformat "obapi" (without any leading -) if(*nam=='-') { OBConversion apiConv; OBFormat* pAPI= OBConversion::FindFormat("obapi"); if(pAPI) { apiConv.SetOutFormat(pAPI); apiConv.AddOption(nam+1, OBConversion::GENOPTIONS, txt.c_str()); apiConv.Write(NULL, &std::cout); } } else // Is a normal long option name, e.g --addtotitle Conv.AddOption(nam,OBConversion::GENOPTIONS,txt.c_str()); } } break; case 'm': //multiple output files SplitOrBatch=true; break; case 'a': //single character input option p = argv[arg]+2; DoOption(p,Conv,OBConversion::INOPTIONS,arg,argc,argv); break; case 'x': //single character output option p = argv[arg]+2; DoOption(p,Conv,OBConversion::OUTOPTIONS,arg,argc,argv); break; //Not essential, but allows these options to be before input filenames //since we know they take one parameter, and are the most likely options to be misplaced case 'f': case 'l': p = argv[arg] + 2; if(!*p) p = argv[++arg]; //space left after -f: use next argument Conv.AddOption(opchar, OBConversion::GENOPTIONS, p); break; case ':': //e.g. -:c1ccccc1. SMILES passed as a file name and handled in OBConversion FileList.push_back(argv[arg]); break; default: //single character general option p = argv[arg]+1; DoOption(p,Conv,OBConversion::GENOPTIONS,arg,argc,argv); break; } } else //filenames FileList.push_back(argv[arg]); } } #ifdef _WIN32 //Expand wildcards in input filenames and add to FileList vector<string> tempFileList(FileList); FileList.clear(); vector<string>::iterator itr; for(itr=tempFileList.begin();itr!=tempFileList.end();++itr) { if((*itr)[0]=='-') FileList.push_back(*itr); else DLHandler::findFiles (FileList, *itr); } #endif if (!gotInType) { if(FileList.empty()) { cerr << "No input file or format spec or possibly a misplaced option.\n" "Options, other than -i -o -O -m, must come after the input files.\n" <<endl; usage(); } } if (!gotOutType) { //check there is a valid output format, but the extension will be re-interpreted in OBConversion pOutFormat = Conv.FormatFromExt(OutputFileName.c_str()); if(OutputFileName.empty() || pOutFormat==NULL) { cerr << "Missing or unknown output file or format spec or possibly a misplaced option.\n" "Options, other than -i -o -O -m, must come after the input files.\n" <<endl; usage(); } } if(!Conv.SetInFormat(pInFormat)) { cerr << "Invalid input format" << endl; usage(); } if(!Conv.SetOutFormat(pOutFormat)) { cerr << "Invalid output format" << endl; usage(); } if(SplitOrBatch) { //Put * into output file name before extension (or ext.gz) if(OutputFileName.empty()) { OutputFileName = "*."; OutputFileName += oext; } else { string::size_type pos = OutputFileName.rfind(".gz"); if(pos==string::npos) pos = OutputFileName.rfind('.'); else pos = OutputFileName.rfind('.',pos-1); if(pos==string::npos) OutputFileName += '*'; else OutputFileName.insert(pos,"*"); } } int count = Conv.FullConvert(FileList, OutputFileName, OutputFileList); Conv.ReportNumberConverted(count); if(OutputFileList.size()>1) { clog << OutputFileList.size() << " files output. The first is " << OutputFileList[0] <<endl; } //std::string messageSummary = obErrorLog.GetMessageSummary(); //if (messageSummary.size()) // { // clog << messageSummary << endl; // } #ifdef _DEBUG //CM keep window open cout << "Press any key to finish" <<endl; getch(); #endif return 0; }
int main(int argc,char *argv[]) { OBConversion Conv(&cin, &cout); //default input and output are console OBFormat* pInFormat = NULL; OBFormat* pOutFormat = NULL; bool inGzip = false; bool outGzip = false; vector<string> FileList, OutputFileList; string OutputFileName; // Parse commandline bool gotInType = false, gotOutType = false; bool SplitOrBatch=false; char *oext = NULL; char *iext = NULL; //load plugs to fully initialize option parameters OBPlugin::LoadAllPlugins(); //Save name of program without its path (and .exe) string pn(argv[0]); string::size_type pos; #ifdef _WIN32 pos = pn.find(".exe"); if(pos!=string::npos) argv[0][pos]='\0'; #endif pos = pn.find_last_of("/\\"); if(pos==string::npos) program_name=argv[0]; else program_name=argv[0]+pos+1; const char* p; int arg; for (arg = 1; arg < argc; ++arg) { if (argv[arg]) { if (argv[arg][0] == '-') { switch (argv[arg][1]) { case 'V': { cout << "Open Babel " << BABEL_VERSION << " -- " << __DATE__ << " -- " << __TIME__ << endl; exit(0); } case 'i': gotInType = true; iext = argv[arg] + 2; if(!*iext) iext = argv[++arg]; //space left after -i: use next argument if (strncasecmp(iext, "MIME", 4) == 0) { // get the MIME type from the next argument iext = argv[++arg]; pInFormat = Conv.FormatFromMIME(iext); } else { //The ID provided by the OBFormat class is used as the identifying file extension pInFormat = Conv.FindFormat(iext); } if(pInFormat==NULL) { cerr << program_name << ": cannot read input format!" << endl; usage(); } break; case 'o': gotOutType = true; oext = argv[arg] + 2; if(!*oext) oext = argv[++arg]; //space left after -i: use next argument if (arg >= argc) usage(); // error in parsing command-line if (strncasecmp(oext, "MIME", 4) == 0) { // get the MIME type from the next argument oext = argv[++arg]; pOutFormat = Conv.FormatFromMIME(oext); } else pOutFormat = Conv.FindFormat(oext); if(pOutFormat==NULL) { cerr << program_name << ": cannot write output format!" << endl; usage(); } break; case 'L': //display a list of plugin type or classes { const char* param=NULL; if(argc>arg+1) param = argv[arg+2]; // First assume first arg is a plugin type and // param is a subtype, like babel -L ops gen3D // or first arg is a plugin ID, like babel -L cml OBPlugin* plugin; if ((OBPlugin::GetPlugin("plugins", argv[arg+1]) && (plugin = OBPlugin::GetPlugin(argv[arg+1], param))) || (plugin = OBPlugin::GetPlugin(NULL, argv[arg+1]))) { //Output details of subtype string txt; plugin->Display(txt, "verbose", argv[arg+1]); cout << "One of the " << plugin->TypeID() << '\n' << txt << endl; return 0; } //...otherwise assume it is a plugin type, like babel -L forcefields //Output list of subtypes OBPlugin::List(argv[arg+1], param); return 0; } case '?': case 'H': if(isalnum(argv[arg][2]) || arg==argc-2) { if(strncasecmp(argv[arg]+2,"all",3)) { const char* pID= (arg==argc-2) ? argv[arg+1] : argv[arg]+2; OBFormat* pFormat = Conv.FindFormat(pID); if(pFormat) { cout << pID << " " << pFormat->Description() << endl; if(pFormat->Flags() & NOTWRITABLE) cout << " This format is Read-only" << endl; if(pFormat->Flags() & NOTREADABLE) cout << " This format is Write-only" << endl; if(strlen(pFormat->SpecificationURL())) cout << "Specification at: " << pFormat->SpecificationURL() << endl; } else cout << "Format type: " << pID << " was not recognized" <<endl; } else { OBPlugin::List("formats","verbose"); } } else help(); return 0; case '-': //long option --name text { //Do nothing if name is empty //Option's text is the next arg provided it doesn't start with - char* nam = argv[arg]+2; if(*nam != '\0') { string txt; int i; for(i=0; i<Conv.GetOptionParams(nam, OBConversion::GENOPTIONS) && arg<argc-1 && argv[arg+1];++i) //removed && *argv[arg+1]!='-' { if(!txt.empty()) txt+=' '; txt += argv[++arg]; } if(*nam=='-') { // Is a API directive, e.g.---errorlevel //Send to the pseudoformat "obapi" (without any leading -) OBConversion apiConv; OBFormat* pAPI= OBConversion::FindFormat("obapi"); if(pAPI) { apiConv.SetOutFormat(pAPI); apiConv.AddOption(nam+1, OBConversion::GENOPTIONS, txt.c_str()); apiConv.Write(NULL, &std::cout); } } else // Is a long option name, e.g --addtotitle Conv.AddOption(nam,OBConversion::GENOPTIONS,txt.c_str()); } } break; case 'm': //multiple output files SplitOrBatch=true; break; case 'a': //single character input option p = argv[arg]+2; DoOption(p,Conv,OBConversion::INOPTIONS,arg,argc,argv); break; case 'x': //single character output option p = argv[arg]+2; DoOption(p,Conv,OBConversion::OUTOPTIONS,arg,argc,argv); break; default: //single character general option p = argv[arg]+1; DoOption(p,Conv,OBConversion::GENOPTIONS,arg,argc,argv); break; } } else { //filenames if(!gotOutType) FileList.push_back(argv[arg]); else OutputFileName = argv[arg]; } } } if(!gotOutType) //the last file is the output { if(FileList.empty()) { cerr << "No output file or format spec!" << endl; usage(); } OutputFileName = FileList.back(); FileList.pop_back(); } #if defined(_WIN32) && defined(USING_DYNAMIC_LIBS) //Expand wildcards in input filenames and add to FileList vector<string> tempFileList(FileList); FileList.clear(); vector<string>::iterator itr; for(itr=tempFileList.begin();itr!=tempFileList.end();++itr) DLHandler::findFiles (FileList, *itr); #endif if (!gotInType) { if(FileList.empty()) { cerr << "No input file or format spec!" <<endl; usage(); } } if (!gotOutType) { pOutFormat = Conv.FormatFromExt(OutputFileName.c_str(), outGzip); if(pOutFormat==NULL) { cerr << program_name << ": cannot write output format!" << endl; usage(); } } if(!Conv.SetInFormat(pInFormat)) { cerr << "Invalid input format" << endl; usage(); } if(!Conv.SetOutFormat(pOutFormat, outGzip)) { cerr << "Invalid output format" << endl; usage(); } if(SplitOrBatch) { //Put * into output file name before extension (or ext.gz) if(OutputFileName.empty()) { OutputFileName = "*."; if (oext != NULL) OutputFileName += oext; } else { string::size_type pos = OutputFileName.rfind(".gz"); if(pos==string::npos) pos = OutputFileName.rfind('.'); else pos = OutputFileName.rfind('.',pos-1); if(pos==string::npos) OutputFileName += '*'; else OutputFileName.insert(pos,"*"); } } int count = Conv.FullConvert(FileList, OutputFileName, OutputFileList); Conv.ReportNumberConverted(count); if(OutputFileList.size()>1) { clog << OutputFileList.size() << " files output. The first is " << OutputFileList[0] <<endl; } std::string messageSummary = obErrorLog.GetMessageSummary(); if (messageSummary.size()) { clog << messageSummary << endl; } #ifdef _DEBUG //CM keep window open cout << "Press any key to finish" <<endl; getch(); #endif return 0; }