~librecad-dev/librecad/librecad

1 by Scott Howard
first commit
1
/****************************************************************************
2
**
3
 * Draw circle by foci and a point on circle
4
5
Copyright (C) 2012 Dongxu Li (dongxuli2011@gmail.com)
6
Copyright (C) 2011 R. van Twisk (librecad@rvt.dds.nl)
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
#include "rs_actiondrawcircletan2_1p.h"
24
25
#include <QAction>
26
#include "rs_dialogfactory.h"
27
#include "rs_graphicview.h"
28
#include "rs_commandevent.h"
29
#include "rs_arc.h"
30
#include "rs_circle.h"
31
#include "lc_quadratic.h"
32
33
/**
34
 * Constructor.
35
 *
36
 */
37
RS_ActionDrawCircleTan2_1P::RS_ActionDrawCircleTan2_1P(
38
        RS_EntityContainer& container,
39
        RS_GraphicView& graphicView)
40
    :RS_PreviewActionInterface("Draw tangent circle 2P",
41
                               container, graphicView),
42
      cData(RS_Vector(0.,0.),1.),
43
      enTypeList()
44
{
45
    //    supported types
46
    enTypeList<<RS2::EntityLine<<RS2::EntityArc<<RS2::EntityCircle;
47
}
48
49
50
51
RS_ActionDrawCircleTan2_1P::~RS_ActionDrawCircleTan2_1P() {
52
}
53
54
55
56
QAction* RS_ActionDrawCircleTan2_1P::createGUIAction(RS2::ActionType /*type*/, QObject* /*parent*/) {
57
    QAction* action;
58
59
    action = new QAction(tr("Common Tangential Circle 1 Point"), NULL);
60
    action->setIcon(QIcon(":/extui/circletan2_1p.png"));
61
    return action;
62
}
63
64
void RS_ActionDrawCircleTan2_1P::init(int status) {
65
    RS_PreviewActionInterface::init(status);
66
    if(status>=0) {
67
        RS_Snapper::suspend();
68
    }
69
70
    if (status<=SetCircle2) {
71
        bool updateNeeded(false);
72
        if(circles.size()>=2 && circles[1]!=NULL) {
73
            if(circles[1]->isHighlighted()){
74
                circles[1]->setHighlighted(false);
75
                updateNeeded=true;
76
            }
77
        }
78
        if(status<= SetCircle1 && circles.size()>=1&&circles[0]!=NULL) {
79
            if(circles[0]->isHighlighted()){
80
                circles[0]->setHighlighted(false);
81
                updateNeeded=true;
82
            }
83
        }
84
        if(updateNeeded) graphicView->redraw(RS2::RedrawDrawing);
85
        circles.clear();
86
    }
87
}
88
89
90
void RS_ActionDrawCircleTan2_1P::finish(bool updateTB){
91
    if( circles.size() >0) {
92
        foreach(RS_AtomicEntity* circle, circles)
93
            circle->setHighlighted(false);
94
        graphicView->redraw(RS2::RedrawDrawing);
95
    }
96
    RS_PreviewActionInterface::finish(updateTB);
97
}
98
99
//void RS_ActionDrawCircleTan2_1P::finish(bool updateTB){
100
////    for(int i=0;i<circles.size();i++) circles[i]->setHighlighted(false);
101
////    graphicView->redraw(RS2::RedrawDrawing);
102
////    circles.clear();
103
//    RS_PreviewActionInterface::finish(updateTB);
104
//}
105
106
107
void RS_ActionDrawCircleTan2_1P::trigger() {
108
    //    std::cout<<__FILE__<<" : "<<__FUNCTION__<<" : line "<<__LINE__<<std::endl;
109
    //    std::cout<<"begin"<<std::endl;
110
111
    RS_PreviewActionInterface::trigger();
112
113
114
    RS_Circle* c=new RS_Circle(container, cData);
115
116
    container->addEntity(c);
117
118
    // upd. undo list:
119
    if (document!=NULL) {
120
        document->startUndoCycle();
121
        document->addUndoable(c);
122
        document->endUndoCycle();
123
    }
124
125
126
    foreach(RS_AtomicEntity* circle, circles)
127
        circle->setHighlighted(false);
128
    graphicView->redraw(RS2::RedrawDrawing);
129
    circles.clear();
130
131
132
    RS_DEBUG->print("RS_ActionDrawCircleTan2_1P::trigger():"
133
                    " entity added: %d", c->getId());
134
    init(SetCircle1);
135
}
136
137
138
bool RS_ActionDrawCircleTan2_1P::getCenters()
139
{
140
    if(circles.size()<2) return false;
141
    LC_Quadratic lc0(circles[0], point);
142
    LC_Quadratic lc1(circles[1], point);
143
144
    auto&& list=LC_Quadratic::getIntersection(lc0,lc1);
145
    centers.clean();
146
    for(unsigned int i=0;i<list.size();i++){
147
        auto&& vp=list.get(i);
148
        auto&& ds=vp.distanceTo(point)-RS_TOLERANCE;
149
        bool validBranch(true);
150
        for(int j=0;j<2;j++){
151
            if(circles[j]->rtti()==RS2::EntityCircle||circles[j]->rtti()==RS2::EntityArc){
152
                if( vp.distanceTo(circles[j]->getCenter()) <= ds) {
153
                    validBranch=false;
154
                    break;
155
                }
156
            }
157
        }
158
        if(validBranch)  centers.push_back(vp);
159
    }
160
    return centers.size()>0;
161
}
162
163
void RS_ActionDrawCircleTan2_1P::mouseMoveEvent(QMouseEvent* e) {
164
    RS_DEBUG->print("RS_ActionDrawCircleTan2_1P::mouseMoveEvent begin");
165
166
    switch( getStatus()){
167
    case SetPoint:
168
        coord=snapPoint(e);
169
        point=coord;
170
        break;
171
    case SetCenter:
172
        coord=graphicView->toGraph(e->x(),e->y());
173
        break;
174
    default:
175
        return;
176
    }
177
    deletePreview();
178
    if(preparePreview()){
179
        RS_Circle* e=new RS_Circle(preview, cData);
180
        preview->addEntity(e);
181
        drawPreview();
182
    }
183
    RS_DEBUG->print("RS_ActionDrawCircleTan2_1P::mouseMoveEvent end");
184
}
185
186
//void RS_ActionDrawCircleTan2_1P::setRadius(const double& r)
187
//{
188
//    cData.radius=r;
189
//    if(getStatus() == SetPoint2){
190
//        RS_Circle c(NULL,cData);
191
//        centers=c.createTan2_1P(circle,cData.radius);
192
//    }
193
//}
194
195
bool RS_ActionDrawCircleTan2_1P::preparePreview(){
196
    if( getCenters() ==false) return false;
197
//    for(int i=0;i<centers.size();i++){
198
//        double ds2=(centers[i]-point).squared();
199
//        if( (centers[i]-circles[0]).squared()<ds2
200
//    }
201
    cData.center=centers.getClosest(coord);
202
    cData.radius=point.distanceTo(cData.center);
203
    return true;
204
}
205
206
RS_Entity* RS_ActionDrawCircleTan2_1P::catchCircle(QMouseEvent* e) {
207
    RS_Entity* ret=NULL;
208
    RS_Entity*  en = catchEntity(e,enTypeList, RS2::ResolveAll);
209
    if(en == NULL) return ret;
210
    if(en->isVisible()==false) return ret;
211
    for(int i=0;i<getStatus();i++) {
212
        if(en->getId() == circles[i]->getId()) return ret; //do not pull in the same line again
213
    }
214
    if(en->getParent() != NULL) {
215
        if ( en->getParent()->rtti() == RS2::EntityInsert         /**Insert*/
216
             || en->getParent()->rtti() == RS2::EntitySpline
217
             || en->getParent()->rtti() == RS2::EntityMText        /**< Text 15*/
218
             || en->getParent()->rtti() == RS2::EntityText         /**< Text 15*/
219
             || en->getParent()->rtti() == RS2::EntityDimAligned   /**< Aligned Dimension */
220
             || en->getParent()->rtti() == RS2::EntityDimLinear    /**< Linear Dimension */
221
             || en->getParent()->rtti() == RS2::EntityDimRadial    /**< Radial Dimension */
222
             || en->getParent()->rtti() == RS2::EntityDimDiametric /**< Diametric Dimension */
223
             || en->getParent()->rtti() == RS2::EntityDimAngular   /**< Angular Dimension */
224
             || en->getParent()->rtti() == RS2::EntityDimLeader    /**< Leader Dimension */
225
             ){
226
            return ret;
227
        }
228
    }
229
    return en;
230
}
231
232
void RS_ActionDrawCircleTan2_1P::mouseReleaseEvent(QMouseEvent* e) {
233
    // Proceed to next status
234
    if (e->button()==Qt::LeftButton) {
235
236
        switch (getStatus()) {
237
        case SetCircle1:
238
        case SetCircle2:
239
        {
240
            circles.resize(getStatus());
241
            RS_AtomicEntity*  en = static_cast<RS_AtomicEntity*>(catchCircle(e));
242
            if (en==NULL) return;
243
//            circle = static_cast<RS_AtomicEntity*>(en);
244
            en->setHighlighted(true);
245
            circles<<en;
246
            graphicView->redraw(RS2::RedrawDrawing);
247
            setStatus(getStatus()+1);
248
        }
249
            break;
250
        case SetPoint:
251
        {
252
            RS_Vector snapped = snapPoint(e);
253
            RS_CoordinateEvent ce(snapped);
254
            coordinateEvent(&ce);
255
        }
256
            break;
257
        case SetCenter:
258
            coord=graphicView->toGraph(e->x(),e->y());
259
            if(preparePreview()) trigger();
260
            break;
261
262
        default:
263
            break;
264
        }
265
    } else if (e->button()==Qt::RightButton) {
266
        // Return to last status:
267
        if(getStatus()>0){
268
            deletePreview();
269
        }
270
        init(getStatus()-1);
271
    }
272
}
273
274
275
void RS_ActionDrawCircleTan2_1P::coordinateEvent(RS_CoordinateEvent* e) {
276
277
    RS_Vector mouse = e->getCoordinate();
278
    switch(getStatus()){
279
280
    case SetPoint:
281
        point=mouse;
282
        coord=mouse;
283
        if(getCenters()) {
284
            if(centers.size()==1) trigger();
285
            else setStatus(getStatus()+1);
286
        }
287
        break;
288
        default:
289
        break;
290
//    case SetCenter:
291
//        coord=mouse;
292
//        trigger();
293
    }
294
295
}
296
297
//fixme, support command line
298
299
/*
300
void RS_ActionDrawCircleTan2_1P::commandEvent(RS_CommandEvent* e) {
301
    QString c = e->getCommand().toLower();
302
303
    if (checkCommand("help", c)) {
304
        if (RS_DIALOGFACTORY!=NULL) {
305
            RS_DIALOGFACTORY->commandMessage(msgAvailableCommands()
306
                                             + getAvailableCommands().join(", "));
307
        }
308
        return;
309
    }
310
311
    switch (getStatus()) {
312
    case SetFocus1: {
313
            bool ok;
314
            double m = RS_Math::eval(c, &ok);
315
            if (ok==true) {
316
                ratio = m / major.magnitude();
317
                if (!isArc) {
318
                    trigger();
319
                } else {
320
                    setStatus(SetAngle1);
321
                }
322
            } else {
323
                if (RS_DIALOGFACTORY!=NULL) {
324
                    RS_DIALOGFACTORY->commandMessage(tr("Not a valid expression"));
325
                }
326
            }
327
        }
328
        break;
329
330
    case SetAngle1: {
331
            bool ok;
332
            double a = RS_Math::eval(c, &ok);
333
            if (ok==true) {
334
                angle1 = RS_Math::deg2rad(a);
335
                setStatus(SetAngle2);
336
            } else {
337
                if (RS_DIALOGFACTORY!=NULL) {
338
                    RS_DIALOGFACTORY->commandMessage(tr("Not a valid expression"));
339
                }
340
            }
341
        }
342
        break;
343
344
    case SetAngle2: {
345
            bool ok;
346
            double a = RS_Math::eval(c, &ok);
347
            if (ok==true) {
348
                angle2 = RS_Math::deg2rad(a);
349
                trigger();
350
            } else {
351
                if (RS_DIALOGFACTORY!=NULL) {
352
                    RS_DIALOGFACTORY->commandMessage(tr("Not a valid expression"));
353
                }
354
            }
355
        }
356
        break;
357
358
    default:
359
        break;
360
    }
361
}
362
*/
363
364
365
//void RS_ActionDrawCircleTan2_1P::showOptions() {
366
//    RS_DEBUG->print("RS_ActionDrawCircleTan2_1P::showOptions");
367
//    if(RS_DIALOGFACTORY != NULL){
368
//        RS_ActionInterface::showOptions();
369
370
//        RS_DIALOGFACTORY->requestOptions(this, true);
371
//    }
372
//    RS_DEBUG->print("RS_ActionDrawCircleTan2_1P::showOptions: OK");
373
//}
374
375
376
377
//void RS_ActionDrawCircleTan2_1P::hideOptions() {
378
//    if(RS_DIALOGFACTORY != NULL){
379
//        RS_ActionInterface::hideOptions();
380
381
//        RS_DIALOGFACTORY->requestOptions(this, false);
382
//    }
383
//}
384
385
386
QStringList RS_ActionDrawCircleTan2_1P::getAvailableCommands() {
387
    QStringList cmd;
388
    return cmd;
389
}
390
391
392
393
void RS_ActionDrawCircleTan2_1P::updateMouseButtonHints() {
394
    if (RS_DIALOGFACTORY!=NULL) {
395
        switch (getStatus()) {
396
        case SetCircle1:
397
            RS_DIALOGFACTORY->updateMouseWidget(tr("Specify a line/arc/circle"),
398
                                                tr("Cancel"));
399
            break;
400
401
        case SetCircle2:
402
            RS_DIALOGFACTORY->updateMouseWidget(tr("Specify the another arc/circle"),
403
                                                tr("Back"));
404
            break;
405
406
        case SetPoint:
407
            RS_DIALOGFACTORY->updateMouseWidget(tr("Specify a point on the tangent circle"),
408
                                                tr("Back"));
409
            break;
410
        case SetCenter:
411
            RS_DIALOGFACTORY->updateMouseWidget(tr("Select the center of the tangent circle"),
412
                                                tr("Back"));
413
            break;
414
        default:
415
            RS_DIALOGFACTORY->updateMouseWidget("", "");
416
            break;
417
        }
418
    }
419
}
420
421
422
423
void RS_ActionDrawCircleTan2_1P::updateMouseCursor() {
424
    graphicView->setMouseCursor(RS2::CadCursor);
425
}
426
427
428
429
//void RS_ActionDrawCircleTan2_1P::updateToolBar() {
430
//    if (RS_DIALOGFACTORY!=NULL) {
431
//        if (isFinished()) {
432
//            RS_DIALOGFACTORY->resetToolBar();
433
//        }
434
//    }
435
//}
436
437
// EOF