~ubuntu-branches/ubuntu/vivid/birdfont/vivid

« back to all changes in this revision

Viewing changes to libbirdfont/Path.vala

  • Committer: Package Import Robot
  • Author(s): Hideki Yamane
  • Date: 2014-04-15 20:35:28 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: package-import@ubuntu.com-20140415203528-evwq2mnksme9fv0t
Tags: upstream-0.37
ImportĀ upstreamĀ versionĀ 0.37

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
        public List<EditPoint> points;
28
28
 
29
29
        EditPoint? last_point = null;
30
 
        EditPoint? second_last_point = null;
31
 
 
 
30
        
32
31
        /** Path boundaries */
33
32
        public double xmax = double.MIN;
34
33
        public double xmin = double.MAX;
170
169
                stroke = width; 
171
170
        }
172
171
 
173
 
        public void draw_boundaries  (Context cr, WidgetAllocation allocation, double view_zoom) {
 
172
        public void draw_boundaries  (Context cr) {
174
173
                double x = Glyph.reverse_path_coordinate_x (xmin); 
175
174
                double y = Glyph.reverse_path_coordinate_y (ymin);
176
175
                double x2 = Glyph.reverse_path_coordinate_x (xmax);
186
185
                cr.restore ();
187
186
        }
188
187
 
189
 
        public void draw_outline (Context cr, WidgetAllocation allocation, double view_zoom) {
 
188
        public void draw_outline (Context cr) {
190
189
                unowned List<EditPoint> ep = points;
191
190
                
192
191
                unowned EditPoint? n = null;
219
218
                cr.stroke ();
220
219
        }
221
220
        
222
 
        public void draw_edit_points (Context cr, WidgetAllocation allocation, double view_zoom) {
 
221
        public void draw_edit_points (Context cr) {
223
222
                unowned List<EditPoint> ep = points;
224
223
                
225
224
                if (is_editable ()) {
237
236
                }
238
237
        }
239
238
 
240
 
        public void fill_path (Context cr, WidgetAllocation allocation, double view_zoom) {
 
239
        /** Add all control points for a path to the cairo context.
 
240
         * Call Context.new_path (); before this method and Context.fill ()
 
241
         * to show the path.
 
242
         */
 
243
        public void draw_path (Context cr, Color? color = null) {
241
244
                unowned List<EditPoint> ep = points;
242
 
                
243
245
                unowned EditPoint? n = null;
244
246
                unowned EditPoint en;
245
247
                unowned EditPoint em;
246
 
                cr.new_path ();
247
 
                                        
 
248
                Color c;
 
249
                Glyph g;
 
250
                double center_x, center_y;
 
251
                double ex, ey;
 
252
 
 
253
                if (points.length () == 0){
 
254
                        return;
 
255
                }
 
256
 
 
257
                g = MainWindow.get_current_glyph ();
 
258
                
 
259
                center_x = g.allocation.width / 2.0;
 
260
                center_y = g.allocation.height / 2.0;
 
261
 
 
262
                ex = center_x + points.first ().data.x;
 
263
                ey = center_y - points.first ().data.y;
 
264
                
 
265
                cr.move_to (ex, ey);
 
266
                
248
267
                // draw lines
249
268
                foreach (EditPoint e in ep) {
250
269
                        if (n != null) {
264
283
 
265
284
                // fill path
266
285
                cr.close_path ();
267
 
                        
268
 
                if (is_clockwise ()) {
269
 
                        cr.set_source_rgba (80/255.0, 95/255.0, 137/255.0, 0.5);
 
286
                
 
287
                if (color != null) {
 
288
                        c = (!) color;
 
289
                        cr.set_source_rgba (c.r, c.g, c.b, c.a);
270
290
                } else {
271
 
                        cr.set_source_rgba (144/255.0, 145/255.0, 236/255.0, 0.5);
 
291
                        if (is_clockwise ()) {
 
292
                                cr.set_source_rgba (80/255.0, 95/255.0, 137/255.0, 0.5);
 
293
                        } else {
 
294
                                cr.set_source_rgba (144/255.0, 145/255.0, 236/255.0, 0.5);
 
295
                        }
272
296
                }
273
 
                
274
 
                cr.fill ();
275
297
        }
276
298
 
277
299
        private void draw_next (EditPoint e, EditPoint en, Context cr) {
313
335
                cr.set_source_rgba (line_color_r, line_color_g, line_color_b, line_color_a);
314
336
                cr.set_line_width (stroke_width / g.view_zoom);
315
337
                
316
 
                cr.line_to (xa, ya); // this point makes sense only if it is the first or last position, the other points are meaningless don't export them
 
338
                cr.line_to (xa, ya); // this point makes sense only if it is in the first or last position
317
339
 
318
340
                if (t == PointType.QUADRATIC || t == PointType.LINE_QUADRATIC || t == PointType.DOUBLE_CURVE || u == PointType.QUADRATIC || u == PointType.LINE_QUADRATIC || u == PointType.DOUBLE_CURVE) {
319
341
                        cr.curve_to ((xa + 2 * xb) / 3, (ya + 2 * yb) / 3, (xd + 2 * xb) / 3, (yd + 2 * yb) / 3, xd, yd);               
753
775
                        Glyph.path_coordinate_x (y2));
754
776
        }
755
777
        
756
 
        private static double get_length_from (EditPoint a, EditPoint b) {
 
778
        public static double get_length_from (EditPoint a, EditPoint b) {
757
779
                double x, y;
758
780
                
759
781
                x = Math.fabs (a.x - a.get_right_handle ().x ());
967
989
                        }
968
990
                }
969
991
                
970
 
                second_last_point = last_point;
971
992
                last_point = p;
972
993
                
973
994
                return np;
1052
1073
        }
1053
1074
 
1054
1075
        public void update_region_boundaries () {
 
1076
                PathList paths;
 
1077
                
1055
1078
                xmax = -10000;
1056
1079
                xmin = 10000;
1057
1080
                ymax = -10000;
1064
1087
                        ymin = 0;
1065
1088
                }
1066
1089
 
1067
 
                foreach (EditPoint p in points) {
1068
 
                        update_region_boundaries_for_point (p);
 
1090
                if (stroke > 0) {
 
1091
                        paths = StrokeTool.get_stroke (this, stroke);
 
1092
                } else {
 
1093
                        paths = new PathList ();
 
1094
                        paths.add (this);
 
1095
                }
 
1096
 
 
1097
                foreach (Path path in paths.paths) {
 
1098
                        foreach (EditPoint p in path.points) {
 
1099
                                update_region_boundaries_for_point (p);
 
1100
                        }
1069
1101
                }
1070
1102
        }
1071
1103
                
1123
1155
        }
1124
1156
 
1125
1157
        /** Add the extra point between line handles for double curve. */
1126
 
        void add_hidden_double_points () requires (points.length () > 1) {
 
1158
        public void add_hidden_double_points () requires (points.length () > 1) {
1127
1159
                EditPoint hidden;
1128
1160
                unowned List<EditPoint> first = points.last ();
1129
1161
                PointType left;
1130
1162
                PointType right;
1131
1163
                double x, y;
1132
1164
 
1133
 
                for (unowned List<EditPoint> next = points.first (); !is_null (next); next = next.next ) {
 
1165
                for (unowned List<EditPoint> next = points.first (); !is_null (next); next = next.next) {
1134
1166
                        left = first.data.get_right_handle ().type;
1135
1167
                        right = next.data.get_left_handle ().type;
1136
1168
                        if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) {
1141
1173
                                y = first.data.get_right_handle ().y () + (next.data.get_left_handle ().y () - first.data.get_right_handle ().y ()) / 2;
1142
1174
                                
1143
1175
                                hidden = new EditPoint (x, y, PointType.QUADRATIC);
1144
 
                                hidden.right_handle = next.data.get_left_handle ().copy ();
 
1176
                                hidden.right_handle.move_to_coordinate_internal (next.data.get_left_handle ().x(), next.data.get_left_handle ().y());
1145
1177
                                hidden.get_right_handle ().type = PointType.QUADRATIC;
 
1178
                                
 
1179
                                hidden.get_left_handle ().type = PointType.QUADRATIC;
1146
1180
                                hidden.type = PointType.QUADRATIC;
1147
1181
                                
1148
1182
                                first.data.get_right_handle ().type = PointType.QUADRATIC;
1149
1183
                                first.data.type = PointType.QUADRATIC;
1150
1184
                                
 
1185
                                next.data.get_left_handle ().type = PointType.QUADRATIC;
 
1186
                                next.data.type = PointType.QUADRATIC;
 
1187
                                
1151
1188
                                add_point_after (hidden, first);
1152
1189
                        }
1153
1190
                        first = next;
1186
1223
                        next = i.next;
1187
1224
                }
1188
1225
                
1189
 
                if (points.last ().data.get_right_handle ().type == PointType.CUBIC 
1190
 
                        ||  points.first ().data.get_left_handle ().type == PointType.CUBIC) {
 
1226
                if (!is_open () && (points.last ().data.get_right_handle ().type == PointType.CUBIC 
 
1227
                        ||  points.first ().data.get_left_handle ().type == PointType.CUBIC)) {
1191
1228
                        add_quadratic_points (points.last ().data, points.first ().data);
1192
1229
                } else {
1193
1230
                        quadratic_path.add_point (points.last ().data.copy ());
1200
1237
 
1201
1238
                quadratic_path.add_hidden_double_points ();
1202
1239
 
1203
 
                quadratic_path.close ();
1204
1240
                quadratic_path.create_list ();
1205
1241
                process_quadratic_handles ();
1206
1242
                
1207
 
                quadratic_path.close ();
1208
1243
                quadratic_path.create_list ();
1209
1244
                process_cubic_handles ();
1210
 
                
1211
 
                quadratic_path.close ();
1212
 
                
 
1245
 
 
1246
                foreach (EditPoint ep in quadratic_path.points) {
 
1247
                        if (ep.type == PointType.QUADRATIC) {
 
1248
                                ep.get_left_handle ().move_to_coordinate (ep.get_prev ().data.get_right_handle ().x (), ep.get_prev ().data.get_right_handle ().y ());
 
1249
                        }
 
1250
                }
 
1251
 
 
1252
                if (!is_open ()) {
 
1253
                        quadratic_path.close ();
 
1254
                } else {
 
1255
                        quadratic_path.reopen ();
 
1256
                }
 
1257
                                                                
1213
1258
                return quadratic_path;
1214
1259
        }
1215
1260
        
1217
1262
                int steps;
1218
1263
                EditPoint prev =  new EditPoint ();
1219
1264
                int added_points = 0;
1220
 
 
 
1265
                
1221
1266
                if (points.length () < 2) {
1222
1267
                        return;
1223
1268
                }
1230
1275
                
1231
1276
                // create quadratic paths
1232
1277
                all_of (start, stop, (x, y, step) => {
1233
 
                        double prev_step = 0;
1234
 
                        EditPoint e =  new EditPoint ();
 
1278
                        EditPoint e;
1235
1279
                        
1236
1280
                        if (step == 1) {
1237
1281
                                return true;
1238
1282
                        }
1239
 
                        
 
1283
                                                
1240
1284
                        e = new EditPoint (x, y, PointType.QUADRATIC);
1241
1285
                        added_points++;
1242
1286
 
1243
 
                        prev_step = step;
1244
1287
                        prev = e;
1245
1288
 
1246
 
                        quadratic_path.add_point (e);
 
1289
                        e = quadratic_path.add_point (e);
1247
1290
                        prev = quadratic_path.points.last ().data;
1248
1291
                        
1249
 
                        prev.type = PointType.LINE_QUADRATIC;
1250
 
                        prev.get_left_handle ().type = PointType.LINE_QUADRATIC;
1251
 
                        prev.get_right_handle ().type = PointType.LINE_QUADRATIC;
1252
1292
                        prev.recalculate_linear_handles ();
1253
1293
                        
1254
1294
                        new_quadratic_points.append (prev);
1296
1336
                        ep.y - (ep.y - prev.y) / 2);            
1297
1337
        }
1298
1338
        
 
1339
        /** Adjust position for the _new_ quadratic points. */
1299
1340
        void process_quadratic_handles () {     
1300
1341
                for (int t = 0; t < 2; t++) {
1301
1342
                        foreach (EditPoint ep in new_quadratic_points) {        
1352
1393
                        return true;
1353
1394
                });
1354
1395
 
1355
 
                if (right == PointType.LINE_QUADRATIC && left == PointType.LINE_QUADRATIC) {
1356
 
                        ep.get_right_handle ().set_point_type (PointType.LINE_QUADRATIC);
1357
 
                        ep.get_left_handle ().set_point_type (PointType.LINE_QUADRATIC);
1358
 
                        ep.type = PointType.QUADRATIC;
1359
 
                } else if (right == PointType.LINE_CUBIC && left == PointType.LINE_CUBIC) {
1360
 
                        ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);
1361
 
                        ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);
1362
 
                        ep.type = PointType.LINE_CUBIC;
1363
 
                } else if (right == PointType.LINE_DOUBLE_CURVE && left == PointType.LINE_DOUBLE_CURVE) {
1364
 
                        ep.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);
1365
 
                        ep.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);
1366
 
                        ep.type = PointType.DOUBLE_CURVE;
1367
 
                } else if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) {
 
1396
                if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) {
1368
1397
                        double_bezier_vector (position, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x, out x0, out x1);
1369
1398
                        double_bezier_vector (position, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y, out y0, out y1);
1370
 
                        
1371
 
                        ep.get_left_handle ().move_to_coordinate (x1, y1);
1372
 
                        ep.get_right_handle ().move_to_coordinate (x0, y0);
1373
1399
 
1374
1400
                        ep.get_left_handle ().set_point_type (PointType.DOUBLE_CURVE);  
1375
1401
                        ep.get_right_handle ().set_point_type (PointType.DOUBLE_CURVE);
 
1402
                                                
 
1403
                        ep.get_left_handle ().move_to_coordinate (x0, y0);  // FIXME: SWAPPED?
 
1404
                        ep.get_right_handle ().move_to_coordinate (x1, y1);
 
1405
 
1376
1406
                        ep.type = PointType.DOUBLE_CURVE;
1377
1407
                } else if (right == PointType.QUADRATIC) {              
1378
1408
                        x0 = quadratic_bezier_vector (1 - position, stop.x, start.get_right_handle ().x (), start.x);
1385
1415
                        ep.get_left_handle ().move_to_coordinate_internal (0, 0);
1386
1416
                        
1387
1417
                        ep.type = PointType.QUADRATIC;                          
1388
 
                } else {
 
1418
                } else if (right == PointType.CUBIC || left == PointType.CUBIC) {
1389
1419
                        bezier_vector (position, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x, out x0, out x1);
1390
1420
                        bezier_vector (position, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y, out y0, out y1);
1391
1421
 
1396
1426
                        ep.get_right_handle ().move_to_coordinate (x1, y1);
1397
1427
                        
1398
1428
                        ep.type = PointType.LINE_CUBIC;
1399
 
                }
 
1429
                } else if (right == PointType.LINE_QUADRATIC && left == PointType.LINE_QUADRATIC) {
 
1430
                        ep.get_right_handle ().set_point_type (PointType.LINE_QUADRATIC);
 
1431
                        ep.get_left_handle ().set_point_type (PointType.LINE_QUADRATIC);
 
1432
                        ep.type = PointType.QUADRATIC;
 
1433
                } else if (right == PointType.LINE_CUBIC && left == PointType.LINE_CUBIC) {
 
1434
                        ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);
 
1435
                        ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);
 
1436
                        ep.type = PointType.LINE_CUBIC;
 
1437
                } else if (right == PointType.LINE_DOUBLE_CURVE && left == PointType.LINE_DOUBLE_CURVE) {
 
1438
                        ep.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);
 
1439
                        ep.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);
 
