Commit 836c66f
merge two paths
Changed files (6)
modifiedsrc/EditPointHandle.valamodifiedsrc/Glyph.valaaddedsrc/Intersection.valaaddedsrc/IntersectionList.valamodifiedsrc/Path.valamodifiedsrc/wscript
Diff
@@ -53,6 +53,16 @@ class EditPointHandle { this.active = false; } + public EditPointHandle copy () {+ EditPointHandle n = new EditPointHandle.empty ();+ n.angle = angle;+ n.length = length;+ n.parent = parent;+ n.type = type;+ n.active = active;+ return n;+ }+ public void set_point_type (PointType point_type) { type = point_type; }@@ -1663,8 +1663,15 @@ class Glyph : FontDisplay { delete_invisible_paths (); - if (path_list.length () >= 2)- ((!)path_list.first ()).data.merge (((!)path_list.last ()).data);+ if (path_list.length () >= 2) {+ m = ((!) path_list.first ()).data.merge (((!) path_list.last ()).data);+ delete_path (path_list.first ().data);+ delete_path (path_list.last ().data);++ ((!) m).close ();+ + add_path (((!) m).copy ());+ } } } new file mode 100644@@ -0,0 +1,36 @@+/*+ Copyright (C) 2012 Johan Mattsson++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+*/++using Math;++namespace Supplement {++class Intersection {+ public double x;+ public double y;+ public double distance;+ + public EditPoint editpoint_a;+ public EditPoint editpoint_b;+ + public Intersection (double x, double y, double distance) {+ this.x = x;+ this.y = y;+ }+}++}new file mode 100644@@ -0,0 +1,235 @@+/*+ Copyright (C) 2012 Johan Mattsson++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+*/++using Math;++namespace Supplement {++class IntersectionList {+ public List<Intersection> points = new List<Intersection> ();+ + public void add (Intersection i) {+ double d;+ Intersection l;+ + if (points.length () == 0) {+ points.append (i);+ return;+ }+ + if (has_point (i)) {+ return;+ }+ + l = ((!) points.last ()).data;+ d = Math.fabs (Math.sqrt (Math.pow (i.x - l.x, 2) + Math.pow (i.y - l.y, 2)));++ if (l.distance >= i.distance) {+ points.remove_link (points.last ());+ points.append (i);+ return;+ }++ if (d < 0.3) {+ return;+ }++ points.append (i);+ }+ + public bool has_edit_point (EditPoint e) {+ foreach (Intersection n in points) {+ if (n.editpoint_a == e || n.editpoint_b == e) {+ return true;+ }+ }+ + return false;+ }+ + bool has_point (Intersection i) {+ foreach (Intersection n in points) {+ if (i.x == n.x && i.y == n.y) {+ return true;+ }+ }+ + return false;+ }+ + public int get_point_index (EditPoint e) {+ int i = 0;+ foreach (Intersection n in points) {+ if (e.x == n.x && e.y == n.y) {+ return i;+ }+ i++;+ }+ return -1;+ }+ + public Intersection? get_next_intersection (EditPoint e) {+ bool found = false;+ foreach (Intersection n in points) {+ if (found) {+ return n;+ }+ + if (n.editpoint_a == e || n.editpoint_b == e) {+ found = true;+ }+ }+ return null;+ }+ + public Intersection? get_intersection (EditPoint e) {+ foreach (Intersection n in points) {+ if (n.editpoint_a == e || n.editpoint_b == e) {+ return n;+ }+ }+ + return null;+ }+ + public void append (IntersectionList i) {+ foreach (Intersection inter in i.points) {+ points.append (inter);+ }+ }++ public static IntersectionList create_intersection_list (Path p1, Path p2) {+ Path new_path = new Path ();+ IntersectionList il = new IntersectionList ();+ + unowned List<EditPoint> a_start, a_stop;+ unowned List<EditPoint> b_start, b_stop;+ + EditPoint e;+ + if (p1 == p2) {+ return il;+ }+ + a_start = p1.points.first ();+ for (int i = 0; i < p1.points.length (); i++) {+ + if (a_start.data.next == null) {+ a_stop = p1.points.first ();+ } else {+ a_stop = a_start.data.get_next ();+ }+ + b_start = p2.points.first ();+ for (int j = 0; j < p2.points.length (); j++) {+ + if (b_start.data.next == null) {+ b_stop = p2.points.first ();+ } else {+ b_stop = b_start.data.get_next ();+ }+ + //if (probably_intersecting (a_start.data, a_stop.data, b_start.data, b_stop.data)) {+ il.append (find_intersections (a_start.data, a_stop.data, b_start.data, b_stop.data));+ //}+ + b_start = b_stop;+ }+ + a_start = a_stop;+ } +/*+ foreach (Intersection inter in il.points) {+ e = new EditPoint ();+ p1.get_closest_point_on_path (e, inter.x, inter.y);+ inter.editpoint_a = e;++ e = new EditPoint ();+ p2.get_closest_point_on_path (e, inter.x, inter.y);+ inter.editpoint_b = e;+ } + */+ return il;+ }++ static IntersectionList find_intersections (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {+ IntersectionList il = new IntersectionList ();+ + double mind = double.MAX; ;+ double distance = double.MAX;+ + Path.all_of (a0, a1, (ax, ay, at) => {+ if (at == 0 || at == 1) {+ return true;+ }+ + Path.all_of (b0, b1, (bx, by, bt) => {+ double d = Math.fabs (Math.sqrt (Math.pow (ax - bx, 2) + Math.pow (ay - by, 2)));+ + if (d < 0.2) {+ il.add (new Intersection (ax, ay, 0));+ }+ + if (d < mind) mind = d;+ return true;+ });+ + return true;+ });++ return il;+ }++ bool probably_intersecting (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {+ if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {+ return true;+ } ++ if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {+ return true;+ } + + return false;+ }+ + /** return true if ranges does overlap */+ bool has_intersection (double a0, double a1, double b0, double b1) {+ if (a0 <= b0 <= a1 || a1 <= b0 <= a0) {+ if (a0 <= b1 <= a1 || a1 <= b1 <= a0) {+ return true;+ }+ + if (b0 <= a1 <= b1 || b1 <= a1 <= b0) {+ return true;+ }+ }+ + if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {+ if (a0 <= a0 <= a1 || a1 <= a0 <= a0) {+ return true;+ }+ + if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {+ return true;+ }+ }+ + return false;+ }+}++}@@ -47,7 +47,7 @@ class Path { bool no_derived_direction = false; bool clockwise_direction = true; - delegate bool RasterIterator (double x, double y, double step); // iterate over each pixel at a given zoom level+ public delegate bool RasterIterator (double x, double y, double step); // iterate over each pixel at a given zoom level public double r = 0; public double g = 0;@@ -1343,11 +1343,11 @@ class Path { } // TODO: Find a clever mathematical solutions instead- private void all_of (EditPoint start, EditPoint stop, RasterIterator iter, int steps = 400) {+ public static void all_of (EditPoint start, EditPoint stop, RasterIterator iter, int steps = 400) { 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); } - private void all_of_curve (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, int steps = 400) {+ private static void all_of_curve (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, int steps = 400) { double px = x1; double py = y1; @@ -1579,13 +1579,24 @@ class Path { public Path? merge (Path p) { EditPoint e;- IntersectionList il = create_intersection_list (this, p);- + IntersectionList il = IntersectionList.create_intersection_list (this, p);+ Path np = new Path ();+ Intersection s = new Intersection (0, 0, 1);+ EditPoint ex = points.last ().data;+ EditPoint ix = points.last ().data;+ uint offset_i = 0;+ uint offset_j;+ uint len_i = points.length ();+ int i, j;+ uint len_j;+ + // add editpoints points on intersections foreach (Intersection inter in il.points) { e = new EditPoint (); get_closest_point_on_path (e, inter.x, inter.y); inter.editpoint_a = e;- + + e = inter.editpoint_a; if (!has_edit_point (e)) { insert_new_point_on_path (e); }@@ -1594,213 +1605,92 @@ class Path { p.get_closest_point_on_path (e, inter.x, inter.y); inter.editpoint_b = e; + e = inter.editpoint_b; if (!p.has_edit_point (e)) { p.insert_new_point_on_path (e); } - print (@" inter.x $(inter.x), $(inter.y)\n"); } - return null;- }-+ // create a new path + for (i = 0; i < points.length (); i++) {+ ex = points.nth (i).data; -class IntersectionList {- public List<Intersection> points = new List<Intersection> ();- - public void add (Intersection i) {- double d;- Intersection l;- - if (points.length () == 0) {- print (@"GIOT\n");- points.append (i);- return;- }- - if (has_point (i)) {- return;- }- - l = ((!) points.last ()).data;- d = Math.fabs (Math.sqrt (Math.pow (i.x - l.x, 2) + Math.pow (i.y - l.y, 2)));- print (@"d $d\n");- - print (@"GIOT REM $(i.distance) $(l.distance) $d\n");- - if (l.distance >= i.distance) {- points.remove_link (points.last ());- points.append (i);- print (@"GIOT REM $(i.distance)\n");- return;- }-- if (d < 0.3) {- return;- }-- print (@"GIOT NEW $(i.distance)\n");- points.append (i);- }- - bool has_point (Intersection i) {- foreach (Intersection n in points) {- if (i.x == n.x && i.y == n.y) {- return true;+ if (ex == points.first ().data && i != 0) {+ break; }- }- - return false;- }- - public void append (IntersectionList i) {- foreach (Intersection inter in i.points) {- points.append (inter);- }- }-} -class Intersection {- public double x;- public double y;- public double distance;- - public EditPoint editpoint_a;- public EditPoint editpoint_b;- - public Intersection (double x, double y, double distance) {- this.x = x;- this.y = y;- }-}- - IntersectionList create_intersection_list (Path p1, Path p2) {- Path new_path = new Path ();- IntersectionList il = new IntersectionList ();- - unowned List<EditPoint> a_start, a_stop;- unowned List<EditPoint> b_start, b_stop;- - if (p1 == p2) {- return il;- }- - a_start = p1.points.first ();- for (int i = 0; i < p1.points.length (); i++) {- - if (a_start.data.next == null) {- a_stop = p1.points.first ();- } else {- a_stop = a_start.data.get_next ();- }+ // add new point for path a+ np.add_point (ex);+ ix.recalculate_linear_handles (); - b_start = p2.points.first ();- for (int j = 0; j < p2.points.length (); j++) {+ // swap paths+ if (il.has_edit_point (ex)) {+ s = (!) il.get_intersection (ex); - if (b_start.data.next == null) {- b_stop = p2.points.first ();- } else {- b_stop = b_start.data.get_next ();+ ex.type = PointType.CURVE;+ ex.right_handle.type = PointType.CURVE;+ ex.right_handle.angle = s.editpoint_b.right_handle.angle;+ ex.right_handle.length = s.editpoint_b.right_handle.length;++ // read until we find ex+ for (j = 0; j < p.points.length (); j++) {+ ix = p.points.nth (j).data;+ + if (ix == s.editpoint_b) {+ break;+ } } - //if (probably_intersecting (a_start.data, a_stop.data, b_start.data, b_stop.data)) {- il.append (find_intersections (a_start.data, a_stop.data, b_start.data, b_stop.data));- //}- - b_start = b_stop;- }- - a_start = a_stop;- } + offset_j = j + 1;+ len_j = p.points.length ();+ for (j = 0; j < p.points.length (); j++) {+ + ix = p.points.nth ((j + offset_j) % len_j).data;+ + // add+ ix.right_handle .move_to_coordinate (0, 0);+ np.add_point (ix);+ ix.recalculate_linear_handles ();+ + if (il.has_edit_point (ix)) {+ s = (!) il.get_intersection (ix);+ break;+ }+ + } - - foreach (Intersection inter in il.points) {- EditPoint e = new EditPoint ();- p1.get_closest_point_on_path (e, inter.x, inter.y);- inter.editpoint_a = e;+ ix.type = PointType.CURVE;+ ix.right_handle.type = PointType.CURVE;+ ix.right_handle.angle = s.editpoint_a.right_handle.angle;+ ix.right_handle.length = s.editpoint_a.right_handle.length; - if (!has_edit_point (e)) {- insert_new_point_on_path (e);- }+ if (j == points.length ()) {+ np.close ();+ return np;+ } - e = new EditPoint ();- p2.get_closest_point_on_path (e, inter.x, inter.y);- inter.editpoint_b = e;- - if (!p2.has_edit_point (e)) {- p2.insert_new_point_on_path (e);- }- - - print (@" inter.x $(inter.x), $(inter.y)\n");- } - return il;- }+ // skip to next intersection+ int k;+ for (k = 0; k < points.length (); k++) {+ ix = points.nth (k).data; - IntersectionList find_intersections (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {- IntersectionList il = new IntersectionList ();- - double mind = double.MAX; ;- double distance = double.MAX;- - all_of (a0, a1, (ax, ay, at) => {- if (at == 0 || at == 1) {- return true;- }- - all_of (b0, b1, (bx, by, bt) => {- double d = Math.fabs (Math.sqrt (Math.pow (ax - bx, 2) + Math.pow (ay - by, 2)));+ if (ix == s.editpoint_a) {+ break;+ }+ } - if (d < 0.2) {- il.add (new Intersection (ax, ay, 0));+ if (k == points.length ()) {+ return np; } - if (d < mind) mind = d;- return true;- }, 200);- - return true;- }, 200);- - print (@"FIND $mind\n");- return il;- }-- bool probably_intersecting (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {- if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {- return true;- } -- if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {- return true;- } - - return false;- }- - /** return true if ranges does overlap */- bool has_intersection (double a0, double a1, double b0, double b1) {- if (a0 <= b0 <= a1 || a1 <= b0 <= a0) {- if (a0 <= b1 <= a1 || a1 <= b1 <= a0) {- return true;+ offset_i = 0;+ i = k; } - if (b0 <= a1 <= b1 || b1 <= a1 <= b0) {- return true;- } } - if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {- if (a0 <= a0 <= a1 || a1 <= a0 <= a0) {- return true;- }- - if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {- return true;- }- }- - return false;+ return np; } }@@ -29,6 +29,8 @@ SUPPLEMENT_MAIN = [ 'MenuTab.vala', 'MergeTool.vala', 'MoveTool.vala', + 'Intersection.vala', + 'IntersectionList.vala', 'IOThread.vala', 'OpenFontFormatWriter.vala', 'OpenFontFormatReader.vala',