1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
7 **
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file gpl-2.0.txt included in the
12 ** packaging of this file.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 **
23 ** This copyright notice MUST APPEAR in all copies of the script!
24 **
25 **********************************************************************/
26 #include<cmath>
27 #include <QAction>
28 #include <QMouseEvent>
29 #include "rs_actiondrawellipseaxis.h"
30
31 #include "rs_dialogfactory.h"
32 #include "rs_graphicview.h"
33 #include "rs_commandevent.h"
34 #include "rs_ellipse.h"
35 #include "rs_line.h"
36 #include "rs_coordinateevent.h"
37 #include "rs_math.h"
38 #include "rs_preview.h"
39 #include "rs_debug.h"
40
41 struct RS_ActionDrawEllipseAxis::Points {
42 /** Center of ellipse */
43 RS_Vector center;
44 /** Endpoint of major axis */
45 RS_Vector m_vMajorP;
46 /** Ratio major / minor */
47 double ratio;
48 /** Start angle */
49 double angle1;
50 /** End angle */
51 double angle2;
52 /** Do we produce an arc (true) or full ellipse (false) */
53 bool isArc;
54 };
55
56 /**
57 * Constructor.
58 *
59 * @param isArc true if this action will produce an ellipse arc.
60 * false if it will produce a full ellipse.
61 */
RS_ActionDrawEllipseAxis(RS_EntityContainer & container,RS_GraphicView & graphicView,bool isArc)62 RS_ActionDrawEllipseAxis::RS_ActionDrawEllipseAxis(
63 RS_EntityContainer& container,
64 RS_GraphicView& graphicView,
65 bool isArc)
66 :RS_PreviewActionInterface("Draw ellipse with axis",
67 container, graphicView)
68 ,pPoints(new Points{{}, {}, 0.5, 0., isArc?2.*M_PI:0., isArc})
69 {
70 actionType=isArc?RS2::ActionDrawEllipseArcAxis:RS2::ActionDrawEllipseAxis;
71 }
72
73 RS_ActionDrawEllipseAxis::~RS_ActionDrawEllipseAxis() = default;
74
75
init(int status)76 void RS_ActionDrawEllipseAxis::init(int status) {
77 RS_PreviewActionInterface::init(status);
78
79 if (status==SetCenter) {
80 pPoints->center = {};
81 }
82 if (status<=SetMajor) {
83 pPoints->m_vMajorP = {};
84 }
85 if (status<=SetMinor) {
86 pPoints->ratio = 0.5;
87 }
88 if (status<=SetAngle1) {
89 pPoints->angle1 = 0.0;
90 }
91 if (status<=SetAngle2) {
92 pPoints->angle2 = 0.0;
93 }
94 }
95
96
97
trigger()98 void RS_ActionDrawEllipseAxis::trigger() {
99 RS_PreviewActionInterface::trigger();
100
101 RS_Ellipse* ellipse = new RS_Ellipse{container,
102 {pPoints->center, pPoints->m_vMajorP, pPoints->ratio,
103 pPoints->angle1, pPoints->angle2, false}
104 };
105 if (pPoints->ratio > 1.){
106 ellipse->switchMajorMinor();
107 }
108 ellipse->setLayerToActive();
109 ellipse->setPenToActive();
110
111 container->addEntity(ellipse);
112
113 // upd. undo list:
114 if (document) {
115 document->startUndoCycle();
116 document->addUndoable(ellipse);
117 document->endUndoCycle();
118 }
119
120 RS_Vector rz = graphicView->getRelativeZero();
121 graphicView->redraw(RS2::RedrawDrawing);
122 graphicView->moveRelativeZero(rz);
123 drawSnapper();
124
125 setStatus(SetCenter);
126
127 RS_DEBUG->print("RS_ActionDrawEllipseAxis::trigger():"
128 " entity added: %d", ellipse->getId());
129 }
130
131
132
mouseMoveEvent(QMouseEvent * e)133 void RS_ActionDrawEllipseAxis::mouseMoveEvent(QMouseEvent* e) {
134 RS_DEBUG->print("RS_ActionDrawEllipseAxis::mouseMoveEvent begin");
135
136 RS_Vector mouse = snapPoint(e);
137
138 switch (getStatus()) {
139 // case SetCenter:
140 // break;
141
142 case SetMajor:
143 if (pPoints->center.valid) {
144 deletePreview();
145 preview->addEntity(new RS_Ellipse{preview.get(),
146 {pPoints->center, mouse-pPoints->center, 0.5, 0.0,
147 pPoints->isArc?2.*M_PI:0.
148 , false}});
149 drawPreview();
150 }
151 break;
152
153 case SetMinor:
154 if (pPoints->center.valid && pPoints->m_vMajorP.valid) {
155 deletePreview();
156 RS_Line line{pPoints->center-pPoints->m_vMajorP, pPoints->center+pPoints->m_vMajorP};
157 double d = line.getDistanceToPoint(mouse);
158 pPoints->ratio = d/(line.getLength()/2);
159 preview->addEntity(new RS_Ellipse{preview.get(),
160 {pPoints->center, pPoints->m_vMajorP, pPoints->ratio, 0., pPoints->isArc?2.*M_PI:0.
161 , false}});
162 drawPreview();
163 }
164 break;
165
166 case SetAngle1:
167 if (pPoints->center.valid && pPoints->m_vMajorP.valid) {
168 deletePreview();
169
170 //angle1 = center.angleTo(mouse);
171
172 RS_Vector m = mouse;
173 m.rotate(pPoints->center, -pPoints->m_vMajorP.angle());
174 RS_Vector v = m-pPoints->center;
175 v.y /= pPoints->ratio;
176 pPoints->angle1 = v.angle(); // + m_vMajorP.angle();
177
178 preview->addEntity(new RS_Line{preview.get(), pPoints->center, mouse});
179
180 preview->addEntity(new RS_Ellipse{preview.get(),
181 {pPoints->center, pPoints->m_vMajorP, pPoints->ratio, pPoints->angle1, pPoints->angle1+1.0
182 , false}});
183 drawPreview();
184 }
185 break;
186
187 case SetAngle2:
188 if (pPoints->center.valid && pPoints->m_vMajorP.valid) {
189 deletePreview();
190 //angle2 = center.angleTo(mouse);
191
192 RS_Vector m = mouse;
193 m.rotate(pPoints->center, -pPoints->m_vMajorP.angle());
194 RS_Vector v = m-pPoints->center;
195 v.y /= pPoints->ratio;
196 pPoints->angle2 = v.angle(); // + m_vMajorP.angle();
197
198 preview->addEntity(new RS_Line{preview.get(), pPoints->center, mouse});
199
200 preview->addEntity(new RS_Ellipse{preview.get(),
201 {pPoints->center, pPoints->m_vMajorP,
202 pPoints->ratio,
203 pPoints->angle1, pPoints->angle2
204 , false}});
205 drawPreview();
206 }
207
208 default:
209 break;
210 }
211
212 RS_DEBUG->print("RS_ActionDrawEllipseAxis::mouseMoveEvent end");
213 }
214
215
216
mouseReleaseEvent(QMouseEvent * e)217 void RS_ActionDrawEllipseAxis::mouseReleaseEvent(QMouseEvent* e) {
218 // Proceed to next status
219 if (e->button()==Qt::LeftButton) {
220 RS_CoordinateEvent ce(snapPoint(e));
221 coordinateEvent(&ce);
222 }
223
224 // Return to last status:
225 else if (e->button()==Qt::RightButton) {
226 deletePreview();
227 init(getStatus()-1);
228 }
229 }
230
231
coordinateEvent(RS_CoordinateEvent * e)232 void RS_ActionDrawEllipseAxis::coordinateEvent(RS_CoordinateEvent* e) {
233 if (!e) return;
234 RS_Vector const& mouse = e->getCoordinate();
235
236 switch (getStatus()) {
237 case SetCenter:
238 pPoints->center = mouse;
239 graphicView->moveRelativeZero(mouse);
240 setStatus(SetMajor);
241 break;
242
243 case SetMajor:
244 pPoints->m_vMajorP = mouse- pPoints->center;
245 setStatus(SetMinor);
246 break;
247
248 case SetMinor: {
249 RS_Line line{pPoints->center-pPoints->m_vMajorP, pPoints->center+pPoints->m_vMajorP};
250 double d = line.getDistanceToPoint(mouse);
251 pPoints->ratio = d/(line.getLength()/2);
252 if (!pPoints->isArc) {
253 trigger();
254 setStatus(SetCenter);
255 } else {
256 setStatus(SetAngle1);
257 }
258 }
259 break;
260
261 case SetAngle1: {
262 //angle1 = center.angleTo(mouse);
263 RS_Vector m = mouse;
264 m.rotate(pPoints->center, -pPoints->m_vMajorP.angle());
265 RS_Vector v = m-pPoints->center;
266 v.y /= pPoints->ratio;
267 pPoints->angle1 = v.angle();
268 setStatus(SetAngle2);
269 } break;
270
271 case SetAngle2: {
272 //angle2 = center.angleTo(mouse);
273 RS_Vector m = mouse;
274 m.rotate(pPoints->center, -pPoints->m_vMajorP.angle());
275 RS_Vector v = m-pPoints->center;
276 v.y /= pPoints->ratio;
277 pPoints->angle2 = v.angle();
278 trigger();
279 }
280 break;
281
282 default:
283 break;
284 }
285 }
286
287
288
commandEvent(RS_CommandEvent * e)289 void RS_ActionDrawEllipseAxis::commandEvent(RS_CommandEvent* e) {
290 QString c = e->getCommand().toLower();
291
292 if (checkCommand("help", c)) {
293 RS_DIALOGFACTORY->commandMessage(msgAvailableCommands()
294 + getAvailableCommands().join(", "));
295 return;
296 }
297
298 switch (getStatus()) {
299 case SetMinor: {
300 bool ok;
301 double m = RS_Math::eval(c, &ok);
302 if (ok) {
303 e->accept();
304 pPoints->ratio = m / pPoints->m_vMajorP.magnitude();
305 if (!pPoints->isArc) {
306 trigger();
307 } else {
308 setStatus(SetAngle1);
309 }
310 } else
311 RS_DIALOGFACTORY->commandMessage(tr("Not a valid expression"));
312 }
313 break;
314
315 case SetAngle1: {
316 bool ok;
317 double a = RS_Math::eval(c, &ok);
318 if (ok) {
319 e->accept();
320 pPoints->angle1 = RS_Math::deg2rad(a);
321 setStatus(SetAngle2);
322 } else
323 RS_DIALOGFACTORY->commandMessage(tr("Not a valid expression"));
324 }
325 break;
326
327 case SetAngle2: {
328 bool ok;
329 double a = RS_Math::eval(c, &ok);
330 if (ok) {
331 e->accept();
332 pPoints->angle2 = RS_Math::deg2rad(a);
333 trigger();
334 } else
335 RS_DIALOGFACTORY->commandMessage(tr("Not a valid expression"));
336 }
337 break;
338
339 default:
340 break;
341 }
342 }
343
344
345
getAvailableCommands()346 QStringList RS_ActionDrawEllipseAxis::getAvailableCommands() {
347 QStringList cmd;
348 return cmd;
349 }
350
351
352
updateMouseButtonHints()353 void RS_ActionDrawEllipseAxis::updateMouseButtonHints() {
354 switch (getStatus()) {
355 case SetCenter:
356 RS_DIALOGFACTORY->updateMouseWidget(tr("Specify ellipse center"),
357 tr("Cancel"));
358 break;
359
360 case SetMajor:
361 RS_DIALOGFACTORY->updateMouseWidget(tr("Specify endpoint of major axis"),
362 tr("Back"));
363 break;
364
365 case SetMinor:
366 RS_DIALOGFACTORY->updateMouseWidget(
367 tr("Specify endpoint or length of minor axis:"),
368 tr("Back"));
369 break;
370
371 case SetAngle1:
372 RS_DIALOGFACTORY->updateMouseWidget(tr("Specify start angle"),
373 tr("Back"));
374 break;
375
376 case SetAngle2:
377 RS_DIALOGFACTORY->updateMouseWidget(tr("Specify end angle"),
378 tr("Back"));
379 break;
380
381 default:
382 RS_DIALOGFACTORY->updateMouseWidget();
383 break;
384 }
385 }
386
387
388
updateMouseCursor()389 void RS_ActionDrawEllipseAxis::updateMouseCursor() {
390 graphicView->setMouseCursor(RS2::CadCursor);
391 }
392
393 // EOF
394