Initial commit
[dyncnn.git] / flatland.cc
1
2 /*
3  *  dyncnn is a deep-learning algorithm for the prediction of
4  *  interacting object dynamics
5  *
6  *  Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
7  *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
8  *
9  *  This file is part of dyncnn.
10  *
11  *  dyncnn is free software: you can redistribute it and/or modify it
12  *  under the terms of the GNU General Public License version 3 as
13  *  published by the Free Software Foundation.
14  *
15  *  dyncnn is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with dyncnn.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include <iostream>
26 #include <fstream>
27 #include <cmath>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/stat.h>
34
35 using namespace std;
36
37 #include "misc.h"
38 #include "universe.h"
39 #include "canvas_cairo.h"
40
41 void generate_png(Universe *universe, scalar_t scale, FILE *file) {
42   CanvasCairo canvas(scale, universe->width(), universe->height());
43   canvas.set_line_width(1.0 / scale);
44   universe->draw(&canvas);
45   canvas.write_png(file);
46 }
47
48 FILE *safe_fopen(const char *name, const char *mode) {
49   FILE *file = fopen(name, mode);
50   if(!file) {
51     cerr << "Cannot open " << name << endl;
52     exit(1);
53   }
54   return file;
55 }
56
57 void print_help(const char *command) {
58   cerr << command << " <nb sequences to generate> [--dir <dir>] [--seed <seed>]]" << endl;
59   exit(1);
60 }
61
62 int main(int argc, char **argv) {
63   const scalar_t world_width = 400;
64   const scalar_t world_height = 400;
65   const scalar_t block_size = 80;
66
67   const scalar_t dt = 0.1;
68   const int nb_iterations_per_steps = 20;
69
70   //////////////////////////////////////////////////////////////////////
71
72   // We will generate images { 0, every_nth, 2 * every_nth, ..., nb_frames - 1 }
73
74   // The framerate every_nth may be set to smaller value to generate
75   // nice materials for presentations or papers.
76
77   int every_nth = 4;
78
79   int nb_frames = 5;
80
81   int multi_grasp = 0;
82   int nb_shapes = 1;
83   char data_dir[1024] = "/tmp/";
84
85   //////////////////////////////////////////////////////////////////////
86
87   Universe *universe;
88   Polygon *grabbed_polygon;
89
90   if(argc < 2) {
91     print_help(argv[0]);
92   }
93
94   int nb_sequences = atoi(argv[1]);
95
96   int i = 2;
97   while(i < argc) {
98     if(strcmp(argv[i], "--dir") == 0) {
99       i++;
100       if(i == argc) { print_help(argv[0]);}
101       strncpy(data_dir, argv[i], sizeof(data_dir) / sizeof(char) - 1);
102       i++;
103     }
104
105     else if(strcmp(argv[i], "--seed") == 0) {
106       i++;
107       if(i == argc) { print_help(argv[0]); }
108       srand48(atoi(argv[i]));
109       i++;
110     }
111
112     else if(strcmp(argv[i], "--nb_shapes") == 0) {
113       i++;
114       if(i == argc) { print_help(argv[0]);}
115       nb_shapes = atoi(argv[i]);
116       i++;
117     }
118
119     else if(strcmp(argv[i], "--multi_grasp") == 0) {
120       multi_grasp = 1;
121       i++;
122     }
123
124     else if(strcmp(argv[i], "--every_nth") == 0) {
125       i++;
126       if(i == argc) { print_help(argv[0]);}
127       every_nth = atoi(argv[i]);
128       i++;
129     }
130
131     else if(strcmp(argv[i], "--nb_frames") == 0) {
132       i++;
133       if(i == argc) { print_help(argv[0]);}
134       nb_frames = atoi(argv[i]);
135       i++;
136     }
137
138     else {
139       cerr << "Unknown option " << argv[i] << "." << endl;
140       abort();
141     }
142   }
143
144   if(nb_shapes < 1 || nb_shapes > 10) {
145     cerr << "nb_shapes has to be in {1, ..., 10}" << endl;
146     abort();
147   }
148
149   if(nb_frames < 0 || nb_frames > 50) {
150     cerr << "nb_frames has to be in {0, ..., 50}" << endl;
151     abort();
152   }
153
154   universe = new Universe(nb_shapes, world_width, world_height);
155
156   for(int n = 0; n < nb_sequences; n++) {
157
158     scalar_t grab_start_x = world_width * 0.5;
159     scalar_t grab_start_y = world_height * 0.75;
160
161     if(multi_grasp) {
162       grab_start_x = world_width * (0.1 + 0.8 * drand48());
163       grab_start_y = world_height * (0.1 + 0.8 * drand48());
164     }
165
166     if((n+1)%100 == 0) {
167       cout << "Created "
168            << n+1 << "/" << nb_sequences << " sequences in "
169            << data_dir
170            << "." << endl;
171     }
172
173     do {
174       universe->clear();
175
176       const int nb_attempts_max = 100;
177       int nb_attempts = 0;
178
179       for(int u = 0; u < nb_shapes; u++) {
180         Polygon *pol = 0;
181
182         nb_attempts = 0;
183
184         do {
185           scalar_t x[] = {
186             - block_size * 0.4,
187             + block_size * 0.4,
188             + block_size * 0.4,
189             - block_size * 0.4,
190           };
191
192           scalar_t y[] = {
193             - block_size * 0.6,
194             - block_size * 0.6,
195             + block_size * 0.6,
196             + block_size * 0.6,
197           };
198
199           scalar_t delta = block_size / sqrt(2.0);
200           scalar_t object_center_x = delta + (world_width - 2 * delta) * drand48();
201           scalar_t object_center_y = delta + (world_height - 2 * delta) * drand48();
202           scalar_t red, green, blue;
203           red = 1.00;
204           green = red;
205           blue = red;
206           delete pol;
207           pol = new Polygon(0.5,
208                             red, green, blue,
209                             x, y, sizeof(x)/sizeof(scalar_t));
210           pol->set_position(object_center_x, object_center_y, M_PI * 2 * drand48());
211           pol->set_speed(0, 0, 0);
212           universe->initialize_polygon(pol);
213           nb_attempts++;
214         } while(nb_attempts < nb_attempts_max && universe->collide(pol));
215
216         if(nb_attempts == nb_attempts_max) {
217           delete pol;
218           u = 0;
219           universe->clear();
220           nb_attempts = 0;
221         } else {
222           universe->add_polygon(pol);
223         }
224       }
225
226       grabbed_polygon = universe->pick_polygon(grab_start_x, grab_start_y);
227     } while(!grabbed_polygon);
228
229     const scalar_t scaling = 0.16;
230
231     CanvasCairo grab_trace(scaling, world_width, world_height);
232
233     {
234       char buffer[1024];
235       sprintf(buffer, "%s/%03d/", data_dir, n/1000);
236       mkdir(buffer, 0777);
237     }
238
239     scalar_t grab_relative_x = grabbed_polygon->relative_x(grab_start_x, grab_start_y);
240     scalar_t grab_relative_y = grabbed_polygon->relative_y(grab_start_x, grab_start_y);
241
242     {
243       int n = 36;
244       scalar_t xp[n], yp[n];
245       for(int k = 0; k < n; k++) {
246         scalar_t radius = 1/scaling;
247         scalar_t alpha = 2 * M_PI * scalar_t(k) / scalar_t(n);
248         xp[k] = grab_start_x + radius * cos(alpha);
249         yp[k] = grab_start_y + radius * sin(alpha);
250       }
251       grab_trace.set_drawing_color(0.0, 0.0, 0.0);
252       grab_trace.set_line_width(2.0);
253       grab_trace.draw_polygon(1, n, xp, yp);
254     }
255
256     for(int s = 0; s < nb_frames; s++) {
257       if(s % every_nth == 0) {
258         char buffer[1024];
259         sprintf(buffer, "%s/%03d/dyn_%06d_world_%03d.png", data_dir, n/1000, n, s);
260         FILE *file = safe_fopen(buffer, "w");
261         generate_png(universe, scaling, file);
262         fclose(file);
263       }
264
265       for(int i = 0; i < nb_iterations_per_steps; i++) {
266         scalar_t xf = grabbed_polygon->absolute_x(grab_relative_x, grab_relative_y);
267         scalar_t yf = grabbed_polygon->absolute_y(grab_relative_x, grab_relative_y);
268         grabbed_polygon->apply_force(dt, xf, yf, 0.0, -1.0);
269         universe->update(dt);
270       }
271     }
272
273     {
274       char buffer[1024];
275       sprintf(buffer, "%s/%03d/dyn_%06d_grab.png", data_dir, n/1000, n);
276       FILE *file = safe_fopen(buffer, "w");
277       grab_trace.write_png(file);
278       fclose(file);
279     }
280   }
281
282   delete universe;
283 }