| /* | |
| * ******************************************************************************** | |
| * 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. | |
| * ******************************************************************************** | |
| */ | |
| LC_DimLineBuilder::LC_DimLineBuilder(RS_Graphic* graphic) { | |
| } | |
| void LC_DimLineBuilder::buildDimensionLine(RS_EntityContainer* container, LC_DimStyle* style, | |
| const RS_Vector& dimLineStart, const RS_Vector& dimLineEnd, bool forceAutoText) { | |
| } | |
| /* | |
| void LC_DimLineBuilder::createDimensionLine(RS_EntityContainer* container, LC_DimStyle* style, const RS_Vector& dimLineStart, | |
| const RS_Vector& dimLineEnd, bool arrow1, bool arrow2, bool forceAutoText) { | |
| if (getInsideHorizontalText()) { | |
| createHorizontalTextDimensionLine(dimLineStart, dimLineEnd, arrow1, arrow2, forceAutoText); | |
| } | |
| else { | |
| createAlignedTextDimensionLine(dimLineStart, dimLineEnd, arrow1, arrow2, forceAutoText); | |
| } | |
| } | |
| void LC_DimLineBuilder::createHorizontalTextDimensionLine(const RS_Vector& p1, | |
| const RS_Vector& p2, bool arrow1, bool arrow2, | |
| bool forceAutoText) { | |
| double dimscale = getGeneralScale(); | |
| double dimtxt = getTextHeight() * dimscale; | |
| double dimgap = getDimensionLineGap() * dimscale; | |
| // length of dimension line: | |
| double distance = p1.distanceTo(p2); | |
| // arrow size: | |
| double arrowSize = getArrowSize() * dimscale; | |
| RS_Pen dimensionLinePen(getDimensionLineColor(), | |
| getDimensionLineWidth(), | |
| RS2::LineByBlock); | |
| // Create dimension line: | |
| RS_Line* dimensionLine{new RS_Line{this, p1, p2}}; | |
| RS_Line* dimensionLineInside1{nullptr}; | |
| RS_Line* dimensionLineInside2{nullptr}; | |
| RS_Line* dimensionLineOutside1{nullptr}; | |
| RS_Line* dimensionLineOutside2{nullptr}; | |
| dimensionLine->setPen(dimensionLinePen); | |
| dimensionLine->setLayer(nullptr); | |
| // Text label: | |
| RS_Vector textPos; | |
| double textAngle = 0.0; | |
| bool autoText = !m_dimGenericData.middleOfText.valid || forceAutoText; | |
| if (autoText) { | |
| textPos = dimensionLine->getMiddlePoint(); | |
| //// the next update should still be able to adjust this | |
| //// auto text position. leave it invalid | |
| m_dimGenericData.middleOfText = textPos; | |
| } | |
| else { | |
| textPos = m_dimGenericData.middleOfText; | |
| } | |
| auto* text = createDimText(textPos, dimtxt, textAngle); | |
| // evaluate intersection between dim line and text | |
| double textIntersectionLength = 0.0; | |
| double w = text->getUsedTextWidth() / 2 + dimgap; | |
| double h = text->getUsedTextHeight() / 2 + dimgap; | |
| // textCorner variables correspond to the corners of the text bounding box | |
| // if the text were to be positioned in the center of the dimensionLine. | |
| RS_Vector textCorner1 = dimensionLine->getMiddlePoint() - RS_Vector{w, h}; | |
| RS_Vector textCorner2 = dimensionLine->getMiddlePoint() + RS_Vector{w, h}; | |
| RS_EntityContainer c; | |
| c.addRectangle(textCorner1, textCorner2); | |
| // treat line as infinitely long in both directions | |
| RS_VectorSolutions sol1 = getIntersectionsLineContainer(dimensionLine, &c,true); | |
| textIntersectionLength = sol1.get(0).distanceTo(sol1.get(1)); | |
| // determine if we should use outside arrows | |
| bool outsideArrows = (textIntersectionLength + 3 * arrowSize) > distance; | |
| // add arrows | |
| // arrow angles: | |
| double arrowAngle1 = outsideArrows ? dimensionLine->getAngle1() : dimensionLine->getAngle2(); | |
| double arrowAngle2 = outsideArrows ? dimensionLine->getAngle2() : dimensionLine->getAngle1(); | |
| const bool showArrows = arrowSize > 1e-6 * p1.distanceTo(p2); | |
| if (outsideArrows) { | |
| // extend dimension line outside arrows | |
| if (showArrows) { | |
| auto dir = RS_Vector::polar(arrowSize * 2, dimensionLine->getAngle1()); | |
| dimensionLineOutside1 = new RS_Line{this, p1 - dir, p1}; | |
| dimensionLineOutside1->setPen(dimensionLinePen); | |
| dimensionLineOutside2 = new RS_Line{this, p2 + dir, p2}; | |
| dimensionLineOutside2->setPen(dimensionLinePen); | |
| } | |
| // move text to the side if it won't fit either | |
| if (textIntersectionLength > distance && autoText) { | |
| double dist = (textIntersectionLength + distance) / 2.0 + arrowSize * 2; | |
| RS_Vector distH = RS_Vector::polar(dist, arrowAngle1); | |
| text->move(distH); | |
| textPos = text->getInsertionPoint(); | |
| m_dimGenericData.middleOfText = textPos; | |
| } | |
| } | |
| double dimtsz = getTickSize() * dimscale; | |
| bool displayArrows = dimtsz < 0.01 && showArrows; | |
| if (displayArrows) { | |
| //display arrow | |
| // Arrows: | |
| RS_SolidData sd{}; | |
| if (arrow1) { | |
| // arrow 1 | |
| auto arrow = new RS_Solid(this, sd); | |
| arrow->shapeArrow(p1,arrowAngle1, arrowSize); | |
| addDimComponentEntity(arrow, dimensionLinePen); | |
| } | |
| if (arrow2) { | |
| // arrow 2: | |
| auto arrow = new RS_Solid(this, sd); | |
| arrow->shapeArrow(p2,arrowAngle2, arrowSize); | |
| addDimComponentEntity(arrow, dimensionLinePen); | |
| } | |
| } | |
| else { | |
| //display ticks | |
| RS_Vector tickVector = RS_Vector::polar(dimtsz, arrowAngle1 + M_PI * 0.25); //tick is 45 degree away | |
| if (arrow1) { | |
| // tick 1 | |
| addDimComponentLine(p1 - tickVector, p1 + tickVector, dimensionLinePen); | |
| } | |
| if (arrow2) {// tick 2: | |
| addDimComponentLine(p2 - tickVector, p2 + tickVector, dimensionLinePen); | |
| } | |
| } | |
| // calculate split dimension lines | |
| bool splitDimensionLine = false; | |
| if (!outsideArrows) { | |
| w = text->getUsedTextWidth() / 2 + dimgap; | |
| h = text->getUsedTextHeight() / 2 + dimgap; | |
| RS_Vector s1 = text->getInsertionPoint() - RS_Vector{w, h}; | |
| RS_Vector s2 = text->getInsertionPoint() + RS_Vector{w, h}; | |
| c = RS_EntityContainer(); | |
| c.addRectangle(s1, s2); | |
| sol1 = getIntersectionsLineContainer(dimensionLine, &c); | |
| if (sol1.size() > 1) { | |
| // the text bounding box intersects dimensionLine on two sides | |
| splitDimensionLine = true; | |
| s1 = sol1.get(0); | |
| s2 = sol1.get(1); | |
| } | |
| else if (sol1.size() == 1) { | |
| // the text bounding box intersects dimensionLine on one side | |
| splitDimensionLine = true; | |
| if (RS_Information::isPointInsideContour(p1, &c)) { | |
| // the dimension line begins inside the text bounds | |
| s1 = p1; | |
| s2 = sol1.get(0); | |
| } | |
| else { | |
| // the dimension line ends inside the text bounds | |
| s1 = sol1.get(0); | |
| s2 = p2; | |
| } | |
| } | |
| else { | |
| // the text bounding box does not intersect with dimensionLine, but we | |
| // should still check if dimensionLine endpoints are completely inside | |
| // the bounding box. | |
| if (RS_Information::isPointInsideContour(p1, &c)) { | |
| splitDimensionLine = true; | |
| s1 = p1; | |
| s2 = p2; | |
| } | |
| } | |
| if (splitDimensionLine) { | |
| dimensionLineInside1 = new RS_Line{this, p1, s1}; | |
| dimensionLineInside1->setPen(dimensionLinePen); | |
| dimensionLineInside2 = new RS_Line{this, s2, p2}; | |
| dimensionLineInside2->setPen(dimensionLinePen); | |
| } | |
| } | |
| // finally, add the dimension line(s) and text to the drawing | |
| if (outsideArrows && dimensionLineOutside1) { | |
| addEntity(dimensionLineOutside1); | |
| addEntity(dimensionLineOutside2); | |
| } | |
| else if (splitDimensionLine && dimensionLineInside1) { | |
| addEntity(dimensionLineInside1); | |
| addEntity(dimensionLineInside2); | |
| } | |
| else { | |
| addEntity(dimensionLine); | |
| } | |
| } | |
| */ | |