770a7dbc84c0652e865e1d9c09867978b0005092
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

1) /*
Stefan Schuermans rename "FlexiPix" to "Ether...

Stefan Schuermans authored 7 years ago

2)  * EtherPix config file generator
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

3)  *
Stefan Schuermans version update

Stefan Schuermans authored 7 years ago

4)  * Copyright 2010-2017 Stefan Schuermans <stefan schuermans info>
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

5)  *
6)  * This program is free software: you can redistribute it and/or modify
7)  * it under the terms of the GNU General Public License as published by
8)  * the Free Software Foundation, version 3 of the License.
9)  *
10)  *
11)  * This program is distributed in the hope that it will be useful,
12)  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13)  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14)  * GNU General Public License for more details.
15)  *
16)  * You should have received a copy of the GNU Lesser General Public License
17)  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18)  */
19) 
20) #include <algorithm>
21) #include <dime/entities/Entity.h>
22) #include <dime/Input.h>
23) #include <dime/Model.h>
24) #include <dime/State.h>
25) #include <fstream>
26) #include <iostream>
27) #include <map>
28) #include <string>
29) 
30) #include "chain.h"
31) #include "constants.h"
32) #include "distri.h"
33) #include "layer.h"
34) #include "line.h"
35) #include "pixel.h"
36) #include "point.h"
37) 
Stefan Schuermans move config into DXF files

Stefan Schuermans authored 7 years ago

38) // layers of drawing
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

39) Layer gLayerVideo, gLayerPixel, gLayerNetwork;
40) std::map<unsigned int, Layer> gLayerCables, gLayerDistributors;
41) Layer gLayerCable;
42) 
Stefan Schuermans move config into DXF files

Stefan Schuermans authored 7 years ago

43) /**
44)  * @brief get configuration from special layer names
45)  * @param[in] model DXF drawing
46)  * @param[out] width virtual frame width in pixels
47)  * @param[out] height virtual frame height in pixels
48)  * @param[out] chains number of outputs / pixel chains per distributor
49)  * @param[out] pixels number of pixels per chain
50)  * return true for success
51)  */
52) static bool get_config(dimeModel const &model,
53)                        unsigned int &width, unsigned int &height,
54)                        unsigned int &chains, unsigned int &pixels)
55) {
56)   int layers, layer_no;
57) 
58)   width = 0;
59)   height = 0;
60)   chains = 0;
61)   pixels = 0;
62) 
63)   layers = model.getNumLayers();
64)   for (layer_no = 0; layer_no < layers; ++layer_no) {
65)     dimeLayer const *layer = model.getLayer(layer_no);
66)     std::string strLayerName = layer->getLayerName();
67) 
68)     if (strLayerName.substr(0, 10) == "cfg_width ") {
69)       if (width != 0) {
70)         std::cerr << "duplicate configuration of width" << std::endl;
71)         return false;
72)       }
73)       width = strtoul(strLayerName.substr(10).c_str(), NULL, 0);
74)       if (width == 0) {
75)         std::cerr << "invalid configuration of width" << std::endl;
76)         return false;
77)       }
78)     } else if (strLayerName.substr(0, 11) == "cfg_height ") {
79)       if (height != 0) {
80)         std::cerr << "duplicate configuration of height" << std::endl;
81)         return false;
82)       }
83)       height = strtoul(strLayerName.substr(11).c_str(), NULL, 0);
84)       if (height == 0) {
85)         std::cerr << "invalid configuration of height" << std::endl;
86)         return false;
87)       }
88)     } else if (strLayerName.substr(0, 12) == "cfg_outputs ") {
89)       if (chains != 0) {
90)         std::cerr << "duplicate configuration of number of outputs per distributor"
91)                   << std::endl;
92)         return false;
93)       }
94)       chains = strtoul(strLayerName.substr(12).c_str(), NULL, 0);
95)       if (chains == 0) {
96)         std::cerr << "invalid configuration of number of outputs per distributor"
97)                   << std::endl;
98)         return false;
99)       }
100)     } else if (strLayerName.substr(0, 11) == "cfg_pixels ") {
101)       if (pixels != 0) {
102)         std::cerr << "duplicate configuration of number of pixels per output"
103)                   << std::endl;
104)         return false;
105)       }
106)       pixels = strtoul(strLayerName.substr(11).c_str(), NULL, 0);
107)       if (pixels == 0) {
108)         std::cerr << "invalid configuration of number of pixels per output"
109)                   << std::endl;
110)         return false;
111)       }
112)     }
113) 
114)   } // for layer_no
115) 
116)   if (width == 0) {
117)     std::cerr << "missing configuration of width" << std::endl;
118)     return false;
119)   }
120)   if (height == 0) {
121)     std::cerr << "missing configuration of height" << std::endl;
122)     return false;
123)   }
124)   if (chains == 0) {
125)     std::cerr << "missing configuration of number of outputs per distributor"
126)               << std::endl;
127)     return false;
128)   }
129)   if (pixels == 0) {
130)     std::cerr << "missing configuration of number of pixels per output"
131)               << std::endl;
132)     return false;
133)   }
134) 
135)   std::cout << "configuration:" << std::endl;
136)   std::cout << "  width: " << width << std::endl;
137)   std::cout << "  height: " << height << std::endl;
138)   std::cout << "  outputs: " << chains << std::endl;
139)   std::cout << "  pixels: " << pixels << std::endl;
140) 
141)   return true;
142) }
143) 
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

