BlinkenArea - GitList
Repositories
Blog
Wiki
libflexipix
Code
Commits
Branches
Tags
Search
Tree:
8fa83e9
Branches
Tags
master
v1.0.0
v1.0.1
v1.0.2
v1.0.3
v1.0.4
v1.0.5
v1.0.6
v1.0.7
v1.0.8
libflexipix
config_gen
src
main.cpp
move config into DXF files
Stefan Schuermans
commited
8fa83e9
at 2017-05-20 12:59:56
main.cpp
Blame
History
Raw
/* * FlexiPix config file generator * * Copyright 2010 Stefan Schuermans <stefan schuermans info> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <algorithm> #include <dime/entities/Entity.h> #include <dime/Input.h> #include <dime/Model.h> #include <dime/State.h> #include <fstream> #include <iostream> #include <map> #include <string> #include "chain.h" #include "constants.h" #include "distri.h" #include "layer.h" #include "line.h" #include "pixel.h" #include "point.h" // layers of drawing Layer gLayerVideo, gLayerPixel, gLayerNetwork; std::map<unsigned int, Layer> gLayerCables, gLayerDistributors; Layer gLayerCable; /** * @brief get configuration from special layer names * @param[in] model DXF drawing * @param[out] width virtual frame width in pixels * @param[out] height virtual frame height in pixels * @param[out] chains number of outputs / pixel chains per distributor * @param[out] pixels number of pixels per chain * return true for success */ static bool get_config(dimeModel const &model, unsigned int &width, unsigned int &height, unsigned int &chains, unsigned int &pixels) { int layers, layer_no; width = 0; height = 0; chains = 0; pixels = 0; layers = model.getNumLayers(); for (layer_no = 0; layer_no < layers; ++layer_no) { dimeLayer const *layer = model.getLayer(layer_no); std::string strLayerName = layer->getLayerName(); if (strLayerName.substr(0, 10) == "cfg_width ") { if (width != 0) { std::cerr << "duplicate configuration of width" << std::endl; return false; } width = strtoul(strLayerName.substr(10).c_str(), NULL, 0); if (width == 0) { std::cerr << "invalid configuration of width" << std::endl; return false; } } else if (strLayerName.substr(0, 11) == "cfg_height ") { if (height != 0) { std::cerr << "duplicate configuration of height" << std::endl; return false; } height = strtoul(strLayerName.substr(11).c_str(), NULL, 0); if (height == 0) { std::cerr << "invalid configuration of height" << std::endl; return false; } } else if (strLayerName.substr(0, 12) == "cfg_outputs ") { if (chains != 0) { std::cerr << "duplicate configuration of number of outputs per distributor" << std::endl; return false; } chains = strtoul(strLayerName.substr(12).c_str(), NULL, 0); if (chains == 0) { std::cerr << "invalid configuration of number of outputs per distributor" << std::endl; return false; } } else if (strLayerName.substr(0, 11) == "cfg_pixels ") { if (pixels != 0) { std::cerr << "duplicate configuration of number of pixels per output" << std::endl; return false; } pixels = strtoul(strLayerName.substr(11).c_str(), NULL, 0); if (pixels == 0) { std::cerr << "invalid configuration of number of pixels per output" << std::endl; return false; } } } // for layer_no if (width == 0) { std::cerr << "missing configuration of width" << std::endl; return false; } if (height == 0) { std::cerr << "missing configuration of height" << std::endl; return false; } if (chains == 0) { std::cerr << "missing configuration of number of outputs per distributor" << std::endl; return false; } if (pixels == 0) { std::cerr << "missing configuration of number of pixels per output" << std::endl; return false; } std::cout << "configuration:" << std::endl; std::cout << " width: " << width << std::endl; std::cout << " height: " << height << std::endl; std::cout << " outputs: " << chains << std::endl; std::cout << " pixels: " << pixels << std::endl; return true; } /** * @brief enumerate a entitiy in the DXF file * @param[in] state current state of libdime * @param[in] entity pointer to entity * @param[in] vp_ctx context pointer * @return if to continue enumeration */ bool cbEntity(const class dimeState * const state, class dimeEntity *entity, void *vp_ctx) { (void)vp_ctx; // get layer std::string strLayerName = entity->getLayerName(); Layer * pLayer; if (strLayerName == "video") { pLayer = &gLayerVideo; } else if (strLayerName == "pixel") { pLayer = &gLayerPixel; } else if (strLayerName == "network") { pLayer = &gLayerNetwork; } else if (strLayerName == "cable") { pLayer = &gLayerCables[0]; } else if (strLayerName.substr(0, 6) == "cable ") { unsigned int no = strtoul(strLayerName.substr(6).c_str(), NULL, 0); pLayer = &gLayerCables[no]; } else if (strLayerName.substr(0, 12) == "distributor ") { unsigned int no = strtoul(strLayerName.substr(12).c_str(), NULL, 0); pLayer = &gLayerDistributors[no]; } else { return true; // unknown layer -> ignore } // get transformation matrix dimeMatrix matrix; state->getMatrix(matrix); // get geometry data dimeArray<dimeVec3f> vertices; dimeArray<int> indices; dimeVec3f extrusionDir; dxfdouble thickness; entity->extractGeometry(vertices, indices, extrusionDir, thickness); // transform geometry data for (int i = 0; i < vertices.count(); ++i) matrix.multMatrixVec(vertices[i]); // build object from geometry data Object *pObject = new Object; for (int i = 1; i < vertices.count(); ++i) { Line *pLine = new Line(Point(vertices[i - 1].x, vertices[i - 1].y), Point(vertices[i].x, vertices[i].y)); if (pLine->length() >= EPSILON) // ignore dots pObject->add(pLine); else { std::cerr << "ignoring dot at " << pLine->mStart.mX << "," << pLine->mStart.mY << std::endl; delete pLine; } } // build object into layer pLayer->build(pObject); return true; } /** * @brief create a chain * @param[in] chain chain to create * @param[in] pObjCable cable to first pixel * @return 0 on success, -1 on error */ int createChain(Chain &chain, const Object *pObjCable) { // add all pixels const Object *pObjPixel = NULL; while (true) { // find pixels connected to cable std::vector<Layer::Intersection> intersectsPixels; gLayerPixel.getIntersections(pObjCable, intersectsPixels); // remove last pixel from results std::vector<Layer::Intersection>::iterator itPixel; for (itPixel = intersectsPixels.begin(); itPixel != intersectsPixels.end(); ++itPixel) { if (itPixel->pObj == pObjPixel) { itPixel = intersectsPixels.erase(itPixel); if (itPixel == intersectsPixels.end()) break; } } // end of chain if (intersectsPixels.size() < 1) return 0; // more than one next pixel if (intersectsPixels.size() > 1) { std::cerr << "pixel cable connects multiple pixels (" << intersectsPixels[0].pt.mX << "," << intersectsPixels[0].pt.mY << ")" << std::endl; return -1; } // pixel found pObjPixel = intersectsPixels[0].pObj; // add pixel to chain chain.mPixels.push_back(Pixel(pObjPixel)); // find cables connected to pixel std::vector<Layer::Intersection> intersectsCables; gLayerCable.getIntersections(pObjPixel, intersectsCables); // remove last cable from results std::vector<Layer::Intersection>::iterator itCable; for (itCable = intersectsCables.begin(); itCable != intersectsCables.end(); ++itCable) { if (itCable->pObj == pObjCable) { itCable = intersectsCables.erase(itCable); if (itCable == intersectsCables.end()) break; } } // end of chain if (intersectsCables.size() < 1) return 0; // more than one next pixel if (intersectsCables.size() > 1) { std::cerr << "pixel connected to multiple pixel cables (" << intersectsCables[0].pt.mX << "," << intersectsCables[0].pt.mY << ")" << std::endl; return -1; } // next cable found pObjCable = intersectsCables[0].pObj; } // while (true) } /// sort helper for distributor/cables intersections bool intersectsCablesSort(const Layer::Intersection& i1, const Layer::Intersection& i2) { return i1.pt.abs_sq() < i2.pt.abs_sq(); } /** * @brief create a distributor * @param[in] distri distributor to create * @param[in] pLayer layer containing distributor * @param[in] pixels number of pixels per chain * @return 0 on success, -1 on error */ int createDistri(Distri &distri, const Layer *pLayer, unsigned int pixels) { // must have exactly one object if (pLayer->mObjects.size() != 1) { std::cerr << "layer of distributor " << std::hex << distri.mNo << "contains no object or multiple objects" << std::endl; return -1; } const Object *pObjDistri = pLayer->mObjects[0]; // get location of network connection std::vector<Layer::Intersection> intersectsNet; gLayerNetwork.getIntersections(pObjDistri, intersectsNet); if (intersectsNet.size() != 1) { std::cerr << "distributor " << std::hex << distri.mNo << "has no network connection or multiple network connections" << std::endl; return -1; } Point ptNetwork = intersectsNet[0].pt; // get cables to pixel chains std::vector<Layer::Intersection> intersectsCables; gLayerCable.getIntersections(pObjDistri, intersectsCables); // sort cables according to distance to network std::vector<Layer::Intersection>::iterator itIntersect; for (itIntersect = intersectsCables.begin(); itIntersect != intersectsCables.end(); ++itIntersect) itIntersect->pt -= ptNetwork; std::sort(intersectsCables.begin(), intersectsCables.end(), intersectsCablesSort); // create chains bool err = false; for (itIntersect = intersectsCables.begin(); itIntersect != intersectsCables.end(); ++itIntersect) { distri.mChains.push_back(Chain(pixels)); if (createChain(distri.mChains.back(), itIntersect->pObj) != 0) err = true; } return err ? -1 : 0; } /** * @brief write config file * @param[in] width width of video in pixels * @param[in] height height of video in pixels * @param[in] distris distributor objects */ int writeCfg(unsigned int width, unsigned int height, const std::vector<Distri> &distris, const std::string & strCfgFileName) { // open output file std::ofstream strm(strCfgFileName.c_str(), std::ios::out); if (!strm.is_open()) { std::cerr << "could not open \"" << strCfgFileName << "\" for wrinting" << std::endl; return -1; } // video size strm << "size = " << width << "," << height << std::endl << std::endl; // distributors std::vector<Distri>::const_iterator itD; for (itD = distris.begin(); itD != distris.end(); ++itD) itD->writeDistri(strm); strm << std::endl; // mappings for (itD = distris.begin(); itD != distris.end(); ++itD) itD->writeMapping(strm); strm << std::endl; // pixels for (itD = distris.begin(); itD != distris.end(); ++itD) itD->writePixels(strm); strm << std::endl; strm.close(); return 0; } /** * @brief main program * @param[in] argc number of parameters * @param[in] argv parameter values * @return 0 on success, -1 on error */ int main(int argc, char *argv[]) { // get parameters if (argc != 3) { std::cerr << "FlexiPix config file generator " << FLPCG_VER_MAJ << "." << FLPCG_VER_MIN << "." << FLPCG_VER_REV << std::endl << "usage: " << argv[0] << " <schematic_drawing.dxf> <config.flp>" << std::endl; return -1; } std::string strDxfFileName = argv[1]; std::string strCfgFileName = argv[2]; // read DXF file dimeInput in; if (!in.setFile(strDxfFileName.c_str())) { std::cerr << "error opening file \"" << strDxfFileName << "\" for reading" << std::endl; return -1; } dimeModel model; if (!model.read(&in)) { std::cerr << "DXF read error in line " << in.getFilePosition() << " of file \"" << strDxfFileName << "\"" << std::endl; return -1; } // get configuration from layers unsigned int width, height, chains, pixels; if (! get_config(model, width, height, chains, pixels)) { return -1; } // enumerate all entities model.traverseEntities(cbEntity, NULL); // merge all cable layers std::map<unsigned int, Layer>::iterator itCable; for (itCable = gLayerCables.begin(); itCable != gLayerCables.end(); ++itCable) gLayerCable.merge(&itCable->second); // gLayerCables[] is now empty and will not be used any more // output object count information std::cout << "object counts:" << std::endl; std::cout << " video: " << gLayerVideo.mObjects.size() << std::endl; std::cout << " pixel: " << gLayerPixel.mObjects.size() << std::endl; std::cout << " cable: " << gLayerCable.mObjects.size() << std::endl; std::cout << " network: " << gLayerNetwork.mObjects.size() << std::endl; std::cout << " distributor:" << std::endl; std::map<unsigned int, Layer>::const_iterator itDistri; for (itDistri = gLayerDistributors.begin(); itDistri != gLayerDistributors.end(); ++itDistri) std::cout << " " << itDistri->first << ": " << itDistri->second.mObjects.size() << std::endl; // get origin and size of pixels in video Box boundsVideo; gLayerVideo.getBounds(boundsVideo); Point ptPixel0(boundsVideo.mBL.mX, boundsVideo.mTR.mY); Point ptPixelSz = boundsVideo.mTR - boundsVideo.mBL; ptPixelSz.mX /= (double)width; ptPixelSz.mY /= (double)height; ptPixelSz.mY *= -1; std::cout << "video bounds: " << boundsVideo.mBL.mX << "," << boundsVideo.mBL.mY << " " << boundsVideo.mTR.mX << "," << boundsVideo.mTR.mY << std::endl; // create distributors bool err = false; std::vector<Distri> distris; for (itDistri = gLayerDistributors.begin(); itDistri != gLayerDistributors.end(); ++itDistri) { distris.push_back(Distri(itDistri->first, chains, pixels)); if (createDistri(distris.back(), &itDistri->second, pixels) != 0) { err = true; } } // obtain pixel coordinates std::vector<Distri>::iterator itD; for (itD = distris.begin(); itD != distris.end(); ++itD) if (itD->pixCoord(ptPixel0, ptPixelSz, width, height) != 0) err = true; // write config file if (writeCfg(width, height, distris, strCfgFileName) != 0) err = true; // output message if errors were detected if (err) { std::cerr << "ERRORs were found" << std::endl; return -1; } return 0; }