/** Creates the SVG element that will a the line. * @param[in] p1 first endpoint in PS point units * @param[in] p2 second endpoint in PS point units * @param[in] c1 cut method of first endpoint ('h', 'v' or 'p') * @param[in] c2 cut method of second endpoint ('h', 'v' or 'p') * @param[in] lw line width in PS point units * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, double lw, SpecialActions &actions) { unique_ptr<XMLElementNode> node; DPair dir = p2-p1; if (dir.x() == 0 || dir.y() == 0 || (c1 == 'p' && c2 == 'p')) { // draw regular line node = util::make_unique<XMLElementNode>("line"); node->addAttribute("x1", p1.x()); node->addAttribute("y1", p1.y()); node->addAttribute("x2", p2.x()); node->addAttribute("y2", p2.y()); node->addAttribute("stroke-width", lw); node->addAttribute("stroke", actions.getColor().svgColorString()); // update bounding box DPair cv = cut_vector('p', dir, lw); actions.embed(p1+cv); actions.embed(p1-cv); actions.embed(p2+cv); actions.embed(p2-cv); } else { // draw polygon DPair cv1 = cut_vector(c1, dir, lw); DPair cv2 = cut_vector(c2, dir, lw); DPair q11 = p1+cv1, q12 = p1-cv1; DPair q21 = p2+cv2, q22 = p2-cv2; ostringstream oss; oss << XMLString(q11.x()) << ',' << XMLString(q11.y()) << ' ' << XMLString(q12.x()) << ',' << XMLString(q12.y()) << ' ' << XMLString(q22.x()) << ',' << XMLString(q22.y()) << ' ' << XMLString(q21.x()) << ',' << XMLString(q21.y()); node = util::make_unique<XMLElementNode>("polygon"); node->addAttribute("points", oss.str()); if (actions.getColor() != Color::BLACK) node->addAttribute("fill", actions.getColor().svgColorString()); // update bounding box actions.embed(q11); actions.embed(q12); actions.embed(q21); actions.embed(q22); } actions.appendToPage(std::move(node)); }
/** Embeds the virtual rectangle (x, y ,w , h) into the current bounding box, * where (x,y) is the lower left vertex composed of the current DVI position. * @param[in] w width of the rectangle in PS point units * @param[in] h height of the rectangle in PS point units * @param[in] d depth of the rectangle in PS point units * @param[in] transform if true, apply the current transformation matrix to the rectangle * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ static void update_bbox (Length w, Length h, Length d, bool transform, SpecialActions &actions) { double x = actions.getX(); double y = actions.getY(); BoundingBox bbox1(x, y, x+w.bp(), y-h.bp()); BoundingBox bbox2(x, y, x+w.bp(), y+d.bp()); if (transform) { bbox1.transform(actions.getMatrix()); bbox2.transform(actions.getMatrix()); } actions.embed(bbox1); actions.embed(bbox2); }
/** Evaluates the special dvisvgm:bbox. * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>] [transform] * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2> [transform] * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2> [transform] * variant 4: dvisvgm:bbox n[ew] <name> * variant 5: dvisvgm:bbox lock | unlock */ void DvisvgmSpecialHandler::processBBox (InputReader &ir, SpecialActions &actions) { ir.skipSpace(); if (ir.check("lock")) actions.bbox().lock(); else if (ir.check("unlock")) actions.bbox().unlock(); else { int c = ir.peek(); try { if (!isalpha(c)) c = 'r'; // no mode specifier => relative box parameters else { while (!isspace(ir.peek())) // skip trailing characters ir.get(); if (c == 'n') { // "new": create new local bounding box ir.skipSpace(); string name; while (isalnum(ir.peek())) name += char(ir.get()); ir.skipSpace(); if (!name.empty() && ir.eof()) actions.bbox(name, true); // create new user box } else if (c == 'a' || c == 'f') { // "abs" or "fix" Length lengths[4]; for (Length &len : lengths) len = read_length(ir); BoundingBox b(lengths[0], lengths[1], lengths[2], lengths[3]); ir.skipSpace(); if (ir.check("transform")) b.transform(actions.getMatrix()); if (c == 'a') actions.embed(b); else { actions.bbox() = b; actions.bbox().lock(); } } } if (c == 'r') { Length w = read_length(ir); Length h = read_length(ir); Length d = read_length(ir); ir.skipSpace(); update_bbox(w, h, d, ir.check("transform"), actions); } } catch (const UnitException &e) { throw SpecialException(string("dvisvgm:bbox: ") + e.what()); } } }