144) /**
Stefan Schuermans comment typo

Stefan Schuermans authored 7 years ago

145)  * @brief enumerate a entity in the DXF file
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

146)  * @param[in] state current state of libdime
147)  * @param[in] entity pointer to entity
148)  * @param[in] vp_ctx context pointer
149)  * @return if to continue enumeration
150)  */
Stefan Schuermans make local functions static

Stefan Schuermans authored 7 years ago

151) static bool cbEntity(const class dimeState * const state,
152)                      class dimeEntity *entity, void *vp_ctx)
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

153) {
154)   (void)vp_ctx;
155) 
156)   // get layer
157)   std::string strLayerName = entity->getLayerName();
158)   Layer * pLayer;
Stefan Schuermans support decimal and hexadec...

Stefan Schuermans authored 7 years ago

159)   if (strLayerName == "video") {
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

160)     pLayer = &gLayerVideo;
Stefan Schuermans support decimal and hexadec...

Stefan Schuermans authored 7 years ago

161)   } else if (strLayerName == "pixel") {
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

162)     pLayer = &gLayerPixel;
Stefan Schuermans support decimal and hexadec...

Stefan Schuermans authored 7 years ago

163)   } else if (strLayerName == "network") {
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

164)     pLayer = &gLayerNetwork;
Stefan Schuermans support decimal and hexadec...

Stefan Schuermans authored 7 years ago

165)   } else if (strLayerName == "cable") {
166)     pLayer = &gLayerCables[0];
167)   } else if (strLayerName.substr(0, 6) == "cable ") {
168)     unsigned int no = strtoul(strLayerName.substr(6).c_str(), NULL, 0);
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

169)     pLayer = &gLayerCables[no];
170)   } else if (strLayerName.substr(0, 12) == "distributor ") {
Stefan Schuermans support decimal and hexadec...

Stefan Schuermans authored 7 years ago

171)     unsigned int no = strtoul(strLayerName.substr(12).c_str(), NULL, 0);
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

172)     pLayer = &gLayerDistributors[no];
Stefan Schuermans support decimal and hexadec...

Stefan Schuermans authored 7 years ago

173)   } else {
Stefan Schuermans move config into DXF files

Stefan Schuermans authored 7 years ago

174)     return true; // unknown layer -> ignore
Stefan Schuermans support decimal and hexadec...

Stefan Schuermans authored 7 years ago

175)   }
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

176) 
177)   // get transformation matrix
178)   dimeMatrix matrix;
179)   state->getMatrix(matrix);
180) 
181)   // get geometry data
182)   dimeArray<dimeVec3f> vertices;
183)   dimeArray<int> indices;
184)   dimeVec3f extrusionDir;
185)   dxfdouble thickness;
186)   entity->extractGeometry(vertices, indices, extrusionDir, thickness);
187) 
188)   // transform geometry data
189)   for (int i = 0; i < vertices.count(); ++i)
190)     matrix.multMatrixVec(vertices[i]);
191) 
192)   // build object from geometry data
193)   Object *pObject = new Object;
194)   for (int i = 1; i < vertices.count(); ++i) {
195)     Line *pLine = new Line(Point(vertices[i - 1].x, vertices[i - 1].y),
196)                            Point(vertices[i].x, vertices[i].y));
197)     if (pLine->length() >= EPSILON) // ignore dots
198)       pObject->add(pLine);
199)     else {
Stefan Schuermans tidy output

Stefan Schuermans authored 7 years ago

200)       std::cerr << "ignoring dot at " << pLine->mStart.mX << ","
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

