/** 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)); }
/** Replaces constants of the form {?name} by their corresponding value. * @param[in,out] str text to expand * @param[in] actions interfcae to the world outside the special handler */ static void expand_constants (string &str, SpecialActions &actions) { bool repl_bbox = true; while (repl_bbox) { size_t pos = str.find("{?bbox "); if (pos == string::npos) repl_bbox = false; else { size_t endpos = pos+7; while (endpos < str.length() && isalnum(str[endpos])) ++endpos; if (str[endpos] == '}') { BoundingBox &box=actions.bbox(str.substr(pos+7, endpos-pos-7)); str.replace(pos, endpos-pos+1, box.toSVGViewBox()); } else repl_bbox = false; } } struct Constant { const char *name; string val; }; const array<Constant, 5> constants {{ {"x", XMLString(actions.getX())}, {"y", XMLString(actions.getY())}, {"color", actions.getColor().svgColorString()}, {"matrix", actions.getMatrix().toSVG()}, {"nl", "\n"}, }}; for (const Constant &constant : constants) { const string pattern = string("{?")+constant.name+"}"; size_t pos = str.find(pattern); while (pos != string::npos) { str.replace(pos, strlen(constant.name)+3, constant.val); pos = str.find(pattern, pos+constant.val.length()); // look for further matches } } }