// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int reduceOrder(const Cubic& cubic, Cubic& reduction, ReduceOrder_Quadratics allowQuadratics, ReduceOrder_Styles reduceStyle) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].x > cubic[index].x) { minX = index; } if (cubic[minY].y > cubic[index].y) { minY = index; } if (cubic[maxX].x < cubic[index].x) { maxX = index; } if (cubic[maxY].y < cubic[index].y) { maxY = index; } } for (index = 0; index < 4; ++index) { double cx = cubic[index].x; double cy = cubic[index].y; double denom = SkTMax(fabs(cx), SkTMax(fabs(cy), SkTMax(fabs(cubic[minX].x), fabs(cubic[minY].y)))); if (denom == 0) { minXSet |= 1 << index; minYSet |= 1 << index; continue; } double inv = 1 / denom; if (approximately_equal_half(cx * inv, cubic[minX].x * inv)) { minXSet |= 1 << index; } if (approximately_equal_half(cy * inv, cubic[minY].y * inv)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, reduction); } return vertical_line(cubic, reduceStyle, reduction); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, reduceStyle, reduction); } int result = check_linear(cubic, reduceStyle, minX, maxX, minY, maxY, reduction); if (result) { return result; } if (allowQuadratics == kReduceOrder_QuadraticsAllowed && (result = check_quadratic(cubic, reduction))) { return result; } memcpy(reduction, cubic, sizeof(Cubic)); return 4; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int SkReduceOrder::reduce(const SkDCubic& cubic, Quadratics allowQuadratics) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].fX > cubic[index].fX) { minX = index; } if (cubic[minY].fY > cubic[index].fY) { minY = index; } if (cubic[maxX].fX < cubic[index].fX) { maxX = index; } if (cubic[maxY].fY < cubic[index].fY) { maxY = index; } } for (index = 0; index < 4; ++index) { double cx = cubic[index].fX; double cy = cubic[index].fY; double denom = SkTMax(fabs(cx), SkTMax(fabs(cy), SkTMax(fabs(cubic[minX].fX), fabs(cubic[minY].fY)))); if (denom == 0) { minXSet |= 1 << index; minYSet |= 1 << index; continue; } double inv = 1 / denom; if (approximately_equal_half(cx * inv, cubic[minX].fX * inv)) { minXSet |= 1 << index; } if (approximately_equal_half(cy * inv, cubic[minY].fY * inv)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, fCubic); } return vertical_line(cubic, fCubic); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, fCubic); } int result = check_linear(cubic, minX, maxX, minY, maxY, fCubic); if (result) { return result; } if (allowQuadratics == SkReduceOrder::kAllow_Quadratics && (result = check_quadratic(cubic, fCubic))) { return result; } fCubic = cubic; return 4; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int reduceOrder(const Cubic& cubic, Cubic& reduction, ReduceOrder_Flags allowQuadratics) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].x > cubic[index].x) { minX = index; } if (cubic[minY].y > cubic[index].y) { minY = index; } if (cubic[maxX].x < cubic[index].x) { maxX = index; } if (cubic[maxY].y < cubic[index].y) { maxY = index; } } for (index = 0; index < 4; ++index) { if (approximately_equal(cubic[index].x, cubic[minX].x)) { minXSet |= 1 << index; } if (approximately_equal(cubic[index].y, cubic[minY].y)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, reduction); } return vertical_line(cubic, reduction); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, reduction); } int result = check_linear(cubic, reduction, minX, maxX, minY, maxY); if (result) { return result; } if (allowQuadratics && (result = check_quadratic(cubic, reduction))) { return result; } memcpy(reduction, cubic, sizeof(Cubic)); return 4; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int SkReduceOrder::reduce(const SkDQuad& quad) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 3; ++index) { if (quad[minX].fX > quad[index].fX) { minX = index; } if (quad[minY].fY > quad[index].fY) { minY = index; } if (quad[maxX].fX < quad[index].fX) { maxX = index; } if (quad[maxY].fY < quad[index].fY) { maxY = index; } } for (index = 0; index < 3; ++index) { if (AlmostEqualUlps(quad[index].fX, quad[minX].fX)) { minXSet |= 1 << index; } if (AlmostEqualUlps(quad[index].fY, quad[minY].fY)) { minYSet |= 1 << index; } } if ((minXSet & 0x05) == 0x5 && (minYSet & 0x05) == 0x5) { // test for degenerate // this quad starts and ends at the same place, so never contributes // to the fill return coincident_line(quad, fQuad); } if (minXSet == 0x7) { // test for vertical line return vertical_line(quad, fQuad); } if (minYSet == 0x7) { // test for horizontal line return horizontal_line(quad, fQuad); } int result = check_linear(quad, minX, maxX, minY, maxY, fQuad); if (result) { return result; } fQuad = quad; return 3; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int SkReduceOrder::reduce(const SkDQuad& quad) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 3; ++index) { if (quad[minX].fX > quad[index].fX) { minX = index; } if (quad[minY].fY > quad[index].fY) { minY = index; } if (quad[maxX].fX < quad[index].fX) { maxX = index; } if (quad[maxY].fY < quad[index].fY) { maxY = index; } } for (index = 0; index < 3; ++index) { if (AlmostEqualUlps(quad[index].fX, quad[minX].fX)) { minXSet |= 1 << index; } if (AlmostEqualUlps(quad[index].fY, quad[minY].fY)) { minYSet |= 1 << index; } } if (minXSet == 0x7) { // test for vertical line if (minYSet == 0x7) { // return 1 if all four are coincident return coincident_line(quad, fQuad); } return vertical_line(quad, fQuad); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(quad, fQuad); } int result = check_linear(quad, minX, maxX, minY, maxY, fQuad); if (result) { return result; } fQuad = quad; return 3; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int reduceOrder(const Quadratic& quad, Quadratic& reduction) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 3; ++index) { if (quad[minX].x > quad[index].x) { minX = index; } if (quad[minY].y > quad[index].y) { minY = index; } if (quad[maxX].x < quad[index].x) { maxX = index; } if (quad[maxY].y < quad[index].y) { maxY = index; } } for (index = 0; index < 3; ++index) { if (AlmostEqualUlps(quad[index].x, quad[minX].x)) { minXSet |= 1 << index; } if (AlmostEqualUlps(quad[index].y, quad[minY].y)) { minYSet |= 1 << index; } } if (minXSet == 0x7) { // test for vertical line if (minYSet == 0x7) { // return 1 if all four are coincident return coincident_line(quad, reduction); } return vertical_line(quad, reduction); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(quad, reduction); } int result = check_linear(quad, reduction, minX, maxX, minY, maxY); if (result) { return result; } memcpy(reduction, quad, sizeof(Quadratic)); return 3; }
int main(int argc, char *argv[]) { struct cell **drawing; int i; enum mode_t { lines = 0, boxes = 1, text = 2, erase = 3 } mode = lines; char *mode_name[] = { "Draw lines", "Draw boxes", "Write text", "Erase" }; /* Click positions, used for line/box drawing. */ MEVENT click[2]; int nclick = 0; /* Text cursor location. */ struct { int insert; int writing, startx, x, wsx, y; } textcursor = {0}; initscr(); cbreak(); noecho(); nonl(); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); mousemask(BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED, NULL); drawing = cells_alloc(COLS, LINES); while ((i = getch()) != ERR) { if (i == KEY_MOUSE) { MEVENT ev; getmouse(&ev); move(ev.y, ev.x); refresh(); if (mode == text) { /* Click in text mode; set start-of-writing. */ textcursor.writing = 1; textcursor.startx = textcursor.x = textcursor.wsx = ev.x; textcursor.y = ev.y; } else if (ev.bstate == BUTTON3_CLICKED && mode == lines) { /* Button 3 click starts a new line. */ nclick = 1; click[0] = ev; } else { /* Any random click in lines/boxes/erase mode. */ click[nclick++] = ev; if (nclick == 2) { nclick = 0; if (mode == lines) { /* We draw two types of corners: * * .---X * | button 1, button 1 * X * * X * | button 1, button 2 * X---' * */ /* if (click[0].x == click[1].x) vertical_line(drawing, click[0].x, click[0].y, click[1].y); else if (click[0].y == click[1].y) horizontal_line(drawing, click[0].x, click[1].x, click[0].y); else */{ if (click[1].bstate & BUTTON1_CLICKED) { if (click[0].x < click[1].x) { horizontal_line(drawing, click[0].x, click[1].x, click[1].y); vertical_line(drawing, click[0].x, click[0].y, click[1].y); } else { horizontal_line(drawing, click[1].x, click[0].x, click[0].y); vertical_line(drawing, click[1].x, click[1].y, click[0].y); } } else if (click[1].bstate & BUTTON2_CLICKED) { if (click[0].x > click[1].x) { horizontal_line(drawing, click[0].x, click[1].x, click[1].y); vertical_line(drawing, click[0].x, click[0].y, click[1].y); } else { horizontal_line(drawing, click[1].x, click[0].x, click[0].y); vertical_line(drawing, click[1].x, click[1].y, click[0].y); } } else beep(); } display_drawing(drawing, COLS, LINES); /* Allow drawing of `polylines'. */ click[0] = click[1]; nclick = 1; move(click[0].y, click[0].x); refresh(); } else if (mode == boxes) { /* Boxes are drawn between the two corners specified. */ vertical_line(drawing, click[0].x, click[0].y, click[1].y); vertical_line(drawing, click[1].x, click[0].y, click[1].y); horizontal_line(drawing, click[0].x, click[1].x, click[0].y); horizontal_line(drawing, click[0].x, click[1].x, click[1].y); display_drawing(drawing, COLS, LINES); } else if (mode == erase) { /* Erase the contents of the box between the two * corners. */ int i, i0, i1, j, j0, j1; i0 = min(click[0].x, click[1].x); i1 = max(click[0].x, click[1].x); j0 = min(click[0].y, click[1].y); j1 = max(click[0].y, click[1].y); flash_box(i0, j0, i1, j1); for (j = j0; j <= j1; ++j) for (i = i0; i <= i1; ++i) drawing[j][i].lines = drawing[j][i].c = 0; display_drawing(drawing, COLS, LINES); } } } } else if (mode != text || !textcursor.writing) { /* Key pressed in non-writing mode; maybe switch mode. */ enum mode_t mm; mm = mode; switch (i) { case 'L': case 'l': mode = lines; break; case 'B': case 'b': mode = boxes; break; case 'T': case 't': mode = text; break; case 'E': case 'e': mode = erase; break; case ' ': nclick = 0; break; } if (mm != mode) { flash_modelabel(mode_name[mode], drawing); nclick = 0; } } else { /* Key pressed in writing mode; say something, probably. */ switch (i) { case KEY_LEFT: if (textcursor.x > textcursor.startx) --textcursor.x; else beep(); break; case KEY_RIGHT: if (textcursor.x < find_end_of_text_block(drawing, textcursor.x, textcursor.y, COLS) - 1) ++textcursor.x; else beep(); break; case KEY_UP: if (textcursor.y > 0) --textcursor.y; else beep(); break; case KEY_DOWN: if (textcursor.y < LINES - 1) ++textcursor.y; else beep(); break; case KEY_HOME: textcursor.x = textcursor.startx; break; case KEY_END: { /* Try to go to the end of the current bit of text. */ int I; for (I = textcursor.x; I < COLS && drawing[textcursor.y][I].c; ++I); --I; textcursor.x = I; break; } case KEY_IC: textcursor.insert = !textcursor.insert; flash_modelabel(textcursor.insert ? "Insert" : "Replace", drawing); break; case KEY_BACKSPACE: if (textcursor.x > textcursor.startx) { --textcursor.x; if (textcursor.insert) { /* Move characters to left. */ int i0, i1; i0 = find_end_of_text_block(drawing, textcursor.x, textcursor.y, COLS); for (i1 = textcursor.x; i1 < i0; ++i1) drawing[textcursor.y][i1].c = drawing[textcursor.y][i1 + 1].c; } else drawing[textcursor.y][textcursor.x].c = ' '; } break; case KEY_ENTER: textcursor.writing = 0; break; default: if (isprint(i)) { if (textcursor.insert) { /* Move characters to right. */ int i0, i1; i0 = find_end_of_text_block(drawing, textcursor.x, textcursor.y, COLS); for (i1 = min(i0 + 1, COLS); i1 > textcursor.x; --i1) drawing[textcursor.y][i1].c = drawing[textcursor.y][i1 - 1].c; } drawing[textcursor.y][textcursor.x].c = i; if (i == ' ') textcursor.wsx = textcursor.x; ++textcursor.x; } break; } display_drawing(drawing, COLS, LINES); move(textcursor.y, textcursor.x); refresh(); } } }