201)                 << pLine->mStart.mY << std::endl;
202)       delete pLine;
203)     }
204)   }
205) 
206)   // build object into layer
207)   pLayer->build(pObject);
208) 
209)   return true;
210) }
211) 
212) /**
213)  * @brief create a chain
214)  * @param[in] chain chain to create
215)  * @param[in] pObjCable cable to first pixel
216)  * @return 0 on success, -1 on error
217)  */
Stefan Schuermans make local functions static

Stefan Schuermans authored 7 years ago

218) static int createChain(Chain &chain, const Object *pObjCable)
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

219) {
220)   // add all pixels
221)   const Object *pObjPixel = NULL;
222)   while (true) {
223) 
224)     // find pixels connected to cable
225)     std::vector<Layer::Intersection> intersectsPixels;
226)     gLayerPixel.getIntersections(pObjCable, intersectsPixels);
227) 
228)     // remove last pixel from results
229)     std::vector<Layer::Intersection>::iterator itPixel;
230)     for (itPixel = intersectsPixels.begin();
231)          itPixel != intersectsPixels.end(); ++itPixel) {
232)       if (itPixel->pObj == pObjPixel) {
233)         itPixel = intersectsPixels.erase(itPixel);
234)         if (itPixel == intersectsPixels.end())
235)           break;
236)       }
237)     }
238) 
239)     // end of chain
240)     if (intersectsPixels.size() < 1)
241)       return 0;
242) 
243)     // more than one next pixel
244)     if (intersectsPixels.size() > 1) {
245)       std::cerr << "pixel cable connects multiple pixels ("
246)                 << intersectsPixels[0].pt.mX << ","
247)                 << intersectsPixels[0].pt.mY << ")" << std::endl;
248)       return -1;
249)     }
250) 
251)     // pixel found
252)     pObjPixel = intersectsPixels[0].pObj;
253) 
254)     // add pixel to chain
Stefan Schuermans make class members private

Stefan Schuermans authored 7 years ago

255)     chain.addPixel(Pixel(pObjPixel));
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

256) 
257)     // find cables connected to pixel
258)     std::vector<Layer::Intersection> intersectsCables;
259)     gLayerCable.getIntersections(pObjPixel, intersectsCables);
260) 
261)     // remove last cable from results
262)     std::vector<Layer::Intersection>::iterator itCable;
263)     for (itCable = intersectsCables.begin();
264)          itCable != intersectsCables.end(); ++itCable) {
265)       if (itCable->pObj == pObjCable) {
266)         itCable = intersectsCables.erase(itCable);
267)         if (itCable == intersectsCables.end())
268)           break;
269)       }
270)     }
271) 
272)     // end of chain
273)     if (intersectsCables.size() < 1)
274)       return 0;
275) 
276)     // more than one next pixel
277)     if (intersectsCables.size() > 1) {
278)       std::cerr << "pixel connected to multiple pixel cables ("
279)                 << intersectsCables[0].pt.mX << ","
280)                 << intersectsCables[0].pt.mY << ")" << std::endl;
281)       return -1;
282)     }
283) 
284)     // next cable found
285)     pObjCable = intersectsCables[0].pObj;
286) 
287)   } // while (true)
288) }
289) 
290) /// sort helper for distributor/cables intersections
Stefan Schuermans make local functions static

Stefan Schuermans authored 7 years ago

291) static bool intersectsCablesSort(const Layer::Intersection& i1,
292)                                  const Layer::Intersection& i2)
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

293) {
Stefan Schuermans code formatting

Stefan Schuermans authored 7 years ago

294)   return i1.pt.abs_sq() < i2.pt.abs_sq();
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

295) }
296) 
297) /**
298)  * @brief create a distributor
299)  * @param[in] distri distributor to create
300)  * @param[in] pLayer layer containing distributor
301)  * @param[in] pixels number of pixels per chain
302)  * @return 0 on success, -1 on error
303)  */
Stefan Schuermans make local functions static

Stefan Schuermans authored 7 years ago

304) static int createDistri(Distri &distri, const Layer *pLayer,
305)                         unsigned int pixels)
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

306) {
307)   // must have exactly one object
308)   if (pLayer->mObjects.size() != 1) {
Stefan Schuermans output hex numbers with 0x...

Stefan Schuermans authored 7 years ago

309)     std::cerr << "layer of distributor 0x" << std::hex << distri.getNo()
Stefan Schuermans improve error messages

Stefan Schuermans authored 7 years ago

310)               << "contains no object or multiple objects" << std::endl;
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

