1 /*
2 */
3
4 /*
5
6 Copyright (C) 2014 Ferrero Andrea
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21
22 */
23
24 /*
25
26 These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27
28 */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 #include <vips/vips.h>
34
35 #include "../external/darktable/src/develop/masks.h"
36 #include "splinecurve.hh"
37
ClosedSplineCurve()38 PF::ClosedSplineCurve::ClosedSplineCurve():
39 PF::Curve(),
40 Dmax(0), border_size(0),
41 wd_last(0),
42 ht_last(0),
43 ypp( NULL ),
44 ypp_size( 0 )
45 {
46 points_mutex = vips_g_mutex_new();
47 //points.push_back( std::make_pair(float(0.5),float(0.2)) );
48 //points.push_back( std::make_pair(float(0.8),float(0.8)) );
49 //points.push_back( std::make_pair(float(0.2),float(0.8)) );
50 center.first = 0.5; center.second = 0.5;
51 //update_polar();
52 //update_spline();
53 }
54
55
56
~ClosedSplineCurve()57 PF::ClosedSplineCurve::~ClosedSplineCurve()
58 {
59 }
60
61
62
update_polar()63 void PF::ClosedSplineCurve::update_polar()
64 {
65 points_polar.clear();
66 for( unsigned int i = 0; i < points.size(); i++ ) {
67 float dx = points[i].first - center.first;
68 float dy = points[i].second - center.second;
69 float r = hypotf(dx,dy);
70 float phi = atan2f(dy,dx);
71 points_polar.push_back( std::make_pair(r,phi) );
72 }
73 }
74
75
76
add_point(int id,float x,float y)77 int PF::ClosedSplineCurve::add_point( int id, float x, float y )
78 {
79 //if( (get_npoints()>0) && (x<=points[0].first) ) return -1;
80 //if( (get_npoints()>1) && (x >= points[get_npoints()-1].first) ) return -1;
81 //return -1;
82 lock();
83 if( id >= 0 ) {
84
85 if( id < (int)points.size() ) {
86 points.insert( points.begin()+id, std::make_pair(x,y) );
87 #ifndef NDEBUG
88 std::cout<<"PF::ClosedSplineCurve::add_point( "<<x<<", "<<y<<" ): point added before "<<points[i].first<<std::endl;
89 #endif
90 } else {
91 points.push_back( std::make_pair(x,y) );
92 }
93 update_polar();
94 unlock();
95 return id;
96 } else {
97 points.push_back( std::make_pair(x,y) );
98 }
99 unlock();
100 return( points.size()-1 );
101
102
103 //#ifndef NDEBUG
104 std::cout<<"PF::ClosedSplineCurve::add_point( "<<x<<", "<<y<<" ): points.size()="<<points.size()<<std::endl;
105 //#endif
106 float dx = x - center.first;
107 float dy = y - center.second;
108 float r = hypotf(dx,dy);
109 float phi = atan2f(dy,dx);
110 std::cout<<"PF::ClosedSplineCurve::add_point( "<<x<<", "<<y<<" ): r="<<r<<" phi="<<phi<<std::endl;
111 std::cout<<" phi[0]="<<points_polar[0].second<<std::endl;
112 std::cout<<" phi["<<points_polar.size()-1<<"]="<<points_polar[points_polar.size()-1].second<<std::endl;
113 int dest_id = -1;
114 if( points_polar.size() == 0 || phi < points_polar[0].second )
115 dest_id = 0;
116 else if( phi >= points_polar[points_polar.size()-1].second )
117 dest_id = points_polar.size();
118 else {
119 for( unsigned int i = 1; i < points_polar.size(); i++ ) {
120 std::cout<<" phi["<<i<<"]="<<points_polar[i].second<<std::endl;
121 if( (phi >= points_polar[i-1].second) && (phi < points_polar[i].second) ) {
122 dest_id = i;
123 break;
124 }
125 }
126 }
127 std::cout<<"PF::ClosedSplineCurve::add_point( "<<x<<", "<<y<<" ): dest_id="<<dest_id<<std::endl;
128
129 if( dest_id >= 0 ) {
130
131 if( dest_id < points.size() ) {
132 points.insert( points.begin()+dest_id, std::make_pair(x,y) );
133 #ifndef NDEBUG
134 std::cout<<"PF::ClosedSplineCurve::add_point( "<<x<<", "<<y<<" ): point added before "<<points[i].first<<std::endl;
135 #endif
136 } else {
137 points.push_back( std::make_pair(x,y) );
138 }
139 update_polar();
140 unlock();
141 return dest_id;
142 }
143 unlock();
144 return( points.size()-1 );
145 }
146
147
remove_point(unsigned int id)148 bool PF::ClosedSplineCurve::remove_point( unsigned int id )
149 {
150 if( id == 0 ) return false;
151 if( id >= (get_npoints()-1) ) return false;
152
153 points.erase( points.begin() + id );
154 //update_spline();
155 return true;
156 }
157
158
set_point(unsigned int id,float x,float y)159 int PF::ClosedSplineCurve::set_point( unsigned int id, float x, float y )
160 {
161 //return 0;
162 #ifndef NDEBUG
163 std::cout<<"PF::ClosedSplineCurve::set_point( "<<x<<", "<<y<<" ): points.size()="<<points.size()<<std::endl;
164 #endif
165 if( id >= points.size() ) return -1;
166 points[id].first = x;
167 points[id].second = y;
168 return id;
169
170 float dx = x - center.first;
171 float dy = y - center.second;
172 float r = hypotf(dx,dy);
173 float phi = atan2f(dy,dx);
174 std::cout<<"PF::ClosedSplineCurve::set_point( "<<x<<", "<<y<<" ): r="<<r<<" phi="<<phi<<std::endl;
175 std::cout<<" phi[0]="<<points_polar[0].second<<std::endl;
176 std::cout<<" phi["<<points_polar.size()-1<<"]="<<points_polar[points_polar.size()-1].second<<std::endl;
177 int dest_id = -1;
178 if( points_polar.size() == 0 || phi < points_polar[0].second )
179 dest_id = 0;
180 else if( phi >= points_polar[points_polar.size()-1].second )
181 dest_id = points_polar.size();
182 else {
183 for( unsigned int i = 1; i < points_polar.size(); i++ ) {
184 std::cout<<" phi["<<i<<"]="<<points_polar[i].second<<std::endl;
185 if( (phi >= points_polar[i-1].second) && (phi < points_polar[i].second) ) {
186 dest_id = i;
187 break;
188 }
189 }
190 }
191 std::cout<<"PF::ClosedSplineCurve::set_point( "<<x<<", "<<y<<" ): dest_id="<<dest_id<<std::endl;
192
193 if( dest_id < 0 ) return -1;
194
195 int result_id = -1;
196
197 std::vector< std::pair<float,float> > points2;
198 std::vector< std::pair<float,float> > points_polar2;
199
200 bool added = false;
201 for( unsigned int i = 0; i < points_polar.size(); i++ ) {
202 if( static_cast<int>(i) == dest_id ) {
203 points2.push_back( std::make_pair(x,y) );
204 points_polar2.push_back( std::make_pair(r,phi) );
205 result_id = points2.size() - 1;
206 added = true;
207 }
208 if( static_cast<int>(i) != id ) {
209 points2.push_back( points[i] );
210 points_polar2.push_back( points_polar[i] );
211 }
212 }
213 if( !added ) {
214 points2.push_back( std::make_pair(x,y) );
215 points_polar2.push_back( std::make_pair(r,phi) );
216 result_id = points2.size() - 1;
217 }
218
219 points_polar = points_polar2;
220 points = points2;
221 return result_id;
222 }
223
224
225
scale(float s)226 void PF::ClosedSplineCurve::scale( float s )
227 {
228 update_center();
229 for( unsigned int i = 0; i < points.size(); i++ ) {
230 float dx = points[i].first - center.first;
231 float dy = points[i].second - center.second;
232 double bpx = dx * s + center.first;
233 double bpy = dy * s + center.second;
234 points[i].first = bpx;
235 points[i].second = bpy;
236 }
237 }
238
239
240
update_spline()241 void PF::ClosedSplineCurve::update_spline()
242 {
243 }
244
245
update_center()246 void PF::ClosedSplineCurve::update_center()
247 {
248 // get the center of gravity of the form (like if it was a simple polygon)
249 float bx = 0.0f;
250 float by = 0.0f;
251 float surf = 0.0f;
252
253 int nb = points.size();
254 if( nb > 0 ) {
255 for(int k = 0; k < nb; k++)
256 {
257 int k2 = (k + 1) % nb;
258 surf += points[k].first * points[k2].second - points[k2].first * points[k].second;
259
260 bx += (points[k].first + points[k2].first)
261 * (points[k].first * points[k2].second - points[k2].first * points[k].second);
262 by += (points[k].second + points[k2].second)
263 * (points[k].first * points[k2].second - points[k2].first * points[k].second);
264 }
265 bx /= 3.0 * surf;
266 by /= 3.0 * surf;
267 }
268
269 center.first = bx; center.second = by;
270 Dmax = 0;
271 for( unsigned int i = 0; i < points.size(); i++ ) {
272 float px = points[i].first;
273 float py = points[i].second;
274 float dx = px - center.first;
275 float dy = py - center.second;
276 float D = hypotf(dx,dy);
277 if( D > Dmax ) Dmax = D;
278 }
279 }
280
281
282
283 #define CLIPD(a) ((a)>0.0?((a)<1.0?(a):1.0):0.0)
284
285
get_value(float x)286 float PF::ClosedSplineCurve::get_value( float x )
287 {
288 return 0;
289 }
290
291
get_delta(float x)292 float PF::ClosedSplineCurve::get_delta( float x )
293 {
294 return( get_value(x) - x );
295 }
296
297
get_values(std::vector<std::pair<float,float>> & vec)298 void PF::ClosedSplineCurve::get_values( std::vector< std::pair<float,float> >& vec )
299 {
300 for (unsigned int i=0; i<vec.size(); i++)
301 vec[i].second = get_value( vec[i].first );
302 }
303
304
get_deltas(std::vector<std::pair<float,float>> & vec)305 void PF::ClosedSplineCurve::get_deltas( std::vector< std::pair<float,float> >& vec )
306 {
307 for (unsigned int i=0; i<vec.size(); i++) {
308 float val = get_value( vec[i].first );
309 vec[i].second = val - vec[i].first;
310 }
311 }
312
313
update_outline(float wd,float ht)314 void PF::ClosedSplineCurve::update_outline( float wd, float ht )
315 {
316 update_center();
317 //float wd = 1000.0f/Dmax;
318 //float ht = wd;
319 //std::cout<<"ClosedSplineCurve::update_outline(): Dmax="<<Dmax<<" wd="<<wd<<" ht="<<ht<<" border_size="<<border_size<<std::endl;
320 dt_masks_form_t *form = (dt_masks_form_t *)malloc(sizeof(dt_masks_form_t));
321 form->type = DT_MASKS_PATH;
322 form->version = DEVELOP_MASKS_VERSION;
323 form->formid = time(NULL);
324
325 form->points = NULL;
326 float masks_border = border_size;
327
328 //printf("ClosedSplineCurve::update_outline(): points.size()=%d\n", (int)points.size());
329 for( unsigned int pi = 0; pi < points.size(); pi++ ) {
330 dt_masks_point_path_t *bzpt = (dt_masks_point_path_t *)(malloc(sizeof(dt_masks_point_path_t)));
331 int nb = g_list_length(form->points);
332 //printf("ClosedSplineCurve::get_points(): nb(1)=%d\n", nb);
333 // change the values
334 bzpt->corner[0] = points[pi].first;
335 bzpt->corner[1] = points[pi].second;
336 bzpt->ctrl1[0] = bzpt->ctrl1[1] = bzpt->ctrl2[0] = bzpt->ctrl2[1] = -1.0;
337 bzpt->state = DT_MASKS_POINT_STATE_NORMAL;
338
339 bzpt->border[0] = bzpt->border[1] = MAX(0.005f, masks_border);
340
341 if( pi==0 ) {
342 form->source[0] = bzpt->corner[0] + 0.02f;
343 form->source[1] = bzpt->corner[1] + 0.02f;
344 }
345
346 // if that's the first point we should add another one as base point
347 if(false && nb == 0)
348 {
349 dt_masks_point_path_t *bzpt2 = (dt_masks_point_path_t *)(malloc(sizeof(dt_masks_point_path_t)));
350 bzpt2->corner[0] = points[pi].first;
351 bzpt2->corner[1] = points[pi].second;
352 bzpt2->ctrl1[0] = bzpt2->ctrl1[1] = bzpt2->ctrl2[0] = bzpt2->ctrl2[1] = -1.0;
353 bzpt2->border[0] = bzpt2->border[1] = MAX(0.005f, masks_border);
354 bzpt2->state = DT_MASKS_POINT_STATE_NORMAL;
355 form->points = g_list_append(form->points, bzpt2);
356 guint nb = g_list_length(form->points);
357 //printf("ClosedSplineCurve::get_points(): nb(2)=%d\n", nb);
358 form->source[0] = bzpt->corner[0] + 0.02f;
359 form->source[1] = bzpt->corner[1] + 0.02f;
360 nb++;
361 }
362 form->points = g_list_append(form->points, bzpt);
363 }
364
365 _path_init_ctrl_points(form);
366 ctrl_points.clear();
367 guint nb = g_list_length(form->points);
368 for(int k = 0; k < (int)nb; k++) {
369 dt_masks_point_path_t *pt = (dt_masks_point_path_t *)g_list_nth_data(form->points, k);
370 std::pair<float,float> ctrl1 = std::make_pair( (float)pt->ctrl1[0], (float)pt->ctrl1[1] );
371 std::pair<float,float> ctrl2 = std::make_pair( (float)pt->ctrl2[0], (float)pt->ctrl2[1] );
372 ctrl_points.push_back( std::make_pair(ctrl1, ctrl2) );
373 }
374
375 float* out_points = NULL;
376 int out_points_count = 0;
377 float* out_border = NULL;
378 int out_border_count = 0;
379 int result = _path_get_points_border(form, 999, wd, ht,
380 &out_points, &out_points_count,
381 &out_border, &out_border_count, 0);
382 //std::cout<<"_path_get_points_border(): result="<<result<<std::endl;
383 //std::cout<<"update_outline(): out_points_count="<<out_points_count
384 // <<" out_border_count="<<out_border_count<<std::endl;
385
386 outline.clear();
387 float* ptr = out_points;
388 int xlast = -999999, ylast = -999999;
389 for( int pi = 0; pi < out_points_count; pi++ ) {
390 if( pi >= (int)points.size()*3 ) {
391 int ix = (int)ptr[0];
392 int iy = (int)ptr[1];
393 //std::cout<<"path point "<<ix<<","<<iy<<" (last "<<xlast<<","<<ylast<<")"<<std::endl;
394 //if( ix!=xlast || iy!=ylast) {
395 outline.push_back( std::make_pair(ptr[0], ptr[1]) );
396 xlast = ix; ylast = iy;
397 //std::cout<<"added path point "<<ptr[0]<<","<<ptr[1]<<std::endl;
398 //}
399 }
400 ptr += 2;
401 }
402 if( out_points ) free( out_points );
403
404 border.clear();
405 ptr = out_border;
406 xlast = -999999; ylast = -999999;
407 for( int pi = 0; pi < out_border_count; pi++ ) {
408 if( pi >= (int)points.size()*3 ) {
409 int ix = (int)ptr[0];
410 int iy = (int)ptr[1];
411 //std::cout<<"path point "<<ix<<","<<iy<<" (last "<<xlast<<","<<ylast<<")"<<std::endl;
412 //if( ix!=xlast || iy!=ylast) {
413 border.push_back( std::make_pair(ptr[0], ptr[1]) );
414 xlast = ix; ylast = iy;
415 //std::cout<<"added path point "<<ptr[0]<<","<<ptr[1]<<std::endl;
416 //}
417 }
418 ptr += 2;
419 }
420 if( out_border ) free( out_border );
421
422 wd_last = wd; ht_last = ht;
423 }
424