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