311)     return -1;
312)   }
313)   const Object *pObjDistri = pLayer->mObjects[0];
314) 
315)   // get location of network connection
316)   std::vector<Layer::Intersection> intersectsNet;
317)   gLayerNetwork.getIntersections(pObjDistri, intersectsNet);
318)   if (intersectsNet.size() != 1) {
Stefan Schuermans output hex numbers with 0x...

Stefan Schuermans authored 7 years ago

319)     std::cerr << "distributor 0x" << std::hex << distri.getNo()
Stefan Schuermans improve error messages

Stefan Schuermans authored 7 years ago

320)               << "has no network connection or multiple network connections"
321)               << std::endl;
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

322)     return -1;
323)   }
324)   Point ptNetwork = intersectsNet[0].pt;
325) 
326)   // get cables to pixel chains
327)   std::vector<Layer::Intersection> intersectsCables;
328)   gLayerCable.getIntersections(pObjDistri, intersectsCables);
329) 
330)   // sort cables according to distance to network
331)   std::vector<Layer::Intersection>::iterator itIntersect;
332)   for (itIntersect = intersectsCables.begin();
333)        itIntersect != intersectsCables.end(); ++itIntersect)
334)     itIntersect->pt -= ptNetwork;
335)   std::sort(intersectsCables.begin(), intersectsCables.end(),
336)             intersectsCablesSort);
337) 
338)   // create chains
339)   bool err = false;
340)   for (itIntersect = intersectsCables.begin();
341)        itIntersect != intersectsCables.end(); ++itIntersect) {
Stefan Schuermans make class members private

Stefan Schuermans authored 7 years ago

342)     distri.addChain(Chain(pixels));
343)     if (createChain(distri.accessLastChain(), itIntersect->pObj) != 0)
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

344)       err = true;
345)   }
346) 
347)   return err ? -1 : 0;
348) }
349) 
350) /**
351)  * @brief write config file
352)  * @param[in] width width of video in pixels
353)  * @param[in] height height of video in pixels
354)  * @param[in] distris distributor objects
355)  */
Stefan Schuermans make local functions static

Stefan Schuermans authored 7 years ago

356) static int writeCfg(unsigned int width, unsigned int height,
357)                     const std::vector<Distri> &distris,
358)                     const std::string & strCfgFileName)
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

359) {
Stefan Schuermans code formatting

Stefan Schuermans authored 7 years ago

360)   // open output file
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

361)   std::ofstream strm(strCfgFileName.c_str(), std::ios::out);
362)   if (!strm.is_open()) {
363)     std::cerr << "could not open \"" << strCfgFileName
364)               << "\" for wrinting" << std::endl;
365)     return -1;
366)   }
367) 
368)   // video size
369)   strm << "size = " << width << "," << height << std::endl
370)        << std::endl;
371) 
372)   // distributors
373)   std::vector<Distri>::const_iterator itD;
374)   for (itD = distris.begin(); itD != distris.end(); ++itD)
375)     itD->writeDistri(strm);
376)   strm << std::endl;
377) 
378)   // mappings
379)   for (itD = distris.begin(); itD != distris.end(); ++itD)
380)     itD->writeMapping(strm);
381)   strm << std::endl;
382) 
383)   // pixels
384)   for (itD = distris.begin(); itD != distris.end(); ++itD)
385)     itD->writePixels(strm);
386)   strm << std::endl;
387) 
388)   strm.close();
389)   return 0;
390) }
391) 
392) /**
393)  * @brief main program
394)  * @param[in] argc number of parameters
395)  * @param[in] argv parameter values
396)  * @return 0 on success, -1 on error
397)  */
398) int main(int argc, char *argv[])
399) {
400)   // get parameters
Stefan Schuermans move config into DXF files

Stefan Schuermans authored 7 years ago

401)   if (argc != 3) {
Stefan Schuermans rename "FlexiPix" to "Ether...

Stefan Schuermans authored 7 years ago

402)     std::cerr << "EtherPix config file generator "
403)               << ETPCG_VER_MAJ << "."
404)               << ETPCG_VER_MIN << "."
405)               << ETPCG_VER_REV << std::endl
406)               << "usage: " << argv[0] << " <schematic_drawing.dxf> <config.etp>"
Stefan Schuermans move config into DXF files

Stefan Schuermans authored 7 years ago

407)               << std::endl;
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

408)     return -1;
409)   }
410)   std::string strDxfFileName = argv[1];
Stefan Schuermans move config into DXF files

Stefan Schuermans authored 7 years ago

411)   std::string strCfgFileName = argv[2];
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

