void add_intersection(Line line, bg::model::segment<bpoint> seg, std::vector<bpoint> &intersections) { bpoint intersect; if (intersect_segment(line, seg, intersect)) { //We must remove the intersection point //if at + and -epsilon not in detector OR // if at + and - epsilon in detector const double epsilon = 0.001; //bpoint temp = line.get_direction_vector(); //bpoint eps_direction_vec = Utils::mul_coords_by_const( // temp, epsilon); bpoint eps_direction_vec = line.get_direction_vector(); bg::multiply_value(eps_direction_vec, epsilon); bpoint before(intersect.get<0>() - eps_direction_vec.get<0>(), intersect.get<1>() - eps_direction_vec.get<1>()); bpoint after = intersect; bg::add_point(after, eps_direction_vec); bool before_in_det = is_point_inside_geometry(before); bool after_in_det = is_point_inside_geometry(after); bool is_a_cross_boundary_point = !((before_in_det && after_in_det) || (!before_in_det && !after_in_det)); if (is_a_cross_boundary_point) { intersections.push_back(intersect); } } }
/* Is segment crossing polygon? (including edges) * 0 don't cross * 1 cross * 2 on a side * 3 touch out (a segment boundary is on a polygon edge, * and the second segment boundary is out of the polygon) */ uint8_t is_crossing_poly(point_t p1, point_t p2, point_t *intersect_pt, poly_t *pol) { uint8_t i; uint8_t ret; point_t p; uint8_t ret1, ret2; uint8_t cpt=0; debug_printf("%" PRIi32 " %" PRIi32 " -> %" PRIi32 " %" PRIi32 " crossing poly %p ?\n", p1.x, p1.y, p2.x, p2.y, pol); debug_printf("poly is : "); for (i=0; i<pol->l; i++) { debug_printf("%" PRIi32 ",%" PRIi32 " ", pol->pts[i].x, pol->pts[i].y); } debug_printf("\n"); for (i=0;i<pol->l;i++) { ret = intersect_segment(&p1, &p2, &pol->pts[i], &pol->pts[(i+1)%pol->l], &p); debug_printf("%" PRIi32 ",%" PRIi32 " -> %" PRIi32 ",%" PRIi32 " return %d\n", pol->pts[i].x, pol->pts[i].y, pol->pts[(i+1)%pol->l].x, pol->pts[(i+1)%pol->l].y, ret); switch(ret) { case 0: break; case 1: if (intersect_pt) *intersect_pt = p; return 1; break; case 2: cpt++; if (intersect_pt) *intersect_pt = p; break; case 3: if (intersect_pt) *intersect_pt = p; return 2; break; } } if (cpt==3 ||cpt==4) return 1; ret1 = is_in_poly(&p1, pol); ret2 = is_in_poly(&p2, pol); debug_printf("is in poly: p1 %d p2: %d cpt %d\r\n", ret1, ret2, cpt); debug_printf("p intersect: %"PRIi32" %"PRIi32"\r\n", p.x, p.y); if (cpt==0) { if (ret1==1 || ret2==1) return 1; return 0; } if (cpt==1) { if (ret1==1 || ret2==1) return 1; return 3; } if (cpt==2) { if (ret1==1 || ret2==1) return 1; if (ret1==0 || ret2==0) return 3; return 1; } return 1; }
int scan_glyph(TTF_Font *font, TTF_Glyph *glyph) { CHECKPTR(font); CHECKPTR(glyph); RETINIT(SUCCESS); if (!glyph->outline) { warn("failed to scan uninitialized glyph outline"); return FAILURE; } else if (glyph->outline->point < 0) { warn("failed to scan unscaled glyph outline"); return FAILURE; } else if (glyph->number_of_contours == 0) { /* Zero-length glyph with no outline. */ return SUCCESS; } TTF_Outline *outline = glyph->outline; TTF_Bitmap *bitmap = NULL; uint32_t bg, fg; if (font->raster_flags & RENDER_FPAA) { /* Anti-aliased rendering - oversample outline then downsample. */ bg = 0xFFFFFF; fg = 0x000000; if (!glyph->bitmap) { glyph->bitmap = create_bitmap((outline->x_max - outline->x_min) / 2, (outline->y_max - outline->y_min) / 2, bg); } /* Intermediate oversampled bitmap. */ bitmap = create_bitmap(outline->x_max - outline->x_min, outline->y_max - outline->y_min, bg); } else if (font->raster_flags & RENDER_ASPAA) { /* Sub-pixel rendering - oversample in x-direction then downsample. */ bg = 0xFFFFFF; fg = 0x000000; if (!glyph->bitmap) { glyph->bitmap = create_bitmap((outline->x_max - outline->x_min) / 3, outline->y_max - outline->y_min, bg); } /* Intermediate oversampled bitmap. */ bitmap = create_bitmap(outline->x_max - outline->x_min, outline->y_max - outline->y_min, bg); } else { /* Normal rendering - write directly to glyph bitmap. */ bg = 0xFFFFFF; fg = 0x000000; if (!glyph->bitmap) { glyph->bitmap = create_bitmap(outline->x_max - outline->x_min, outline->y_max - outline->y_min, bg); } bitmap = glyph->bitmap; } /* Create a scan-line for each row in the scaled outline. */ int num_scanlines = outline->y_max - outline->y_min; TTF_Scan_Line *scanlines = malloc(num_scanlines * sizeof(*scanlines)); CHECKFAIL(scanlines, warnerr("failed to alloc glyph scan lines")); /* Find intersections of each scan-line with contour segments. */ for (int i = 0; i < num_scanlines; i++) { TTF_Scan_Line *scanline = &scanlines[i]; init_scanline(scanline, outline->num_contours * 2); scanline->y = outline->y_max - i; for (int j = 0; j < outline->num_contours; j++) { TTF_Contour *contour = &outline->contours[j]; int k; for (k = 0; k < contour->num_segments; k++) { TTF_Segment *segment = &contour->segments[k]; intersect_segment(segment, scanline); } } /* Round pixel intersection values to 1/64 of a pixel. */ for (int j = 0; j < scanline->num_intersections; j++) { scanline->x[j] = round_pixel(scanline->x[j]); } /* Sort intersections from left to right. */ qsort(scanline->x, scanline->num_intersections, sizeof(*scanline->x), cmp_intersections); // printf("Intersections: "); // char *sep = ""; // for (int j = 0; j < scanline->num_intersections; j++) { // printf("%s%f", sep, scanline->x[j]); // sep = ", "; // } // printf("\n"); int int_index = 0, fill = 0; for (int j = 0; j < bitmap->w; j++) { if (int_index < scanline->num_intersections) { if ((outline->x_min + j) >= scanline->x[int_index]) { fill = !fill; /* Skip over duplicate intersections. */ int k; for (k = 1; int_index+k < scanline->num_intersections; k++) { if (scanline->x[int_index] != scanline->x[int_index+k]) { break; } } int_index += k; } } if (fill) { bitmap_set(bitmap, j, i, fg); } } } if (font->raster_flags & RENDER_FPAA) { /* Downsample intermediate bitmap. */ for (int y = 0; y < glyph->bitmap->h; y++) { for (int x = 0; x < glyph->bitmap->w; x++) { /* Calculate pixel coverage: * coverage = number filled samples / number samples */ float coverage = 0; if (bitmap_get(bitmap, (2*x), (2*y)) == 0x000000) coverage++; if (bitmap_get(bitmap, (2*x)+1, (2*y)) == 0x000000) coverage++; if (bitmap_get(bitmap, (2*x), (2*y)+1) == 0x000000) coverage++; if (bitmap_get(bitmap, (2*x)+1, (2*y)+1) == 0x000000) coverage++; coverage /= 4; uint8_t shade = 0xFF*(1-coverage); uint32_t pixel = (shade << 16) | (shade << 8) | (shade << 0); bitmap_set(glyph->bitmap, x, y, pixel); } } free_bitmap(bitmap); } else if (font->raster_flags & RENDER_ASPAA) { /* Perform five element low-pass filter. */ TTF_Bitmap *temp = create_bitmap(bitmap->w, bitmap->h, bg); for (int y = 0; y < bitmap->h; y++) { for (int x = 0; x < bitmap->w; x++) { uint32_t pixel = 0x000000; pixel += bitmap_get(bitmap, x-2, y) * (1.0 / 9.0); pixel += bitmap_get(bitmap, x-1, y) * (2.0 / 9.0); pixel += bitmap_get(bitmap, x, y) * (3.0 / 9.0); pixel += bitmap_get(bitmap, x+1, y) * (2.0 / 9.0); pixel += bitmap_get(bitmap, x+2, y) * (1.0 / 9.0); bitmap_set(temp, x, y, pixel); } } free_bitmap(bitmap); bitmap = temp; /* Downsample intermediate bitmap. */ for (int y = 0; y < glyph->bitmap->h; y++) { for (int x = 0; x < glyph->bitmap->w; x++) { uint8_t r, g, b; r = (bitmap_get(bitmap, (3*x), y) * 0xFF) / 0xFFFFFF; g = (bitmap_get(bitmap, (3*x)+1, y) * 0xFF) / 0xFFFFFF; b = (bitmap_get(bitmap, (3*x)+2, y) * 0xFF) / 0xFFFFFF; uint32_t pixel = (r << 16) | (g << 8) | (b << 0); bitmap_set(glyph->bitmap, x, y, pixel); } } free_bitmap(bitmap); } RETRELEASE(free_scanlines(scanlines, num_scanlines)); }