Bug Summary

File:librecad/src/lib/actions/visual_snap/lc_visual_snap_solution_solver.cpp
Warning:line 575, column 19
Value stored to 'v' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name lc_visual_snap_solution_solver.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/runner/work/LibreCAD/LibreCAD/librecad/src -fcoverage-compilation-dir=/home/runner/work/LibreCAD/LibreCAD/librecad/src -resource-dir /usr/lib/llvm-18/lib/clang/18 -D _REENTRANT -D DWGSUPPORT -D MUPARSER_STATIC -D QC_APPDIR="librecad" -D LC_VERSION=2.2.2_alpha1-607-g330d41cec -D LC_PRERELEASE=true; -D QT_NO_DEBUG -D QT_SVG_LIB -D QT_PRINTSUPPORT_LIB -D QT_WIDGETS_LIB -D QT_GUI_LIB -D QT_NETWORK_LIB -D QT_CORE_LIB -I . -I /usr/include -I ../../libraries/lciconengine -I ../../libraries/libdxfrw/src -I ../../libraries/jwwlib/src -I ../../libraries/shapelib/src -I cmd -I lib/actions -I lib/actions/visual_snap -I lib/actions/options -I lib/creation -I lib/debug -I lib/engine -I lib/engine/document -I lib/engine/document/blocks -I lib/engine/document/container -I lib/engine/document/dimstyles -I lib/engine/document/entities -I lib/engine/document/entities/support -I lib/engine/document/fonts -I lib/engine/document/io -I lib/engine/document/layers -I lib/engine/document/patterns -I lib/engine/document/selection -I lib/engine/document/textstyles -I lib/engine/document/ucs -I lib/engine/document/variables -I lib/engine/document/views -I lib/engine/clipboard -I lib/engine/overlays -I lib/engine/overlays/angles_base -I lib/engine/overlays/highlight -I lib/engine/overlays/preview -I lib/engine/overlays/references -I lib/engine/overlays/crosshair -I lib/engine/overlays/info_cursor -I lib/engine/overlays/overlay_box -I lib/engine/overlays/ucs_mark -I lib/engine/undo -I lib/engine/utils -I lib/engine/settings -I lib/fileio -I lib/filters -I lib/generators -I lib/generators/makercamsvg -I lib/generators/layers -I lib/generators/image -I lib/gui -I lib/gui/grid -I lib/gui/render -I lib/gui/render/headless -I lib/gui/render/widget -I lib/information -I lib/math -I lib/modification -I lib/selection -I lib/selection/metaentity -I lib/selection/metaentity/entities -I lib/printing -I lib/properties -I actions -I actions/dock_widgets -I actions/dock_widgets/block -I actions/dock_widgets/entity_info -I actions/dock_widgets/layer -I actions/dock_widgets/library -I actions/dock_widgets/ucs_list -I actions/drawing -I actions/drawing/draw -I actions/drawing/draw/arc -I actions/drawing/draw/circle -I actions/drawing/draw/curve -I actions/drawing/draw/spline -I actions/drawing/draw/dimensions -I actions/drawing/draw/ellipse -I actions/drawing/draw/hatch -I actions/drawing/draw/image -I actions/drawing/draw/line -I actions/drawing/draw/point -I actions/drawing/draw/rect -I actions/drawing/draw/polygon -I actions/drawing/draw/misc -I actions/drawing/draw/line/shapes -I actions/drawing/draw/line/misc -I actions/drawing/draw/line/shapes/rect -I actions/drawing/draw/line/shapes/polygon -I actions/drawing/draw/polyline -I actions/drawing/draw/text -I actions/drawing/edit -I actions/drawing/info -I actions/drawing/pick -I actions/drawing/modify -I actions/drawing/pen -I actions/drawing/rel_zero -I actions/drawing/selection -I actions/drawing/snap -I actions/drawing/zoom -I actions/file -I actions/options -I actions/print_preview -I ui -I ui/action_options -I ui/action_options/circle -I ui/action_options/curve -I ui/action_options/spline -I ui/action_options/dimensions -I ui/action_options/edit -I ui/action_options/image -I ui/action_options/info -I ui/action_options/insert -I ui/action_options/line -I ui/action_options/rect -I ui/action_options/polygon -I ui/action_options/misc -I ui/action_options/modify -I ui/action_options/ellipse -I ui/action_options/other -I ui/action_options/polyline -I ui/action_options/point -I ui/action_options/print_preview -I ui/action_options/selection -I ui/action_options/snap -I ui/action_options/text -I ui/actions -I ui/components -I ui/components/relative_position_assistant -I ui/components/comboboxes -I ui/components/containers -I ui/components/creators -I ui/components/layouts -I ui/components/pen -I ui/components/status_bar -I ui/components/toolbars -I ui/components/utils -I ui/dialogs -I ui/dialogs/actions -I ui/dialogs/actions/modify -I ui/dialogs/actions/quick_selection -I ui/dialogs/modify -I ui/dialogs/entity -I ui/dialogs/creators -I ui/dialogs/file -I ui/dialogs/file/export -I ui/dialogs/file/export/layers -I ui/dialogs/file/export/image -I ui/dialogs/file/export/makercam -I ui/dialogs/main -I ui/dialogs/settings -I ui/dialogs/settings/dimstyles -I ui/dialogs/settings/dimstyles/dimstyle_manager -I ui/dialogs/settings/dimstyles/dimstyle_manager/support -I ui/dialogs/settings/options_device -I ui/dialogs/settings/options_drawing -I ui/dialogs/settings/options_general -I ui/dialogs/settings/options_widget -I ui/dialogs/settings/shortcuts -I ui/dock_widgets -I ui/dock_widgets/block_widget -I ui/dock_widgets/command_line -I ui/dock_widgets/entity_info -I ui/dock_widgets/layer_widget -I ui/dock_widgets/layers_tree -I ui/dock_widgets/library_widget -I ui/dock_widgets/pen_palette -I ui/dock_widgets/pen_wizard -I ui/dock_widgets/property_sheet -I ui/dock_widgets/property_sheet/lib -I ui/dock_widgets/property_sheet/lib/properties -I ui/dock_widgets/property_sheet/lib/view -I ui/dock_widgets/property_sheet/lib/view/edit -I ui/dock_widgets/property_sheet/lib/widgets -I ui/dock_widgets/property_sheet/lib/widgets/sheet -I ui/dock_widgets/property_sheet/metaentity -I ui/dock_widgets/property_sheet/metaentity/entities -I ui/dock_widgets/property_sheet/metaentity/entities/document -I ui/dock_widgets/property_sheet/properties -I ui/dock_widgets/property_sheet/properties/action -I ui/dock_widgets/property_sheet/properties/bool -I ui/dock_widgets/property_sheet/properties/color -I ui/dock_widgets/property_sheet/properties/double -I ui/dock_widgets/property_sheet/properties/enum -I ui/dock_widgets/property_sheet/properties/int -I ui/dock_widgets/property_sheet/properties/layer -I ui/dock_widgets/property_sheet/properties/linetype -I ui/dock_widgets/property_sheet/properties/linewidth -I ui/dock_widgets/property_sheet/properties/rect -I ui/dock_widgets/property_sheet/properties/rsvector -I ui/dock_widgets/property_sheet/properties/string -I ui/dock_widgets/views_list -I ui/dock_widgets/ucs_list -I ui/dock_widgets/workspaces -I ui/dock_widgets/cad -I ui/main -I ui/main/init -I ui/main/persistence -I ui/main/release_check -I ui/main/support -I ui/main/fontviewer -I ui/main/workspaces -I ui/view -I main -I main/console_dxf2pdf -I test -I plugins -I ../res -I ../res/arrows -I ../res/controls -I ../res/dxf -I ../res/gdt -I ../res/icons -I ../res/images -I ../../../Qt/6.9.0/gcc_64/include -I ../../../Qt/6.9.0/gcc_64/include/QtSvg -I ../../../Qt/6.9.0/gcc_64/include/QtPrintSupport -I ../../../Qt/6.9.0/gcc_64/include/QtWidgets -I ../../../Qt/6.9.0/gcc_64/include/QtGui -I ../../../Qt/6.9.0/gcc_64/include/QtNetwork -I ../../../Qt/6.9.0/gcc_64/include/QtCore -I ../../generated/librecad/moc -I ../../generated/librecad/ui -I ../../../Qt/6.9.0/gcc_64/mkspecs/linux-g++ -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=gnu++1z -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/runner/work/LibreCAD/LibreCAD/out/2026-08-04-154929-5069-1 -x c++ lib/actions/visual_snap/lc_visual_snap_solution_solver.cpp
1/*
2 * ********************************************************************************
3 * This file is part of the LibreCAD project, a 2D CAD program
4 *
5 * Copyright (C) 2026 LibreCAD.org
6 * Copyright (C) 2026 sand1024
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * ********************************************************************************
22 */
23
24#include "lc_visual_snap_solution_solver.h"
25
26#include "lc_ref_snap_circle.h"
27#include "lc_ref_snap_construction_line.h"
28#include "lc_ref_snap_entity.h"
29#include "lc_ref_snap_line.h"
30#include "lc_visual_snap_data.h"
31#include "lc_visual_snap_options.h"
32#include "lc_visual_snap_solution.h"
33#include "rs.h"
34#include "rs_creation.h"
35#include "rs_information.h"
36#include "rs_snapper.h"
37#include "rs_vector.h"
38
39namespace {
40 constexpr double g_rayDirectionOffset = 10.0;
41
42 void clearVertexProcessedFlag(LC_VisualSnapSolution& solution) {
43 solution.snapData->forEachVertex([](LC_VisualSnapVertex* v) -> void {
44 v->flagProcessed = false;
45 });
46 }
47
48 void clearDocumentProcessedFlag(LC_VisualSnapSolution& solution) {
49 solution.snapData->forEachDocRef([](LC_VisualSnapDocumentEntityRef* v) -> void {
50 v->processed = false;
51 });
52 }
53}
54
55void LC_VisualSnapSolutionSolver::solveVisualSnap(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution) const {
56 solution.wcsPoint = wcsPos;
57 addOrthoRaysForVertexes(wcsPos, solution);
58 addLineRays(wcsPos, solution);
59 std::vector<LC_VisualSnapPointHolder> specialPointSnapCandidates;
60 addTangentialAndNormalRaysFromArcEndpoint(wcsPos, solution);
61 addTangentialRaysFromVertexesToArcs(wcsPos, specialPointSnapCandidates, solution);
62 addTangentialRaysBetwenCirclesArcs(wcsPos, specialPointSnapCandidates, solution);
63 addExplicitlySetDistanceCirclesForVertexes(wcsPos, solution);
64 addVertexToVertexLinesAndDistances(wcsPos, specialPointSnapCandidates, solution);
65 addGuideEntitiesByDocumentEntities(wcsPos, solution);
66 addNormalsFromVertexToEntities(wcsPos, solution);
67 addRelativePositionsEntities(wcsPos, solution);
68 addOrdinaryRestrictionLines(wcsPos, solution);
69 findSnapPoint(wcsPos, solution, specialPointSnapCandidates);
70}
71
72void LC_VisualSnapSolutionSolver::findSnapPoint(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
73 const std::vector<LC_VisualSnapPointHolder>& specialPointSnapCandidates) const {
74 // finding closest intersection point
75 RS2::LC_VisualSnapIntersectionInfo minSnapIntersectionInfo;
76
77 solution.restrictedOriginalSnapType = RS2::SnapType::NO_SNAP;
78
79 double minDist = m_wcsSnapRange;
80 RS_Vector minSnap{false};
81 for (auto& e : solution.guidingEntities) {
82 e.processed = true;
83 for (const auto& ee : solution.guidingEntities) {
84 if (ee.processed) {
85 continue;
86 }
87 RS_VectorSolutions intersections = RS_Information::getIntersection(e.entity, ee.entity, true);
88 if (!intersections.empty()) {
89 double dist;
90 const RS_Vector closestSnap = intersections.getClosest(wcsPos, &dist);
91 if (dist < minDist) {
92 minSnap = closestSnap;
93 minSnapIntersectionInfo.entity1 = e.snapEntityType;
94 minSnapIntersectionInfo.entity2 = ee.snapEntityType;
95
96 if (e.snapEntityType == RS2::VSNAP_LINE_VERTEX_ANGLE_STEP || e.snapEntityType == RS2::VSNAP_LINE_ENDPOINT_ANGLE_STEP) {
97 minSnapIntersectionInfo.rayAngle1 = e.wcsRayAngleRad;
98 }
99 if (ee.snapEntityType == RS2::VSNAP_LINE_VERTEX_ANGLE_STEP || ee.snapEntityType ==
100 RS2::VSNAP_LINE_ENDPOINT_ANGLE_STEP) {
101 minSnapIntersectionInfo.rayAngle2 = ee.wcsRayAngleRad;
102 }
103 // LC_ERR << "min Intersection " << closestSnap << " " << e.snapEntityType << " " << ee.snapEntityType;
104 }
105 }
106 }
107 }
108
109 for (const auto& ph : specialPointSnapCandidates) {
110 RS_Vector v = ph.pos;
111 const double dist = v.distanceTo(wcsPos);
112 if (dist < minDist) {
113 minDist = dist;
114 minSnap = v;
115 minSnapIntersectionInfo.entity1 = RS2::VSNAP_NONE;
116 minSnapIntersectionInfo.entity2 = ph.snapEntityType;
117 // LC_ERR << "min Point " << v << " " << ph.snapEntityType;
118 }
119 }
120
121 solution.snapData->forEachVertex([&minDist, &minSnap, &minSnapIntersectionInfo, wcsPos, &solution](LC_VisualSnapVertex* vertex) {
122 const RS_Vector v = vertex->wcsSnapCoordinate;
123 const double dist = v.distanceTo(wcsPos);
124 if (dist < minDist) {
125 minDist = dist;
126 minSnap = v;
127 minSnapIntersectionInfo.entity1 = RS2::VSNAP_NONE;
128 minSnapIntersectionInfo.entity2 = RS2::VSNAP_NONE;
129 const auto snapType = vertex->snapType;
130 if (snapType != RS2::SnapType::VISUAL_SNAP) {
131 solution.restrictedOriginalSnapType = snapType;
132 }
133 // LC_ERR << "min Point " << v << " " << ph.snapEntityType;
134 }
135 });
136
137 if (minSnap.valid) {
138 solution.addSnapCandidate(minSnap);
139 // LC_ERR << "Snap found";
140 }
141 else {
142 // LC_ERR << "No Snap";
143 }
144
145 solution.setFoundSnapPoint(minSnap, minSnapIntersectionInfo);
146}
147
148void LC_VisualSnapSolutionSolver::addOrthoAndAngleRaysForPoint(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
149 const double angleStepRad, double wcsRaysStartAngle, double wcsRaysEndAngle,
150 double wcsMPI_2Angle, const RS_Vector& vertexWCSPoint) const {
151 double dist;
152 if (hasNoLinesForPoint(solution, vertexWCSPoint, RS2::VisualSnapGuideEntityType::VSNAP_LINE_VERTEX_HORIZONTAL)) {
153 // create horizontal ray
154 const auto horizontalPoint = m_viewport->restrictHorizontal(vertexWCSPoint,
155 RS_Vector(vertexWCSPoint.x + g_rayDirectionOffset, vertexWCSPoint.y));
156 const auto lineHor = tryCreateGuidingConstructionLine(wcsPos, vertexWCSPoint, horizontalPoint, dist,
157 RS2::VisualSnapGuideEntityType::VSNAP_LINE_VERTEX_HORIZONTAL);
158 if (lineHor != nullptr) {
159 solution.addGuidingEntity(lineHor);
160 }
161 }
162
163 if (hasNoLinesForPoint(solution, vertexWCSPoint, RS2::VisualSnapGuideEntityType::VSNAP_LINE_VERTEX_VERTICAL)) {
164 // create vertical ray
165 const auto verticalPoint = m_viewport->restrictVertical(vertexWCSPoint,
166 RS_Vector(vertexWCSPoint.x, vertexWCSPoint.y + g_rayDirectionOffset));
167
168 const auto lineVert = tryCreateGuidingConstructionLine(wcsPos, vertexWCSPoint, verticalPoint, dist,
169 RS2::VisualSnapGuideEntityType::VSNAP_LINE_VERTEX_VERTICAL);
170
171 if (lineVert != nullptr) {
172 solution.addGuidingEntity(lineVert);
173 }
174 }
175
176 // create angle snap rays, if needed. Only ones with minimal distance to mouse will be used
177 if (m_options->createAngleStepRaysForVertexes) {
178 double minDistance = m_wcsSnapRange;
179 double minDistanceAngle = RS_MAXDOUBLE1.0E+10;
180 LC_RefSnapConstructionLine* minDistanceRay = nullptr;
181 double angle = wcsRaysStartAngle;
182
183 do {
184 if (LC_LineMath::isNotMeaningful(std::abs(angle - wcsMPI_2Angle))) {
185 angle = angle + angleStepRad;
186 continue;
187 }
188 RS_Vector secondPoint = vertexWCSPoint.relative(g_rayDirectionOffset, angle);
189 const auto lineRay = tryCreateGuidingConstructionLine(wcsPos, vertexWCSPoint, secondPoint, dist, angle,
190 RS2::VisualSnapGuideEntityType::VSNAP_LINE_VERTEX_ANGLE_STEP);
191 if (lineRay != nullptr) {
192 if (dist < minDistance) {
193 delete minDistanceRay;
194 minDistanceRay = lineRay;
195 minDistanceAngle = angle;
196 minDistance = dist;
197 }
198 else {
199 delete lineRay;
200 }
201 }
202 angle = angle + angleStepRad;
203 }
204 while (angle < wcsRaysEndAngle);
205
206 if (minDistanceRay != nullptr) {
207 solution.addGuidingEntity(minDistanceRay, minDistanceAngle);
208 }
209 }
210}
211
212void LC_VisualSnapSolutionSolver::addOrthoRaysForVertexes(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution) const {
213 // horizontal/vertical rays for points
214 const double angleStepRad = m_snapper->getAngleStep();
215 double wcsRaysStartAngle = 0.0;
216 double wcsRaysEndAngle = 0.0;
217 double wcsMPI_2Angle = 0.0;
218 if (m_options->createAngleStepRaysForVertexes) {
219 wcsRaysStartAngle = m_viewport->toWorldAngle(angleStepRad);
220 wcsRaysEndAngle = m_viewport->toWorldAngle(M_PI3.14159265358979323846);
221 wcsMPI_2Angle = m_viewport->toWorldAngle(M_PI_21.57079632679489661923);
222 }
223 solution.snapData->forEachVertex(
224 [this, wcsPos, &solution, angleStepRad, wcsRaysStartAngle, wcsRaysEndAngle, wcsMPI_2Angle](LC_VisualSnapVertex* vertex) {
225 vertex->flagProcessed = false;
226 const auto vertexWCSPoint = vertex->wcsSnapCoordinate;
227 addOrthoAndAngleRaysForPoint(wcsPos, solution, angleStepRad, wcsRaysStartAngle, wcsRaysEndAngle, wcsMPI_2Angle, vertexWCSPoint);
228 });
229}
230
231void LC_VisualSnapSolutionSolver::addLineRayAndNormal(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
232 const RS_Vector& wcsSnapCoordinate, const LC_RefSnapConstructionLine* refLine) const {
233 double dist;
234 // create ray that is in line direction
235 const auto endPoint = refLine->getEndpoint();
236 const auto startPoint = refLine->getStartpoint();
237
238 const bool createLineRay = hasNoLinesForPoints(solution, endPoint, startPoint);
239 if (createLineRay) {
240 const auto nearestPointOnEntity = refLine->getNearestPointOnEntity(wcsPos, false, &dist);
241 const double wcsDistance = nearestPointOnEntity.distanceTo(wcsPos);
242 const bool withinSnapRange = wcsDistance < m_wcsSnapRange;
243 if (withinSnapRange || m_options->showNotSnappableGuides) {
244 const auto clone = static_cast<LC_RefSnapConstructionLine*>(refLine->clone());
245 const double refLineAngle = startPoint.angleTo(endPoint);
246 clone->setupForPoint(nearestPointOnEntity, RS2::VisualSnapGuideEntityType::VSNAP_LINE_RAY, withinSnapRange, refLineAngle);
247 solution.addGuidingEntity(clone);
248 }
249 }
250
251 // create ray that is normal to line (under 90 degrees)
252 const double wcsLineAngle = refLine->getDirection1();
253 const double wcsNormalLineAngle = wcsLineAngle + M_PI_21.57079632679489661923;
254
255 const RS_Vector secondPoint = wcsSnapCoordinate.relative(g_rayDirectionOffset, wcsNormalLineAngle);
256 const auto normalLine = tryCreateGuidingConstructionLine(wcsPos, wcsSnapCoordinate, secondPoint, dist, wcsNormalLineAngle,
257 RS2::VisualSnapGuideEntityType::VSNAP_LINE_ENDPOINT_NORMAL);
258 if (normalLine != nullptr) {
259 solution.addGuidingEntity(normalLine);
260 }
261}
262
263void LC_VisualSnapSolutionSolver::addLineRays(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution) const {
264 // lines extensions rays
265 solution.snapData->forEachVertex([this, &wcsPos, &solution](LC_VisualSnapVertex* vertex) {
266 const auto refLine = vertex->refLine;
267 if (refLine != nullptr) {
268 addLineRayAndNormal(wcsPos, solution, vertex->wcsSnapCoordinate, refLine);
269 }
270 });
271}
272
273void LC_VisualSnapSolutionSolver::addTangentialAndNormlRaysForArcEndpoint(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
274 const RS_Vector& wcsSnapCoordinate, LC_RefSnapArc* arc) const {
275 const RS_Vector startPoint = arc->getStartpoint();
276 const RS_Vector endPoint = arc->getEndpoint();
277 RS_Vector endpointToUse;
278 double direction;
279 if (LC_LineMath::isNotMeaningfulDistance(wcsSnapCoordinate, startPoint)) {
280 const double angle1 = arc->getAngle1();
281 direction = angle1 + M_PI_21.57079632679489661923;
282 endpointToUse = startPoint;
283 }
284 else if (LC_LineMath::isNotMeaningfulDistance(wcsSnapCoordinate, endPoint)) {
285 const double angle2 = arc->getAngle2();
286 direction = angle2 + M_PI_21.57079632679489661923;
287 endpointToUse = endPoint;
288 }
289 else {
290 return;
291 }
292 // tangent
293 const RS_Vector second = endpointToUse.relative(g_rayDirectionOffset, direction);
294 double dist;
295
296 const auto tangent = tryCreateGuidingConstructionLine(wcsPos, endpointToUse, second, dist, direction,
297 RS2::VisualSnapGuideEntityType::VSNAP_LINE_ENDPOINT_TANGENT);
298 if (tangent != nullptr) {
299 solution.addGuidingEntity(tangent);
300 }
301
302 // normal
303 const auto center = arc->getCenter();
304 const auto lineToCenter = tryCreateGuidingConstructionLine(wcsPos, endpointToUse, center, dist,
305 RS2::VisualSnapGuideEntityType::VSNAP_LINE_ENDPOINT_NORMAL);
306 if (lineToCenter != nullptr) {
307 solution.addGuidingEntity(lineToCenter);
308 }
309}
310
311void LC_VisualSnapSolutionSolver::addTangentialAndNormalRaysFromArcEndpoint(const RS_Vector& wcsPos,
312 LC_VisualSnapSolution& solution) const {
313 // arc - tangents to endpoints points
314 solution.snapData->forEachVertex([this, wcsPos, &solution](LC_VisualSnapVertex* vertex) {
315 if (vertex->refArc != nullptr) {
316 LC_RefSnapArc* arc = vertex->refArc;
317 const auto wcsSnapCoordinate = vertex->wcsSnapCoordinate;
318 addTangentialAndNormlRaysForArcEndpoint(wcsPos, solution, wcsSnapCoordinate, arc);
319 }
320 });
321}
322
323void LC_VisualSnapSolutionSolver::addTangentialRayFromVertexToEntity(const RS_Vector& wcsPos,
324 std::vector<LC_VisualSnapPointHolder>& specialPointSnapCandidates,
325 LC_VisualSnapSolution& solution, const RS_Entity* entity,
326 const RS_Vector& vertexSnapCoord) const {
327 RS_Vector tangentPoint;
328 RS_Vector altTangentPoint;
329
330 const auto* tangentLine = RS_Creation::createTangent1(vertexSnapCoord, vertexSnapCoord, entity, tangentPoint, altTangentPoint);
331 if (tangentLine != nullptr) {
332 double dist;
333 auto line = tryCreateGuidingConstructionLine(wcsPos, vertexSnapCoord, tangentPoint, dist,
334 RS2::VisualSnapGuideEntityType::VSNAP_LINE_TANGENT1);
335 if (line != nullptr) {
336 solution.addGuidingEntity(line);
337 specialPointSnapCandidates.push_back(LC_VisualSnapPointHolder(tangentPoint, RS2::VisualSnapGuideEntityType::VSNAP_LINE_TANGENT1));
338 solution.addSnapCandidate(tangentPoint);
339 }
340 if (altTangentPoint.valid) {
341 line = tryCreateGuidingConstructionLine(wcsPos, vertexSnapCoord, altTangentPoint, dist,
342 RS2::VisualSnapGuideEntityType::VSNAP_LINE_TANGENT1);
343 if (line != nullptr) {
344 specialPointSnapCandidates.push_back(LC_VisualSnapPointHolder(altTangentPoint, RS2::VisualSnapGuideEntityType::VSNAP_LINE_TANGENT1));
345 solution.addGuidingEntity(line);
346 solution.addSnapCandidate(altTangentPoint);
347 }
348 }
349 delete tangentLine;
350 }
351}
352
353void LC_VisualSnapSolutionSolver::addTangentialRaysFromVertexesToArcs(const RS_Vector& wcsPos,
354 std::vector<LC_VisualSnapPointHolder>& specialPointSnapCandidates,
355 LC_VisualSnapSolution& solution) const {
356 clearVertexProcessedFlag(solution);
357 // tangent line from vertexes to arcs circles
358 solution.snapData->forEachDocRef([this,wcsPos, &solution, &specialPointSnapCandidates](LC_VisualSnapDocumentEntityRef* docRef) {
359 const auto ent = docRef->guidingEntity.get();
360 const RS2::EntityType type = ent->rtti();
361 RS_Vector vertexStart{false};
362 RS_Vector vertexEnd{false};
363 const RS_Entity* entity = nullptr;
364 if (type == RS2::EntitySnapArc) {
365 vertexStart = ent->getStartpoint();
366 vertexEnd = ent->getEndpoint();
367 entity = ent;
368 }
369 else if (type == RS2::EntitySnapCircle) {
370 entity = ent;
371 }
372 else {
373 return;
374 }
375
376 solution.snapData->forEachVertex(
377 [this,entity, vertexStart, vertexEnd, wcsPos, &solution, &specialPointSnapCandidates](LC_VisualSnapVertex* vertexInner) {
378 const auto vertexSnapCoord = vertexInner->wcsSnapCoordinate;
379 // avoid situation where endpoints of arc are vertexes and so additional tangents are created
380 if (LC_LineMath::isNotMeaningfulDistance(vertexSnapCoord, vertexStart) || LC_LineMath::isNotMeaningfulDistance(
381 vertexSnapCoord, vertexEnd)) {
382 return;
383 }
384 addTangentialRayFromVertexToEntity(wcsPos, specialPointSnapCandidates, solution, entity, vertexSnapCoord);
385 });
386 });
387}
388
389void LC_VisualSnapSolutionSolver::createTangentialBetwenTwoEntities(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
390 const RS_Entity* entityFirst, const RS_Entity* entitySecond,
391 std::vector<LC_VisualSnapPointHolder>& specialPointSnapCandidates,
392 RS2::VisualSnapGuideEntityType snapEntityType) const {
393 const std::vector<std::unique_ptr<RS_Line>> tangentLines = RS_Creation::createTangent2(entityFirst, entitySecond);
394 if (!tangentLines.empty()) {
395 for (const auto& l : tangentLines) {
396 double dist;
397 auto start = l->getStartpoint();
398 auto end = l->getEndpoint();
399 const auto line = tryCreateGuidingConstructionLine(wcsPos, start, end, dist, snapEntityType);
400 if (line != nullptr) {
401 solution.addGuidingEntity(line);
402 solution.addSnapCandidate(start); // snap middle
403 solution.addSnapCandidate(end);
404 specialPointSnapCandidates.push_back(LC_VisualSnapPointHolder(start, snapEntityType));
405 specialPointSnapCandidates.push_back(LC_VisualSnapPointHolder(end, snapEntityType));
406 }
407 }
408 }
409}
410
411void LC_VisualSnapSolutionSolver::addTangentialRaysBetwenCirclesArcs(const RS_Vector& wcsPos,
412 std::vector<LC_VisualSnapPointHolder>& specialPointSnapCandidates,
413 LC_VisualSnapSolution& solution) const {
414 clearDocumentProcessedFlag(solution);
415 // mutual tangents (arc-arc, arc-circle etc) - only for document entities
416 solution.snapData->forEachDocRef([this, wcsPos, &solution, &specialPointSnapCandidates](LC_VisualSnapDocumentEntityRef* docFirst) {
417 unsigned long long firstEntityId = docFirst->originalEntityId;
418 const auto entityFirst = docFirst->guidingEntity.get();
419 const RS2::EntityType type = entityFirst->rtti();
420 if (type == RS2::EntitySnapArc || type == RS2::EntitySnapCircle) {
421 docFirst->processed = true;
422 solution.snapData->forEachDocRef(
423 [this, wcsPos, &solution, &specialPointSnapCandidates, entityFirst, firstEntityId](LC_VisualSnapDocumentEntityRef* secondDocRef) {
424 if (secondDocRef->processed) {
425 return;
426 }
427 const unsigned long long secondEntityId = secondDocRef->originalEntityId;
428 if (firstEntityId == secondEntityId) {
429 return;
430 }
431 const auto ent = secondDocRef->guidingEntity.get();
432 if (ent == entityFirst) {
433 return;
434 }
435 const RS2::EntityType entityType = ent->rtti();
436 if (entityType == RS2::EntitySnapArc || entityType == RS2::EntitySnapCircle) {
437 createTangentialBetwenTwoEntities(wcsPos, solution, entityFirst, ent, specialPointSnapCandidates,
438 RS2::VisualSnapGuideEntityType::VSNAP_LINE_TANGENT2);
439 }
440 });
441 }
442 });
443}
444
445void LC_VisualSnapSolutionSolver::addExplicitlySetDistanceCircle(const RS_Vector& wcsPos, const RS_Vector& wcsCenter, double distanceWCS,
446 LC_VisualSnapSolution& solution) const {
447 const double distance = wcsCenter.distanceTo(wcsPos);
448 const double distanceDelta = std::abs(distance - distanceWCS);
449 const bool withinSnapRange = distanceDelta < m_wcsSnapRange;
450 if (withinSnapRange || m_options->showNotSnappableGuides) {
451 const auto circle = new LC_RefSnapCircle(wcsCenter, distanceWCS);
452 circle->setupForPoint(circle->getNearestPointOnEntity(wcsPos), RS2::VSNAP_POINT_DISTANCE_EXPLICIT, withinSnapRange);
453 solution.addGuidingEntity(circle);
454 }
455}
456
457void LC_VisualSnapSolutionSolver::addExplicitlySetDistanceCirclesForVertexes(const RS_Vector& wcsPos,
458 LC_VisualSnapSolution& solution) const {
459 // distances - radius from vertexes
460 const RS_SnapMode* snap = m_snapper->getSnapMode();
461 const bool useDistance = snap->snapDistance;
462 if (useDistance) {
463 const double distanceWCS = m_snapper->getSnapDistance();
464 solution.snapData->forEachVertex([this, wcsPos, distanceWCS, &solution](LC_VisualSnapVertex* vertex) {
465 const auto wcsSnapCoordinate = vertex->wcsSnapCoordinate;
466 addExplicitlySetDistanceCircle(wcsPos, wcsSnapCoordinate, distanceWCS, solution);
467 });
468 }
469}
470
471void LC_VisualSnapSolutionSolver::addVertexToVertexLines(const RS_Vector& wcsPos, std::vector<LC_VisualSnapPointHolder>& specialPointSnapCandidates,
472 LC_VisualSnapSolution& solution, const RS_Vector& firstVertexSnap,
473 const RS_Vector& innerVertexSnap) const {
474 // create vertex-vertex only if there is snap-middle?
475 double dist;
476 // create vertex-vertex line
477 const auto line = tryCreateVertexVertexLineAndOrthoLine(wcsPos, firstVertexSnap, innerVertexSnap, dist, solution);
478
479 if (line != nullptr) {
480 solution.addGuidingEntity(line);
481 int middlePoints = 2; // just default value for middle point (if no snap to middle)
482 const RS_SnapMode* snapMode = m_snapper->getSnapMode();
483 if (snapMode->snapMiddle) {
484 middlePoints = m_snapper->getSnapMiddlePoints();
485 // higlight possible snaps
486 const double lineLength = firstVertexSnap.distanceTo(innerVertexSnap);
487 const int segmentsCount = middlePoints + 1;
488 const double segmentLength = lineLength / segmentsCount;
489 const double lineAngle = firstVertexSnap.angleTo(innerVertexSnap);
490
491 for (int i = 1; i < segmentsCount; i++) {
492 const double distanceOnLine = segmentLength * i;
493 // if we're still within line, calculate snap point for tick on the line
494 RS_Vector snapPosition = firstVertexSnap.relative(distanceOnLine, lineAngle);
495 const double distance = snapPosition.distanceTo(wcsPos);
496 if (distance < m_wcsSnapRange) {
497 specialPointSnapCandidates.push_back(LC_VisualSnapPointHolder(snapPosition, RS2::VisualSnapGuideEntityType::VSNAP_POINT_MIDDLE));
498 }
499 solution.addSnapCandidate(snapPosition);
500 }
501 }
502 // add strict middle regardless snap to middle is enabled and if one is enabled, yet it is odd
503 const bool odd = middlePoints % 2 == 0;
504 if (odd) {
505 const RS_Vector actualMiddle = (firstVertexSnap + innerVertexSnap) / 2;
506 if (dist < m_wcsSnapRange) {
507 specialPointSnapCandidates.push_back(LC_VisualSnapPointHolder(actualMiddle, RS2::VisualSnapGuideEntityType::VSNAP_POINT_MIDDLE));
508 }
509 solution.addSnapCandidate(actualMiddle);
510 }
511 }
512 else {
513 delete line;
514 }
515}
516
517void LC_VisualSnapSolutionSolver::addVertexToVertexMutualDistanceCircles(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
518 const RS_Vector& firstVertexSnap,
519 const RS_Vector& innerVertexSnap) const {
520 if (m_options->createVertexVertexDistanceCircles) {
521 createDistanceCircle2Point(wcsPos, firstVertexSnap, innerVertexSnap, solution);
522 createDistanceCircle2Point(wcsPos, innerVertexSnap, firstVertexSnap, solution);
523 }
524}
525
526void LC_VisualSnapSolutionSolver::addVertexToVertexLinesAndDistances(const RS_Vector& wcsPos,
527 std::vector<LC_VisualSnapPointHolder>& specialPointSnapCandidates,
528 LC_VisualSnapSolution& solution) const {
529 clearVertexProcessedFlag(solution);
530 bool snapMiddle = m_snapper->getSnapMode()->snapMiddle;
531 bool snapDistance = m_snapper->getSnapMode()->snapDistance;
532 const bool snapCenter = m_snapper->getSnapMode()->snapCenter;
533 bool createVertexDistanceTangents = snapDistance && snapCenter && m_options->createVertexVertexDistanceCirclesTangents;
534 const double snapDistanceRadius = m_snapper->getSnapDistance();
535
536 auto circleFirst = RS_Circle(RS_CircleData(RS_Vector(0, 0), snapDistanceRadius));
537 auto circleSecond = RS_Circle(RS_CircleData(RS_Vector(0, 0), snapDistanceRadius));
538 // lines between marked points - and snap is on these lines
539 solution.snapData->forEachVertex(
540 [snapMiddle, wcsPos, &solution, &specialPointSnapCandidates, this, &circleFirst, &circleSecond, snapDistance,
541 createVertexDistanceTangents](LC_VisualSnapVertex* vertexFirst) {
542 vertexFirst->flagProcessed = true;
543 solution.snapData->forEachVertex(
544 [vertexFirst,snapMiddle, wcsPos, &solution, &specialPointSnapCandidates, this, &circleFirst, &circleSecond, snapDistance,
545 createVertexDistanceTangents](LC_VisualSnapVertex* vertexInner) {
546 if (vertexInner->flagProcessed) {
547 return;
548 }
549 const auto firstVertexSnap = vertexFirst->wcsSnapCoordinate;
550 const auto innerVertexSnap = vertexInner->wcsSnapCoordinate;
551
552 if (snapMiddle) {
553 addVertexToVertexLines(wcsPos, specialPointSnapCandidates, solution, firstVertexSnap, innerVertexSnap);
554 }
555
556 // create distance circles with radius equal to the distance between vertexes
557 if (snapDistance) {
558 addVertexToVertexMutualDistanceCircles(wcsPos, solution, firstVertexSnap, innerVertexSnap);
559 }
560 if (createVertexDistanceTangents) {
561 circleFirst.setCenter(firstVertexSnap);
562 circleSecond.setCenter(innerVertexSnap);
563 createTangentialBetwenTwoEntities(wcsPos, solution, &circleFirst, &circleSecond, specialPointSnapCandidates,
564 RS2::VisualSnapGuideEntityType::VSNAP_LINE_DISTANCE_TANGENT2);
565 }
566 });
567 });
568}
569
570void LC_VisualSnapSolutionSolver::addGuideEntitiesForDocumentEntity(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
571 LC_VisualSnapDocumentEntityRef* docEntityRef) const {
572 double dist;
573 if (docEntityRef->guidingEntity != nullptr) {
574 const auto entity = docEntityRef->guidingEntity.get();
575 RS_Vector v = entity->getNearestPointOnEntity(wcsPos, true, &dist);
Value stored to 'v' during its initialization is never read
576 const bool withinSnapRange = dist < m_wcsSnapRange;
577 if (withinSnapRange || m_options->showNotSnappableGuides) {
578 RS_Entity* clone = entity->clone();
579 solution.addGuidingEntity(clone, RS2::VisualSnapGuideEntityType::VSNAP_DOC_ENTITY);
580 }
581 const auto entityRtti = docEntityRef->guidingEntity->rtti();
582 if (entityRtti == RS2::EntitySnapLine) {
583 const auto& endpoint = entity->getEndpoint();
584 const auto& startPoint = entity->getStartpoint();
585 if (m_options->createAngleStepRaysForEntitiesEndpoints) {
586 tryAddRelativeRaysForStartAndEndPoints(wcsPos, startPoint, endpoint, solution);
587 }
588 const bool snapDistance = m_snapper->getSnapMode()->snapDistance;
589 if (snapDistance && m_options->createVertexVertexDistanceCircles) {
590 createDistanceCircle2Point(wcsPos, startPoint, endpoint, solution);
591 createDistanceCircle2Point(wcsPos, endpoint, startPoint, solution);
592 }
593 }
594 else if (entityRtti == RS2::EntitySnapArc) {
595 // fixme - review and complete - endpoints, normals, center
596 }
597 }
598}
599
600void LC_VisualSnapSolutionSolver::addGuideEntitiesByDocumentEntities(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution) const {
601 solution.snapData->forEachDocRef([this, wcsPos, &solution](LC_VisualSnapDocumentEntityRef* docEntityRef) {
602 addGuideEntitiesForDocumentEntity(wcsPos, solution, docEntityRef);
603 });
604}
605
606// todo - potentially, this function may be used not only for line entities - but also for rays between vertexes, and for endpoints of arcs...
607// todo - yet this may lead to graphical mess and may complicate snapping??
608void LC_VisualSnapSolutionSolver::tryAddRelativeRaysForStartAndEndPoints(const RS_Vector& wcsPos, const RS_Vector& startPoint,
609 const RS_Vector& endPoint, LC_VisualSnapSolution& solution) const {
610 // create angle step rays that are relative to the line (so 0 for such rays is the same as line direction).
611 // for relative rays we'll always show only snappable rays, otherwise it will be total graphical mess on the screen
612 const double wcsLineAngleRad = startPoint.angleTo(endPoint);
613 const double angleStepRad = m_snapper->getAngleStep();
614 const double wcsRaysStartAngle = m_viewport->toWorldAngle(angleStepRad + wcsLineAngleRad);
615 const double wcsRaysEndAngle = m_viewport->toWorldAngle(M_PI3.14159265358979323846 + wcsLineAngleRad);
616
617 double wcsAngle = wcsRaysStartAngle;
618 double minDistanceStartPoint = RS_MAXDOUBLE1.0E+10;
619 double minDistanceAngleStartPoint = RS_MAXDOUBLE1.0E+10;
620 LC_RefSnapConstructionLine* minDistanceRayStartPoint = nullptr;
621 double minDistanceEndPoint = RS_MAXDOUBLE1.0E+10;
622 double minDistanceAngleEndPoint = RS_MAXDOUBLE1.0E+10;
623 LC_RefSnapConstructionLine* minDistanceRayEndPoint = nullptr;
624 do {
625 // create rays for start point of line
626 double dist;
627 RS_Vector secondPointStart = startPoint.relative(g_rayDirectionOffset, wcsAngle);
628 const auto rayStart = tryCreateGuidingConstructionLine(wcsPos, startPoint, secondPointStart, dist, wcsAngle,
629 RS2::VisualSnapGuideEntityType::VSNAP_LINE_ENDPOINT_ANGLE_STEP);
630 if (rayStart != nullptr) {
631 if (dist < minDistanceStartPoint) {
632 delete minDistanceRayStartPoint;
633 minDistanceStartPoint = dist;
634 minDistanceRayStartPoint = rayStart;
635 minDistanceAngleStartPoint = wcsAngle;
636 }
637 else {
638 delete rayStart;
639 }
640 }
641
642 // create rays for end point of line
643 RS_Vector secondPointEnd = endPoint.relative(g_rayDirectionOffset, wcsAngle);
644 const auto rayEnd = tryCreateGuidingConstructionLine(wcsPos, endPoint, secondPointEnd, dist, wcsAngle,
645 RS2::VisualSnapGuideEntityType::VSNAP_LINE_ENDPOINT_ANGLE_STEP);
646 if (rayEnd != nullptr) {
647 if (dist < minDistanceEndPoint) {
648 delete minDistanceRayEndPoint;
649 minDistanceEndPoint = dist;
650 minDistanceRayEndPoint = rayEnd;
651 minDistanceAngleEndPoint = wcsAngle;
652 }
653 }
654 wcsAngle = wcsAngle + angleStepRad;
655 }
656 while (wcsAngle < wcsRaysEndAngle);
657
658 if (minDistanceRayStartPoint != nullptr) {
659 solution.addGuidingEntity(minDistanceRayStartPoint, minDistanceAngleStartPoint - wcsLineAngleRad);
660 }
661 if (minDistanceRayEndPoint != nullptr) {
662 solution.addGuidingEntity(minDistanceRayEndPoint, minDistanceAngleEndPoint - wcsLineAngleRad);
663 }
664}
665
666void LC_VisualSnapSolutionSolver::addNormalFromVertexToDocEntity(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution,
667 LC_VisualSnapVertex* vertex, LC_VisualSnapDocumentEntityRef* docEntityRef) const {
668 const unsigned long long vertexEntityId = vertex->entityId;
669 const unsigned long long secondEntityId = docEntityRef->originalEntityId;
670 if (vertexEntityId == secondEntityId) {
671 return;
672 }
673 double dist;
674 const auto guideEntity = docEntityRef->guidingEntity.get();
675 const auto nearestPointOnEntity = guideEntity->getNearestPointOnEntity(vertex->wcsSnapCoordinate, false, &dist);
676 if (LC_LineMath::isMeaningfulDistance(nearestPointOnEntity, vertex->wcsSnapCoordinate)) {
677 // additional check that vertex is not on entity
678 const auto normalLine = tryCreateGuidingConstructionLine(wcsPos, vertex->wcsSnapCoordinate, nearestPointOnEntity, dist,
679 RS2::VisualSnapGuideEntityType::VSNAP_LINE_VERTEX_ORTHO);
680 if (normalLine != nullptr) {
681 solution.addGuidingEntity(normalLine);
682 }
683 }
684}
685
686void LC_VisualSnapSolutionSolver::addNormalsFromVertexToEntities(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution) const {
687 solution.snapData->forEachVertex([wcsPos, &solution, this](LC_VisualSnapVertex* vertex) {
688 solution.snapData->forEachDocRef([wcsPos, &solution, vertex, this](LC_VisualSnapDocumentEntityRef* docEntityRef) {
689 addNormalFromVertexToDocEntity(wcsPos, solution, vertex, docEntityRef);
690 });
691 });
692}
693
694void LC_VisualSnapSolutionSolver::addRelativePositionEntities(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution, const LC_RelativePositionData& data) const {
695 if (data.valid) {
696 const auto projectionPoint = data.wcsProjection;
697 const auto basePoint = data.wcsBasePoint;
698 const double angle = data.wcsAngle;
699
700 if (data.explicitLength) {
701 const auto distanceCircle = new LC_RefSnapCircle(basePoint, data.length);
702 const auto nearestPoint = distanceCircle->getNearestPointOnEntity(wcsPos);
703 const double wcsDistance = nearestPoint.distanceTo(wcsPos);
704 const bool withinSnapRange = wcsDistance < m_wcsSnapRange;
705 distanceCircle->setupForPoint(nearestPoint, RS2::VSNAP_POINT_RELATIVE_DISTANCE, withinSnapRange);
706 solution.addGuidingEntity(distanceCircle);
707 }
708
709 const double wcsAngleToBasePoint = projectionPoint.angleTo(basePoint);
710 if (data.explicitAngle) {
711 createAndAddGuidingConstructionLine(wcsPos, basePoint, projectionPoint, RS2::VSNAP_POINT_RELATIVE_ANGLE_RAY, solution,
712 wcsAngleToBasePoint);
713 }
714
715 if (data.showLengthNormal) {
716 const RS_Vector normal = projectionPoint.relative(g_rayDirectionOffset, angle + M_PI_21.57079632679489661923);
717 createAndAddGuidingConstructionLine(wcsPos, projectionPoint, normal, RS2::VSNAP_POINT_RELATIVE_NORMAL, solution,
718 wcsAngleToBasePoint);
719 }
720
721 if (data.explicitDX) {
722 const auto horizontalPoint = m_viewport->restrictVertical(projectionPoint,
723 RS_Vector(projectionPoint.x,
724 projectionPoint.y + g_rayDirectionOffset));
725
726 createAndAddGuidingConstructionLine(wcsPos, projectionPoint, horizontalPoint, RS2::VSNAP_POINT_RELATIVE_VERTICAL_DX,
727 solution, wcsAngleToBasePoint);
728 }
729
730 if (data.explicitDY) {
731 const auto verticalPoint = m_viewport->restrictHorizontal(projectionPoint,
732 RS_Vector(projectionPoint.x + g_rayDirectionOffset,
733 projectionPoint.y));
734 createAndAddGuidingConstructionLine(wcsPos, projectionPoint, verticalPoint, RS2::VSNAP_POINT_RELATIVE_HORIZONTAL_DY,
735 solution, wcsAngleToBasePoint);
736 }
737 }
738}
739
740void LC_VisualSnapSolutionSolver::addRelativePositionsEntities(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution) const {
741 solution.snapData->forEachRelativePosition([this, wcsPos, &solution](const LC_RelativePositionData& data) {
742 addRelativePositionEntities(wcsPos, solution, data);
743 });
744}
745
746void LC_VisualSnapSolutionSolver::addOrdinaryRestrictionLines(const RS_Vector& wcsPos, LC_VisualSnapSolution& solution) const {
747 const RS_SnapMode* snapMode = m_snapper->getSnapMode();
748 const RS_Vector relZero = m_snapper->getRelativeZero();
749 double dist;
750 switch (snapMode->restriction) {
751 case RS2::RestrictOrthogonal: {
752 const auto lineVert = new LC_RefSnapConstructionLine(relZero,
753 m_viewport->restrictVertical(relZero, relZero + g_rayDirectionOffset));
754 auto nearestPointOnEntity = lineVert->getNearestPointOnEntity(wcsPos, false, &dist);
755 lineVert->setupForPoint(nearestPointOnEntity, RS2::VSNAP_LINE_RESTR_VERTICAL, false, M_PI_21.57079632679489661923);
756 solution.addGuidingEntity(lineVert);
757
758 const auto lineHor = new LC_RefSnapConstructionLine(relZero,
759 m_viewport->restrictHorizontal(relZero, relZero + g_rayDirectionOffset));
760
761 nearestPointOnEntity = lineHor->getNearestPointOnEntity(wcsPos, false, &dist);
762 lineHor->setupForPoint(nearestPointOnEntity, RS2::VSNAP_LINE_RESTR_HORIZONTAL, false, 0);
763 solution.addGuidingEntity(lineHor);
764 break;
765 }
766 case RS2::RestrictHorizontal: {
767 const auto lineHor = new LC_RefSnapConstructionLine(relZero,
768 m_viewport->restrictHorizontal(relZero, relZero + g_rayDirectionOffset));
769 const auto nearestPointOnEntity = lineHor->getNearestPointOnEntity(wcsPos, false, &dist);
770 lineHor->setupForPoint(nearestPointOnEntity, RS2::VSNAP_LINE_RESTR_HORIZONTAL, false, 0);
771 solution.addGuidingEntity(lineHor);
772 break;
773 }
774 case RS2::RestrictVertical: {
775 const auto lineVert = new LC_RefSnapConstructionLine(relZero,
776 m_viewport->restrictVertical(relZero, relZero + g_rayDirectionOffset));
777 const auto nearestPointOnEntity = lineVert->getNearestPointOnEntity(wcsPos, false, &dist);
778 lineVert->setupForPoint(nearestPointOnEntity, RS2::VSNAP_LINE_RESTR_VERTICAL, false, M_PI_21.57079632679489661923);
779 solution.addGuidingEntity(lineVert);
780 break;
781 }
782 default: {
783 break;
784 }
785 }
786}
787
788void LC_VisualSnapSolutionSolver::createDistanceCircle2Point(const RS_Vector& wcsPos, const RS_Vector& centerPoint,
789 const RS_Vector& circlePoint, LC_VisualSnapSolution& solution) const {
790 const double distanceBetweenVertexes = centerPoint.distanceTo(circlePoint);
791 const double distanceFromFirstToMouse = centerPoint.distanceTo(wcsPos);
792 const double distanceDelta = std::abs(distanceBetweenVertexes - distanceFromFirstToMouse);
793 const bool withinSnapRange = distanceDelta < m_wcsSnapRange;
794 if (withinSnapRange || m_options->showNotSnappableGuides) {
795 // mouse is close to circle
796 const auto circle = new LC_RefSnapCircle(centerPoint, distanceBetweenVertexes);
797 circle->setupForPoint(circlePoint, RS2::VSNAP_POINT_DISTANCE_VERTEX, withinSnapRange);
798 solution.addGuidingEntity(circle);
799 }
800}
801
802LC_RefSnapConstructionLine* LC_VisualSnapSolutionSolver::tryCreateGuidingConstructionLine(const RS_Vector& wcsPos, const RS_Vector& start,
803 const RS_Vector& end, double& dist,
804 double wcsLineAngle,
805 RS2::VisualSnapGuideEntityType guideType) const {
806 const auto line = new LC_RefSnapConstructionLine(start, end);
807 const auto nearestPointOnEntity = line->getNearestPointOnEntity(wcsPos, false, &dist);
808 const double wcsDistance = nearestPointOnEntity.distanceTo(wcsPos);
809 const bool withinSnapRange = wcsDistance < m_wcsSnapRange;
810 if (withinSnapRange || m_options->showNotSnappableGuides) {
811 line->setupForPoint(nearestPointOnEntity, guideType, withinSnapRange, wcsLineAngle);
812 return line;
813 }
814 delete line;
815 return nullptr;
816}
817
818LC_RefSnapConstructionLine* LC_VisualSnapSolutionSolver::tryCreateGuidingConstructionLine(const RS_Vector& wcsPos, const RS_Vector& start,
819 const RS_Vector& end, double& dist,
820 RS2::VisualSnapGuideEntityType guideType) const {
821 const auto line = new LC_RefSnapConstructionLine(start, end);
822 const auto nearestPointOnEntity = line->getNearestPointOnEntity(wcsPos, false, &dist);
823 const double wcsDistance = nearestPointOnEntity.distanceTo(wcsPos);
824 const bool withinSnapRange = wcsDistance < m_wcsSnapRange;
825 if (withinSnapRange || m_options->showNotSnappableGuides) {
826 const double wcsAngle = start.angleTo(end);
827 line->setupForPoint(nearestPointOnEntity, guideType, withinSnapRange, wcsAngle);
828 return line;
829 }
830 delete line;
831 return nullptr;
832}
833
834LC_RefSnapConstructionLine* LC_VisualSnapSolutionSolver::tryCreateVertexVertexLineAndOrthoLine(
835 const RS_Vector& wcsPos, const RS_Vector& start, const RS_Vector& end, double& dist, LC_VisualSnapSolution& solution) const {
836 const auto line = new LC_RefSnapConstructionLine(start, end);
837 const auto nearestPointOnEntity = line->getNearestPointOnEntity(wcsPos, false, &dist);
838 const double wcsDistance = nearestPointOnEntity.distanceTo(wcsPos);
839 const bool withinSnapRange = wcsDistance < m_wcsSnapRange;
840 const double wcsLineAngle = start.angleTo(end);
841 bool includeLine = false;
842 if (withinSnapRange || m_options->showNotSnappableGuides) {
843 line->setupForPoint(nearestPointOnEntity, RS2::VSNAP_LINE_VERTEX_VERTEX, withinSnapRange, wcsLineAngle);
844 includeLine = true;
845 }
846
847 // try to build ortho line from previous snapped point to vertex-vertex line
848 const RS_Vector basePoint = solution.previousSnapPoint;
849 if (basePoint.valid && LC_LineMath::isMeaningfulDistance(basePoint, start) && LC_LineMath::isMeaningfulDistance(basePoint, end)) {
850 // check that base point does not lie on vertex-vertex line
851 double distFormBase;
852 const auto pointOnLine = line->getNearestPointOnEntity(basePoint, false, &distFormBase);
853 if (LC_LineMath::isMeaningful(distFormBase)) {
854 const double wcsNormalAngle = wcsLineAngle + M_PI_21.57079632679489661923;
855 const auto normalLine = new LC_RefSnapConstructionLine(basePoint, pointOnLine);
856 double distanceToNormal;
857 const auto nearestPointOnNormal = normalLine->getNearestPointOnEntity(wcsPos, false, &distanceToNormal);
858 const double wcsNormalDistance = nearestPointOnNormal.distanceTo(wcsPos);
859 const bool normalWithinSnapRange = wcsNormalDistance < m_wcsSnapRange;
860 if (normalWithinSnapRange || m_options->showNotSnappableGuides) {
861 normalLine->setupForPoint(nearestPointOnNormal, RS2::VSNAP_LINE_VERTEX_VERTEX_ORTHO, withinSnapRange, wcsNormalAngle);
862 solution.addGuidingEntity(normalLine);
863 }
864 else {
865 delete normalLine;
866 }
867 }
868 }
869 if (includeLine) {
870 return line;
871 }
872
873 delete line;
874 return nullptr;
875}
876
877void LC_VisualSnapSolutionSolver::createAndAddGuidingConstructionLine(const RS_Vector& wcsPos, const RS_Vector& start, const RS_Vector& end,
878 RS2::VisualSnapGuideEntityType guideType,
879 LC_VisualSnapSolution& solution, double wcsAngleToBasePoint) const {
880 const auto verticalRay = new LC_RefSnapConstructionLine(start, end);
881 const auto nearestPoint = verticalRay->getNearestPointOnEntity(wcsPos);
882 const double wcsDistance = nearestPoint.distanceTo(wcsPos);
883 const bool withinSnapRange = wcsDistance < m_wcsSnapRange;
884 verticalRay->setupForPoint(nearestPoint, guideType, withinSnapRange, wcsAngleToBasePoint);
885 solution.addGuidingEntity(verticalRay);
886}
887
888LC_RefSnapLine* LC_VisualSnapSolutionSolver::tryCreateCloseSnapLine(const RS_Vector& wcsPos, const RS_Vector& start, const RS_Vector& end,
889 double& dist, RS2::VisualSnapGuideEntityType guideType) const {
890 const auto line = new LC_RefSnapLine(start, end);
891 const auto nearestPointOnEntity = line->getNearestPointOnEntity(wcsPos, false, &dist);
892 const double wcsDistance = nearestPointOnEntity.distanceTo(wcsPos);
893 const bool withinSnapRange = wcsDistance < m_wcsSnapRange;
894 if (withinSnapRange || m_options->showNotSnappableGuides) {
895 const double wcsAngle = start.angleTo(end);
896 line->setupForPoint(nearestPointOnEntity, guideType, withinSnapRange, wcsAngle);
897 return line;
898 }
899 delete line;
900 return nullptr;
901}
902
903bool LC_VisualSnapSolutionSolver::hasNoLinesForPoints(const LC_VisualSnapSolution& solution, const RS_Vector& endPoint, const RS_Vector& startPoint) const {
904 bool noLines = true;
905 // ensure that line rays it not created already for another endpoint of line
906 for (const auto guide : solution.guidingEntities) {
907 if (LC_LineMath::isNotMeaningfulDistance(startPoint, guide.entity->getStartpoint())) {
908 if (LC_LineMath::isNotMeaningfulDistance(endPoint, guide.entity->getEndpoint())) {
909 noLines = false;
910 break;
911 }
912 }
913 }
914 return noLines;
915}
916
917bool LC_VisualSnapSolutionSolver::hasNoLinesForPoint(const LC_VisualSnapSolution& solution, const RS_Vector& point,
918 RS2::VisualSnapGuideEntityType guideType) const {
919 bool noLines = true;
920 // ensure that line rays it not created already for another endpoint of line
921 for (const auto guide : solution.guidingEntities) {
922 const auto snapEntity = dynamic_cast<const LC_RefSnapEntity*>(guide.entity);
923 if (snapEntity->getGuideType() == guideType) {
924 if (LC_LineMath::isNotMeaningfulDistance(point, guide.entity->getStartpoint()) || LC_LineMath::isNotMeaningfulDistance(
925 point, guide.entity->getEndpoint())) {
926 noLines = false;
927 break;
928 }
929 }
930 }
931 return noLines;
932}