Skip to content

Commit a864897

Browse files
author
vrobles
committed
Pseudo langage de script (CloseEnough) pour permettre de paramétrer le traitement à l'exécution et non à la compilation
1 parent 07c5d2a commit a864897

10 files changed

+330
-81
lines changed

CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,13 @@ else ()
103103
install(FILES ${CMAKE_SOURCE_DIR}/font.ttf
104104
DESTINATION ~/.config/inkscape/extensions/
105105
PERMISSIONS OWNER_READ OWNER_WRITE)
106+
install(FILES ${CMAKE_SOURCE_DIR}/conf/default.ce
107+
DESTINATION ~/.config/inkscape/extensions/
108+
PERMISSIONS OWNER_READ OWNER_WRITE)
106109
endif ()
107110
configure_file(${CMAKE_SOURCE_DIR}/extensions/packer.inx ${CMAKE_BINARY_DIR}/packer.inx @ONLY)
108111
file(COPY ${CMAKE_SOURCE_DIR}/font.ttf DESTINATION ${CMAKE_BINARY_DIR})
112+
file(COPY ${CMAKE_SOURCE_DIR}/conf/default.ce DESTINATION ${CMAKE_BINARY_DIR})
109113

110114
# Use Astyle to reformat source files
111115
add_custom_target(format

extensions/packer.inx

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@
55
<dependency type="executable" location="extensions">@EXE_NAME_PLUGIN@</dependency>
66
<param name="tab" type="notebook">
77
<page name = "size" _gui-text="Dimensions Plaque">
8-
<param name="width" type="int" min="0" max="9999" gui-text="Largeur plaque : ">
8+
<param name="width" type="int" min="0" max="99999" gui-text="Largeur plaque : ">
99
</param>
10-
<param name="height" type="int" min="0" max="9999" gui-text="Hauteur plaque : ">
10+
<param name="height" type="int" min="0" max="99999" gui-text="Hauteur plaque : ">
1111
</param>
1212
<param name="dup" type="boolean" gui-text="Dupliquer en bas de la page">
1313
</param>
14-
<param name="buffer" type="int" min="0" max="9999" gui-text="Distance minimale entre les objets (px): ">
15-
</param>
16-
<param name="nbMerge" type="int" min="0" max="100" gui-text="Nombre de passes du Transformer">
14+
<param name="buffer" type="int" min="0" max="99999" gui-text="Distance minimale entre les objets (px): ">
1715
</param>
1816
<param name="display" type="boolean" gui-text="Activation de l'affichage temps-réel (si disponible)">
1917
</param>
2018
</page>
19+
<page name="conf" _gui-text="Configuration">
20+
<param name="conf" type="string" gui-text="Fichier configuration CloseEnough">default.ce</param>
21+
</page>
2122
</param>
2223

2324
<effect>

src/CloseEnough.hpp

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
#ifndef CLOSE_ENOUGH__HPP
2+
#define CLOSE_ENOUGH__HPP
3+
4+
#include <boost/spirit/include/qi.hpp>
5+
#include <boost/spirit/include/phoenix_core.hpp>
6+
#include <boost/spirit/include/phoenix_operator.hpp>
7+
#include <boost/spirit/include/phoenix_stl.hpp>
8+
#include <boost/phoenix/bind/bind_function.hpp>
9+
#include <boost/phoenix/bind/bind_member_function.hpp>
10+
#include <iostream>
11+
#include <string>
12+
13+
namespace qi = boost::spirit::qi;
14+
namespace ascii = boost::spirit::ascii;
15+
namespace phoenix = boost::phoenix;
16+
17+
using qi::double_;
18+
using qi::int_;
19+
using qi::_1;
20+
using qi::_2;
21+
using qi::_3;
22+
using qi::_4;
23+
using qi::eps;
24+
using qi::_val;
25+
using qi::lit;
26+
using qi::lexeme;
27+
using ascii::space;
28+
using ascii::char_;
29+
using phoenix::ref;
30+
using phoenix::bind;
31+
32+
/*
33+
Grammaire
34+
============
35+
36+
program = big_block | big_block program
37+
big_block = bloc | 'DO' NUM 'TIMES' bloc
38+
bloc = instruction | 'BEGIN' instruction_list 'END'
39+
instruction_list = instruction | instruction instruction_list
40+
instruction = fonction '(' arguments ')' ';'
41+
fonction = transformer | solver
42+
transformer = 'SimpleTransformer'
43+
solver = 'ScanlineSolver' | 'TheSkyIsTheLimitSolver'
44+
arguments = argument | argument ',' arguments
45+
argument = STRING '=' primitive
46+
primitive = NUM | STRING
47+
48+
Exemple
49+
=========
50+
DO 2 TIMES
51+
BEGIN
52+
SimpleTransformer(criteria=IntersectionCriteria, rotateStep=30, translateStep=2);
53+
SimpleTransformer(criteria=BoxCriteria, rotateStep=30, translateStep=2);
54+
END
55+
ScanlineSolver();
56+
*/
57+
58+
59+
struct Value {
60+
bool isNum;
61+
double number;
62+
std::string str;
63+
};
64+
65+
std::ostream& operator<< (std::ostream& os, const Value& c) {
66+
os << (c.isNum ? std::to_string(c.number) : c.str);
67+
return os;
68+
}
69+
70+
struct Parameter {
71+
std::string name;
72+
Value value;
73+
};
74+
75+
bool getParameter(std::vector<Parameter> p, std::string key, std::string& value) {
76+
auto it = std::find_if(p.begin(), p.end(), [key](const Parameter & p) {
77+
return p.name == key;
78+
});
79+
80+
if (it == p.end() || it->value.isNum)
81+
return false;
82+
83+
value = it->value.str;
84+
return true;
85+
}
86+
87+
bool getParameter(std::vector<Parameter> p, std::string key, double& value) {
88+
auto it = std::find_if(p.begin(), p.end(), [key](const Parameter & p) {
89+
return p.name == key;
90+
});
91+
92+
if (it == p.end() || !it->value.isNum)
93+
return false;
94+
95+
value = it->value.number;
96+
return true;
97+
}
98+
99+
enum funcCategory { FUNC_TRANSFORMER, FUNC_SOLVER };
100+
struct Function {
101+
std::string name;
102+
funcCategory cat;
103+
};
104+
105+
struct Call {
106+
Function func;
107+
std::vector<Parameter> params;
108+
109+
void operator()(std::vector<Shape>& shapes) {
110+
static Merger merge(shapes);
111+
112+
if (func.cat == FUNC_TRANSFORMER) {
113+
std::vector<std::vector<unsigned>> transformed;
114+
115+
if (func.name == "SimpleTransformer") {
116+
std::string criteria, mergeP;
117+
118+
if (!getParameter(params, "criteria", criteria))
119+
throw std::runtime_error("Please specify a criteria for the transformer");
120+
121+
if (!getParameter(params, "merge", mergeP))
122+
mergeP = "true";
123+
124+
if (criteria == "intersection") {
125+
SimpleTransformer<IntersectionCriteria> st(shapes);
126+
transformed = st.transform();
127+
}
128+
else if (criteria == "box") {
129+
SimpleTransformer<BoxCriteria> st(shapes);
130+
transformed = st.transform();
131+
}
132+
133+
if (mergeP == "true")
134+
merge.merge(transformed);
135+
}
136+
}
137+
else if (func.cat == FUNC_SOLVER) {
138+
if (func.name == "ScanlineSolver") {
139+
Scanline solver(shapes);
140+
solver.solve();
141+
}
142+
else if (func.name == "TheSkyIsTheLimitSolver") {
143+
TheSkyIsTheLimit solver(shapes);
144+
solver.solve();
145+
}
146+
147+
merge.reset();
148+
}
149+
else
150+
throw std::runtime_error("Unknown type function");
151+
}
152+
};
153+
154+
std::ostream& operator<< (std::ostream& os, const Call& call) {
155+
os << "Calling " << call.func.name << " (" << call.func.cat << ")" << std::endl;
156+
os << "with parameters ";
157+
158+
for (auto && i : call.params)
159+
os << "(" << i.name << ", " << i.value << ") ";
160+
161+
os << std::endl;
162+
return os;
163+
}
164+
165+
Value makeNumberValue(double d) {
166+
return {true, d, ""};
167+
}
168+
Value makeStringValue(std::string s) {
169+
return {false, 0., s};
170+
}
171+
Parameter makeParameter(std::string s, Value v) {
172+
return {s, v};
173+
}
174+
Function makeTransFunction(std::string s) {
175+
return {s, FUNC_TRANSFORMER};
176+
}
177+
Function makeSolverFunction(std::string s) {
178+
return {s, FUNC_SOLVER};
179+
}
180+
Call makeCall(Function f, std::vector<Parameter> p) {
181+
return {f, p};
182+
}
183+
184+
void callEverything(std::vector<Call> block, int n, std::vector<Shape>* shapes) {
185+
for (int i = 0 ; i < n ; ++i)
186+
for (auto && j : block)
187+
j(*shapes);
188+
}
189+
190+
template <typename Iterator>
191+
struct CE_Parser : qi::grammar<Iterator, void(), ascii::space_type> {
192+
193+
qi::rule<Iterator, Value, ascii::space_type> value;
194+
qi::rule<Iterator, std::string(), ascii::space_type> string_;
195+
qi::rule<Iterator, Parameter(), ascii::space_type> parameter;
196+
qi::rule<Iterator, std::vector<Parameter>(), ascii::space_type> parameter_list;
197+
qi::rule<Iterator, std::string(), ascii::space_type> transformer;
198+
qi::rule<Iterator, std::string(), ascii::space_type> solver;
199+
qi::rule<Iterator, Function(), ascii::space_type> function_;
200+
qi::rule<Iterator, Call(), ascii::space_type> instruction;
201+
qi::rule<Iterator, std::vector<Call>(), ascii::space_type> instruction_list;
202+
qi::rule<Iterator, std::vector<Call>(), ascii::space_type> block;
203+
qi::rule<Iterator, void(), ascii::space_type> big_block;
204+
qi::rule<Iterator, void(), ascii::space_type> start;
205+
206+
CE_Parser(std::vector<Shape>& s) : CE_Parser::base_type(start) {
207+
string_ %= lexeme[+(char_ - '"' - ',' - '(' - ')' - '=')];
208+
value = double_[_val = bind(makeNumberValue, _1)]
209+
| string_[_val = bind(makeStringValue, _1)];
210+
parameter = (string_ >> '=' >> value)[_val = bind(makeParameter, _1, _2)];
211+
parameter_list = parameter [phoenix::push_back(ref(_val), _1)] % ',' | eps;
212+
transformer %= qi::string("SimpleTransformer")
213+
| qi::string("Reset");
214+
solver %= qi::string("ScanlineSolver")
215+
| qi::string("TheSkyIsTheLimitSolver");
216+
function_ = transformer[_val = bind(makeTransFunction, _1)]
217+
| solver[_val = bind(makeSolverFunction, _1)];
218+
instruction = (function_ >> '(' >> parameter_list >> ')')[_val = bind(makeCall, _1, _2)];
219+
instruction_list = instruction [phoenix::push_back(ref(_val), _1)] % ';';
220+
block = instruction[phoenix::push_back(ref(_val), _1)]
221+
| (qi::string("BEGIN") >> instruction_list >> qi::string("END"))[_val = _2];
222+
big_block = block[phoenix::bind(callEverything, _1, 1, &s)]
223+
| (qi::string("DO") >> int_ >> qi::string("TIMES") >> block)
224+
[phoenix::bind(callEverything, _4, _2, &s)];
225+
start = *(big_block);
226+
}
227+
};
228+
229+
#endif

src/Outer.cpp

+63
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
#include <rapidxml_ns/rapidxml_ns_print.hpp>
55
#include <rapidxml_ns/rapidxml_ns_utils.hpp>
6+
#include <boost/geometry/io/svg/svg_mapper.hpp>
7+
#include <boost/geometry/algorithms/envelope.hpp>
8+
#include <boost/geometry/algorithms/area.hpp>
9+
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
610

711
#include "Outer.hpp"
812
#include "Matrix.hpp"
@@ -272,3 +276,62 @@ void Outer::Write(const std::string& path, bool addto, std::vector<std::string>&
272276
outer.groupShapes();
273277
LOG(info) << "SVG successfully generated." << endl;
274278
}
279+
280+
/**
281+
* Computes the compression ratio :
282+
* actual area / minimal area
283+
*/
284+
double compressionRatio(const vector<Shape>& _shapes) {
285+
//Computing the total enveloppe of shapes
286+
std::vector<Box> boxes(_shapes.size());
287+
288+
for (unsigned i = 0; i < _shapes.size(); i++)
289+
bg::envelope(_shapes[i].getMultiP(), boxes[i]);
290+
291+
//Max x-axis point
292+
auto xIt = max_element(boxes.begin(), boxes.end(),
293+
[](Box & a, Box & b) {
294+
return a.max_corner().x() < b.max_corner().x();
295+
});
296+
//Max y-axis point
297+
auto yIt = max_element(boxes.begin(), boxes.end(),
298+
[](Box & a, Box & b) {
299+
return a.max_corner().y() < b.max_corner().y();
300+
});
301+
int binNumber = yIt->max_corner().y() / Parser::getDims().y();
302+
//Compensate spacing between bins
303+
Point maxCorner((*xIt).max_corner().x(),
304+
(*yIt).max_corner().y() - (binNumber - 1) * Parser::getDims().y() * (SPACE_COEF - 1));
305+
LOG(debug) << "Max point is (" << maxCorner.x() << ", " << maxCorner.y() << ")\n";
306+
LOG(debug) << "(total area : " << maxCorner.x() * maxCorner.y() << endl;
307+
//Computing the sum of every shape area
308+
double sum = 0.;
309+
310+
for (auto && s : _shapes)
311+
sum += bg::area(s.getMultiP());
312+
313+
LOG(debug) << "Minimal area is " << sum << endl;
314+
//Computing ratio
315+
return (maxCorner.x() * maxCorner.y()) / sum;
316+
}
317+
318+
/**
319+
* Output function using the svg output methods of BOOST.
320+
* Should be used for debug only.
321+
* Outputs what the solver actually sees.
322+
*/
323+
string debugOutputSVG(const vector<Shape>& _shapes) {
324+
stringstream ret;
325+
bg::svg_mapper <Point> mapper(ret, Parser::getDims().x(), Parser::getDims().y());
326+
327+
for (const Shape& s : _shapes)
328+
mapper.add(s.getMultiP());
329+
330+
for (const Shape& s : _shapes) {
331+
mapper.map(s.getMultiP(), "fill:rgb(" + to_string(rand() % 256) + "," +
332+
to_string(rand() % 256) + "," + to_string(rand() % 256) + ")");
333+
}
334+
335+
LOG(info) << "Debug SVG generated" << endl;
336+
return ret.str() + "</svg>";
337+
}

src/Outer.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ class Outer {
4242
void groupShapes();
4343
};
4444

45+
double compressionRatio(const std::vector<Shape>& _shapes);
46+
std::string debugOutputSVG(const std::vector<Shape>& _shapes);
4547
#endif

0 commit comments

Comments
 (0)