My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
arrow.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  arrow.cpp
3  -----------
4  begin : Sun Nov 23 2003
5  copyright : (C) 2003 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "arrow.h"
19 #include "arrowdialog.h"
20 
21 #include <qlineedit.h>
22 #include <qpushbutton.h>
23 #include <qcombobox.h>
24 
25 #include <math.h>
26 
27 
29 {
30  Name = "Arrow ";
31  isSelected = false;
32  Pen = QPen(QColor());
33  cx = cy = 0;
34  x1 = x2 = 0;
35  y1 = y2 = 0;
36 
37  Height = 20.0;
38  Width = 8.0;
39  Style = 0; // arrow head not filled
40  beta = atan2(double(Width), double(Height));
42 }
43 
45 {
46 }
47 
48 // --------------------------------------------------------------------------
50 {
51  QPointArray Points;
52  int x1_, y1_, x2_, y2_, x3_, y3_;
53  if(isSelected) {
54  p->Painter->setPen(QPen(QPen::darkGray,Pen.width()+5));
55  p->drawLine(cx, cy, cx+x2, cy+y2);
56  p->drawLine(cx+x2, cy+y2, cx+xp1, cy+yp1);
57  p->drawLine(cx+x2, cy+y2, cx+xp2, cy+yp2);
58  if(Style == 0) { // arrow head with two lines ?
59  p->Painter->setPen(QPen(QPen::white, Pen.width(), Pen.style()));
60  p->drawLine(cx, cy, cx+x2, cy+y2);
61  p->Painter->setPen(QPen(QPen::white, Pen.width(), Qt::SolidLine));
62  p->drawLine(cx+x2, cy+y2, cx+xp1, cy+yp1);
63  p->drawLine(cx+x2, cy+y2, cx+xp2, cy+yp2);
64  }
65  else { // filled arrow head
66  p->drawLine(cx+xp1, cy+yp1, cx+xp2, cy+yp2);
67  p->Painter->setPen(QPen(QPen::white, Pen.width(), Pen.style()));
68  p->drawLine(cx, cy, cx+x2, cy+y2);
69 
70  p->Painter->setPen(QPen(QPen::white, Pen.width(), Qt::SolidLine));
71  p->Painter->setBrush(QPen::white);
72  p->map(cx+xp1, cy+yp1, x1_, y1_);
73  p->map(cx+x2, cy+y2, x2_, y2_);
74  p->map(cx+xp2, cy+yp2, x3_, y3_);
75  Points.setPoints(3, x1_, y1_, x2_, y2_, x3_, y3_);
76  p->Painter->drawConvexPolygon(Points);
77  p->Painter->setBrush(QBrush::NoBrush); // no filling for next paintings
78  }
79 
80  p->Painter->setPen(QPen(QPen::darkRed,2));
81  p->drawResizeRect(cx, cy); // markers for changing the size
82  p->drawResizeRect(cx+x2, cy+y2);
83  return;
84  }
85  p->Painter->setPen(Pen);
86  p->drawLine(cx, cy, cx+x2, cy+y2);
87  p->Painter->setPen(QPen(Pen.color(), Pen.width(), Qt::SolidLine));
88  if(Style == 0) { // arrow head with two lines ?
89  p->drawLine(cx+x2, cy+y2, cx+xp1, cy+yp1);
90  p->drawLine(cx+x2, cy+y2, cx+xp2, cy+yp2);
91  }
92  else { // filled arrow head
93  p->Painter->setBrush(Pen.color());
94  p->map(cx+xp1, cy+yp1, x1_, y1_);
95  p->map(cx+x2, cy+y2, x2_, y2_);
96  p->map(cx+xp2, cy+yp2, x3_, y3_);
97  Points.setPoints(3, x1_, y1_, x2_, y2_, x3_, y3_);
98  p->Painter->drawConvexPolygon(Points);
99  p->Painter->setBrush(QBrush::NoBrush); // no filling for next paintings
100  }
101 }
102 
103 // --------------------------------------------------------------------------
104 void Arrow::paintScheme(QPainter *p)
105 {
106  p->drawLine(cx, cy, cx+x2, cy+y2);
107  p->drawLine(cx+x2, cy+y2, cx+xp1, cy+yp1);
108  p->drawLine(cx+x2, cy+y2, cx+xp2, cy+yp2);
109 }
110 
111 // --------------------------------------------------------------------------
112 void Arrow::getCenter(int& x, int &y)
113 {
114  x = cx+(x2>>1);
115  y = cy+(y2>>1);
116 }
117 
118 // --------------------------------------------------------------------------
119 // Sets the center of the painting to x/y.
120 void Arrow::setCenter(int x, int y, bool relative)
121 {
122  if(relative) { cx += x; cy += y; }
123  else { cx = x-(x2>>1); cy = y-(y2>>1); }
124 }
125 
126 // --------------------------------------------------------------------------
128 {
129  return new Arrow();
130 }
131 
132 // --------------------------------------------------------------------------
133 Element* Arrow::info(QString& Name, char* &BitmapFile, bool getNewOne)
134 {
135  Name = QObject::tr("Arrow");
136  BitmapFile = (char *) "arrow";
137 
138  if(getNewOne) return new Arrow();
139  return 0;
140 }
141 
142 // --------------------------------------------------------------------------
143 bool Arrow::load(const QString& s)
144 {
145  bool ok;
146 
147  QString n;
148  n = s.section(' ',1,1); // cx
149  cx = n.toInt(&ok);
150  if(!ok) return false;
151 
152  n = s.section(' ',2,2); // cy
153  cy = n.toInt(&ok);
154  if(!ok) return false;
155 
156  n = s.section(' ',3,3); // x2
157  x2 = n.toInt(&ok);
158  if(!ok) return false;
159 
160  n = s.section(' ',4,4); // y2
161  y2 = n.toInt(&ok);
162  if(!ok) return false;
163 
164  n = s.section(' ',5,5); // height
165  Height = n.toDouble(&ok);
166  if(!ok) return false;
167 
168  n = s.section(' ',6,6); // width
169  Width = n.toDouble(&ok);
170  if(!ok) return false;
171 
172  n = s.section(' ',7,7); // color
173  QColor co;
174  co.setNamedColor(n);
175  Pen.setColor(co);
176  if(!Pen.color().isValid()) return false;
177 
178  n = s.section(' ',8,8); // thickness
179  Pen.setWidth(n.toInt(&ok));
180  if(!ok) return false;
181 
182  n = s.section(' ',9,9); // line style
183  Pen.setStyle((Qt::PenStyle)n.toInt(&ok));
184  if(!ok) return false;
185 
186  n = s.section(' ',10,10); // arrow style
187  if(!n.isEmpty()) { // backward compatible
188  Style = n.toInt(&ok);
189  if(!ok) return false;
190  }
191 
192  beta = atan2(double(Width), double(Height));
194  calcArrowHead();
195  return true;
196 }
197 
198 // --------------------------------------------------------------------------
199 QString Arrow::save()
200 {
201  QString s = Name+QString::number(cx)+" "+QString::number(cy)+" ";
202  s += QString::number(x2)+" "+QString::number(y2)+" ";
203  s += QString::number(int(Height))+" "+QString::number(int(Width))+" ";
204  s += Pen.color().name()+" "+QString::number(Pen.width())+" ";
205  s += QString::number(Pen.style()) + " " + QString::number(Style);
206  return s;
207 }
208 
209 // --------------------------------------------------------------------------
210 QString Arrow::saveCpp()
211 {
212  // arrow not allowed in symbols, thus we use line here
213  QString s =
214  QString ("new Line (%1, %2, %3, %4, QPen (QColor (\"%5\"), %6, %7))").
215  arg(cx+x1).arg(cy+y1).arg(cx+x2).arg(cy+y2).
216  arg(Pen.color().name()).arg(Pen.width()).arg(toPenString(Pen.style()));
217  s = "Lines.append (" + s + ");";
218  return s;
219 }
220 
221 // --------------------------------------------------------------------------
222 // Checks if the resize area was clicked.
223 bool Arrow::resizeTouched(float fX, float fY, float len)
224 {
225  float fCX = float(cx),fCY = float(cy);
226  if(fX < fCX+len) if(fX > fCX-len) if(fY < fCY+len) if(fY > fCY-len) {
227  State = 1;
228  return true;
229  }
230 
231  fCX += float(x2);
232  fCY += float(y2);
233  if(fX < fCX+len) if(fX > fCX-len) if(fY < fCY+len) if(fY > fCY-len) {
234  State = 2;
235  return true;
236  }
237 
238  State = 0;
239  return false;
240 }
241 
242 // --------------------------------------------------------------------------
243 // Mouse move action during resize.
244 void Arrow::MouseResizeMoving(int x, int y, QPainter *p)
245 {
246  paintScheme(p); // erase old painting
247  if(State == 1) { x2 += cx-x; y2 += cy-y; cx = x; cy = y; } // moving shaft
248  else { x2 = x-cx; y2 = y-cy; } // moving head
249 
250  calcArrowHead();
251  paintScheme(p); // paint new painting
252 }
253 
254 // --------------------------------------------------------------------------
256 {
257  double phi = atan2(double(y2), double(x2));
258 
259  double w = beta+phi;
260  xp1 = x2-int(Length*cos(w));
261  yp1 = y2-int(Length*sin(w));
262 
263  w = phi-beta;
264  xp2 = x2-int(Length*cos(w));
265  yp2 = y2-int(Length*sin(w));
266 }
267 
268 // --------------------------------------------------------------------------
269 // fx/fy are the precise coordinates, gx/gy are the coordinates set on grid.
270 // x/y are coordinates without scaling.
272  QPainter *paintScale, int, int, int gx, int gy,
273  QPainter *p, int x, int y, bool drawn)
274 {
275  if(State > 0) {
276  if(State > 1) {
277  calcArrowHead();
278  paintScheme(paintScale); // erase old painting
279  }
280  State++;
281  x2 = gx-cx;
282  y2 = gy-cy;
283  calcArrowHead();
284  paintScheme(paintScale); // paint new painting
285  }
286  else { cx = gx; cy = gy; }
287 
288 
289  p->setPen(Qt::SolidLine);
290  if(drawn) {
291  p->drawLine(x1+25, y1, x1+13, y1+12); // erase old cursor symbol
292  p->drawLine(x1+18, y1+2, x1+25, y1);
293  p->drawLine(x1+23, y1+7, x1+25, y1);
294  }
295  x1 = x;
296  y1 = y;
297  p->drawLine(x1+25, y1, x1+13, y1+12); // paint new cursor symbol
298  p->drawLine(x1+18, y1+2, x1+25, y1);
299  p->drawLine(x1+23, y1+7, x1+25, y1);
300 }
301 
302 // --------------------------------------------------------------------------
304 {
305  State++;
306  if(State > 2) {
307  x1 = y1 = 0;
308  State = 0;
309 
310  calcArrowHead();
311  return true; // painting is ready
312  }
313  return false;
314 }
315 
316 // --------------------------------------------------------------------------
317 // Checks if the coordinates x/y point to the painting.
318 // 5 is the precision the user must point onto the painting.
319 bool Arrow::getSelected(float fX, float fY, float w)
320 {
321  float A, xn, yn;
322  // first check if coordinates match the arrow body
323  fX -= float(cx);
324  fY -= float(cy);
325 
326  if(fX < -w) {
327  if(fX < float(x2)-w) // is point between x coordinates ?
328  goto Head1;
329  }
330  else {
331  if(fX > w)
332  if(fX > float(x2)+w)
333  goto Head1;
334  }
335 
336  if(fY < -w) {
337  if(fY < float(y2)-w) // is point between y coordinates ?
338  goto Head1;
339  }
340  else {
341  if(fY > w)
342  if(fY > float(y2)+w)
343  goto Head1;
344  }
345 
346  A = float(x2)*fY - fX*float(y2); // calculate the rectangle area spanned
347  A *= A; // avoid the need for square root
348 
349  if(A <= w*w*float(x2*x2 + y2*y2))
350  return true; // x/y lies on the graph line
351 
352 Head1: // check if coordinates match the first arrow head line
353  xn = float(xp1-x2); fX -= float(x2);
354  yn = float(yp1-y2); fY -= float(y2);
355 
356  if(fX < -w) {
357  if(fX < xn-w) // is point between x coordinates ?
358  goto Head2;
359  }
360  else {
361  if(fX > w)
362  if(fX > xn+w)
363  goto Head2;
364  }
365 
366  if(fY < -w) {
367  if(fY < yn-w) // is point between y coordinates ?
368  goto Head2;
369  }
370  else
371  if(fY > w)
372  if(fY > yn+w)
373  goto Head2;
374 
375  A = xn*fY - fX*yn; // calculate the rectangle area spanned
376  A *= A; // avoid the need for square root
377 
378  if(A <= w*w*(xn*xn + yn*yn))
379  return true; // x/y lies on the arrow head
380 
381 Head2: // check if coordinates match the second arrow head line
382  xn = float(xp2-x2);
383  yn = float(yp2-y2);
384 
385  if(fX < -w) {
386  if(fX < xn-w) // is point between x coordinates ?
387  return false;
388  }
389  else
390  if(fX > w)
391  if(fX > xn+w)
392  return false;
393 
394  if(fY < -w) {
395  if(fY < yn-w) // is point between y coordinates ?
396  return false;
397  }
398  else
399  if(fY > w)
400  if(fY > yn+w)
401  return false;
402 
403  A = xn*fY - fX*yn; // calculate the rectangle area spanned
404  A *= A; // avoid the need for square root
405 
406  if(A <= w*w*(xn*xn + yn*yn))
407  return true; // x/y lies on the arrow head
408 
409  return false;
410 }
411 
412 // --------------------------------------------------------------------------
413 void Arrow::Bounding(int& _x1, int& _y1, int& _x2, int& _y2)
414 {
415  if(x2 < 0) { _x1 = cx+x2; _x2 = cx; }
416  else { _x1 = cx; _x2 = cx+x2; }
417 
418  if(y2 < 0) { _y1 = cy+y2; _y2 = cy; }
419  else { _y1 = cy; _y2 = cy+y2; }
420 }
421 
422 // --------------------------------------------------------------------------
423 // Rotates around the center.
425 {
426  cx += (x2>>1) - (y2>>1);
427  cy += (x2>>1) + (y2>>1);
428 
429  int tmp = x2;
430  x2 = y2;
431  y2 = -tmp;
432 
433  tmp = xp1;
434  xp1 = yp1;
435  yp1 = -tmp;
436 
437  tmp = xp2;
438  xp2 = yp2;
439  yp2 = -tmp;
440 }
441 
442 // --------------------------------------------------------------------------
443 // Mirrors about center line.
445 {
446  yp1 = -yp1;
447  yp2 = -yp2;
448  cy += y2; // change cy after the other changes !
449  y2 = -y2;
450 }
451 
452 // --------------------------------------------------------------------------
453 // Mirrors about center line.
455 {
456  xp1 = -xp1;
457  xp2 = -xp2;
458  cx += x2; // change cx after the other changes !
459  x2 = -x2;
460 }
461 
462 // --------------------------------------------------------------------------
463 // Calls the property dialog for the painting and changes them accordingly.
464 // If there were changes, it returns 'true'.
466 {
467  bool changed = false;
468 
469  ArrowDialog *d = new ArrowDialog();
470  d->HeadWidth->setText(QString::number(Width));
471  d->HeadLength->setText(QString::number(Height));
472  d->ColorButt->setPaletteBackgroundColor(Pen.color());
473  d->LineWidth->setText(QString::number(Pen.width()));
474  d->SetComboBox(Pen.style());
475  d->ArrowStyleBox->setCurrentItem(Style);
476 
477  if(d->exec() == QDialog::Rejected) {
478  delete d;
479  return false;
480  }
481 
482  if(Width != d->HeadWidth->text().toDouble()) {
483  Width = d->HeadWidth->text().toDouble();
484  changed = true;
485  }
486  if(Height != d->HeadLength->text().toDouble()) {
487  Height = d->HeadLength->text().toDouble();
488  changed = true;
489  }
490  if(Pen.color() != d->ColorButt->paletteBackgroundColor()) {
491  Pen.setColor(d->ColorButt->paletteBackgroundColor());
492  changed = true;
493  }
494  if(Pen.width() != d->LineWidth->text().toUInt()) {
495  Pen.setWidth(d->LineWidth->text().toUInt());
496  changed = true;
497  }
498  if(Pen.style() != d->LineStyle) {
499  Pen.setStyle(d->LineStyle);
500  changed = true;
501  }
502  if(Style != d->ArrowStyleBox->currentItem()) {
503  Style = d->ArrowStyleBox->currentItem();
504  changed = true;
505  }
506 
507  beta = atan2(double(Width), double(Height));
509  calcArrowHead();
510 
511  delete d;
512  return changed;
513 }