Author: spouliot
Date: 2007-10-18 10:06:32 -0400 (Thu, 18 Oct 2007)
New Revision: 87748
Removed:
trunk/moon/src/rsvg.cpp
trunk/moon/src/rsvg.h
Modified:
trunk/moon/src/ChangeLog
trunk/moon/src/Makefile.am
trunk/moon/src/geometry.cpp
trunk/moon/src/libmoon.h
Log:
2007-10-18 Sebastien Pouliot <[EMAIL PROTECTED]>
* geometry.cpp: New code to handle arc segments. No known issues
(except the handling of near zero values which doesn't seems to
be constant).
* libmoon.h, Makefile.am: Remove reference to rsvg.h
* rsvg.cpp|h: Remove from SVN.
Modified: trunk/moon/src/ChangeLog
===================================================================
--- trunk/moon/src/ChangeLog 2007-10-18 12:27:08 UTC (rev 87747)
+++ trunk/moon/src/ChangeLog 2007-10-18 14:06:32 UTC (rev 87748)
@@ -1,3 +1,11 @@
+2007-10-18 Sebastien Pouliot <[EMAIL PROTECTED]>
+
+ * geometry.cpp: New code to handle arc segments. No known issues
+ (except the handling of near zero values which doesn't seems to
+ be constant).
+ * libmoon.h, Makefile.am: Remove reference to rsvg.h
+ * rsvg.cpp|h: Remove from SVN.
+
2007-10-17 Andrew Jorgensen <[EMAIL PROTECTED]>
* cairo-embed.h, pixman-embed.h: Added symbol renaming headers
Modified: trunk/moon/src/Makefile.am
===================================================================
--- trunk/moon/src/Makefile.am 2007-10-18 12:27:08 UTC (rev 87747)
+++ trunk/moon/src/Makefile.am 2007-10-18 14:06:32 UTC (rev 87748)
@@ -37,7 +37,6 @@
playlist.h \
point.h \
rect.h \
- rsvg.h \
runtime.h \
shape.h \
stylus.h \
@@ -83,7 +82,6 @@
point.cpp \
playlist.cpp \
rect.cpp \
- rsvg.cpp \
runtime.cpp \
shape.cpp \
stylus.cpp \
Modified: trunk/moon/src/geometry.cpp
===================================================================
--- trunk/moon/src/geometry.cpp 2007-10-18 12:27:08 UTC (rev 87747)
+++ trunk/moon/src/geometry.cpp 2007-10-18 14:06:32 UTC (rev 87748)
@@ -24,8 +24,6 @@
#include "shape.h"
#include "array.h"
-#include "rsvg.h"
-
//
// Geometry
//
@@ -1010,17 +1008,181 @@
segment->SetValue (ArcSegment::SweepDirectionProperty, Value
(direction));
}
+// is it true only for arcs or for everything ? if so using the same values ?
+#define IS_ZERO(x) (fabs(x) < 0.000019)
+#define IS_TOO_SMALL(x) (fabs(x) < 0.000117)
+
void
ArcSegment::Append (moon_path *path)
{
+ // from tests it seems that Silverlight closely follows SVG arc
+ // behavior (which is very different from the model used with GDI+)
+ // some helpful stuff is available here:
+ // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
+
+ // get start point from the existing path
+ double sx, sy;
+ moon_get_current_point (path, &sx, &sy);
+ // end point
+ Point* ep = arc_segment_get_point (this);
+
+ // if start and end points are identical, then no arc is drawn
+ // FIXME: what's the logic (if any) to compare points
+ // e.g. 60 and 60.000002 are drawn while 80 and 80.000003 aren't
+ if (IS_ZERO (ep->x - sx) && IS_ZERO (ep->y - sy))
+ return;
+
Point *size = arc_segment_get_size (this);
- double angle = arc_segment_get_rotation_angle (this);
- int large = arc_segment_get_is_large_arc (this) ? 1 : 0;
- int direction = arc_segment_get_sweep_direction (this) ==
SweepDirectionCounterclockwise ? 0 : 1;
- Point* p = arc_segment_get_point (this);
+ // Correction of out-of-range radii, see F6.6 (step 1)
+ if (IS_ZERO (size->x) || IS_ZERO (size->y)) {
+ // treat this as a straight line (to end point)
+ moon_line_to (path, ep->x, ep->y);
+ return;
+ }
- // FIXME: there's no cairo_arc_to so we reuse librsvg code (see
rsvg.cpp)
- rsvg_arc_to (path, size->x, size->y, angle, large, direction, p->x,
p->y);
+ // Silverlight "too small to be useful"
+ if (IS_TOO_SMALL (size->x) || IS_TOO_SMALL (size->y)) {
+ // yes it does mean there's a hole between "normal" FP values
and "zero" FP values
+ // and SL doesn't render anything in this twilight sonze
+ return;
+ }
+
+ // Correction of out-of-range radii, see F6.6.1 (step 2)
+ double rx = fabs (size->x);
+ double ry = fabs (size->y);
+
+ // convert angle into radians
+ double angle = arc_segment_get_rotation_angle (this) * M_PI / 180.0;
+
+ // variables required for F6.3.1
+ double cos_phi = cos (angle);
+ double sin_phi = sin (angle);
+ double dx2 = (sx - ep->x) / 2.0;
+ double dy2 = (sy - ep->y) / 2.0;
+ double x1p = cos_phi * dx2 + sin_phi * dy2;
+ double y1p = cos_phi * dy2 - sin_phi * dx2;
+ double x1p2 = x1p * x1p;
+ double y1p2 = y1p * y1p;
+ double rx2 = rx * rx;
+ double ry2 = ry * ry;
+
+ // Correction of out-of-range radii, see F6.6.2 (step 4)
+ double lambda = (x1p2 / rx2) + (y1p2 / ry2);
+ if (lambda > 1.0) {
+ // see F6.6.3
+ double lambda_root = sqrt (lambda);
+ rx *= lambda_root;
+ ry *= lambda_root;
+ // update rx2 and ry2
+ rx2 = rx * rx;
+ ry2 = ry * ry;
+ }
+
+ bool sweep = arc_segment_get_sweep_direction (this);
+ double cxp, cyp, cx, cy;
+ double c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2);
+
+ // check if there is no possible solution (i.e. we can't do a square
root of a negative value)
+ if (c < 0.0) {
+ // scale uniformly until we have a single solution (see F6.2)
i.e. when c == 0.0
+ double scale = sqrt (1.0 - c / (rx2 * ry2));
+ rx *= scale;
+ ry *= scale;
+ // update rx2 and ry2
+ rx2 = rx * rx;
+ ry2 = ry * ry;
+
+ // step 2 (F6.5.2) - simplified since c == 0.0
+ cxp = 0.0;
+ cyp = 0.0;
+
+ // step 3 (F6.5.3 first part) - simplified since cxp and cyp ==
0.0
+ cx = 0.0;
+ cy = 0.0;
+ } else {
+ // complete c calculation
+ c = sqrt (c / ((rx2 * y1p2) + (ry2 * x1p2)));
+
+ // inverse sign if Fa == Fs
+ if (arc_segment_get_is_large_arc (this) == sweep)
+ c = -c;
+
+ // step 2 (F6.5.2)
+ cxp = c * ( rx * y1p / ry);
+ cyp = c * (-ry * x1p / rx);
+
+ // step 3 (F6.5.3 first part)
+ cx = cos_phi * cxp - sin_phi * cyp;
+ cy = sin_phi * cxp + cos_phi * cyp;
+ }
+
+ // step 3 (F6.5.3 second part) we now have the center point of the
ellipse
+ cx += (sx + ep->x) / 2.0;
+ cy += (sy + ep->y) / 2.0;
+
+ // step 4 (F6.5.4)
+ // we dont' use arccos (as per w3c doc), see
http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
+ // note: atan2 (0.0, 1.0) == 0.0
+ double at = atan2 (((y1p - cyp) / ry), ((x1p - cxp) / rx));
+ double theta1 = (at < 0.0) ? 2.0 * M_PI + at : at;
+
+ double nat = atan2 (((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
+ double delta_theta = (nat < at) ? 2.0 * M_PI - at + nat : nat - at;
+
+ if (sweep) {
+ // ensure delta theta < 0 or else add 360 degrees
+ if (delta_theta < 0.0)
+ delta_theta += 2.0 * M_PI;
+ } else {
+ // ensure delta theta > 0 or else substract 360 degrees
+ if (delta_theta > 0.0)
+ delta_theta -= 2.0 * M_PI;
+ }
+
+ // add several cubic bezier to approximate the arc (smaller than 90
degrees)
+ // we add one extra segment because we want something smaller than
90deg (i.e. not 90 itself)
+ int segments = (int) (fabs (delta_theta / M_PI_2)) + 1;
+ double delta = delta_theta / segments;
+
+ // http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt
(section 2.13)
+ double bcp = 4.0 / 3 * (1 - cos (delta / 2)) / sin (delta / 2);
+
+ double cos_phi_rx = cos_phi * rx;
+ double cos_phi_ry = cos_phi * ry;
+ double sin_phi_rx = sin_phi * rx;
+ double sin_phi_ry = sin_phi * ry;
+
+ double cos_theta1 = cos (theta1);
+ double sin_theta1 = sin (theta1);
+
+ for (int i = 0; i < segments; ++i) {
+ // end angle (for this segment) = current + delta
+ double theta2 = theta1 + delta;
+ double cos_theta2 = cos (theta2);
+ double sin_theta2 = sin (theta2);
+
+ // first control point (based on start point sx,sy)
+ double c1x = sx - bcp * (cos_phi_rx * sin_theta1 + sin_phi_ry *
cos_theta1);
+ double c1y = sy + bcp * (cos_phi_ry * cos_theta1 - sin_phi_rx *
sin_theta1);
+
+ // end point (for this segment)
+ double ex = cx + (cos_phi_rx * cos_theta2 - sin_phi_ry *
sin_theta2);
+ double ey = cy + (sin_phi_rx * cos_theta2 + cos_phi_ry *
sin_theta2);
+
+ // second control point (based on end point ex,ey)
+ double c2x = ex + bcp * (cos_phi_rx * sin_theta2 + sin_phi_ry *
cos_theta2);
+ double c2y = ey + bcp * (sin_phi_rx * sin_theta2 - cos_phi_ry *
cos_theta2);
+
+ moon_curve_to (path, c1x, c1y, c2x, c2y, ex, ey);
+
+ // next start point is the current end point (same for angle)
+ sx = ex;
+ sy = ey;
+ theta1 = theta2;
+ // avoid recomputations
+ cos_theta1 = cos_theta2;
+ sin_theta1 = sin_theta2;
+ }
}
//
Modified: trunk/moon/src/libmoon.h
===================================================================
--- trunk/moon/src/libmoon.h 2007-10-18 12:27:08 UTC (rev 87747)
+++ trunk/moon/src/libmoon.h 2007-10-18 14:06:32 UTC (rev 87748)
@@ -31,7 +31,6 @@
#include "playlist.h"
#include "point.h"
#include "rect.h"
-#include "rsvg.h"
#include "runtime.h"
#include "shape.h"
#include "stylus.h"
Deleted: trunk/moon/src/rsvg.cpp
===================================================================
--- trunk/moon/src/rsvg.cpp 2007-10-18 12:27:08 UTC (rev 87747)
+++ trunk/moon/src/rsvg.cpp 2007-10-18 14:06:32 UTC (rev 87748)
@@ -1,141 +0,0 @@
-/* This is (modified) LGPL code from librsvg 2.16.1
-
- Copyright (C) 2000 Eazel, Inc.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-
- Author: Raph Levien <[EMAIL PROTECTED]>
-*/
-
-#include <config.h>
-#include <glib.h>
-#include <math.h>
-#include <cairo.h>
-#include "rsvg.h"
-
-static void
-rsvg_path_arc_segment (moon_path *path,
- double xc, double yc,
- double th0, double th1,
- double rx, double ry, double x_axis_rotation)
-{
- double sin_th, cos_th;
- double a00, a01, a10, a11;
- double x1, y1, x2, y2, x3, y3;
- double t;
- double th_half;
-
- sin_th = sin (x_axis_rotation * (M_PI / 180.0));
- cos_th = cos (x_axis_rotation * (M_PI / 180.0));
- /* inverse transform compared with rsvg_path_arc */
- a00 = cos_th * rx;
- a01 = -sin_th * ry;
- a10 = sin_th * rx;
- a11 = cos_th * ry;
-
- th_half = 0.5 * (th1 - th0);
- t = (8.0 / 3.0) * sin (th_half * 0.5) * sin (th_half * 0.5) / sin (th_half);
- x1 = xc + cos (th0) - t * sin (th0);
- y1 = yc + sin (th0) + t * cos (th0);
- x3 = xc + cos (th1);
- y3 = yc + sin (th1);
- x2 = x3 + t * sin (th1);
- y2 = y3 - t * cos (th1);
- moon_curve_to (path,
- a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
- a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
- a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
-}
-
-/**
- * rsvg_path_arc: Add an RSVG arc to the path context.
- * @ctx: Path context.
- * @rx: Radius in x direction (before rotation).
- * @ry: Radius in y direction (before rotation).
- * @x_axis_rotation: Rotation angle for axes.
- * @large_arc_flag: 0 for arc length <= 180, 1 for arc >= 180.
- * @sweep: 0 for "negative angle", 1 for "positive angle".
- * @x: New x coordinate.
- * @y: New y coordinate.
- *
- **/
-void
-rsvg_arc_to (moon_path *path, double rx, double ry, double x_axis_rotation,
int large_arc_flag, int sweep_flag,
- double x, double y)
-{
- double sin_th, cos_th;
- double a00, a01, a10, a11;
- double x0, y0, x1, y1, xc, yc;
- double d, sfactor, sfactor_sq;
- double th0, th1, th_arc;
- int i, n_segs;
-
- /* Check that neither radius is zero, since its isn't either
- geometrically or mathematically meaningful and will
- cause divide by zero and subsequent NaNs. We should
- really do some ranged check ie -0.001 < x < 000.1 rather
- can just a straight check again zero.
- */
- if ((rx == 0.0) || (ry == 0.0)) return;
-
- sin_th = sin (x_axis_rotation * (M_PI / 180.0));
- cos_th = cos (x_axis_rotation * (M_PI / 180.0));
- a00 = cos_th / rx;
- a01 = sin_th / rx;
- a10 = -sin_th / ry;
- a11 = cos_th / ry;
-
- double cpx, cpy;
- moon_get_current_point (path, &cpx, &cpy);
-
- x0 = a00 * cpx + a01 * cpy;
- y0 = a10 * cpx + a11 * cpy;
- x1 = a00 * x + a01 * y;
- y1 = a10 * x + a11 * y;
- /* (x0, y0) is current point in transformed coordinate space.
- (x1, y1) is new point in transformed coordinate space.
-
- The arc fits a unit-radius circle in this space.
- */
- d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
- sfactor_sq = 1.0 / d - 0.25;
- if (sfactor_sq < 0) sfactor_sq = 0;
- sfactor = sqrt (sfactor_sq);
- if (sweep_flag == large_arc_flag) sfactor = -sfactor;
- xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
- yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
- /* (xc, yc) is center of the circle. */
-
- th0 = atan2 (y0 - yc, x0 - xc);
- th1 = atan2 (y1 - yc, x1 - xc);
-
- th_arc = th1 - th0;
- if (th_arc < 0 && sweep_flag)
- th_arc += 2 * M_PI;
- else if (th_arc > 0 && !sweep_flag)
- th_arc -= 2 * M_PI;
-
- n_segs = (int)ceil (fabs (th_arc / (M_PI * 0.5 + 0.001)));
-
- for (i = 0; i < n_segs; i++)
- rsvg_path_arc_segment (path, xc, yc,
- th0 + i * th_arc / n_segs,
- th0 + (i + 1) * th_arc / n_segs,
- rx, ry, x_axis_rotation);
-
-// ctx->cpx = x;
-// ctx->cpy = y;
-}
Deleted: trunk/moon/src/rsvg.h
===================================================================
--- trunk/moon/src/rsvg.h 2007-10-18 12:27:08 UTC (rev 87747)
+++ trunk/moon/src/rsvg.h 2007-10-18 14:06:32 UTC (rev 87748)
@@ -1,35 +0,0 @@
-/* This is (modified) LGPL code from librsvg 2.16.1
-
- Copyright (C) 2000 Eazel, Inc.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-
- Author: Raph Levien <[EMAIL PROTECTED]>
-*/
-
-#ifndef __RSVG_H__
-#define __RSVG_H__
-
-#include "moon-path.h"
-
-G_BEGIN_DECLS
-
-void rsvg_arc_to (moon_path *path, double rx, double ry, double
x_axis_rotation, int large_arc_flag, int sweep_flag,
- double x, double y);
-
-G_END_DECLS
-
-#endif
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches