skO *parse_string_literal (char **next, jmp_buf jmp) { skO *list; if (**next != '"') return NULL; ++*next; list = skO_list_new(); while (**next != '"') sk_list_append(list, parse_character(next, jmp)); ++*next; #ifdef SK_PARSER_DEBUG printf("Parsed STRING\n"); #endif return list; }
bool transform_cg_polygon ( sk_cg_geometry *source, cg_element **transformation, sk_cg_geometry *dest ) { if (!source || !transformation || !dest) { return false; } sk_iterator it; if (dest != source) { sk_list_init(&dest->geometry.polygon.points, NULL); sk_list_begin(&it, &source->geometry.polygon.points); while(it.has_next(&it)) { sk_cg_point *clone = ALLOC(*clone, 1); sk_cg_point *element = it.next(&it); clone->x = element->x; clone->y = element->y; sk_list_append(&dest->geometry.polygon.points, clone); } it.destroy(&it); } sk_list_begin(&it, &dest->geometry.polygon.points); sk_cg_point *point = NULL; while (it.has_next(&it)) { point = it.next(&it); transform_cg_point(point, transformation, point); } it.destroy(&it); // FIXME // Check return values return true; }
bool clip_cg_polygon ( sk_cg_geometry *source, int x_min, int y_min, int x_max, int y_max, sk_list *dest ) { if (!source || !dest) { return false; } sk_cg_point V0 = { .x = x_min, .y = y_min }; sk_cg_point V1 = { .x = x_max, .y = y_min }; sk_cg_point V2 = { .x = x_max, .y = y_max }; sk_cg_point V3 = { .x = x_min, .y = y_max }; struct w_a_node; typedef struct w_a_node w_a_node; struct w_a_node { sk_cg_point *point; w_a_node *A_prev; w_a_node *A_next; w_a_node *B_prev; w_a_node *B_next; bool in; }; bool retval = true; // Initialize the output list if (!sk_list_init(dest, NULL)) { retval = false; goto dest_init_fail; } // Initialize the clipping polygon sk_cg_geometry clipping_polygon; clipping_polygon.type = POLYGON; if (!( sk_list_init(&clipping_polygon.geometry.polygon.points, NULL) && sk_list_append(&clipping_polygon.geometry.polygon.points, &V0) && sk_list_append(&clipping_polygon.geometry.polygon.points, &V1) && sk_list_append(&clipping_polygon.geometry.polygon.points, &V2) && sk_list_append(&clipping_polygon.geometry.polygon.points, &V3) ) ) { retval = false; goto clipping_poly_init_fail; } w_a_node *A_head; w_a_node *B_head; w_a_node **curr; w_a_node *prev; // Establish the Weiler-Atherton list for the clipping polygon curr = &A_head; prev = NULL; sk_iterator A_it; if (!sk_list_begin(&A_it, &clipping_polygon.geometry.polygon.points)) { retval = false; goto A_W_A_list_fail; } while (A_it.has_next(&A_it)) { *curr = ALLOC(*(*curr), 1); (*curr)->point = A_it.next(&A_it); (*curr)->in = is_inside((*curr)->point, source); (*curr)->A_prev = prev; prev = *curr; curr = &(*curr)->A_next; } *curr = A_head; A_head->A_prev = prev; A_it.destroy(&A_it); // Establish the Weiler-Atherton list for the source polygon curr = &B_head; prev = NULL; sk_iterator B_it; bool found_out = false; bool found_in = false; if (!sk_list_begin(&B_it, &source->geometry.polygon.points)) { retval = false; goto B_W_A_list_fail; } while (B_it.has_next(&B_it)) { *curr = ALLOC(*(*curr), 1); (*curr)->point = B_it.next(&B_it); (*curr)->in = is_inside((*curr)->point, &clipping_polygon); if (!(*curr)->in) { found_out = true; } if ((*curr)->in) { found_in = true; } (*curr)->B_prev = prev; prev = *curr; curr = &(*curr)->B_next; } *curr = B_head; B_head->B_prev = prev; B_it.destroy(&B_it); // If source is entirely inside the clipping polygon, it is already clipped. if (!found_out) { sk_cg_geometry *poly = ALLOC(*poly, 1); poly->type = POLYGON; sk_iterator it; sk_list_begin(&it, &source->geometry.polygon.points); while (it.has_next(&it)) { sk_list_append(&poly->geometry.polygon.points, it.next(&it)); sk_list_remove(&it); } it.destroy(&it); sk_list_append(dest, poly); retval = true; goto cleanup; } // If source is entirely outside the clipping polygon, determine whether the clipping polygon is inside source if (!found_in) { sk_list_begin(&A_it, &clipping_polygon.geometry.polygon.points); while (A_it.has_next(&A_it)) { if (is_inside(A_it.next(&A_it), source)) { found_in = true; break; } break; } A_it.destroy(&A_it); // Clipping polygon is inside source. Source becomes clipping polygon. if (found_in) { sk_cg_geometry *poly = ALLOC(*poly, 1); poly->type = POLYGON; sk_iterator it; sk_list_begin(&it, &clipping_polygon.geometry.polygon.points); while (it.has_next(&it)) { sk_cg_point *point = ALLOC(*point, 1); sk_cg_point *old_point = it.next(&it); *point = *old_point; sk_list_append(&poly->geometry.polygon.points, point); } it.destroy(&it); sk_list_append(dest, poly); retval = true; goto cleanup; } else { retval = false; goto cleanup; } } sk_cg_point intersection_point; w_a_node *intersection_node; w_a_node *B_node; bool B_end; w_a_node *A_node; bool A_end; // Loop across polygon B until no new intersection points with A have been found for (B_node = B_head, B_end = false; (!B_end || B_node != B_head); B_node = B_node->B_next) { B_end = true; // Loop across polygon A searching for a new intersection point for (A_node = A_head, A_end = false; (!A_end || A_node != A_head); A_node = A_node->A_next) { A_end = true; // If we're starting on an intersection point, don't try to intersect with itself if (B_node->A_next && B_node->B_next) { if (sk_cg_point_equals(B_node->point, A_node->point) || sk_cg_point_equals(B_node->point, A_node->A_next->point)) { continue; } } // If we're ending on an intersection point don't try to intersect with itself if (B_node->B_next->A_next && B_node->B_next->B_next) { if (sk_cg_point_equals(B_node->B_next->point, A_node->point) || sk_cg_point_equals(B_node->B_next->point, A_node->A_next->point)) { continue; } } // Find the intersection between the current line segments for polygons A and B if (intersection(B_node->point, B_node->B_next->point, A_node->point, A_node->A_next->point, &intersection_point)) { intersection_node = ALLOC(*intersection_node, 1); intersection_node->point = ALLOC(*intersection_node->point, 1); *intersection_node->point = intersection_point; intersection_node->in = true; intersection_node->A_next = A_node->A_next; intersection_node->A_prev = A_node; intersection_node->B_next = B_node->B_next; intersection_node->B_prev = B_node; // If the head of either list will be replaced, point the head at the new intersection nodes if (sk_cg_point_equals(A_head->point, &intersection_point)) { A_head = intersection_node; } if (sk_cg_point_equals(B_head->point, &intersection_point)) { B_head = intersection_node; } // Update the W_A list for polygon A // if intersected at the beginning vertex, replace it with intersection point // if intersected at the ending vertex, replace it with intersection point if (sk_cg_point_equals(A_node->point, &intersection_point)) { intersection_node->A_prev = A_node->A_prev; if (A_node->A_next && A_node->B_next) { free(A_node->point); } free(A_node); A_node = intersection_node; } else if (sk_cg_point_equals(A_node->A_next->point, &intersection_point)) { intersection_node->A_next = A_node->A_next->A_next; if (A_node->A_next->A_next && A_node->A_next->B_next) { free(A_node->A_next->point); } free(A_node->A_next); } // Update the W_A list for polygon B // if intersected at the beginning vertex, replace it with intersection point // if intersected at the ending vertex, replace it with intersection point if (sk_cg_point_equals(B_node->point, &intersection_point)) { intersection_node->B_prev = B_node->B_prev; if (B_node->A_next && B_node->B_next) { free(B_node->point); } free(B_node); B_node = intersection_node; } else if (sk_cg_point_equals(B_node->B_next->point, &intersection_point)) { intersection_node->B_next = B_node->B_next->B_next; if (B_node->B_next->A_next && B_node->B_next->B_next) { free(B_node->B_next->point); } free(B_node->B_next); } // Update the intersection node's neighbors intersection_node->A_prev->A_next = intersection_node; intersection_node->A_next->A_prev = intersection_node; intersection_node->B_prev->B_next = intersection_node; intersection_node->B_next->B_prev = intersection_node; // Make the head of W_A list B point to this intersection node B_head = intersection_node; // Loop ends when we iterate over the entire polygon once without finding a new intersection point B_end = false; break; } } } w_a_node *node; // false = A, true = B // Iterate over polygon B until we don't find any more intersection nodes for (node = B_head, B_end = false; (!B_end || node != B_head);) { B_end = true; // Continue until we find an intersection node if (!(node->A_next && node->B_next)) { node = node->B_next; continue; } // Node is an intersection node: sk_cg_geometry *polygon = ALLOC(*polygon, 1); polygon->type = POLYGON; sk_list_init(&polygon->geometry.polygon.points, NULL); // Remove intersection node, and all subsequent nodes until the next node is outside A. w_a_node *final_node = node; w_a_node *temp; while (final_node) { sk_cg_point *new_node = ALLOC(*new_node, 1); *new_node = *final_node->point; // Add this node's point to the new polygon, then remove this node from both lists. sk_list_append(&polygon->geometry.polygon.points, new_node); if (final_node->A_next && final_node->B_next) { free(final_node->point); final_node->point = NULL; } if (final_node->A_next) { if (final_node->A_next == final_node) { A_head = NULL; } else { if (A_head == final_node) { A_head = final_node->A_next; } final_node->A_next->A_prev = final_node->A_prev; final_node->A_prev->A_next = final_node->A_next; } } if (final_node->B_next) { final_node->B_next->B_prev = final_node->B_prev; final_node->B_prev->B_next = final_node->B_next; } temp = final_node; if (final_node->B_next && (final_node->B_next->in || (final_node->B_next->A_next && final_node->B_next->B_next))) { final_node = final_node->B_next; node = final_node; B_head = node->B_next; } else if (final_node->B_prev && (final_node->B_prev->in || (final_node->B_prev->A_next && final_node->B_prev->B_next))) { final_node = final_node->B_prev; node = final_node; B_head = node->B_next;; } else if ((final_node->A_next) && final_node->A_next->in) { final_node = final_node->A_next; } else if ((final_node->A_prev) && final_node->A_prev->in) { final_node = final_node->A_prev; } else { if (final_node->B_prev) { node = final_node->B_prev; B_head = node->B_next; } B_end = false; final_node = NULL; } free(temp); } sk_list_append(dest, polygon); node = node->B_next; } cleanup: { w_a_node *B_node; for (B_node = B_head->B_prev; B_node != B_head;) { B_node = B_node->B_prev; free(B_node->B_next); } free(B_node); } B_W_A_list_fail: { w_a_node *A_node; if (A_head) { for (A_node = A_head->A_prev; A_node != A_head;) { A_node = A_node->A_prev; free(A_node->A_next); } free(A_node); } } A_W_A_list_fail: sk_list_destroy(&clipping_polygon.geometry.polygon.points); clipping_poly_init_fail: if (!retval) { sk_list_destroy(dest); } dest_init_fail: return retval; }
bool parse_cg_polygon(sk_str *source, sk_cg_geometry *buffer) { if (!source || !buffer) { return false; } bool retval = true; char delimiter = ' '; sk_iterator tokens; if (!sk_str_split(&tokens, source, delimiter)) { retval = false; goto str_split_fail; } if (!sk_list_init(&buffer->geometry.polygon.points, NULL)) { retval = false; goto list_init_fail; } char *token; sk_str str_token; SINT_64 x_coord; SINT_64 y_coord; while (tokens.has_next(&tokens)) { token = tokens.next(&tokens); if (!tokens.has_next(&tokens)) { retval = false; goto parse_point_fail; } sk_str_init(&str_token, token, 8); if (!parse_long(&str_token, 0, &x_coord)) { retval = false; sk_str_destroy(&str_token); goto parse_point_fail; } sk_str_destroy(&str_token); token = tokens.next(&tokens); sk_str_init(&str_token, token, 8); if (!parse_long(&str_token, 0, &y_coord)) { retval = false; sk_str_destroy(&str_token); goto parse_point_fail; } sk_str_destroy(&str_token); sk_cg_point *point = ALLOC(*point, 1); point->x = x_coord; point->y = y_coord; sk_list_append(&buffer->geometry.polygon.points, point); } sk_cg_point *first = sk_list_pop_head(&buffer->geometry.polygon.points); sk_cg_point *last = sk_list_pop_tail(&buffer->geometry.polygon.points); if (!sk_cg_point_equals(first, last)) { retval = false; goto parse_point_fail; } sk_list_prepend(&buffer->geometry.polygon.points, first); buffer->type = POLYGON; parse_point_fail: if (!retval) { sk_iterator it; sk_list_begin(&it, &buffer->geometry.polygon.points); while(it.has_next(&it)) { free(it.next(&it)); } sk_list_destroy(&buffer->geometry.polygon.points); } list_init_fail: tokens.destroy(&tokens); str_split_fail: return retval; }
bool scan_fill_cg_polygon ( sk_cg_geometry *source, pixel **framebuffer ) { if (!source || POLYGON != source->type || !framebuffer) { return false; } // Convert polygon into list of lines sk_list poly_lines; sk_list_init(&poly_lines, NULL); sk_cg_point *a; sk_cg_point *b; sk_cg_point *first; sk_cg_point *line; sk_iterator it; sk_list_begin(&it, &source->geometry.polygon.points); a = it.next(&it); first = a; while (it.has_next(&it)) { b = it.next(&it); line = ALLOC(*line, 2); line[0] = *a; line[1] = *b; sk_list_append(&poly_lines, line); a = b; } it.destroy(&it); line = ALLOC(*line, 2); line[0] = *a; line[1] = *first; sk_list_append(&poly_lines, line); // Determine minimum and maximum y axes, to instantiate scan line list int y_min = 0; int y_max = 0; // Also determine x_min and x_max to create concrete scan lines later on int x_min = 0; int x_max = 0; sk_cg_point *p; sk_list_begin(&it, &source->geometry.polygon.points); p = it.next(&it); y_min = p->y; y_max = p->y; x_min = p->x; x_max = p->x; while (it.has_next(&it)) { p = it.next(&it); y_min = (p->y < y_min) ? p->y : y_min; y_max = (p->y > y_max) ? p->y : y_max; x_min = (p->x < x_min) ? p->x : x_min; x_max = (p->x > x_max) ? p->x : x_max; } it.destroy(&it); // Create a list for each scan line this polygon intersects : [y_min, y_max) sk_list *scan_lines = ALLOC(*scan_lines, y_max - y_min); int i; for (i = 0; i < y_max - y_min; ++i) { sk_list_init(&scan_lines[i], NULL); } // For each polygon edge, add it to each scan line which intersects that edge sk_list_begin(&it, &poly_lines); while (it.has_next(&it)) { line = it.next(&it); if (line[0].y == line[1].y) { continue; } else if (line[0].y < line[1].y) { for (i = line[0].y; i < line[1].y; ++i) { sk_list_append(&scan_lines[i - y_min], line); } } else { for (i = line[0].y - 1; i >= line[1].y; --i) { sk_list_append(&scan_lines[i - y_min], line); } } } it.destroy(&it); // Convert each scan line list into a list of intersection points, sorted by x coordinate sk_cg_point *intersection_point; sk_cg_point scan_min = { .x = x_min - 1, .y = 0 }; sk_cg_point scan_max = { .x = x_max + 1, .y = 0 }; sk_list temp; sk_list_init(&temp, NULL); sk_iterator temp_it; for (i = 0; i < y_max - y_min; ++i) { scan_min.y = i + y_min; scan_max.y = i + y_min; sk_list_begin(&it, &scan_lines[i]); while (it.has_next(&it)) { line = it.next(&it); // Calculate the intersection of this edge with the scan line intersection_point = ALLOC(*intersection_point, 1); if (!intersection(line, line + 1, &scan_min, &scan_max, intersection_point)) { // FIXME error here } // We no longer need this edge sk_list_remove(&it); // Insert this point into our new list of intersections sk_list_begin(&temp_it, &temp); if (temp_it.has_next(&temp_it)) { while (temp_it.has_next(&temp_it)) { p = temp_it.next(&temp_it); if (intersection_point->x < p->x) { sk_list_pre_insert(&temp_it, intersection_point); break; } if (!temp_it.has_next(&temp_it)) { sk_list_append(&temp, intersection_point); break; } } } else { sk_list_append(&temp, intersection_point); } temp_it.destroy(&temp_it); } it.destroy(&it); sk_list_begin(&temp_it, &temp); while (temp_it.has_next(&temp_it)) { sk_list_append(&scan_lines[i], temp_it.next(&temp_it)); sk_list_remove(&temp_it); } temp_it.destroy(&temp_it); } sk_list_destroy(&temp); int x; for (i = 0; i < y_max - y_min; ++i) { sk_list_begin(&it, &scan_lines[i]); if (!it.has_next(&it)) { it.destroy(&it); continue; } while (it.has_next(&it)) { a = it.next(&it); b = it.next(&it); for (x = a->x; x < b->x; ++x) { framebuffer[a->y][x] = 1; } } it.destroy(&it); } // Destroy polygon line list sk_list_begin(&it, &poly_lines); while(it.has_next(&it)) { free(it.next(&it)); } it.destroy(&it); sk_list_destroy(&poly_lines); for (i = 0; i < y_max - y_min; ++i) { sk_list_destroy(&scan_lines[i]); } free(scan_lines); return true; } bool clip_x ( sk_cg_point *a, sk_cg_point *b, sk_cg_point *dest, int x ) { if (!a || !b || !dest) { return false; } SINT_64 x_c; SINT_64 y_c; x_c = x; y_c = (((double)abs((x - a->x)) / (double)abs((b->x - a->x))) * abs((b->y - a->y))); if (b->y < a->y) { y_c -= a->y; y_c = -y_c; } else { y_c += a->y; } dest->x = x_c; dest->y = y_c; return true; } bool clip_y ( sk_cg_point *a, sk_cg_point *b, sk_cg_point *dest, int y ) { if (!a || !b || !dest) { return false; } SINT_64 x_c; SINT_64 y_c; y_c = y; x_c = (((double)abs((b->x - a->x)) / (double)abs((b->y - a->y))) * abs((y - a->y))); if (b->x < a->x) { x_c -= a->x; x_c = -x_c; } else { x_c += a->x; } dest->x = x_c; dest->y = y_c; return true; } bool intersection ( sk_cg_point *a1, sk_cg_point *b1, sk_cg_point *a2, sk_cg_point *b2, sk_cg_point *dest ) { // Edge 0: (a1, b1) // Edge 2: (a2, b2) // E_0 = a1 + t_0 * (b1 - a1) // (D0) // E_2 = a2 + t_2 * (b2 - a2) // (D2) // // a1x + t1 * d1x = a2x + t2 * d2x // a1y + t1 * d1y = a2y + t2 * d2y // // t1 = (a2x - a1x) + (t2 * d2x) / d1x // // a1y + ((a2y - a1x) + (t2 * d2x)) / d1x * d1y = a2y + t2 * d2y // ((a2x - a1x) + (t2 * d2x)) / d1x = ((a2y - a1y) + (t2 * d2y)) / d1y // // d1y (a2x - a1x) + d1y * d2x * t2 = d1x (a2y - a1y) + d1x *d2y * t2 // // (d1x * d2y * t2) - (d1y * d2x * t2) = d1y (a2x - a1x) - d1x (a2y - a1y) // // t2 = d1y (a2x - a1x) - d1x (a2y - a1y) // --------------------------------- // (d1x * d2y) - (d1y * d2x) // // // t2 = (a1y - a2y) + (t1 * d1y) / d2y // // a1x + t1 * d1x = a2x + (d2x / d2y) ((a1y - a2y) + (t1 * d1y)) // // d2y ((a1x - a2x) + (t1 * d1x)) = d2x ((a1y - a2y) + (t1 * d1y)) // // d2y (a1x - a2x) + t1 (d1x * d2y) = d2x (a1y - a2y) + t1 (d1y * d2x) // // t1 = d2x (a1y - a2y) - d2y (a1x - a2x) // --------------------------------- // (d1x * d2y) - (d1y * d2x) // // t1 = d2y (a2x - a1x) - d2x (a2y - a1y) // --------------------------------- // (d1x * d2y) - (d1y * d2x) // Quantities: // d1x // d1y // d2x // d2y // A (a2x - a1x) * { d1y, d2y } // B (a2y - a1y) * { d1x, d2x } // C (d1x * d2y) - (d1y * d2x) if (!a1 || !b1 || !a2 || !b2|| !dest) { return false; } SINT_64 d1x = b1->x - a1->x; SINT_64 d1y = b1->y - a1->y; SINT_64 d2x = b2->x - a2->x; SINT_64 d2y = b2->y - a2->y; SINT_64 A, B; SINT_64 Ad1y, Ad2y; SINT_64 Bd1x, Bd2x; SINT_64 C = (d1x * d2y) - (d1y * d2x); double t1; double t2; if (!C) { return false; } A = a2->x - a1->x; B = a2->y - a1->y; Ad1y = A * d1y; Ad2y = A * d2y; Bd1x = B * d1x; Bd2x = B * d2x; t1 = (Ad2y - Bd2x) / (double)C; t2 = (Ad1y - Bd1x) / (double)C; if (t1 < 0 || t1 > 1 || t2 < 0 || t2 > 1) { return false; } dest->x = a1->x + t1 * d1x; dest->y = a1->y + t1 * d1y; return true; } bool is_inside ( sk_cg_point *source, sk_cg_geometry *target ) { if (!source || !target || POLYGON != target->type) { return false; } SINT_64 min_x = 0; sk_iterator it; sk_list_begin(&it, &target->geometry.polygon.points); sk_cg_point *element = NULL; if (!it.has_next(&it)) { it.destroy(&it); return false; } while (it.has_next(&it)) { element = it.next(&it); min_x = (element->x < min_x) ? element->x : min_x; } it.destroy(&it); sk_cg_point outside = { .x = min_x - 1, .y = 0 }; sk_cg_point intersect_point; int num_intersections = 0; sk_list_begin(&it, &target->geometry.polygon.points); sk_cg_point *first = it.next(&it); sk_cg_point *A = first; sk_cg_point *B = NULL; bool intersected_first = false; bool intersected_B = false; while (it.has_next(&it)) { B = it.next(&it); if (intersection(source, &outside, A, B, &intersect_point)) { if (sk_cg_point_equals(&intersect_point, A)) { if ((A == first)) { intersected_first = true; } if (intersected_B) { --num_intersections; } } intersected_B = sk_cg_point_equals(&intersect_point, B); ++num_intersections; } A = B; } if (intersection(source, &outside, A, first, &intersect_point)) { if ( !(intersected_B && sk_cg_point_equals(&intersect_point, A)) && !(intersected_first && sk_cg_point_equals(&intersect_point, first)) ) { ++num_intersections; } } it.destroy(&it); return (num_intersections & 0x1); }
skO *skO_parse (char **next, jmp_buf jmp, char *delim) { skO *obj; /* parsed token (or NULL) */ skO *list = skO_list_new(); /* used to store parsed objects */ skO *prefixed = NULL; /* store "prefix sugar" tokens */ char *src = *next; jmp_buf pe; int ended = 0; consume_leading(&src); if (setjmp(pe)) { if (prefixed) free(prefixed); skO_free(list); printf("parse jmp\n"); } if (delim) { if (*src != delim[0]) return NULL; src++; consume_leading(&src); #ifdef SK_PARSER_DEBUG printf("Parsed %c\n", delim[0]); #endif } else if (*src == 0) { ended = 1; exit(EXIT_FAILURE); } while (!ended) { consume_leading(&src); if (*src == 0) { ended = 1; *next = src; break; } /* Handle end of lists and prefixed syntax. */ if (delim) { if (*src == delim[1]) { src++; *next = src; #ifdef SK_PARSER_DEBUG printf("Parsed %c\n", delim[1]); #endif return list; } } /* Handle "prefix style" syntactic sugar. */ prefixed = skO_parse(&src, pe, "()"); if (prefixed) consume_leading(&src); /* Handle "reserving operations" syntactic sugar. */ obj = parse_op_def(&src); if (obj) { sk_list_append(list, obj); obj = skO_symbol_new("$=>"); goto matched; } obj = parse_obj_reserve(&src); if (obj) { sk_list_append(list, obj); obj = skO_symbol_new("$->"); goto matched; } obj = parse_obj_restore(&src); if (obj) { sk_list_append(list, obj); obj = skO_symbol_new("$<-"); goto matched; } /* Handle regular tokens. */ if ((obj = parse_string_literal(&src, pe)) || (obj = parse_number(&src)) || (obj = parse_qidentifier(&src)) || (obj = parse_identifier(&src)) || (obj = parse_character_literal(&src, pe)) || (obj = skO_parse(&src, pe, "[]"))) goto matched; /* If everything failed... */ fprintf(stderr, "PANIC! Parsing error: %s\n", src); longjmp(jmp, 1); matched: sk_list_append(list, obj); if (prefixed) { sk_list_append(list, prefixed->data.list); free(prefixed); prefixed = NULL; } } *next = src; return list; }
bool clip_cg_bezier ( sk_cg_geometry *source, double increment, int x_min, int y_min, int x_max, int y_max, sk_list *dest ) { if (!source || BEZIER != source->type || !dest || increment <= 0 || increment > 1) { if (dest) { sk_list_init(dest, NULL); } return false; } sk_list_init(dest, NULL); sk_cg_point P[4]; sk_cg_point *p = P; sk_cg_point *next; sk_iterator it; sk_list_begin(&it, &source->geometry.bezier.control_points); while (it.has_next(&it)) { next = it.next(&it); p->x = next->x; p->y = next->y; p++; } it.destroy(&it); sk_cg_point A, B; A = P[0]; double t; for (t = increment; t < 1; t += increment) { double t2 = t * t; double t3 = t2 * t; double nt = 1 - t; double nt2 = nt * nt; double nt3 = nt2 * nt; B.x = (nt3 * P[0].x) + (3 * t * nt2 * P[1].x) + (3 * t2 * nt * P[2].x) + (t3 * P[3].x); B.y = (nt3 * P[0].y) + (3 * t * nt2 * P[1].y) + (3 * t2 * nt * P[2].y) + (t3 * P[3].y); sk_cg_geometry *line = ALLOC(*line, 1); line->type = LINE; line->geometry.line.a = A; line->geometry.line.b = B; sk_list_append(dest, line); A = B; } t = 1; double t2 = t * t; double t3 = t2 * t; double nt = 1 - t; double nt2 = nt * nt; double nt3 = nt2 * nt; B.x = roundf((nt3 * P[0].x) + (3 * t * nt2 * P[1].x) + (3 * t2 * nt * P[2].x) + (t3 * P[3].x)); B.y = roundf((nt3 * P[0].y) + (3 * t * nt2 * P[1].y) + (3 * t2 * nt * P[2].y) + (t3 * P[3].y)); sk_cg_geometry *line = ALLOC(*line, 1); line->type = LINE; line->geometry.line.a = A; line->geometry.line.b = B; sk_list_append(dest, line); sk_cg_geometry *g; sk_list_begin(&it, dest); while (it.has_next(&it)) { g = it.next(&it); if (!clip_cg_line(g, x_min, y_min, x_max, y_max)) { sk_list_remove(&it); sk_cg_geometry_destroy(g); free(g); } } return true; }