/* * ******************************************************************************** * This file is part of the LibreCAD project, a 2D CAD program * * Copyright (C) 2025 LibreCAD.org * Copyright (C) 2025 sand1024 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************** */ #include #include "lc_tolerance.h" #include #include "rs_color.h" #include "rs_debug.h" #include "rs_document.h" #include "rs_filterdxfrw.h" #include "rs_line.h" #include "rs_text.h" #include "rs_units.h" LC_ToleranceData::~LC_ToleranceData() = default; LC_Tolerance::LC_Tolerance(RS_EntityContainer* parent, const LC_ToleranceData& d) :RS_EntityContainer(parent), m_toleranceData(d){ RS_EntityContainer::calculateBorders(); } RS_Entity* LC_Tolerance::clone() const { auto* d = new LC_Tolerance(*this); d->setOwner(isOwner()); d->detach(); return d; } void LC_Tolerance::update() { clear(); if (isUndone()) { return; } doUpdateDim(); calculateBorders(); } RS_VectorSolutions LC_Tolerance::getRefPoints() const { return {m_toleranceData.m_insertionPoint}; } void LC_Tolerance::move(const RS_Vector& offset) { m_toleranceData.m_insertionPoint.move(offset); update(); } void LC_Tolerance::rotate(const RS_Vector& center, double angle) { m_toleranceData.m_insertionPoint.rotate(center, angle); update(); } void LC_Tolerance::rotate(const RS_Vector& center, const RS_Vector& angleVector) { m_toleranceData.m_insertionPoint.rotate(center, angleVector); update(); } void LC_Tolerance::scale(const RS_Vector& center, const RS_Vector& factor) { m_toleranceData.m_insertionPoint.scale(center, factor); update(); } void LC_Tolerance::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) { m_toleranceData.m_insertionPoint.mirror(axisPoint1, axisPoint2); update(); } void LC_Tolerance::moveRef(const RS_Vector& ref, const RS_Vector& offset) { if (ref.distanceTo(m_toleranceData.m_insertionPoint)<1.0e-4) { m_toleranceData.m_insertionPoint += offset; update(); } } std::ostream& operator<<(std::ostream& os, const LC_ToleranceData& td) { os << "(" << td.m_insertionPoint << ',' << td.m_directionVector << ',' << td.m_dimStyleName.toLatin1().data() << ',' << td.m_textCode.toLatin1().data() << ")"; return os; } std::ostream& operator<<(std::ostream& os, const LC_Tolerance& d) { os << " Tolerance: " << d.getData() << "\n"; return os; } void LC_Tolerance::doUpdate() { } QList LC_Tolerance::getFields() const { // create list of string lists with field texts: QList ret; QStringList lines = m_toleranceData.m_textCode.split("^J"); for (int k=0; k0.0) { v = dimtxt; } else { v = getTextHeight(); } if (scale) { v *= getDimscale(); } return v; } void LC_Tolerance::setDimtxt(double f) { dimtxt = f; update(); } double LC_Tolerance::getGeneralScale() { return getGraphicVariable("$DIMSCALE", 1.0, 40); } double LC_Tolerance::getDimscale() { // get value from override: if (dimscale>0.0) { return dimscale; } double v = getGeneralScale(); return v; } QString LC_Tolerance::getTextStyle() { return getGraphicVariableString("$DIMTXSTY", "standard"); } RS_Color LC_Tolerance::getTextColor() { return RS_FilterDXFRW::numberToColor(getGraphicVariableInt("$DIMCLRT", 0)); } RS_Pen LC_Tolerance::getPenForText() { RS_Pen result(getTextColor(), RS2::WidthByBlock, RS2::SolidLine); return result; } RS_Color LC_Tolerance::getDimensionLineColor() { return RS_FilterDXFRW::numberToColor(getGraphicVariableInt("$DIMCLRD", 0)); } RS_Pen LC_Tolerance::getPenForLines() { // RS_Pen result(RS_Color(RS2::FlagByBlock), RS2::WidthByBlock, RS2::SolidLine); RS_Pen result(getDimensionLineColor(), RS2::WidthByBlock, RS2::SolidLine); return result; } void LC_Tolerance::doUpdateDim(){ QList> divisionPoints; createTextLabels(divisionPoints); createFrameLines(divisionPoints); divisionPoints.clear(); } void LC_Tolerance::createTextLabels(QList> &divisions) { double dimtxt = getDimtxt(); //qDebug() << "text:" << text; QList fields = getFields(); joinFirstField = false; // find out if we need to join the first fields of the first two lines: if (fields.length()>1 && fields[0].length()>0 && fields[1].length()>0) { QString field1 = fields[0][0]; QString field2 = fields[1][0]; QRegularExpression reg = QRegularExpression("\\\\F[gG][dD][tT];", QRegularExpression::CaseInsensitiveOption); field1.replace(reg, "\\Fgdt;"); field2.replace(reg, "\\Fgdt;"); if (!field1.isEmpty()) { joinFirstField = (field1==field2); } } double cursorY = 0; double angle = m_toleranceData.m_directionVector.angle(); double textAngle = 0.0; RS_Pen textPen = getPenForText(); for (int k=0; k row; row << 0.0; divisions.append(row); // render text strings with distance of dimtxt: for (int i=0; imove({0, -dimtxt}); } cursorX += text->getUsedTextWidth(); cursorX += dimtxt; divisions.last().push_back(cursorX - dimtxt/2); if (k==1 && i==0 && joinFirstField) { // skip first symbol of second line if fields are joined: continue; } text->rotate({0,0},angle); text->move(m_toleranceData.m_insertionPoint); } if (!divisions.isEmpty() && divisions.last().length() ==1) { // remove single division line: divisions.removeLast(); } else { cursorY -= dimtxt * 2; } } } void LC_Tolerance::createFrameLines(QList> &divisions) { QList ret; double dimtxt = getDimtxt(); double offsetY = 0.0; RS_Vector location = m_toleranceData.m_insertionPoint; double angle = m_toleranceData.m_directionVector.angle(); RS_Pen linesPen = getPenForLines(); for (int i = 0; i < divisions.length(); i++) { //qDebug() << "divisions:" << divisions[i]; auto current = divisions[i]; qsizetype currentLength = current.length(); // never show vertical lines for empty rows: if (currentLength > 1) { for (int k = 0; k < currentLength; k++) { double division = current.at(k); RS_Line* line = addDimComponentLine({division, -dimtxt + offsetY}, {division, dimtxt + offsetY}, linesPen); line->rotate(angle); line->move(location); } { // top line of current line: double startX = current.first(); if (joinFirstField && i == 1 && currentLength > 1) { startX = current[1]; } RS_Line* line = addDimComponentLine({startX, dimtxt + offsetY}, {current.last(), dimtxt + offsetY}, linesPen); line->rotate(angle); line->move(location); } { // bottom line of current line: double startX = current.first(); if (joinFirstField && i == 0 && currentLength > 1) { startX = current[1]; } RS_Line* line = addDimComponentLine({startX, -dimtxt + offsetY}, {current.last(), -dimtxt + offsetY}, linesPen); line->rotate(angle); line->move(location); } } if (!current.isEmpty()) { offsetY -= dimtxt * 2; } } } RS_Line* LC_Tolerance::addDimComponentLine(RS_Vector start, RS_Vector end, const RS_Pen &pen) { auto line = new RS_Line(this, {start, end}); line->setPen(pen); line->setLayer(nullptr); addEntity(line); return line; } void LC_Tolerance::addDimComponentEntity(RS_Entity* en, const RS_Pen &pen) { en->setPen(pen); en->setLayer(nullptr); addEntity(en); }