1440
                        ep.type = PointType.DOUBLE_CURVE;
 
1441
                } else 
1400
1442
 
1401
1443
                ep.get_left_handle ().parent = ep;
1402
1444
                ep.get_right_handle ().parent = ep;
1535
1577
        }
1536
1578
 
1537
1579
        public static void all_of (EditPoint start, EditPoint stop, RasterIterator iter, int steps = -1) {
1538
 
                PointType right = start.get_right_handle ().type;
1539
 
                PointType left = stop.get_left_handle ().type;
 
1580
                PointType right = PenTool.to_curve (start.get_right_handle ().type);
 
1581
                PointType left = PenTool.to_curve (stop.get_left_handle ().type);
1540
1582
                
1541
1583
                if (steps == -1) {
1542
1584
                        steps = (int) (10 * get_length_from (start, stop));
1544
1586
                
1545
1587
                if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) {
1546
1588
                        all_of_double (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.get_left_handle ().x (), stop.get_left_handle ().y (), stop.x, stop.y, iter, steps);
1547
 
                } else if (right == PointType.QUADRATIC) {
 
1589
                } else if (right == PointType.QUADRATIC && left == PointType.QUADRATIC) {
1548
1590
                        all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.x, stop.y, iter, steps);
1549
 
                } else {
 
1591
                } else if (right == PointType.CUBIC && left == PointType.CUBIC) {
1550
1592
                        all_of_curve (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.get_left_handle ().x (), stop.get_left_handle ().y (), stop.x, stop.y, iter, steps);
 
1593
                } else {
 
1594
                        warning (@"Mixed point types in segment $(start.x),$(start.y) to $(stop.x),$(stop.y)");
 
1595
                        all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.x, stop.y, iter, steps);
