diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2016-05-02 22:57:13 -0400 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2016-05-02 22:57:13 -0400 |
commit | 330f75e663c22e1198a92fd134865ada98c3957b (patch) | |
tree | b78f8aa762fcc93c14a0905546b694cddaaa3041 /infinite.cpp | |
download | infinite-330f75e663c22e1198a92fd134865ada98c3957b.tar.gz infinite-330f75e663c22e1198a92fd134865ada98c3957b.tar.bz2 infinite-330f75e663c22e1198a92fd134865ada98c3957b.zip |
Initial commit
Diffstat (limited to 'infinite.cpp')
-rw-r--r-- | infinite.cpp | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/infinite.cpp b/infinite.cpp new file mode 100644 index 0000000..bf09fe2 --- /dev/null +++ b/infinite.cpp | |||
@@ -0,0 +1,772 @@ | |||
1 | #include "fractal.h" | ||
2 | #include <Magick++.h> | ||
3 | #include <ctime> | ||
4 | #include <cstdio> | ||
5 | #include <iostream> | ||
6 | #include <verbly.h> | ||
7 | #include <fstream> | ||
8 | #include <dirent.h> | ||
9 | #include <yaml-cpp/yaml.h> | ||
10 | #include <unistd.h> | ||
11 | #include <twitter.h> | ||
12 | |||
13 | class fill_blanks { | ||
14 | private: | ||
15 | verbly::data& database; | ||
16 | |||
17 | public: | ||
18 | fill_blanks(verbly::data& database) : database(database) | ||
19 | { | ||
20 | |||
21 | } | ||
22 | |||
23 | verbly::filter<verbly::noun> parse_selrestrs(verbly::frame::selrestr selrestr) | ||
24 | { | ||
25 | switch (selrestr.get_type()) | ||
26 | { | ||
27 | case verbly::frame::selrestr::type::empty: | ||
28 | { | ||
29 | return verbly::filter<verbly::noun>{}; | ||
30 | } | ||
31 | |||
32 | case verbly::frame::selrestr::type::singleton: | ||
33 | { | ||
34 | verbly::noun n; | ||
35 | |||
36 | if (selrestr.get_restriction() == "concrete") | ||
37 | { | ||
38 | n = database.nouns().with_singular_form("physical entity").limit(1).run().front(); | ||
39 | } else if (selrestr.get_restriction() == "time") | ||
40 | { | ||
41 | n = database.nouns().with_singular_form("time").limit(1).run().front(); | ||
42 | } else if (selrestr.get_restriction() == "state") | ||
43 | { | ||
44 | n = database.nouns().with_singular_form("state").limit(1).run().front(); | ||
45 | } else if (selrestr.get_restriction() == "abstract") | ||
46 | { | ||
47 | n = database.nouns().with_singular_form("abstract entity").limit(1).run().front(); | ||
48 | } else if (selrestr.get_restriction() == "time") | ||
49 | { | ||
50 | n = database.nouns().with_singular_form("time").limit(1).run().front(); | ||
51 | } else if (selrestr.get_restriction() == "scalar") | ||
52 | { | ||
53 | n = database.nouns().with_singular_form("number").limit(1).run().front(); | ||
54 | } else if (selrestr.get_restriction() == "currency") | ||
55 | { | ||
56 | auto nn2 = database.nouns().with_singular_form("currency").limit(2).run(); | ||
57 | std::vector<verbly::noun> nn(std::begin(nn2), std::end(nn2)); | ||
58 | n = nn[1]; | ||
59 | } else if (selrestr.get_restriction() == "location") | ||
60 | { | ||
61 | n = database.nouns().with_singular_form("location").limit(1).run().front(); | ||
62 | } else if (selrestr.get_restriction() == "organization") | ||
63 | { | ||
64 | n = database.nouns().with_singular_form("organization").limit(1).run().front(); | ||
65 | } else if (selrestr.get_restriction() == "int_control") | ||
66 | { | ||
67 | n = database.nouns().with_singular_form("causal agent").limit(1).run().front(); | ||
68 | } else if (selrestr.get_restriction() == "natural") | ||
69 | { | ||
70 | n = database.nouns().with_singular_form("natural object").limit(1).run().front(); | ||
71 | } else if (selrestr.get_restriction() == "phys_obj") | ||
72 | { | ||
73 | n = database.nouns().with_singular_form("physical object").limit(1).run().front(); | ||
74 | } else if (selrestr.get_restriction() == "solid") | ||
75 | { | ||
76 | n = database.nouns().with_singular_form("solid").limit(1).run().front(); | ||
77 | } else if (selrestr.get_restriction() == "shape") | ||
78 | { | ||
79 | n = database.nouns().with_singular_form("shape").limit(1).run().front(); | ||
80 | } else if (selrestr.get_restriction() == "substance") | ||
81 | { | ||
82 | n = database.nouns().with_singular_form("substance").limit(1).run().front(); | ||
83 | } else if (selrestr.get_restriction() == "idea") | ||
84 | { | ||
85 | n = database.nouns().with_singular_form("idea").limit(1).run().front(); | ||
86 | } else if (selrestr.get_restriction() == "sound") | ||
87 | { | ||
88 | auto nn2 = database.nouns().with_singular_form("sound").limit(4).run(); | ||
89 | std::vector<verbly::noun> nn(std::begin(nn2), std::end(nn2)); | ||
90 | n = nn[3]; | ||
91 | } else if (selrestr.get_restriction() == "communication") | ||
92 | { | ||
93 | n = database.nouns().with_singular_form("communication").limit(1).run().front(); | ||
94 | } else if (selrestr.get_restriction() == "region") | ||
95 | { | ||
96 | n = database.nouns().with_singular_form("region").limit(1).run().front(); | ||
97 | } else if (selrestr.get_restriction() == "place") | ||
98 | { | ||
99 | n = database.nouns().with_singular_form("place").limit(1).run().front(); | ||
100 | } else if (selrestr.get_restriction() == "machine") | ||
101 | { | ||
102 | n = database.nouns().with_singular_form("machine").limit(1).run().front(); | ||
103 | } else if (selrestr.get_restriction() == "animate") | ||
104 | { | ||
105 | n = database.nouns().with_singular_form("animate being").limit(1).run().front(); | ||
106 | } else if (selrestr.get_restriction() == "plant") | ||
107 | { | ||
108 | auto nn2 = database.nouns().with_singular_form("plant").limit(2).run(); | ||
109 | std::vector<verbly::noun> nn(std::begin(nn2), std::end(nn2)); | ||
110 | n = nn[1]; | ||
111 | } else if (selrestr.get_restriction() == "comestible") | ||
112 | { | ||
113 | n = database.nouns().with_singular_form("food").limit(1).run().front(); | ||
114 | } else if (selrestr.get_restriction() == "artifact") | ||
115 | { | ||
116 | n = database.nouns().with_singular_form("artifact").limit(1).run().front(); | ||
117 | } else if (selrestr.get_restriction() == "vehicle") | ||
118 | { | ||
119 | n = database.nouns().with_singular_form("vehicle").limit(1).run().front(); | ||
120 | } else if (selrestr.get_restriction() == "human") | ||
121 | { | ||
122 | n = database.nouns().with_singular_form("person").limit(1).run().front(); | ||
123 | } else if (selrestr.get_restriction() == "animal") | ||
124 | { | ||
125 | n = database.nouns().with_singular_form("animal").limit(1).run().front(); | ||
126 | } else if (selrestr.get_restriction() == "body_part") | ||
127 | { | ||
128 | n = database.nouns().with_singular_form("body part").limit(1).run().front(); | ||
129 | } else if (selrestr.get_restriction() == "garment") | ||
130 | { | ||
131 | n = database.nouns().with_singular_form("clothing").limit(1).run().front(); | ||
132 | } else if (selrestr.get_restriction() == "tool") | ||
133 | { | ||
134 | n = database.nouns().with_singular_form("tool").limit(1).run().front(); | ||
135 | } else { | ||
136 | return verbly::filter<verbly::noun>{}; | ||
137 | } | ||
138 | |||
139 | return verbly::filter<verbly::noun>{n, !selrestr.get_pos()}; | ||
140 | } | ||
141 | |||
142 | case verbly::frame::selrestr::type::group: | ||
143 | { | ||
144 | verbly::filter<verbly::noun> ret; | ||
145 | ret.set_orlogic(selrestr.get_orlogic()); | ||
146 | |||
147 | std::transform(std::begin(selrestr), std::end(selrestr), std::back_inserter(ret), [&] (verbly::frame::selrestr sr) { | ||
148 | return parse_selrestrs(sr); | ||
149 | }); | ||
150 | |||
151 | return ret; | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | void visit(verbly::token& it) | ||
157 | { | ||
158 | switch (it.get_type()) | ||
159 | { | ||
160 | case verbly::token::type::utterance: | ||
161 | { | ||
162 | for (auto& tkn : it) | ||
163 | { | ||
164 | if (!tkn.is_complete()) | ||
165 | { | ||
166 | visit(tkn); | ||
167 | |||
168 | break; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | break; | ||
173 | } | ||
174 | |||
175 | case verbly::token::type::fillin: | ||
176 | { | ||
177 | switch (it.get_fillin_type()) | ||
178 | { | ||
179 | case verbly::token::fillin_type::participle_phrase: | ||
180 | { | ||
181 | for (;;) | ||
182 | { | ||
183 | verbly::verb v = database.verbs().has_frames().random().limit(1).run().front(); | ||
184 | auto frames = v.frames().run(); | ||
185 | std::vector<verbly::frame> filtered; | ||
186 | std::remove_copy_if(std::begin(frames), std::end(frames), std::back_inserter(filtered), [] (verbly::frame& f) { | ||
187 | if (f.parts().size() < 2) | ||
188 | { | ||
189 | return true; | ||
190 | } | ||
191 | |||
192 | if (f.parts()[0].get_type() != verbly::frame::part::type::noun_phrase) | ||
193 | { | ||
194 | return true; | ||
195 | } | ||
196 | |||
197 | if (f.parts()[0].get_role() != "Agent") | ||
198 | { | ||
199 | return true; | ||
200 | } | ||
201 | |||
202 | if (f.parts()[1].get_type() != verbly::frame::part::type::verb) | ||
203 | { | ||
204 | return true; | ||
205 | } | ||
206 | |||
207 | return false; | ||
208 | }); | ||
209 | |||
210 | if (filtered.empty()) | ||
211 | { | ||
212 | continue; | ||
213 | } | ||
214 | |||
215 | verbly::frame fr = filtered[rand() % filtered.size()]; | ||
216 | verbly::token utter; | ||
217 | for (auto part : fr.parts()) | ||
218 | { | ||
219 | switch (part.get_type()) | ||
220 | { | ||
221 | case verbly::frame::part::type::noun_phrase: | ||
222 | { | ||
223 | if (part.get_role() == "Agent") | ||
224 | { | ||
225 | continue; | ||
226 | } | ||
227 | |||
228 | if (part.get_synrestrs().count("adjp") == 1) | ||
229 | { | ||
230 | utter << verbly::token{verbly::token::fillin_type::adjective_phrase}; | ||
231 | |||
232 | continue; | ||
233 | } else if ((part.get_synrestrs().count("be_sc_ing") == 1) | ||
234 | || (part.get_synrestrs().count("ac_ing") == 1) | ||
235 | || (part.get_synrestrs().count("sc_ing") == 1) | ||
236 | || (part.get_synrestrs().count("np_omit_ing") == 1) | ||
237 | || (part.get_synrestrs().count("oc_ing") == 1)) | ||
238 | { | ||
239 | utter << verbly::token{verbly::token::fillin_type::participle_phrase}; | ||
240 | |||
241 | continue; | ||
242 | } else if ((part.get_synrestrs().count("poss_ing") == 1) | ||
243 | || (part.get_synrestrs().count("possing") == 1) | ||
244 | || (part.get_synrestrs().count("pos_ing") == 1)) | ||
245 | { | ||
246 | utter << verbly::token{"their"}; | ||
247 | utter << verbly::token{verbly::token::fillin_type::participle_phrase}; | ||
248 | |||
249 | continue; | ||
250 | } else if (part.get_synrestrs().count("genitive") == 1) | ||
251 | { | ||
252 | utter << verbly::token{"their"}; | ||
253 | |||
254 | continue; | ||
255 | } else if (part.get_synrestrs().count("adv_loc") == 1) | ||
256 | { | ||
257 | if (rand() % 2 == 0) | ||
258 | { | ||
259 | utter << verbly::token{"here"}; | ||
260 | } else { | ||
261 | utter << verbly::token{"there"}; | ||
262 | } | ||
263 | |||
264 | continue; | ||
265 | } else if (part.get_synrestrs().count("refl") == 1) | ||
266 | { | ||
267 | utter << verbly::token{"themselves"}; | ||
268 | |||
269 | continue; | ||
270 | } else if ((part.get_synrestrs().count("sc_to_inf") == 1) | ||
271 | || (part.get_synrestrs().count("ac_to_inf") == 1) | ||
272 | || (part.get_synrestrs().count("vc_to_inf") == 1) | ||
273 | || (part.get_synrestrs().count("rs_to_inf") == 1) | ||
274 | || (part.get_synrestrs().count("oc_to_inf") == 1)) | ||
275 | { | ||
276 | utter << verbly::token{verbly::token::fillin_type::infinitive_phrase}; | ||
277 | |||
278 | continue; | ||
279 | } else if (part.get_synrestrs().count("oc_bare_inf") == 1) | ||
280 | { | ||
281 | verbly::token tkn{verbly::token::fillin_type::infinitive_phrase}; | ||
282 | tkn.set_extra(1); | ||
283 | |||
284 | utter << tkn; | ||
285 | |||
286 | continue; | ||
287 | } | ||
288 | |||
289 | auto selrestrs = fr.roles()[part.get_role()]; | ||
290 | auto query = database.nouns().limit(1).random().is_not_proper().full_hyponym_of(parse_selrestrs(selrestrs)); | ||
291 | verbly::noun n = query.run().front(); | ||
292 | if ((rand() % 2 == 0) && (part.get_synrestrs().count("definite") == 0)) | ||
293 | { | ||
294 | utter << verbly::token{"the"}; | ||
295 | } else { | ||
296 | if (n.starts_with_vowel_sound()) | ||
297 | { | ||
298 | utter << verbly::token{"an"}; | ||
299 | } else { | ||
300 | utter << verbly::token{"a"}; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | if (part.get_synrestrs().count("plural") == 1) | ||
305 | { | ||
306 | utter << verbly::token{n, verbly::token::noun_inflection::plural}; | ||
307 | } else { | ||
308 | utter << verbly::token{n}; | ||
309 | } | ||
310 | |||
311 | if (part.get_synrestrs().count("acc_ing") == 1) | ||
312 | { | ||
313 | utter << verbly::token{verbly::token::fillin_type::participle_phrase}; | ||
314 | } | ||
315 | |||
316 | break; | ||
317 | } | ||
318 | |||
319 | case verbly::frame::part::type::verb: | ||
320 | { | ||
321 | utter << verbly::token{v, verbly::token::verb_inflection::ing_form}; | ||
322 | |||
323 | break; | ||
324 | } | ||
325 | |||
326 | case verbly::frame::part::type::literal_preposition: | ||
327 | { | ||
328 | utter << verbly::token{part.get_choices()[rand() % part.get_choices().size()]}; | ||
329 | |||
330 | break; | ||
331 | } | ||
332 | |||
333 | case verbly::frame::part::type::selection_preposition: | ||
334 | { | ||
335 | auto query = database.prepositions(); | ||
336 | for (auto preprestr : part.get_preprestrs()) | ||
337 | { | ||
338 | query.in_group(preprestr); | ||
339 | } | ||
340 | utter << verbly::token{query.random().limit(1).run().front()}; | ||
341 | |||
342 | break; | ||
343 | } | ||
344 | |||
345 | case verbly::frame::part::type::adjective: | ||
346 | { | ||
347 | utter << verbly::token{verbly::token::fillin_type::adjective_phrase}; | ||
348 | |||
349 | break; | ||
350 | } | ||
351 | |||
352 | case verbly::frame::part::type::adverb: | ||
353 | { | ||
354 | utter << verbly::token{verbly::token::fillin_type::adverb_phrase}; | ||
355 | |||
356 | break; | ||
357 | } | ||
358 | |||
359 | case verbly::frame::part::type::literal: | ||
360 | { | ||
361 | utter << verbly::token{part.get_literal()}; | ||
362 | |||
363 | break; | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
368 | it = utter; | ||
369 | |||
370 | break; | ||
371 | } | ||
372 | |||
373 | break; | ||
374 | } | ||
375 | |||
376 | case verbly::token::fillin_type::adjective_phrase: | ||
377 | { | ||
378 | verbly::token phrase; | ||
379 | |||
380 | if (rand() % 4 == 0) | ||
381 | { | ||
382 | phrase << verbly::token{verbly::token::fillin_type::adverb_phrase}; | ||
383 | } | ||
384 | |||
385 | if (rand() % 2 == 0) | ||
386 | { | ||
387 | phrase << verbly::token{verbly::token::fillin_type::participle_phrase}; | ||
388 | } else { | ||
389 | phrase << verbly::token{database.adjectives().random().limit(1).run().front()}; | ||
390 | } | ||
391 | |||
392 | it = phrase; | ||
393 | |||
394 | break; | ||
395 | } | ||
396 | |||
397 | case verbly::token::fillin_type::adverb_phrase: | ||
398 | { | ||
399 | it = verbly::token{database.adverbs().random().limit(1).run().front()}; | ||
400 | |||
401 | break; | ||
402 | } | ||
403 | |||
404 | case verbly::token::fillin_type::infinitive_phrase: | ||
405 | { | ||
406 | verbly::token utter; | ||
407 | if (it.get_extra() != 1) | ||
408 | { | ||
409 | utter << verbly::token{"to"}; | ||
410 | } | ||
411 | |||
412 | utter << verbly::token{database.verbs().random().limit(1).run().front()}; | ||
413 | |||
414 | it = utter; | ||
415 | |||
416 | break; | ||
417 | } | ||
418 | |||
419 | default: | ||
420 | { | ||
421 | it = verbly::token{"*the reality of the situation*"}; | ||
422 | |||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | break; | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | }; | ||
432 | |||
433 | int main(int argc, char** argv) | ||
434 | { | ||
435 | srand(time(NULL)); | ||
436 | Magick::InitializeMagick(nullptr); | ||
437 | |||
438 | int delay = 60 * 60; | ||
439 | |||
440 | YAML::Node config = YAML::LoadFile("config.yml"); | ||
441 | twitter::auth auth; | ||
442 | auth.setConsumerKey(config["consumer_key"].as<std::string>()); | ||
443 | auth.setConsumerSecret(config["consumer_secret"].as<std::string>()); | ||
444 | auth.setAccessKey(config["access_key"].as<std::string>()); | ||
445 | auth.setAccessSecret(config["access_secret"].as<std::string>()); | ||
446 | |||
447 | twitter::client client(auth); | ||
448 | |||
449 | for (;;) | ||
450 | { | ||
451 | std::cout << "Generating text..." << std::endl; | ||
452 | |||
453 | std::vector<std::string> forms; | ||
454 | std::ifstream datafile("forms.txt"); | ||
455 | if (!datafile.is_open()) | ||
456 | { | ||
457 | std::cout << "Could not find forms.txt" << std::endl; | ||
458 | return 1; | ||
459 | } | ||
460 | |||
461 | std::string line; | ||
462 | while (getline(datafile, line)) | ||
463 | { | ||
464 | if (line.back() == '\r') | ||
465 | { | ||
466 | line.pop_back(); | ||
467 | } | ||
468 | |||
469 | forms.push_back(line); | ||
470 | } | ||
471 | |||
472 | datafile.close(); | ||
473 | |||
474 | verbly::data database {"data.sqlite3"}; | ||
475 | std::string action = forms[rand() % forms.size()]; | ||
476 | int tknloc; | ||
477 | while ((tknloc = action.find("{")) != std::string::npos) | ||
478 | { | ||
479 | std::string token = action.substr(tknloc+1, action.find("}")-tknloc-1); | ||
480 | |||
481 | std::string canontkn; | ||
482 | std::transform(std::begin(token), std::end(token), std::back_inserter(canontkn), [] (char ch) { | ||
483 | return std::toupper(ch); | ||
484 | }); | ||
485 | |||
486 | std::string result; | ||
487 | if (canontkn == "NOUN") | ||
488 | { | ||
489 | result = database.nouns().is_not_proper().random().limit(1).with_complexity(1).run().front().singular_form(); | ||
490 | } else if (canontkn == "PLURAL_NOUN") | ||
491 | { | ||
492 | result = database.nouns().is_not_proper().requires_plural_form().random().limit(1).with_complexity(1).run().front().plural_form(); | ||
493 | } else if (canontkn == "ADJECTIVE") | ||
494 | { | ||
495 | result = database.adjectives().with_complexity(1).random().limit(1).run().front().base_form(); | ||
496 | } else if (canontkn == "VERB") | ||
497 | { | ||
498 | result = database.verbs().random().limit(1).run().front().infinitive_form(); | ||
499 | } else if (canontkn == "VERBED") | ||
500 | { | ||
501 | result = database.verbs().random().limit(1).run().front().past_tense_form(); | ||
502 | } else if (canontkn == "VERBS") | ||
503 | { | ||
504 | result = database.verbs().random().limit(1).run().front().s_form(); | ||
505 | } else if (canontkn == "VERBING") | ||
506 | { | ||
507 | result = database.verbs().random().limit(1).run().front().ing_form(); | ||
508 | } else if (canontkn == "LOCATION") | ||
509 | { | ||
510 | auto hem1 = database.nouns().with_singular_form("eastern hemisphere").limit(1).run().front(); | ||
511 | auto hem2 = database.nouns().with_singular_form("western hemisphere").limit(1).run().front(); | ||
512 | verbly::filter<verbly::noun> region{hem1, hem2}; | ||
513 | region.set_orlogic(true); | ||
514 | |||
515 | result = database.nouns().full_part_holonym_of(region).random().limit(1).run().front().singular_form(); | ||
516 | } else if (canontkn == "LANGUAGE") | ||
517 | { | ||
518 | auto natlan = database.nouns().with_singular_form("natural language").limit(1).run().front(); | ||
519 | result = database.nouns().full_hyponym_of(natlan).is_proper().random().limit(1).run().front().singular_form(); | ||
520 | } else if (canontkn == "ADVERB") | ||
521 | { | ||
522 | result = database.adverbs().with_complexity(1).random().limit(1).run().front().base_form(); | ||
523 | } else if (canontkn == "SENTENCE") | ||
524 | { | ||
525 | fill_blanks yeah {database}; | ||
526 | verbly::token action{ | ||
527 | {"I am"}, | ||
528 | {verbly::token::fillin_type::adjective_phrase} | ||
529 | }; | ||
530 | while (!action.is_complete()) | ||
531 | { | ||
532 | yeah.visit(action); | ||
533 | } | ||
534 | result = action.compile(); | ||
535 | } | ||
536 | |||
537 | std::string finalresult; | ||
538 | if (islower(token[0])) | ||
539 | { | ||
540 | std::transform(std::begin(result), std::end(result), std::back_inserter(finalresult), [] (char ch) { | ||
541 | return std::tolower(ch); | ||
542 | }); | ||
543 | } else if (isupper(token[0]) && !isupper(token[1])) | ||
544 | { | ||
545 | auto words = verbly::split<std::list<std::string>>(result, " "); | ||
546 | for (auto& word : words) | ||
547 | { | ||
548 | word[0] = std::toupper(word[0]); | ||
549 | } | ||
550 | |||
551 | finalresult = verbly::implode(std::begin(words), std::end(words), " "); | ||
552 | } else { | ||
553 | finalresult = result; | ||
554 | } | ||
555 | |||
556 | action.replace(tknloc, action.find("}")-tknloc+1, finalresult); | ||
557 | } | ||
558 | |||
559 | double zoom = 2.0; | ||
560 | double target_w = 1280; | ||
561 | double target_h = 800; | ||
562 | double sample_rate = 3; | ||
563 | |||
564 | std::cout << "Generating flame fractal..." << std::endl; | ||
565 | |||
566 | Magick::Image image(Magick::Geometry(target_w, target_h), "black"); | ||
567 | image.type(Magick::TrueColorMatteType); | ||
568 | |||
569 | for (;;) | ||
570 | { | ||
571 | Fractal fractal = Fractal::random(); | ||
572 | std::vector<Color> irradiance(target_w*target_h*sample_rate*sample_rate, Color(0.0, 0.0, 0.0, 0.0)); | ||
573 | |||
574 | double x = (double)rand()/(double)RAND_MAX*2.0-1.0; | ||
575 | double y = (double)rand()/(double)RAND_MAX*2.0-1.0; | ||
576 | double c = (double)rand()/RAND_MAX; | ||
577 | |||
578 | double widthmul = fractal.width/target_w*zoom; | ||
579 | double heightmul = fractal.height/target_w*zoom; | ||
580 | double widthmul2 = widthmul * 2.0; | ||
581 | double heightmul2 = heightmul * 2.0; | ||
582 | |||
583 | int maxrad = 0; | ||
584 | for (int i=0; i<50000000; i++) | ||
585 | { | ||
586 | fractal.sample(x, y, c); | ||
587 | |||
588 | int fx = (x+widthmul)/widthmul2*target_w*sample_rate; | ||
589 | int fy = (y+heightmul)/heightmul2*target_h*sample_rate; | ||
590 | |||
591 | if (fx >= 0 && fx < target_w*sample_rate && fy >= 0 && fy < target_h*sample_rate && i > 20) | ||
592 | { | ||
593 | auto& irr = irradiance[fx+fy*target_w*sample_rate]; | ||
594 | irr += fractal.get_color(c); | ||
595 | double alph = irr.a; | ||
596 | irr *= 0.5; | ||
597 | irr.a = alph; | ||
598 | |||
599 | if (irr.a > maxrad) | ||
600 | { | ||
601 | maxrad = irr.a; | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | |||
606 | image.modifyImage(); | ||
607 | Magick::Pixels view(image); | ||
608 | Magick::PixelPacket* pixels = view.get(0, 0, target_w, target_h); | ||
609 | |||
610 | double white = 200.0; | ||
611 | double quality = sample_rate*sample_rate; | ||
612 | double vibrancy = 1.0; | ||
613 | double contrast = 1.0; | ||
614 | double brightadjust = 2.3; | ||
615 | double k1 = contrast * (268.0 * brightadjust) * 100.0 / fractal.brightness / (256.0*256.0); | ||
616 | double k2 = 1.0 / (contrast * white * quality); | ||
617 | int covered = 0; | ||
618 | for (int j=0; j<target_h; j++) | ||
619 | { | ||
620 | for (int i=0; i<target_w; i++) | ||
621 | { | ||
622 | double freq_avg = 0.0; | ||
623 | double freq_max = 0.0; | ||
624 | Color color_avg(0.0,0.0,0.0,0.0); | ||
625 | for (int sy = 0; sy<sample_rate; sy++) | ||
626 | { | ||
627 | for (int sx = 0; sx<sample_rate; sx++) | ||
628 | { | ||
629 | auto& fc = irradiance[i*sample_rate+sx+(j*sample_rate+sy)*target_w*sample_rate]; | ||
630 | freq_avg += fc.a; | ||
631 | color_avg += fc; | ||
632 | if (fc.a > freq_max) | ||
633 | { | ||
634 | freq_max = fc.a; | ||
635 | } | ||
636 | } | ||
637 | } | ||
638 | |||
639 | if (freq_max > 0) | ||
640 | { | ||
641 | covered++; | ||
642 | } | ||
643 | |||
644 | freq_avg *= (white * fractal.filterlevel)/(sample_rate * sample_rate); | ||
645 | color_avg *= (fractal.filterlevel/(sample_rate*sample_rate)); | ||
646 | |||
647 | double alph = k1 * std::log(1+white*freq_avg*k2)/(std::log(10*white*freq_max)); | ||
648 | double alphg = pow(alph, 1.0/fractal.gamma); | ||
649 | if (alph <= fractal.gammathresh) | ||
650 | { | ||
651 | double frac = alph / fractal.gammathresh; | ||
652 | alphg = (1-frac)*alph*pow(fractal.gammathresh, 1.0/fractal.gamma - 1.0) + frac*alphg; | ||
653 | } | ||
654 | |||
655 | double ls = vibrancy*alphg/alph; | ||
656 | Color finc = color_avg * ls; | ||
657 | finc.a = 1.0; | ||
658 | |||
659 | if (finc.r > 1.0) | ||
660 | { | ||
661 | finc *= (1.0 / finc.r); | ||
662 | } | ||
663 | |||
664 | if (finc.g > 1.0) | ||
665 | { | ||
666 | finc *= (1.0 / finc.g); | ||
667 | } | ||
668 | |||
669 | if (finc.b > 1.0) | ||
670 | { | ||
671 | finc *= (1.0 / finc.b); | ||
672 | } | ||
673 | |||
674 | *pixels++ = Magick::ColorRGB(finc.r, finc.g, finc.b); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | double coverage = ((double)covered/(double)(target_w*target_h)); | ||
679 | std::cout << coverage << " coverage" << std::endl; | ||
680 | |||
681 | view.sync(); | ||
682 | |||
683 | if (coverage >= 0.05) | ||
684 | { | ||
685 | break; | ||
686 | } | ||
687 | |||
688 | std::cout << "Regenerating..." << std::endl; | ||
689 | } | ||
690 | |||
691 | DIR* fontdir; | ||
692 | struct dirent* ent; | ||
693 | if ((fontdir = opendir("fonts")) == nullptr) | ||
694 | { | ||
695 | std::cout << "Couldn't find fonts." << std::endl; | ||
696 | return -1; | ||
697 | } | ||
698 | |||
699 | std::vector<std::string> fonts; | ||
700 | while ((ent = readdir(fontdir)) != nullptr) | ||
701 | { | ||
702 | std::string dname(ent->d_name); | ||
703 | if ((dname.find(".otf") != std::string::npos) || (dname.find(".ttf") != std::string::npos)) | ||
704 | { | ||
705 | fonts.push_back(dname); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | closedir(fontdir); | ||
710 | |||
711 | Magick::Image textimage(Magick::Geometry(target_w, target_h), "transparent"); | ||
712 | textimage.type(Magick::TrueColorMatteType); | ||
713 | textimage.fillColor(Magick::Color("white")); | ||
714 | textimage.fontPointsize(72.0); | ||
715 | textimage.font("fonts/" + fonts[rand() % fonts.size()]); | ||
716 | |||
717 | auto words = verbly::split<std::list<std::string>>(action, " "); | ||
718 | std::string towrite = ""; | ||
719 | std::string curline = ""; | ||
720 | Magick::TypeMetric metric; | ||
721 | while (!words.empty()) | ||
722 | { | ||
723 | std::string temp = curline + " " + words.front(); | ||
724 | textimage.fontTypeMetrics(temp, &metric); | ||
725 | if (metric.textWidth() > ((target_w/10)*9)) | ||
726 | { | ||
727 | towrite += "\n" + words.front(); | ||
728 | curline = words.front(); | ||
729 | } else { | ||
730 | towrite += " " + words.front(); | ||
731 | curline = temp; | ||
732 | } | ||
733 | |||
734 | words.pop_front(); | ||
735 | } | ||
736 | |||
737 | textimage.annotate(towrite, Magick::CenterGravity); | ||
738 | textimage.opacity(((double)MaxRGB) * 0.8); | ||
739 | image.composite(textimage, 0, 0, Magick::OverCompositeOp); | ||
740 | |||
741 | image.magick("png"); | ||
742 | |||
743 | Magick::Blob outputimg; | ||
744 | image.write(&outputimg); | ||
745 | |||
746 | std::cout << "Generated image!" << std::endl << "Tweeting..." << std::endl; | ||
747 | |||
748 | long media_id; | ||
749 | twitter::response resp = client.uploadMedia("image/png", (const char*) outputimg.data(), outputimg.length(), media_id); | ||
750 | if (resp != twitter::response::ok) | ||
751 | { | ||
752 | std::cout << "Twitter error while uploading image: " << resp << std::endl; | ||
753 | sleep(delay); | ||
754 | |||
755 | continue; | ||
756 | } | ||
757 | |||
758 | twitter::tweet tw; | ||
759 | resp = client.updateStatus("", tw, {media_id}); | ||
760 | if (resp != twitter::response::ok) | ||
761 | { | ||
762 | std::cout << "Twitter error while tweeting: " << resp << std::endl; | ||
763 | sleep(delay); | ||
764 | |||
765 | continue; | ||
766 | } | ||
767 | |||
768 | std::cout << "Done!" << std::endl << "Waiting..." << std::endl << std::endl; | ||
769 | |||
770 | sleep(delay); | ||
771 | } | ||
772 | } | ||