412) 
413)   // read DXF file
414)   dimeInput in;
415)   if (!in.setFile(strDxfFileName.c_str())) {
416)     std::cerr << "error opening file \"" << strDxfFileName
417)               << "\" for reading" << std::endl;
418)     return -1;
419)   }
420)   dimeModel model;
421)   if (!model.read(&in)) {
422)     std::cerr << "DXF read error in line " << in.getFilePosition()
423)               << " of file \"" << strDxfFileName << "\""
424)               << std::endl;
425)     return -1;
426)   }
427) 
Stefan Schuermans move config into DXF files

Stefan Schuermans authored 7 years ago

428)   // get configuration from layers
429)   unsigned int width, height, chains, pixels;
430)   if (! get_config(model, width, height, chains, pixels)) {
431)     return -1;
432)   }
433) 
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

434)   // enumerate all entities
435)   model.traverseEntities(cbEntity, NULL);
436) 
437)   // merge all cable layers
438)   std::map<unsigned int, Layer>::iterator itCable;
439)   for (itCable = gLayerCables.begin();
440)        itCable != gLayerCables.end(); ++itCable)
441)   gLayerCable.merge(&itCable->second);
442)   // gLayerCables[] is now empty and will not be used any more
443) 
Stefan Schuermans tidy output

Stefan Schuermans authored 7 years ago

444)   // output object count information
445)   std::cout << "object counts:" << std::endl;
446)   std::cout << "  video: " << gLayerVideo.mObjects.size() << std::endl;
447)   std::cout << "  pixel: " << gLayerPixel.mObjects.size() << std::endl;
448)   std::cout << "  cable: " << gLayerCable.mObjects.size() << std::endl;
449)   std::cout << "  network: " << gLayerNetwork.mObjects.size() << std::endl;
450)   std::cout << "  distributor:" << std::endl;
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

451)   std::map<unsigned int, Layer>::const_iterator itDistri;
452)   for (itDistri = gLayerDistributors.begin();
453)        itDistri != gLayerDistributors.end(); ++itDistri)
Stefan Schuermans tidy output

Stefan Schuermans authored 7 years ago

454)     std::cout << "    " << itDistri->first << ": "
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

455)               << itDistri->second.mObjects.size() << std::endl;
456) 
457)   // get origin and size of pixels in video
458)   Box boundsVideo;
459)   gLayerVideo.getBounds(boundsVideo);
460)   Point ptPixel0(boundsVideo.mBL.mX, boundsVideo.mTR.mY);
461)   Point ptPixelSz = boundsVideo.mTR - boundsVideo.mBL;
462)   ptPixelSz.mX /= (double)width;
463)   ptPixelSz.mY /= (double)height;
464)   ptPixelSz.mY *= -1;
465)   std::cout << "video bounds: "
466)             << boundsVideo.mBL.mX << "," << boundsVideo.mBL.mY
467)             << " " << boundsVideo.mTR.mX << "," << boundsVideo.mTR.mY
468)             << std::endl;
469) 
470)   // create distributors
471)   bool err = false;
472)   std::vector<Distri> distris;
473)   for (itDistri = gLayerDistributors.begin();
474)        itDistri != gLayerDistributors.end(); ++itDistri) {
475)     distris.push_back(Distri(itDistri->first, chains, pixels));
Stefan Schuermans code formatting

Stefan Schuermans authored 7 years ago

476)     if (createDistri(distris.back(), &itDistri->second, pixels) != 0) {
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

477)       err = true;
Stefan Schuermans code formatting

Stefan Schuermans authored 7 years ago

478)     }
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

479)   }
480) 
481)   // obtain pixel coordinates
482)   std::vector<Distri>::iterator itD;
483)   for (itD = distris.begin(); itD != distris.end(); ++itD)
484)     if (itD->pixCoord(ptPixel0, ptPixelSz, width, height) != 0)
485)       err = true;
486) 
Stefan Schuermans check number of connected p...

Stefan Schuermans authored 7 years ago

487)   // count pixels connected to distributors and compare to total pixels
488)   size_t distri_pixels = 0;
489)   for (itD = distris.begin(); itD != distris.end(); ++itD)
490)     distri_pixels += itD->countPixels();
491)   std::cout << "pixels connected to distributors: "
492)             << distri_pixels << std::endl;
493)   if (distri_pixels != gLayerPixel.mObjects.size()) {
494)     std::cerr << "number of connected pixels (" << distri_pixels
495)               << ") does not match total number of pixels ("
496)               << gLayerPixel.mObjects.size() << ")" << std::endl;
497)     err = true;
498)   }
499)