void Map::saveOtbm(const std::string &fileName) { FileStreamPtr fin = g_resources.createFile(fileName); if(!fin) stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName)); std::string dir; if(fileName.find_last_of('/') == std::string::npos) dir = g_resources.getWorkDir(); else dir = fileName.substr(0, fileName.find_last_of('/')); uint32 version = 0; /// Support old versions (< 810 or 860 IIRC) /// TODO: Use constants? if(g_things.getOtbMajorVersion() < 10) version = 1; else version = 2; /// Usually when a map has empty house/spawn file it means the map is new. /// TODO: Ask the user for a map name instead of those ugly uses of substr std::string::size_type sep_pos; std::string houseFile = getHouseFile(); std::string spawnFile = getSpawnFile(); std::string cpyf; if((sep_pos = fileName.rfind('.')) != std::string::npos && stdext::ends_with(fileName, ".otbm")) cpyf = fileName.substr(0, sep_pos); if(houseFile.empty()) houseFile = cpyf + "-houses.xml"; if(spawnFile.empty()) spawnFile = cpyf + "-spawns.xml"; /// we only need the filename to save to, the directory should be resolved by the OTBM loader not here if((sep_pos = spawnFile.rfind('/')) != std::string::npos) spawnFile = spawnFile.substr(sep_pos + 1); if((sep_pos = houseFile.rfind('/')) != std::string::npos) houseFile = houseFile.substr(sep_pos + 1); #if 0 if(version > 1) m_houses->save(dir + "/" + houseFile); saveSpawns(dir + "/" + spawnFile); #endif fin->addU32(0); // file version BinaryWriteTreePtr root(new BinaryWriteTree(fin)); root->startNode(0); { root->writeU32(version); Size mapSize = getSize(); root->writeU16(mapSize.width()); root->writeU16(mapSize.height()); root->writeU32(g_things.getOtbMajorVersion()); root->writeU32(g_things.getOtbMinorVersion()); root->startNode(OTBM_MAP_DATA); { // own description. for(const auto& desc : getDescriptions()) { root->writeU8(OTBM_ATTR_DESCRIPTION); root->writeString(desc); } // special one root->writeU8(OTBM_ATTR_DESCRIPTION); root->writeString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion())); // spawn file. root->writeU8(OTBM_ATTR_SPAWN_FILE); root->writeString(spawnFile); // house file. if(version > 1) { root->writeU8(OTBM_ATTR_HOUSE_FILE); root->writeString(houseFile); } Position base(-1, -1, -1); bool firstNode = true; for(uint8_t z = 0; z < Otc::MAX_Z + 1; ++z) { for(const auto& it : m_tileBlocks[z]) { const TileBlock& block = it.second; for(const TilePtr& tile : block.getTiles()) { if(!tile) continue; const Position& pos = tile->getPosition(); if(!pos.isValid()) continue; if(pos.x < base.x || pos.x >= base.x + 256 || pos.y < base.y|| pos.y >= base.y + 256 || pos.z != base.z) { if(!firstNode) root->endNode(); /// OTBM_TILE_AREA root->startNode(OTBM_TILE_AREA); firstNode = false; root->writePos(base = pos & 0xFF00); } uint32 flags = tile->getFlags(); root->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE); root->writePoint(Point(pos.x, pos.y) & 0xFF); // if(tileNode->getType() == OTBM_HOUSETILE) // tileNode->writeU32(tile->getHouseId()); if(flags) { root->writeU8(OTBM_ATTR_TILE_FLAGS); root->writeU32(flags); } for(const ItemPtr& item : tile->getItems()) { if(item->isGround()) { root->writeU8(OTBM_ATTR_ITEM); root->writeU16(item->getId()); continue; } item->serializeItem(root); } root->endNode(); // OTBM_TILE } } } if(!firstNode) root->endNode(); // OTBM_TILE_AREA root->startNode(OTBM_TOWNS); for(const TownPtr& town : m_towns.getTowns()) { root->writeU32(town->getId()); root->writeString(town->getName()); root->writePos(town->getPos()); } root->endNode(); if(version > 1) { root->startNode(OTBM_WAYPOINTS); for(const auto& it : m_waypoints) { root->writeString(it.second); root->writePos(it.first); } root->endNode(); } } root->endNode(); // OTBM_MAP_DATA } root->endNode(); // 0 (root) }
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); //Command line arguments TCLAP::CmdLine cmd("GOBLET (c) 2012, International Livestock Research Institute (ILRI) \n Developed by Carlos Quiros ([email protected])", ' ', "1.0 (Beta 1)"); //Required arguments TCLAP::ValueArg<std::string> databaseArg("d","database","Database name",true,"","string"); TCLAP::ValueArg<std::string> calculationArg("c","calculation","Calculation to perform. For example: 'sum(DatasetA),sum(DatasetB)' ",true,"","string"); TCLAP::ValueArg<std::string> ouputArg("o","output","Output type: (h)uman readable or (c)omputer readable",true,"","string"); //Non required arguments TCLAP::ValueArg<std::string> pathArg("a","path","Path to database. Default .",false,".","string"); TCLAP::ValueArg<std::string> hostArg("H","host","Connect to host. Default localhost",false,"localhost","string"); TCLAP::ValueArg<std::string> portArg("P","port","Port number to use. Default 3306",false,"3306","string"); TCLAP::ValueArg<std::string> userArg("u","user","User. Default empty",false,"","string"); TCLAP::ValueArg<std::string> passArg("p","password","Passwork. Default no password",false,"","string"); TCLAP::ValueArg<std::string> descArg("s","descriptions","Descriptions for the calculations separated by coma. Default value is the calculation string",false,"","string"); //Switches TCLAP::SwitchArg remoteSwitch("r","remote","Connect to remote host", cmd, false); cmd.add(databaseArg); cmd.add(calculationArg); cmd.add(ouputArg); cmd.add(pathArg); cmd.add(hostArg); cmd.add(portArg); cmd.add(userArg); cmd.add(passArg); cmd.add(descArg); //Parsing the command lines cmd.parse( argc, argv ); //Getting the variables from the command bool remote = remoteSwitch.getValue(); QString path = QString::fromUtf8(pathArg.getValue().c_str()); QString dbName = QString::fromUtf8(databaseArg.getValue().c_str()); QString host = QString::fromUtf8(hostArg.getValue().c_str()); QString port = QString::fromUtf8(portArg.getValue().c_str()); QString userName = QString::fromUtf8(userArg.getValue().c_str()); QString password = QString::fromUtf8(passArg.getValue().c_str()); QString calculation = QString::fromUtf8(calculationArg.getValue().c_str()); QString format = QString::fromUtf8(ouputArg.getValue().c_str()); QString description = QString::fromUtf8(descArg.getValue().c_str()); myDBConn con; QSqlDatabase mydb; if (!remote) { QDir dir; dir.setPath(path); if (con.connectToDB(dir.absolutePath()) == 1) { if (!dir.cd(dbName)) { gbtLog(QObject::tr("The database does not exists")); con.closeConnection(); return 1; } mydb = QSqlDatabase::addDatabase(con.getDriver(),"connection1"); } } else { mydb = QSqlDatabase::addDatabase("QMYSQL","connection1"); mydb.setHostName(host); mydb.setPort(port.toInt()); if (!userName.isEmpty()) mydb.setUserName(userName); if (!password.isEmpty()) mydb.setPassword(password); } mydb.setDatabaseName(dbName); if (!mydb.open()) { gbtLog(QObject::tr("Cannot open database")); con.closeConnection(); return 1; } else { QTime procTime; procTime.start(); QString sql; QSqlQuery qry(mydb); QList <TdatasetInfo> datasets; if (constructSQL(calculation,sql,mydb,datasets)) { gbtLog(QObject::tr("Error in calculation.")); gbtLog(qry.lastError().databaseText()); mydb.close(); con.closeConnection(); return 1; } QDomDocument doc; QDomElement root; doc = QDomDocument("GOBLETXML"); root = doc.createElement("CalcXML"); root.setAttribute("version", "1.0"); doc.appendChild(root); QDomElement varName; QDomText varValue; QList<TfieldDef> fields; int ncols; ncols = 0; if (!qry.exec(sql)) { gbtLog(QObject::tr("Cannot reset dataset.")); gbtLog(qry.lastError().databaseText()); mydb.close(); con.closeConnection(); return 1; } int nfields; nfields = qry.record().count(); QString nfield; int pos; QStringList descriptions; descriptions = getDescriptions(description); if (descriptions.count() != nfields) { descriptions.clear(); descriptions.append("Class code"); for (pos = 1; pos <= nfields-1; pos++) { descriptions.append(qry.record().field(pos).name()); } } for (pos = 0; pos <= nfields-1;pos++) { ncols++; nfield = descriptions[pos]; nfield.replace("T" + datasets[pos].code + ".",datasets[pos].name + "."); nfield.replace(".cellvalue",""); TfieldDef field; field.fieldName = nfield; field.fieldDesc = nfield; //Change for description if (pos == 0) { field.fieldType = "CHAR"; } else field.fieldType = "DEC"; fields.append(field); } QDomElement shapevars; shapevars = doc.createElement("Values"); root.appendChild(shapevars); for (pos = 0; pos <= fields.count()-1;pos++) { varName = doc.createElement("Field"); shapevars.appendChild(varName); varValue = doc.createTextNode(fields[pos].fieldDesc); varName.appendChild(varValue); } int nrows; nrows = 0; while (qry.next()) { nrows++; } nrows++; QVector<QVector<QString> > grid; grid.resize(nrows); int r; for(r=0; r<nrows; r++) { grid[r].resize(ncols); } for (pos = 0; pos <= fields.count()-1;pos++) grid[0][pos] = fields[pos].fieldDesc; r = 1; qry.first(); QString value; while (qry.isValid()) { for (pos = 0; pos <= fields.count()-1;pos++) { if (fields[pos].fieldType == "DEC") value = QString::number(qry.value(pos).toDouble(),'f',3); else value = qry.value(pos).toString(); grid[r][pos] = value; } r++; qry.next(); } if (format == "h") { QVector< int> colSizes; colSizes.resize(ncols); for (pos = 0; pos <= ncols-1;pos++) colSizes[pos] = 0; //Get the maximum size of each column for (pos = 0; pos <= ncols-1;pos++) { for(r=0; r<nrows; r++) { if (grid[r][pos].length() +2 > colSizes[pos]) { colSizes[pos] = grid[r][pos].length() +2; } } } //Print the table printf("\n"); //Print top line for (pos=0;pos<= ncols-1;pos++) { printf("+"); printf(fixLine("-",colSizes[pos]).toLocal8Bit().data()); } printf("+"); printf("\n"); //Print the columns headings for (pos=0;pos<= ncols-1;pos++) { printf("+"); printf(fixString(" " + grid[0][pos] + " ",colSizes[pos]).toLocal8Bit().data()); } printf("+"); printf("\n"); //Print separation for (pos=0;pos<= ncols-1;pos++) { printf("+"); printf(fixLine("-",colSizes[pos]).toLocal8Bit().data()); } printf("+"); printf("\n"); //Print the values for (r=1;r<=nrows-1;r++) { printf("|"); for (pos=0;pos<= ncols-1;pos++) { printf(fixString(" " + grid[r][pos] + " ",colSizes[pos]).toLocal8Bit().data()); printf("|"); } printf("\n"); } //Print the end //Print separation for (pos=0;pos<= ncols-1;pos++) { printf("+"); printf(fixLine("-",colSizes[pos]).toLocal8Bit().data()); } printf("+"); printf("\n"); } else { QDomElement shapeData; shapeData = doc.createElement("CalcData"); root.appendChild(shapeData); QDomElement rowData; QDomElement fieldData; QDomText fieldValue; for (r=1;r<=nrows-1;r++) { rowData = doc.createElement("Row"); shapeData.appendChild(rowData); for (pos=0;pos<= ncols-1;pos++) { fieldData = doc.createElement("Field"); fieldData.setAttribute("Name",fields[pos].fieldDesc); rowData.appendChild(fieldData); fieldValue = doc.createTextNode(grid[r][pos]); fieldData.appendChild(fieldValue); } } QTextStream out(stdout); out.setCodec("UTF-8"); doc.save(out,1,QDomNode::EncodingFromTextStream); } int Hours; int Minutes; int Seconds; int Milliseconds; Milliseconds = procTime.elapsed(); Hours = Milliseconds / (1000*60*60); Minutes = (Milliseconds % (1000*60*60)) / (1000*60); Seconds = ((Milliseconds % (1000*60*60)) % (1000*60)) / 1000; if (format == "h") gbtLog("Finished in " + QString::number(Hours) + " Hours," + QString::number(Minutes) + " Minutes and " + QString::number(Seconds) + " Seconds."); mydb.close(); con.closeConnection(); return 0; } return 0; }
MatrixOpDataRcPtr MatrixOpData::compose(ConstMatrixOpDataRcPtr & B) const { if (getOutputBitDepth() != B->getInputBitDepth()) { std::ostringstream oss; oss << "Matrix bit-depth missmatch between '"; oss << getID(); oss << "' and '"; oss << B->getID(); oss << "'. "; throw Exception(oss.str().c_str()); } // Ensure that both matrices will have the right dimension (ie. 4x4). if (m_array.getLength() != 4 || B->m_array.getLength() != 4) { // Note: By design, only 4x4 matrices are instantiated. // The CLF 3x3 (and 3x4) matrices are automatically converted // to 4x4 matrices, and a Matrix Transform only expects 4x4 matrices. throw Exception("MatrixOpData: array content issue."); } Descriptions newDesc = getDescriptions(); newDesc += B->getDescriptions(); MatrixOpDataRcPtr out = std::make_shared<MatrixOpData>( getInputBitDepth(), B->getOutputBitDepth()); out->setID(getID() + B->getID()); out->getDescriptions() = newDesc; // TODO: May want to revisit how the metadata is set. // By definition, A.compose(B) implies that op A precedes op B // in the opList. The LUT format coefficients follow matrix math: // vec2 = A x vec1 where A is 3x3 and vec is 3x1. // So the composite operation in matrix form is vec2 = B x A x vec1. // Hence we compute B x A rather than A x B. MatrixArrayPtr outPtr = B->m_array.inner(this->m_array); out->getArray() = *outPtr.get(); // Compute matrix B times offsets from A. Offsets offs; B->m_array.inner(getOffsets(), offs); const unsigned long dim = this->m_array.getLength(); // Determine overall scaling of the offsets prior to any catastrophic // cancellation that may occur during the add. double val, max_val = 0.; for (unsigned long i = 0; i<dim; ++i) { val = fabs(offs[i]); max_val = max_val > val ? max_val : val; val = fabs(B->getOffsets()[i]); max_val = max_val > val ? max_val : val; } // Add offsets from B. for (unsigned long i = 0; i<dim; ++i) { offs[i] += B->getOffsets()[i]; } out->setOffsets(offs); // To enable use of strict float comparisons above, we adjust the // result so that values very near integers become exactly integers. out->cleanUp(max_val); return out; }
void Map::saveOtbm(const std::string& fileName, const UIWidgetPtr&/* pbar*/) { FileStreamPtr fin = g_resources.createFile(fileName); if(!fin) stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName)); fin->cache(); std::string dir; if(fileName.find_last_of('/') == std::string::npos) dir = g_resources.getWorkDir(); else dir = fileName.substr(0, fileName.find_last_of('/')); uint32 version = 0; if(g_things.getOtbMajorVersion() < ClientVersion820) version = 1; else version = 2; /// Usually when a map has empty house/spawn file it means the map is new. /// TODO: Ask the user for a map name instead of those ugly uses of substr std::string::size_type sep_pos; std::string houseFile = getHouseFile(); std::string spawnFile = getSpawnFile(); std::string cpyf; if((sep_pos = fileName.rfind('.')) != std::string::npos && stdext::ends_with(fileName, ".otbm")) cpyf = fileName.substr(0, sep_pos); if(houseFile.empty()) houseFile = cpyf + "-houses.xml"; if(spawnFile.empty()) spawnFile = cpyf + "-spawns.xml"; /// we only need the filename to save to, the directory should be resolved by the OTBM loader not here if((sep_pos = spawnFile.rfind('/')) != std::string::npos) spawnFile = spawnFile.substr(sep_pos + 1); if((sep_pos = houseFile.rfind('/')) != std::string::npos) houseFile = houseFile.substr(sep_pos + 1); fin->addU32(0); // file version OutputBinaryTreePtr root(new OutputBinaryTree(fin)); { root->addU32(version); Size mapSize = getSize(); root->addU16(mapSize.width()); root->addU16(mapSize.height()); root->addU32(g_things.getOtbMajorVersion()); root->addU32(g_things.getOtbMinorVersion()); root->startNode(OTBM_MAP_DATA); { // own description. for(const auto& desc : getDescriptions()) { root->addU8(OTBM_ATTR_DESCRIPTION); root->addString(desc); } // special one root->addU8(OTBM_ATTR_DESCRIPTION); root->addString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion())); // spawn file. root->addU8(OTBM_ATTR_SPAWN_FILE); root->addString(spawnFile); // house file. if(version > 1) { root->addU8(OTBM_ATTR_HOUSE_FILE); root->addString(houseFile); } int px = -1, py = -1, pz =-1; bool firstNode = true; for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) { for(const auto& it : m_tileBlocks[z]) { const TileBlock& block = it.second; for(const TilePtr& tile : block.getTiles()) { if(!tile || tile->isEmpty()) continue; const Position& pos = tile->getPosition(); if(!pos.isValid()) continue; if(pos.x < px || pos.x >= px + 256 || pos.y < py || pos.y >= py + 256 || pos.z != pz) { if(!firstNode) root->endNode(); /// OTBM_TILE_AREA firstNode = false; root->startNode(OTBM_TILE_AREA); px = pos.x & 0xFF00; py = pos.y & 0xFF00; pz = pos.z; root->addPos(Position(px, py, pz)); } root->startNode(tile->isHouseTile() ? OTBM_HOUSETILE : OTBM_TILE); root->addPoint(Point(pos.x, pos.y) & 0xFF); if(tile->isHouseTile()) root->addU32(tile->getHouseId()); if(tile->getFlags()) { root->addU8(OTBM_ATTR_TILE_FLAGS); root->addU32(tile->getFlags()); } const auto& itemList = tile->getItems(); const ItemPtr& ground = tile->getGround(); if(ground) { // Those types are called "complex" needs other stuff to be written. // For containers, there is container items, for depot, depot it and so on. if(!ground->isContainer() && !ground->isDepot() && !ground->isDoor() && !ground->isTeleport()) { root->addU8(OTBM_ATTR_ITEM); root->addU16(ground->getServerId()); } else ground->serializeItem(root); } for(const ItemPtr& item : itemList) if(!item->isGround()) item->serializeItem(root); root->endNode(); // OTBM_TILE } } } if(!firstNode) root->endNode(); // OTBM_TILE_AREA root->startNode(OTBM_TOWNS); for(const TownPtr& town : g_towns.getTowns()) { root->addU32(town->getId()); root->addString(town->getName()); root->addPos(town->getPos()); } root->endNode(); if(version > 1) { root->startNode(OTBM_WAYPOINTS); for(const auto& it : m_waypoints) { root->addString(it.second); root->addPos(it.first); } root->endNode(); } } root->endNode(); // OTBM_MAP_DATA } root->endNode(); fin->flush(); fin->close(); }