58df37c6be423de5ae2941cf106bfc19bac3846c
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)  */
151) bool cbEntity(const class dimeState * const state, class dimeEntity *entity,
152)             void *vp_ctx)
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)  */
218) int createChain(Chain &chain, const Object *pObjCable)
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
291) bool intersectsCablesSort(const Layer::Intersection& i1,
292)                           const Layer::Intersection& i2)
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)  */
304) int createDistri(Distri &distri, const Layer *pLayer, unsigned int pixels)
305) {
306)   // must have exactly one object
307)   if (pLayer->mObjects.size() != 1) {
Stefan Schuermans make class members private

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

343)       err = true;
344)   }
345) 
346)   return err ? -1 : 0;
347) }
348) 
349) /**
350)  * @brief write config file
351)  * @param[in] width width of video in pixels
352)  * @param[in] height height of video in pixels
353)  * @param[in] distris distributor objects
354)  */
355) int writeCfg(unsigned int width, unsigned int height,
356)              const std::vector<Distri> &distris,
357)              const std::string & strCfgFileName)
358) {
Stefan Schuermans code formatting

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

476)       err = true;
Stefan Schuermans code formatting

Stefan Schuermans authored 7 years ago

477)     }
Stefan Schuermans add config file generator

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

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