void LC_MakerCamSVG::writeInsert(RS_Insert* insert) { RS_Block* block = insert->getBlockForInsert(); RS_Vector insertionpoint = convertToSvg(insert->getInsertionPoint()); if (writeBlocksInline) { RS_DEBUG->print("RS_MakerCamSVG::writeInsert: Writing insert inline ..."); offset.set(insertionpoint.x, insertionpoint.y - (max.y - min.y)); xmlWriter->addElement("g", NAMESPACE_URI_SVG); xmlWriter->addAttribute("blockname", qPrintable(block->getName()), NAMESPACE_URI_LC); writeLayers(block); xmlWriter->closeElement(); offset.set(0, 0); } else { RS_DEBUG->print("RS_MakerCamSVG::writeInsert: Writing insert as reference to block ..."); xmlWriter->addElement("use", NAMESPACE_URI_SVG); xmlWriter->addAttribute("x", numXml(insertionpoint.x)); xmlWriter->addAttribute("y", numXml(insertionpoint.y - (max.y - min.y))); xmlWriter->addAttribute("href", "#" + std::to_string(block->getId()), NAMESPACE_URI_XLINK); xmlWriter->closeElement(); } }
std::string LC_MakerCamSVG::svgPathArc(RS_Vector point, double radius_x, double radius_y, double x_axis_rotation, bool large_arc_flag, bool sweep_flag) { return "A" + numXml(radius_x) + "," + numXml(radius_y) + " " + numXml(x_axis_rotation) + " " + (large_arc_flag ? "1" : "0") + "," + (sweep_flag ? "1" : "0") + " " + numXml(point.x) + "," + numXml(point.y) + " "; }
void LC_MakerCamSVG::writeCircle(RS_Circle* circle) { RS_DEBUG->print("RS_MakerCamSVG::writeCircle: Writing circle ..."); RS_Vector center = convertToSvg(circle->getCenter()); xmlWriter->addElement("circle", NAMESPACE_URI_SVG); xmlWriter->addAttribute("cx", numXml(center.x)); xmlWriter->addAttribute("cy", numXml(center.y)); xmlWriter->addAttribute("r", numXml(circle->getRadius())); xmlWriter->closeElement(); }
void LC_MakerCamSVG::writeLine(RS_Line* line) { RS_DEBUG->print("RS_MakerCamSVG::writeLine: Writing line ..."); RS_Vector startpoint = convertToSvg(line->getStartpoint()); RS_Vector endpoint = convertToSvg(line->getEndpoint()); xmlWriter->addElement("line", NAMESPACE_URI_SVG); xmlWriter->addAttribute("x1", numXml(startpoint.x)); xmlWriter->addAttribute("y1", numXml(startpoint.y)); xmlWriter->addAttribute("x2", numXml(endpoint.x)); xmlWriter->addAttribute("y2", numXml(endpoint.y)); xmlWriter->closeElement(); }
void LC_MakerCamSVG::writePoint(RS_Point* point) { RS_DEBUG->print("RS_MakerCamSVG::writePoint: Writing point ..."); // NOTE: There is no "point" element in SVG, therefore creating a circle // with minimal radius. RS_Vector center = convertToSvg(point->getPos()); xmlWriter->addElement("circle", NAMESPACE_URI_SVG); xmlWriter->addAttribute("cx", numXml(center.x)); xmlWriter->addAttribute("cy", numXml(center.y)); xmlWriter->addAttribute("r", numXml(0.1)); xmlWriter->closeElement(); }
void LC_MakerCamSVG::write(RS_Graphic* graphic) { RS_DEBUG->print("RS_MakerCamSVG::write: Writing root node ..."); graphic->calculateBorders(); min = graphic->getMin(); max = graphic->getMax(); RS2::Unit raw_unit = graphic->getUnit(); switch (raw_unit) { case RS2::Millimeter: unit = "mm"; break; case RS2::Centimeter: unit = "cm"; break; case RS2::Inch: unit = "in"; break; default: unit = ""; break; } xmlWriter->createRootElement("svg", NAMESPACE_URI_SVG); xmlWriter->addNamespaceDeclaration("lc", NAMESPACE_URI_LC); xmlWriter->addNamespaceDeclaration("xlink", NAMESPACE_URI_XLINK); xmlWriter->addAttribute("width", numXml(max.x - min.x) + unit); xmlWriter->addAttribute("height", numXml(max.y - min.y) + unit); xmlWriter->addAttribute("viewBox", "0 0 "+ numXml(max.x - min.x) + " " + numXml(max.y - min.y)); writeBlocks(graphic); writeLayers(graphic); }
std::string LC_MakerCamSVG::svgPathMoveTo(RS_Vector point) { return "M" + numXml(point.x) + "," + numXml(point.y) + " "; }
std::string LC_MakerCamSVG::svgPathCurveTo(RS_Vector point, RS_Vector controlpoint1, RS_Vector controlpoint2) { return "C" + numXml(controlpoint1.x) + "," + numXml(controlpoint1.y) + " " + numXml(controlpoint2.x) + "," + numXml(controlpoint2.y) + " " + numXml(point.x) + "," + numXml(point.y) + " "; }
void LC_MakerCamSVG::writeEllipse(RS_Ellipse* ellipse) { RS_Vector center = convertToSvg(ellipse->getCenter()); const RS_Vector centerTranslation=center - ellipse->getCenter(); double majorradius = ellipse->getMajorRadius(); double minorradius = ellipse->getMinorRadius(); if (convertEllipsesToBeziers) { std::string path = ""; if (ellipse->isArc()) { const int segments = 4; RS_DEBUG->print("RS_MakerCamSVG::writeEllipse: Writing ellipse arc approximated by 'path' with %d cubic bézier segments (as discussed in https://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf) ...", segments); double x_axis_rotation = 2 * M_PI - ellipse->getAngle(); double start_angle = 2 * M_PI - ellipse->getAngle2(); double end_angle = 2 * M_PI - ellipse->getAngle1(); if (ellipse->isReversed()) { double temp_angle = start_angle; start_angle = end_angle; end_angle = temp_angle; } if (end_angle <= start_angle) { end_angle += 2 * M_PI; } double total_angle = end_angle - start_angle; double alpha = calcAlpha(total_angle / segments); RS_Vector start_point = centerTranslation + ellipse->getEllipsePoint(start_angle); path = svgPathMoveTo(start_point); for (int i = 1; i <= segments; i++) { double segment_start_angle = start_angle + ((i - 1) / (double)segments) * total_angle; double segment_end_angle = start_angle + (i / (double)segments) * total_angle; RS_Vector segment_start_point = centerTranslation + ellipse->getEllipsePoint(segment_start_angle); RS_Vector segment_end_point = centerTranslation + ellipse->getEllipsePoint(segment_end_angle); RS_Vector segment_control_point_1 = segment_start_point + calcEllipsePointDerivative(majorradius, minorradius, x_axis_rotation, segment_start_angle) * alpha; RS_Vector segment_control_point_2 = segment_end_point - calcEllipsePointDerivative(majorradius, minorradius, x_axis_rotation, segment_end_angle) * alpha; path += svgPathCurveTo(segment_end_point, segment_control_point_1, segment_control_point_2); } } else { RS_DEBUG->print("RS_MakerCamSVG::writeEllipse: Writing ellipse approximated by 'path' with 4 cubic bézier segments (as discussed in http://www.tinaja.com/glib/ellipse4.pdf) ..."); const double kappa = 0.551784; RS_Vector major {majorradius, 0.0}; RS_Vector minor {0.0, minorradius}; RS_Vector flip_y {1.0, -1.0}; major.rotate(ellipse->getAngle()); minor.rotate(ellipse->getAngle()); major.scale(flip_y); minor.scale(flip_y); RS_Vector offsetmajor {major * kappa}; RS_Vector offsetminor {minor * kappa}; path = svgPathMoveTo(center - major) + svgPathCurveTo((center - minor), (center - major - offsetminor), (center - minor - offsetmajor)) + svgPathCurveTo((center + major), (center - minor + offsetmajor), (center + major - offsetminor)) + svgPathCurveTo((center + minor), (center + major + offsetminor), (center + minor + offsetmajor)) + svgPathCurveTo((center - major), (center + minor - offsetmajor), (center - major + offsetminor)) + svgPathClose(); } xmlWriter->addElement("path", NAMESPACE_URI_SVG); xmlWriter->addAttribute("d", path); xmlWriter->closeElement(); } else { if (ellipse->isArc()) { RS_DEBUG->print("RS_MakerCamSVG::writeEllipse: Writing ellipse arc as 'path' with arc segments ..."); double x_axis_rotation = 180 - (RS_Math::rad2deg(ellipse->getAngle())); double startangle = RS_Math::rad2deg(ellipse->getAngle1()); double endangle = RS_Math::rad2deg(ellipse->getAngle2()); if (endangle <= startangle) { endangle += 360; } bool large_arc_flag = ((endangle - startangle) > 180); bool sweep_flag = false; if (ellipse->isReversed()) { large_arc_flag = !large_arc_flag; sweep_flag = !sweep_flag; } std::string path = svgPathMoveTo(convertToSvg(ellipse->getStartpoint())) + svgPathArc(convertToSvg(ellipse->getEndpoint()), majorradius, minorradius, x_axis_rotation, large_arc_flag, sweep_flag); xmlWriter->addElement("path", NAMESPACE_URI_SVG); xmlWriter->addAttribute("d", path); xmlWriter->closeElement(); } else { RS_DEBUG->print("RS_MakerCamSVG::writeEllipse: Writing full ellipse as 'ellipse' ..."); double angle = 180 - (RS_Math::rad2deg(ellipse->getAngle()) - 90); std::string transform = "translate(" + numXml(center.x) + ", " + numXml(center.y) + ") " + "rotate(" + numXml(angle) + ")"; xmlWriter->addElement("ellipse", NAMESPACE_URI_SVG); xmlWriter->addAttribute("rx", numXml(minorradius)); xmlWriter->addAttribute("ry", numXml(majorradius)); xmlWriter->addAttribute("transform", transform); xmlWriter->closeElement(); } } }
std::string LC_MakerCamSVG::lengthXml(double value) const { return numXml(lengthFactor*value); }