(float x1, float y1,
float rx, float ry,
float angle,
boolean fa, boolean fs,
float x2, float y2)
| 970 | // Based on arc to bezier curve equations from: |
| 971 | // http://www.spaceroots.org/documents/ellipse/node22.html |
| 972 | private void parsePathArcto(float x1, float y1, |
| 973 | float rx, float ry, |
| 974 | float angle, |
| 975 | boolean fa, boolean fs, |
| 976 | float x2, float y2) { |
| 977 | if (x1 == x2 && y1 == y2) return; |
| 978 | if (rx == 0 || ry == 0) { parsePathLineto(x2, y2); return; } |
| 979 | |
| 980 | rx = PApplet.abs(rx); ry = PApplet.abs(ry); |
| 981 | |
| 982 | float phi = PApplet.radians(((angle % 360) + 360) % 360); |
| 983 | float cosPhi = PApplet.cos(phi), sinPhi = PApplet.sin(phi); |
| 984 | |
| 985 | float x1r = ( cosPhi * (x1 - x2) + sinPhi * (y1 - y2)) / 2; |
| 986 | float y1r = (-sinPhi * (x1 - x2) + cosPhi * (y1 - y2)) / 2; |
| 987 | |
| 988 | float cxr, cyr; |
| 989 | { |
| 990 | float A = (x1r*x1r) / (rx*rx) + (y1r*y1r) / (ry*ry); |
| 991 | if (A > 1) { |
| 992 | // No solution, scale ellipse up according to SVG standard |
| 993 | float sqrtA = PApplet.sqrt(A); |
| 994 | rx *= sqrtA; cxr = 0; |
| 995 | ry *= sqrtA; cyr = 0; |
| 996 | } else { |
| 997 | float k = ((fa == fs) ? -1f : 1f) * |
| 998 | PApplet.sqrt((rx*rx * ry*ry) / ((rx*rx * y1r*y1r) + (ry*ry * x1r*x1r)) - 1f); |
| 999 | cxr = k * rx * y1r / ry; |
| 1000 | cyr = -k * ry * x1r / rx; |
| 1001 | } |
| 1002 | } |
| 1003 | |
| 1004 | float cx = cosPhi * cxr - sinPhi * cyr + (x1 + x2) / 2; |
| 1005 | float cy = sinPhi * cxr + cosPhi * cyr + (y1 + y2) / 2; |
| 1006 | |
| 1007 | float phi1, phiDelta; |
| 1008 | { |
| 1009 | float sx = ( x1r - cxr) / rx, sy = ( y1r - cyr) / ry; |
| 1010 | float tx = (-x1r - cxr) / rx, ty = (-y1r - cyr) / ry; |
| 1011 | phi1 = PApplet.atan2(sy, sx); |
| 1012 | phiDelta = (((PApplet.atan2(ty, tx) - phi1) % TWO_PI) + TWO_PI) % TWO_PI; |
| 1013 | if (!fs) phiDelta -= TWO_PI; |
| 1014 | } |
| 1015 | |
| 1016 | // One segment can not cover more that PI, less than PI/2 is |
| 1017 | // recommended to avoid visible inaccuracies caused by rounding errors |
| 1018 | int segmentCount = PApplet.ceil(PApplet.abs(phiDelta) / TWO_PI * 4); |
| 1019 | |
| 1020 | float inc = phiDelta / segmentCount; |
| 1021 | float a = PApplet.sin(inc) * |
| 1022 | (PApplet.sqrt(4 + 3 * PApplet.sq(PApplet.tan(inc / 2))) - 1) / 3; |
| 1023 | |
| 1024 | float sinPhi1 = PApplet.sin(phi1), cosPhi1 = PApplet.cos(phi1); |
| 1025 | |
| 1026 | float p1x = x1; |
| 1027 | float p1y = y1; |
| 1028 | float relq1x = a * (-rx * cosPhi * sinPhi1 - ry * sinPhi * cosPhi1); |
| 1029 | float relq1y = a * (-rx * sinPhi * sinPhi1 + ry * cosPhi * cosPhi1); |
no test coverage detected