/** * write_filled_rectangle: draw a filled rectangle. * * Uses an optimised algorithm which is similar to the horizontal * line writing algorithm, but optimised for writing the lines * multiple times without recalculating lots of stuff. * * @param buff pointer to buffer to write in * @param x x coordinate (left) * @param y y coordinate (top) * @param width rectangle width * @param height rectangle height * @param mode 0 = clear, 1 = set, 2 = toggle */ void write_filled_rectangle(uint8_t *buff, int x, int y, int width, int height, int mode) { int yy, addr0_old, addr1_old; CHECK_COORDS(x, y); CHECK_COORDS(x + width, y + height); if (width <= 0 || height <= 0) { return; } // Calculate as if the rectangle was only a horizontal line. We then // step these addresses through each row until we iterate `height` times. int addr0 = CALC_BUFF_ADDR(x, y); int addr1 = CALC_BUFF_ADDR(x + width, y); int addr0_bit = CALC_BIT_IN_WORD(x); int addr1_bit = CALC_BIT_IN_WORD(x + width); int mask, mask_l, mask_r, i; // If the addresses are equal, we need to write one word vertically. if (addr0 == addr1) { mask = COMPUTE_HLINE_ISLAND_MASK(addr0_bit, addr1_bit); while (height--) { WRITE_WORD_MODE(buff, addr0, mask, mode); addr0 += BUFFER_WIDTH; } } else { // Otherwise we need to write the edges and then the middle repeatedly. mask_l = COMPUTE_HLINE_EDGE_L_MASK(addr0_bit); mask_r = COMPUTE_HLINE_EDGE_R_MASK(addr1_bit); // Write edges first. yy = 0; addr0_old = addr0; addr1_old = addr1; while (yy < height) { WRITE_WORD_MODE(buff, addr0, mask_l, mode); WRITE_WORD_MODE(buff, addr1, mask_r, mode); addr0 += BUFFER_WIDTH; addr1 += BUFFER_WIDTH; yy++; } // Now write 0xffff words from start+1 to end-1 for each row. yy = 0; addr0 = addr0_old; addr1 = addr1_old; while (yy < height) { for (i = addr0 + 1; i <= addr1 - 1; i++) { uint8_t m = 0xff; WRITE_WORD_MODE(buff, i, m, mode); } addr0 += BUFFER_WIDTH; addr1 += BUFFER_WIDTH; yy++; } } }
/** * write_circle_filled: fill a circle on a given buffer. * * @param buff pointer to buffer to write in * @param cx origin x coordinate * @param cy origin y coordinate * @param r radius * @param mode 0 = clear, 1 = set, 2 = toggle */ void write_circle_filled(uint8_t *buff, int cx, int cy, int r, int mode) { CHECK_COORDS(cx, cy); int error = -r, x = r, y = 0, xch = 0; // It turns out that filled circles can take advantage of the midpoint // circle algorithm. We simply draw very fast horizontal lines across each // pair of X,Y coordinates. In some cases, this can even be faster than // drawing an outlined circle! // // Due to multiple writes to each set of pixels, we have a special exception // for when using the toggling draw mode. while (x >= y) { if (y != 0) { write_hline(buff, cx - x, cx + x, cy + y, mode); write_hline(buff, cx - x, cx + x, cy - y, mode); if (mode != 2 || (mode == 2 && xch && (cx - x) != (cx - y))) { write_hline(buff, cx - y, cx + y, cy + x, mode); write_hline(buff, cx - y, cx + y, cy - x, mode); xch = 0; } } error += (y * 2) + 1; y++; if (error >= 0) { --x; xch = 1; error -= x * 2; } } // Handle toggle mode. if (mode == 2) { write_hline(buff, cx - r, cx + r, cy, mode); } }
/** * write_pixel: Write a pixel at an x,y position to a given surface. * * @param buff pointer to buffer to write in * @param x x coordinate * @param y y coordinate * @param mode 0 = clear bit, 1 = set bit, 2 = toggle bit */ void write_pixel(uint8_t *buff, int x, int y, int mode) { CHECK_COORDS(x, y); // Determine the bit in the word to be set and the word // index to set it in. int bitnum = CALC_BIT_IN_WORD(x); int wordnum = CALC_BUFF_ADDR(x, y); // Apply a mask. uint16_t mask = 1 << (7 - bitnum); WRITE_WORD_MODE(buff, wordnum, mask, mode); }
/** * write_pixel_lm: write the pixel on both surfaces (level and mask.) * Uses current draw buffer. * * @param x x coordinate * @param y y coordinate * @param mmode 0 = clear, 1 = set, 2 = toggle * @param lmode 0 = black, 1 = white, 2 = toggle */ void write_pixel_lm(int x, int y, int mmode, int lmode) { CHECK_COORDS(x, y); // Determine the bit in the word to be set and the word // index to set it in. int bitnum = CALC_BIT_IN_WORD(x); int wordnum = CALC_BUFF_ADDR(x, y); // Apply the masks. uint16_t mask = 1 << (7 - bitnum); WRITE_WORD_MODE(draw_buffer_mask, wordnum, mask, mmode); WRITE_WORD_MODE(draw_buffer_level, wordnum, mask, lmode); }
void write_upper_arc_outlined(int cx, int cy, int r, int x1, int x2, int dashp, int bmode, int mode, int mmode) { int stroke, fill; CHECK_COORDS(cx, cy); SETUP_STROKE_FILL(stroke, fill, mode); // This is a two step procedure. First, we draw the outline of the // circle, then we draw the inner part. int error = -r, x = r, y = 0; while (x >= y) { if (dashp == 0 || (y % dashp) < (dashp / 2)) { UPPER_ARC_PLOT_8(draw_buffer_mask, cx, cy, x + 1, y, x1, x2, mmode); UPPER_ARC_PLOT_8(draw_buffer_level, cx, cy, x + 1, y, x1, x2, stroke); UPPER_ARC_PLOT_8(draw_buffer_mask, cx, cy, x, y + 1, x1, x2, mmode); UPPER_ARC_PLOT_8(draw_buffer_level, cx, cy, x, y + 1, x1, x2, stroke); UPPER_ARC_PLOT_8(draw_buffer_mask, cx, cy, x - 1, y, x1, x2, mmode); UPPER_ARC_PLOT_8(draw_buffer_level, cx, cy, x - 1, y, x1, x2, stroke); UPPER_ARC_PLOT_8(draw_buffer_mask, cx, cy, x, y - 1, x1, x2, mmode); UPPER_ARC_PLOT_8(draw_buffer_level, cx, cy, x, y - 1, x1, x2, stroke); if (bmode == 1) { UPPER_ARC_PLOT_8(draw_buffer_mask, cx, cy, x + 1, y + 1, x1, x2, mmode); UPPER_ARC_PLOT_8(draw_buffer_level, cx, cy, x + 1, y + 1, x1, x2, stroke); UPPER_ARC_PLOT_8(draw_buffer_mask, cx, cy, x - 1, y - 1, x1, x2, mmode); UPPER_ARC_PLOT_8(draw_buffer_level, cx, cy, x - 1, y - 1, x1, x2, stroke); } } error += (y * 2) + 1; y++; if (error >= 0) { --x; error -= x * 2; } } error = -r; x = r; y = 0; while (x >= y) { if (dashp == 0 || (y % dashp) < (dashp / 2)) { UPPER_ARC_PLOT_8(draw_buffer_mask, cx, cy, x, y, x1, x2, mmode); UPPER_ARC_PLOT_8(draw_buffer_level, cx, cy, x, y, x1, x2, fill); } error += (y * 2) + 1; y++; if (error >= 0) { --x; error -= x * 2; } } }
/** * write_circle: draw the outline of a circle on a given buffer, * with an optional dash pattern for the line instead of a normal line. * * @param buff pointer to buffer to write in * @param cx origin x coordinate * @param cy origin y coordinate * @param r radius * @param dashp dash period (pixels) - zero for no dash * @param mode 0 = clear, 1 = set, 2 = toggle */ void write_circle(uint8_t *buff, int cx, int cy, int r, int dashp, int mode) { CHECK_COORDS(cx, cy); int error = -r, x = r, y = 0; while (x >= y) { if (dashp == 0 || (y % dashp) < (dashp / 2)) { CIRCLE_PLOT_8(buff, cx, cy, x, y, mode); } error += (y * 2) + 1; y++; if (error >= 0) { --x; error -= x * 2; } } }
TEST(MeshLib, CoordinatesMappingLocalLowerDimLineZ) { auto ele = TestLine2::createZ(); MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(MeshLib::CoordinateSystemType::Z)); auto matR(mapping.getRotationMatrixToGlobal()); //debugOutput(ele, mapping); double exp_R[3*3] = {0, 0, -1, 0, 1, 0, 1, 0, 0}; const double eps(std::numeric_limits<double>::epsilon()); ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); CHECK_COORDS(ele,mapping); for (std::size_t n = 0; n < ele->getNumberOfNodes(); ++n) delete ele->getNode(n); }
TEST(MeshLib, CoordinatesMappingLocalLowerDimLineXYZ) { auto ele = TestLine2::createXYZ(); MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(*ele)); auto matR(mapping.getRotationMatrixToGlobal()); //debugOutput(ele, mapping); double exp_R[3*3] = {0.57735026918962584, -0.81649658092772626, 0, 0.57735026918962584, 0.40824829046386313, -0.70710678118654757, 0.57735026918962584, 0.40824829046386313, 0.70710678118654757}; const double eps(std::numeric_limits<double>::epsilon()); ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); CHECK_COORDS(ele,mapping); for (std::size_t n = 0; n < ele->getNumberOfNodes(); ++n) delete ele->getNode(n); }
TEST(MeshLib, CoordinatesMappingLocalLowerDimQuadXYZ) { auto ele = TestQuad4::createXYZ(); MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(*ele)); auto matR(mapping.getRotationMatrixToGlobal()); //debugOutput(ele, mapping); // results when using GeoLib::ComputeRotationMatrixToXY() double exp_R[3*3] = { 1, 0, 0, 0, 0.70710678118654757, -0.70710678118654757, 0, 0.70710678118654757, 0.70710678118654757}; const double eps(std::numeric_limits<double>::epsilon()); ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); CHECK_COORDS(ele,mapping); for (std::size_t n = 0; n < ele->getNumberOfNodes(); ++n) delete ele->getNode(n); }