571
* Append old_types[start, end] to new_types, adjusting flags.
574
reverse_subpath_adjust_flags (int start, int end, GByteArray *old_types, GByteArray *new_types, BOOL *prev_had_marker)
576
BYTE t, prev_first, prev_last;
579
/* Copy all but PathPointTypeStart */
581
g_byte_array_append (new_types, old_types->data + start + 1, end - start);
583
/* Append PathPointTypeStart */
584
t = PathPointTypeStart;
585
g_byte_array_append (new_types, &t, 1);
587
g_assert (new_types->len == end + 1);
589
prev_first = g_array_index (old_types, BYTE, start);
590
prev_last = g_array_index (old_types, BYTE, end);
592
/* Remove potential flags from our future start point */
594
new_types->data[end - 1] &= PathPointTypePathTypeMask;
595
/* Set the flags on our to-be-last point */
596
if (prev_last & PathPointTypeDashMode)
597
new_types->data[start] |= PathPointTypeDashMode;
598
if (prev_last & PathPointTypeCloseSubpath)
599
new_types->data[start] |= PathPointTypeCloseSubpath;
604
for (i = start + 1; i < end; i++) {
605
if (g_array_index (old_types, BYTE, i - 1) & PathPointTypePathMarker)
606
new_types->data[i] |= PathPointTypePathMarker;
608
new_types->data[i] &= ~PathPointTypePathMarker;
611
/* If the last point of the previous subpath had a marker, we inherit it */
612
if (*prev_had_marker)
613
new_types->data[start] |= PathPointTypePathMarker;
615
new_types->data[start] &= ~PathPointTypePathMarker;
617
*prev_had_marker = ((prev_last & PathPointTypePathMarker) == PathPointTypePathMarker);
573
621
GdipReversePath (GpPath *path)
627
BOOL prev_had_marker = FALSE;
579
630
return InvalidParameter;
581
632
length = path->count;
582
/* shortcut to avoid allocations */
586
/* NOTE: PathTypes are NOT reversed */
637
/* PathTypes reversal */
588
/* FIXME: this could be done without allocations */
589
points = g_array_sized_new (FALSE, TRUE, sizeof (GpPointF), length);
639
/* First adjust the flags for each subpath */
640
types = g_byte_array_sized_new (length);
591
642
return OutOfMemory;
593
for (i = length - 1; i >= 0; i--) {
594
GpPointF pt = g_array_index (path->points, GpPointF, i);
595
g_array_append_val (points, pt);
644
for (i = 1; i < length; i++) {
645
BYTE t = g_array_index (path->types, BYTE, i);
646
if ((t & PathPointTypePathTypeMask) == PathPointTypeStart) {
647
reverse_subpath_adjust_flags (start, i - 1, path->types, types, &prev_had_marker);
651
if (start < length - 1)
652
reverse_subpath_adjust_flags (start, length - 1, path->types, types, &prev_had_marker);
654
/* Then reverse the resulting array */
655
for (i = 0; i < (length >> 1); i++) {
656
BYTE *a = &g_array_index (types, BYTE, i);
657
BYTE *b = &g_array_index (types, BYTE, length - i - 1);
662
g_byte_array_free (path->types, TRUE);
665
/* PathPoints reversal
666
* note: if length is odd then the middle point doesn't need to switch side
668
for (i = 0; i < (length >> 1); i++) {
669
GpPointF *first = &g_array_index (path->points, GpPointF, i);
670
GpPointF *last = &g_array_index (path->points, GpPointF, length - i - 1);
597
g_array_free (path->points, TRUE);
598
path->points = points;
1811
/* adapted from http://www.visibone.com/inpoly/inpoly.c.txt */
1813
gdip_point_in_polygon (GpPath *path, int start, int end, float x, float y)
1816
float x1, y1, x2, y2;
1817
int x0 = iround (x);
1818
int y0 = iround (y);
1819
BOOL inside = FALSE;
1820
int npoints = end - start + 1;
1824
return FALSE; /* not a polygon */
1826
old = g_array_index (path->points, GpPointF, end);
1827
for (i = 0; i < npoints ; i++) {
1828
new = g_array_index (path->points, GpPointF, start + i);
1829
if (new.X > old.X) {
1841
if ((new.X <= x0) == (x0 < old.X) && ((y0 - y1) * (x2 - x1) < (y2 - y1) * (x0 - x1))) {
1849
/* MonoTODO - GpGraphics is ignored */
1851
1901
GdipIsVisiblePathPoint (GpPath *path, float x, float y, GpGraphics *graphics, BOOL *result)
1853
1903
GpStatus status = Ok;
1854
GpPath *workpath = NULL;
1904
cairo_surface_t* s = NULL;
1906
GpUnit page_unit = UnitPixel;
1857
1908
if (!path || !result)
1858
1909
return InvalidParameter;
1862
/* we clone the supplied path if it contains curves (we only deal with lines) */
1863
if (gdip_path_has_curve (path)) {
1864
status = GdipClonePath (path, &workpath);
1867
GdipDeletePath (workpath);
1871
status = GdipFlattenPath (workpath, NULL, 25.0f);
1877
/* FIXME - graphics isn't always ignored, e.g. when we set the matrix, pageunit and pagescale */
1880
/* there may be multiple polygons inside a path */
1881
for (start = 0, end = 0; end < workpath->count && !*result; end++) {
1882
BYTE type = g_array_index (workpath->types, BYTE, end);
1883
if (type & PathPointTypeCloseSubpath) {
1884
*result = gdip_point_in_polygon (workpath, start, end, x, y);
1885
} else if (type == PathPointTypeStart) {
1886
/* reset the start index */
1891
if (workpath != path)
1892
GdipDeletePath (workpath);
1914
page_unit = g->page_unit;
1916
/* create a temporary context */
1917
s = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
1918
g = gdip_graphics_new (s);
1921
cairo_new_path (g->ct);
1922
/* unit tests shows that PageUnit isn't consireded (well x, y are probably considered to be the same unit format ) */
1923
g->page_unit = UnitPixel;
1924
status = gdip_plot_path (g, path, FALSE);
1926
cairo_set_fill_rule (g->ct, gdip_convert_fill_mode (path->fill_mode));
1927
cairo_set_antialias (g->ct, CAIRO_ANTIALIAS_NONE);
1928
*result = cairo_in_fill (g->ct, x + CAIRO_AA_OFFSET_X, y + CAIRO_AA_OFFSET_Y);
1934
/* restore GpGraphics to original state */
1935
cairo_restore (graphics->ct);
1936
g->page_unit = page_unit;
1938
/* delete temporary context */
1939
cairo_surface_destroy (s);
1940
GdipDeleteGraphics (g);
1896
/* MonoTODO - GpGraphics is ignored */
1898
1947
GdipIsVisiblePathPointI (GpPath *path, int x, int y, GpGraphics *graphics, BOOL *result)
1900
1949
return GdipIsVisiblePathPoint (path, x, y, graphics, result);
1904
gdip_check_point_within_distance (float x0, float y0, GpPointF *p1, GpPointF *p2, float distance)
1912
/* quick out (to avoid heavy calculations) for out of range points */
1913
if ((x0 < min (x1, x2) - distance) || (x0 > max (x1, x2) + distance) ||
1914
(y0 < min (y1, y2) - distance) || (y0 > max (y1, y2) + distance))
1917
/* close enough, do the full math */
1920
/* if the provided line is a point (simpler calculation and avoids a division by zero) */
1921
if ((x2x1 == 0.0) && (y2y1 == 0.0)) {
1922
/* check distance between two points */
1923
/* ref: http://mathworld.wolfram.com/Point-PointDistance2-Dimensional.html */
1924
float x1x0 = x1 - x0;
1925
float y1y0 = y1 - y0;
1926
return (sqrt ((x1x0 * x1x0) + (y1y0 * y1y0)) <= distance);
1928
/* normal case: distance of a point to a line */
1929
/* ref: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html */
1930
float d1 = fabs ((x2x1 * (y1 - y0)) - ((x1 - x0) * y2y1));
1931
float d2 = sqrt ((x2x1 * x2x1) + (y2y1 * y2y1));
1932
return (d1 / d2 <= distance);
1936
/* MonoTODO - GpGraphics is ignored */
1938
1953
GdipIsOutlineVisiblePathPoint (GpPath *path, float x, float y, GpPen *pen, GpGraphics *graphics, BOOL *result)
1940
1955
GpStatus status = Ok;
1941
GpPath *workpath = NULL;
1956
cairo_surface_t* s = NULL;
1958
GpUnit page_unit = UnitPixel;
1943
1960
if (!path || !pen || !result)
1944
1961
return InvalidParameter;
1948
if (path->count < 2) {
1949
/* FIXME - equality check ? */
1953
/* we clone the supplied path if it contains curves (we only deal with lines) */
1954
if (gdip_path_has_curve (path)) {
1955
status = GdipClonePath (path, &workpath);
1958
GdipDeletePath (workpath);
1962
status = GdipFlattenPath (workpath, NULL, 25.0f);
1965
cairo_save (graphics->ct);
1966
page_unit = g->page_unit;
1968
/* FIXME - graphics isn't always ignored, e.g. when we set the matrix, pageunit and pagescale */
1968
/* create a temporary context */
1969
s = cairo_image_surface_create (CAIRO_FORMAT_A1, 1, 1);
1970
g = gdip_graphics_new (s);
1973
cairo_new_path (g->ct);
1974
/* unit tests shows that PageUnit isn't consireded (well x, y are probably considered to be the same unit format ) */
1975
g->page_unit = UnitPixel;
1976
status = gdip_plot_path (g, path, FALSE);
1971
1977
if (status == Ok) {
1972
/* check if the supplied point is within half the pen's width of any path segment */
1973
float half_width = pen->width / 2;
1974
int start_index = 0;
1978
GpPointF p1 = g_array_index (workpath->points, GpPointF, 0);
1981
for (i = 1; i < path->count && !*result; i++) {
1982
/* check the line between the previous point and this point */
1983
p2 = g_array_index (workpath->points, GpPointF, i);
1984
*result = gdip_check_point_within_distance (x, y, &p1, &p2, half_width);
1986
/* check for closure (to match with the last starting point) */
1987
type = g_array_index (path->types, BYTE, i);
1988
if (!*result && (type & PathPointTypeCloseSubpath)) {
1989
p1 = g_array_index (workpath->points, GpPointF, start_index);
1990
/* compare last point with first (if the path is closed) */
1991
*result = gdip_check_point_within_distance (x, y, &p2, &p1, half_width);
1994
/* switch point for the next line */
1997
/* reset the start index */
1998
if (type == PathPointTypeStart)
2003
if (workpath != path)
2004
GdipDeletePath (workpath);
1978
/* we must fight around cairo AA */
1979
cairo_set_antialias (g->ct, CAIRO_ANTIALIAS_NONE);
1980
cairo_set_line_width (g->ct, pen->width - CAIRO_AA_OFFSET_Y);
1981
*result = cairo_in_stroke (g->ct, x, y);
1987
/* restore GpGraphics to original state */
1988
cairo_restore (graphics->ct);
1989
g->page_unit = page_unit;
1991
/* delete temporary context */
1992
cairo_surface_destroy (s);
1993
GdipDeleteGraphics (g);
2008
/* MonoTODO - GpGraphics is ignored */
2010
2000
GdipIsOutlineVisiblePathPointI (GpPath *path, int x, int y, GpPen *pen, GpGraphics *graphics, BOOL *result)
2012
2002
return GdipIsOutlineVisiblePathPoint (path, x, y, pen, graphics, result);