1551
1596
                }
1552
1597
        }
1553
1598
 
1702
1747
        public static double double_bezier_path (double step, double p0, double p1, double p2, double p3) {
1703
1748
                double middle = p1 + (p2 - p1) / 2;
1704
1749
                
 
1750
                if (step == 0.5) {
 
1751
                        // FIXME: return the middle point
 
1752
                        warning ("Middle");
 
1753
                }
 
1754
                
1705
1755
                if (step < 0.5) {
1706
1756
                        return quadratic_bezier_path (2 * step, p0, p1, middle);
1707
1757
                }
1712
1762
        public static void double_bezier_vector (double step, double p0, double p1, double p2, double p3, out double a0, out double a1) {
1713
1763
                double b0, b1, c0, c1, d0, d1;
1714
1764
        
 
1765
                if (unlikely (step <= 0 || step >= 1)) {
 
1766
                        warning (@"Bad step: $step");
 
1767
                        step += 0.00004;
 
1768
                }
 
1769
 
 
1770
                // set angle
 
1771
                b0 = double_bezier_path (step + 0.00001, p0, p1, p2, p3);
 
1772
                c0 = double_bezier_path (step + 0.00002, p0, p1, p2, p3);
 
1773
 
 
1774
                b1 = double_bezier_path (step - 0.00001, p0, p1, p2, p3);
 
1775
                c1 = double_bezier_path (step - 0.00002, p0, p1, p2, p3);
 
1776
                
 
1777
                // adjust length
 
1778
                d0 = b0 + (b0 - c0) * 25000 * (step);
 
1779
                d1 = b1 + (b1 - c1) * 25000 * (1 - step);
 
1780
        
 
1781
        // FIXME: DELETE                
 
1782
        /*
1715
1783
                // set angle
1716
1784
                b0 = double_bezier_path (step - 0.00001, p0, p1, p2, p3);
1717
1785
                c0 = double_bezier_path (step - 0.00002, p0, p1, p2, p3);
1722
1790
                // adjust length
1723
1791
                d0 = b0 + (b0 - c0) * 25000 * (1 - step);
1724
1792
                d1 = b1 + (b1 - c1) * 25000 * step;
1725
 
                
 
1793
        */      
 
1794
        
1726
1795
                a0 = d0;
1727
1796
                a1 = d1;
1728
1797
        }
2270
2339
                        return;
2271
2340
                }
2272
2341
 
 
2342
                // FIXME: DELETE
 
2343
                /*
2273
2344
                points.last ().data.right_handle.type = path.points.first ().data.type;
2274
2345
                points.last ().data.right_handle.move_to_coordinate (
2275
2346
                        path.points.first ().data.right_handle.x (),
2277
2348
                        
2278
2349
                path.points.first ().data.right_handle.type = 
2279
2350
                        points.last ().data.right_handle.type;
2280
 
 
 
2351
                */
2281
2352
                path.points.first ().data.recalculate_linear_handles ();
2282
2353
                points.last ().data.recalculate_linear_handles ();
2283
2354
                
2284
 
                // FIXME: path.points.remove_link (path.points.first ());
2285
 
                
2286
2355
                // copy remaining points
2287
2356
                foreach (EditPoint p in path.points) {
2288
2357
                        add_point (p.copy ());
2330
2399
        public void flip_vertical () {
2331
2400
                EditPointHandle hl, hr;
2332
2401
                double lx, ly, rx, ry;
 
2402
 
2333
2403
                foreach (EditPoint e in points) {
2334
2404
                        hl = e.get_left_handle ();
2335
2405
                        hr = e.get_right_handle ();
2403
2473
                get_first_point ().get_left_handle ().convert_to_line ();
2404
2474
                get_last_point ().get_right_handle ().convert_to_line ();               
2405
2475
        }
 
2476
        
 
2477
        public void print_all_types () {
 
2478
                print (@"Control points:\n");
 
2479
                foreach (EditPoint ep in points) {
 
2480
                        print (@"$(ep.type) L: $(ep.get_left_handle ().type) R: L: $(ep.get_right_handle ().type)\n");
 
2481
                }
 
2482
        }
 
2483
        
 
2484
        /** Find the point where two lines intersect. */
 
2485
        public static void find_intersection (double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4,
 
2486
                out double point_x, out double point_y) {
 
2487
                point_x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
 
2488
                point_y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
 
2489
        }
 
2490
 
 
2491
        public static void find_intersection_handle (EditPointHandle h1, EditPointHandle h2, out double point_x, out double point_y) {
 
2492
                find_intersection (h1.parent.x, h1.parent.y, h1.x (), h1.y (), h2.parent.x, h2.parent.y, h2.x (), h2.y (), out point_x, out point_y);
 
2493
        }
 
2494
        
 
2495
        public void add_extrema () {
 
2496
                double x0, y0, x1, y1, x2, y2, x3, y3;
 
2497
                double minx, maxx, miny, maxy;
 
2498
                
 
2499
                if (unlikely (points.length () < 2)) {
 
2500
                        warning (@"Missing points, $(points.length ()) points in path.");
 
2501
                        return;
 
2502
                }
 
2503
                
 
2504
                minx = double.MAX;
 
2505
                miny = double.MAX;
 
2506
                maxx = double.MIN;
 
2507
                maxy = double.MIN;
 
2508
                
 
2509
                x0 = 0;
 
2510
                y0 = 0; 
 
2511
                x1 = 0;
 
2512
                y1 = 0; 
 
2513
                x2 = 0;
 
2514
                y2 = 0;
 
2515
                x3 = 0;
 
2516
                y3 = 0;
 
2517
                                
 
2518
                all_of_path ((x, y) => {
 
2519
                        if (x < minx) {
 
2520
                                x0 = x;
 
2521
                                y0 = y;
 
2522
                                minx = x;
 
2523
                        }
 
2524
                        
 
2525
                        if (x > maxx) {
 
2526
                                x1 = x;
 
2527
                                y1 = y;
 
2528
                                maxx = x;
 
2529
                        }
 
2530
 
 
2531
                        if (y < miny) {
 
2532
                                x2 = x;
 
2533
                                y2 = y;
 
2534
                                miny = y;
 
2535
                        }
 
2536
                                        
 
2537
                        if (y > maxy) {
 
2538
                                x3 = x;
 
2539
                                y3 = y;
 
2540
                                maxy = y;
 
2541
                        }
 
2542
                        
 
2543
                        return true;
 
2544
                });
 
2545
                
 
2546
                insert_new_point_on_path_at (x0 - 1, y0);
 
2547
                insert_new_point_on_path_at (x1 + 1, y1);
 
2548
                insert_new_point_on_path_at (x2, y2 - 1);
 
2549
                insert_new_point_on_path_at (x3, y3 + 1);
 
2550
        }
 
2551
        
 
2552
        void insert_new_point_on_path_at (double x, double y) {
 
2553
                EditPoint ep = new EditPoint ();
 
2554
                bool exists;
 
2555
                
 
2556
                get_closest_point_on_path (ep, x, y);
 
2557
 
 
2558
                exists = ep.get_prev ().data.x == ep.x && ep.get_prev ().data.y == ep.y;
 
2559
                exists |= ep.get_next ().data.x == ep.x && ep.get_next ().data.y == ep.y;
 
2560
                
 
2561
                if (!exists) {
 
2562
                        insert_new_point_on_path (ep);
 
2563
                }
 
2564
        }
2406
2565
}
2407
2566
 
2408
2567
}