1 /*
2 * countries.cc
3 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
4 * DIN Is Noise is released under GNU Public License 2.0
5 * For more information, please visit https://dinisnoise.org/
6 */
7 
8 
9 #include "countries.h"
10 #include "vector2d.h"
11 #include "console.h"
12 #include "log.h"
13 #include <vector>
14 #include <fstream>
15 #include <algorithm>
16 using namespace std;
17 
18 
19 extern string user_data_dir;
20 extern string country_data_dir;
21 
22 extern console cons;
23 
operator <(const area & rhs) const24 bool area::operator< (const area& rhs) const {
25  return num_vertices > rhs.num_vertices;
26 }
27 
countries()28 countries::countries () {
29   name = "Countries";
30 	id = -1;
31 	p_cur_country = 0;
32 	area_id = 0;
33 	change_curve_name = 1;
34 }
35 
~countries()36 countries::~countries () {
37 	widget_save ("d_countries", ctrls);
38 	save_params ();
39 }
40 
load_params()41 void countries::load_params () {
42   ifstream f (make_fname().c_str(), ios::in);
43 	string ignore;
44 	float step;
45 	f >> ignore >> id >> ignore >> area_id >> ignore >> step;
46 	pt.step.set_value (step);
47 	load_country (index[id]);
48 }
49 
save_params()50 void countries::save_params () {
51   ofstream f (make_fname().c_str(), ios::out);
52 	if (f) {
53 		f << "id " << id << endl;
54 		f << "area_id " << area_id << endl;
55 		f << "step " << int(pt.step.f_value) << endl;
56 	}
57 }
58 
load_index()59 void countries::load_index () {
60 	string fname (country_data_dir + "index");
61 	ifstream f (fname.c_str(), ios::in);
62 	if (!f) {
63 		dlog << "couldnt read from : " << fname << endl;
64 		return;
65 	}
66 	f >> num_countries;
67   index.resize (num_countries);
68 	for (int i = 0; i < num_countries; ++i) {
69 		f >> fname;
70     index[i] = fname;
71 	}
72 	sort (index.begin (), index.end());
73 }
74 
75 
setup()76 void countries::setup () {
77 
78 	plugin::setup ();
79 
80 	load_index ();
81 
82   widget* _ctrls [] = {&ol_country, &ol_area,  &lf_search, &pt.step, &pt.start, &pt.end, &close};
83   for (int i = 0; i < 7; ++i) {
84     ctrls.push_back (_ctrls[i]);
85   }
86 
87   num_ctrls = ctrls.size ();
88 
89   //for (int i = 0; i < num_ctrls; ++i) ctrls[i]->set_moveable(1);
90 
91 	lf_search.set_text ("Country?");
92 	lf_search.set_listener (this);
93 	lf_search.fld.expr = 0;
94 
95 	ol_country.set_text ("Country = ");
96 	ol_country.set_listener (this);
97 	ol_country.set_click_repeat (1);
98 
99 	ol_area.set_listener (this);
100 	ol_area.set_click_repeat (1);
101 	ol_area.set_text ("Area = ");
102 
103   pt.start.set ("Start", 1, 1, MILLION, this, 0);
104   pt.end.set ("End", 1, 1, MILLION, this, 0);
105   pt.step.set ("Step", 1, 1, MILLION, this, 0);
106 
107   close.set_text ("Close");
108   close.set_listener (&cll);
109 
110 	widget_load ("d_countries", ctrls);
111 
112 	load_params ();
113 	lf_search.fld.set_text (index[id]);
114 
115 }
116 
render()117 void countries::render () {
118 	if (p_cur_country) {
119 		points.clear ();
120 		area& a0 = p_cur_country->areas[area_id];
121     int start = pt.start.f_value;
122 		float a0x = a0.x[start], a0y = a0.y[start];
123 		point<float> pa0 (a0x, a0y);
124 		points.push_back (pa0);
125 		for (int i = start + 1, j = pt.end.f_value, di = pt.step.f_value; i < j; i += di) points.push_back (point<float>(a0.x[i], a0.y[i]));
126 		if (close.state || (points.size () == 1)) points.push_back (pa0);
127     gen_pts ();
128   	ss.str("");
129   	ss << p_cur_country->name;
130 	}
131 }
132 
load_country(const string & which)133 country* countries::load_country (const string& which) {
134 	country& c = the_countries [which];
135 	if (c.num_areas ==  0) {
136 		string fname (country_data_dir + which);
137 		ifstream f (fname.c_str(), ios::in);
138 		if (!f) {
139 			dlog << "couldnt load from : " << fname << endl;
140 			return 0;
141 		}
142 		c.name = which;
143 		string ignore;
144 		while (!f.eof()) {
145 			f >> ignore >> c.num_areas;
146 			for (int i = 0; i < c.num_areas; ++i) {
147 				c.areas.push_back (area());
148 				area& ai = c.areas[i];
149 				f >> ignore >> ai.num_vertices;
150 				float l, b, r, t; f >> ignore >> l >> b >> r >> t;
151 				ai.bbox (l, b, r, t);
152 
153         /*dlog << "name = " << c.name << " ratio = " << ai.bbox.width * 1.0 / ai.bbox.height << endl;
154         float fac = ai.bbox.width * 1.0 / ai.bbox.height - 1.0;*/
155 
156         int& q = ai.num_vertices;
157         int n1 = q + 1;
158         ai.x.resize (n1);
159         ai.y.resize (n1);
160 				for (int p = 0; p < q; ++p) f >> ai.x[p] >> ai.y[p];
161         ai.x[q] = ai.x[0];
162         ai.y[q] = ai.y[0];
163         ++q;
164 			}
165 		}
166 	}
167 	p_cur_country = &c;
168 	set_country (which);
169 	return &c;
170 }
171 
picked(label & lbl,int dir)172 void countries::picked (label& lbl, int dir) {
173 	if (&lbl == &ol_country.option) {
174 		id += dir;
175 		if (id < 0) id = num_countries - 1; else if (id >= num_countries) id = 0;
176 		string name (index[id]);
177 		load_country (name);
178 	} else if (&lbl == &ol_area.option) {
179 		if (p_cur_country) {
180 			area_id += dir;
181 			render_area ();
182 		}
183 	}
184 }
185 
changed(field & f)186 void countries::changed (field& f) {
187 	if (&f == &lf_search.fld) {
188 		string name (f.text);
189     for (int i = 0, j = name.size (); i < j; ++i) if (name[i] == ' ') name[i]= '_';
190 		int nid = find_id (name);
191 		if (nid == -1) {
192 			cons << RED << "Couldnt find " << name << eol;
193 			if (name == "") f.set_text (index[id]);
194 		} else {
195 			id = nid;
196 			load_country (name);
197 		}
198 	} else {
199 		render ();
200 		if (cb_auto_apply.state) clicked (b_apply);
201 	}
202 }
203 
render_area()204 void countries::render_area () {
205 	if (area_id < 0) area_id = p_cur_country->num_areas - 1; else if (area_id >= p_cur_country->num_areas) area_id = 0;
206 	stringstream ss; ss << "Area " << (area_id+1) << " of " << p_cur_country->num_areas;
207 	ol_area.set_text (ss.str());
208 
209   int n_1 = p_cur_country->areas[area_id].num_vertices - 1;
210   pt.start.set_limits (0, n_1);
211   pt.end.set_limits (0, n_1);
212   pt.start.set_value (0);
213   pt.end.set_value (n_1);
214 
215 	render ();
216 	if (cb_auto_apply.state) clicked (b_apply);
217 }
218 
set_country(const string & name)219 void countries::set_country (const string& name) {
220 	ol_country.set_text (name);
221 	lf_search.set_text (name);
222 	area_id = 0;
223 	render_area ();
224 }
225 
find_id(const string & name)226 int countries::find_id (const string& name) {
227 	for (int i = 0, j = index.size (); i < j; ++i) if (index[i] == name) return i;
228 	return -1;
229 }
230 
changed(checkbutton & cb)231 void countries::closer::changed (checkbutton& cb) {
232   extern countries countries_;
233   countries_.do_render ();
234 }
235 
calc_bbox()236 void area::calc_bbox () {
237 	if (num_vertices) {
238 		float xmin = x[0], ymin = y[0];
239     float xmax = xmin, ymax = ymin;
240 		for (int i = 1, j = num_vertices; i < j; ++i) {
241 			float xi = x[i], yi = y[i];
242 			if (xi < xmin) xmin = xi; else if (xi > xmax) xmax = xi;
243 			if (yi < ymin) ymin = yi; else if (yi > ymax) ymax = yi;
244 		}
245 		bbox (xmin, ymin, xmax, ymax);
246 	}
247 }
248 
normalise()249 void area::normalise () {
250 	float aspect_ratio = bbox.width * 1. / bbox.height;
251 	float xw = aspect_ratio * 2.0f, xwh = xw / 2.0f;
252 	for (int i = 0, j = num_vertices; i < j; ++i) {
253 		float xi = x[i], yi = y[i];
254 		float fx = (xi - bbox.left) * bbox.width_1;
255 		float fy = (yi - bbox.bottom) * bbox.height_1;
256 		float xj = -xwh + fx * xw;
257 		float yj = -1 + fy * 2.0f;
258 		x[i] = xj;
259 		y[i] = yj;
260 	}
261 	bbox (-xwh, -1.0f, xwh, 1.0f);
262 }
263