From 11802354d1ddc5bc571d83d8fc9b600618cb4372 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Sun, 4 Aug 2013 19:54:44 -0500 Subject: [PATCH] Added ability to edit grid unit in base units, work on Dimension. Basically, the Dimension object now has a thickness based on its size. Also, it will correctly move the arrowheads to outside of the extension lines if there is not enough room to draw them. Added Parameter() class method to Vector to facilitate this. :-) --- src/applicationwindow.cpp | 21 +++++++++++++++ src/applicationwindow.h | 1 + src/dimension.cpp | 55 ++++++++++++++++++++------------------ src/drawingview.cpp | 56 +++++++++++---------------------------- src/painter.cpp | 23 +++------------- src/vector.cpp | 44 +++++++++++++++++++++++++++++- src/vector.h | 1 + 7 files changed, 114 insertions(+), 87 deletions(-) diff --git a/src/applicationwindow.cpp b/src/applicationwindow.cpp index 03f8cb5..96b13ca 100644 --- a/src/applicationwindow.cpp +++ b/src/applicationwindow.cpp @@ -469,6 +469,22 @@ void ApplicationWindow::HandleGridSizeInPixels(int size) } +void ApplicationWindow::HandleGridSizeInBaseUnits(QString text) +{ + // Parse the text... + bool ok; + double value = text.toDouble(&ok); + + // Nothing parsable to a double, so quit... + if (!ok) + return; + + drawing->gridSpacing = value; + Painter::zoom = drawing->gridPixels / drawing->gridSpacing; + drawing->update(); +} + + void ApplicationWindow::CreateActions(void) { exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."), @@ -630,8 +646,11 @@ void ApplicationWindow::CreateToolbars(void) toolbar->setObjectName("View"); toolbar->addAction(zoomInAct); toolbar->addAction(zoomOutAct); + QSpinBox * spinbox = new QSpinBox; toolbar->addWidget(spinbox); + QLineEdit * lineedit = new QLineEdit; + toolbar->addWidget(lineedit); toolbar = addToolBar(tr("Edit")); toolbar->setObjectName("Edit"); @@ -650,7 +669,9 @@ void ApplicationWindow::CreateToolbars(void) spinbox->setRange(4, 256); spinbox->setValue(12); + lineedit->setText("12"); connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int))); + connect(lineedit, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString))); } diff --git a/src/applicationwindow.h b/src/applicationwindow.h index 89fb9aa..f20cd35 100644 --- a/src/applicationwindow.h +++ b/src/applicationwindow.h @@ -43,6 +43,7 @@ class ApplicationWindow: public QMainWindow void Settings(void); void HandleGrouping(void); void HandleGridSizeInPixels(int); + void HandleGridSizeInBaseUnits(QString); private: void ClearUIToolStatesExcept(QAction *); diff --git a/src/dimension.cpp b/src/dimension.cpp index 8b930f0..203e26f 100644 --- a/src/dimension.cpp +++ b/src/dimension.cpp @@ -56,7 +56,10 @@ Dimension::~Dimension() if (state == OSSelected) painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine)); else - painter->SetPen(QPen(Qt::blue, 1.0, Qt::SolidLine)); +// painter->SetPen(QPen(Qt::blue, 1.0, Qt::SolidLine)); + painter->SetPen(QPen(Qt::blue, 1.0 * Painter::zoom * size, Qt::SolidLine)); + + painter->SetBrush(QBrush(QColor(Qt::blue))); // Draw an aligned dimension line double angle = Vector(endpoint - position).Angle(); @@ -64,21 +67,11 @@ Dimension::~Dimension() Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle)); Vector unit = Vector(endpoint - position).Unit(); -#if 0 -//NOTE: SCREEN_ZOOM is our kludge factor... We need to figure out a better -// way of doing this... - // Get our line parallel to our points - Point p1 = position + (orthogonal * 10.0 * SCREEN_ZOOM); - Point p2 = endpoint + (orthogonal * 10.0 * SCREEN_ZOOM); - - // Draw main dimension line - painter->DrawLine(p1, p2); +// Arrowhead: +// Point p1 = head - (unit * 9.0 * size); +// Point p2 = p1 + (orthogonal * 3.0 * size); +// Point p3 = p1 - (orthogonal * 3.0 * size); - Point p3 = position + (orthogonal * 16.0 * SCREEN_ZOOM); - Point p4 = endpoint + (orthogonal * 16.0 * SCREEN_ZOOM); - Point p5 = position + (orthogonal * 4.0 * SCREEN_ZOOM); - Point p6 = endpoint + (orthogonal * 4.0 * SCREEN_ZOOM); -#else /* The numbers hardcoded into here, what are they? I believe they are pixels. @@ -88,32 +81,42 @@ I believe they are pixels. Point p1 = position + (orthogonal * 10.0 * size); Point p2 = endpoint + (orthogonal * 10.0 * size); - // Draw main dimension line - painter->DrawLine(p1, p2); - Point p3 = position + (orthogonal * 16.0 * size); Point p4 = endpoint + (orthogonal * 16.0 * size); Point p5 = position + (orthogonal * 4.0 * size); Point p6 = endpoint + (orthogonal * 4.0 * size); -#endif // Draw extension lines painter->DrawLine(p3, p5); painter->DrawLine(p4, p6); - painter->SetBrush(QBrush(QColor(Qt::blue))); -// painter->DrawArrowhead(p1, p2); -// painter->DrawArrowhead(p2, p1); - painter->DrawArrowhead(p1, p2, size); - painter->DrawArrowhead(p2, p1, size); + // Calculate whether or not the arrowheads are too crowded to put inside + // the extension lines. 9.0 is the length of the arrowhead. + double t = Vector::Parameter(position, endpoint, endpoint - (unit * 9.0 * size)); +//printf("Dimension::Draw(): t = %lf\n", t); + + if (t > 0.5) + { + // Draw main dimension line + arrowheads + painter->DrawLine(p1, p2); + painter->DrawArrowhead(p1, p2, size); + painter->DrawArrowhead(p2, p1, size); + } + else + { + Point p7 = p1 - (unit * 9.0 * size); + Point p8 = p2 + (unit * 9.0 * size); + painter->DrawArrowhead(p1, p7, size); + painter->DrawArrowhead(p2, p8, size); + painter->DrawLine(p1, p1 - (unit * 14.0 * size)); + painter->DrawLine(p2, p2 + (unit * 14.0 * size)); + } // Draw length of dimension line... -// painter->SetFont(QFont("Arial", 10.0 * Painter::zoom * SCREEN_ZOOM)); painter->SetFont(QFont("Arial", 10.0 * Painter::zoom * size)); Vector v1((p1.x - p2.x) / 2.0, (p1.y - p2.y) / 2.0); Point ctr = p2 + v1; QString dimText = QString("%1\"").arg(Vector(endpoint - position).Magnitude()); -// painter->DrawAngledText(ctr, angle, dimText); painter->DrawAngledText(ctr, angle, dimText, size); } diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 06f4496..8f689a8 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -221,15 +221,11 @@ void DrawingView::SetGridSize(uint32_t size) void DrawingView::UpdateGridBackground(void) { -//was: 128 -//#define BG_BRUSH_SPAN 72 -#define BG_BRUSH_SPAN (gridPixels) // Transform the origin to Qt coordinates Vector pixmapOrigin = Painter::CartesianToQtCoords(Vector()); int x = (int)pixmapOrigin.x; int y = (int)pixmapOrigin.y; // Use mod arithmetic to grab the correct swatch of background - // Problem with mod 128: Negative numbers screw it up... [FIXED] /* Negative numbers still screw it up... Need to think about what we're trying to do here. The fact that it worked with 72 seems to have been pure luck. @@ -268,51 +264,33 @@ Which means we need to grab the sample from x = 3. @ x = -1: | | | | Which means we need to grab the sample from x = 1. Which means we have to take -the inverse of the modulus of gridPixels. +the mirror of the modulus of gridPixels. Doing a mod of a negative number is problematic: 1st, the compiler converts the negative number to an unsigned int, then it does the mod. Gets you wrong answers -most of the time, unless you use a power of 2. :-P - -This has been solved below: -UGB: pmo=(2.000000,687.000000) X=2, X%48=2, new x=45 -UGB: pmo=(1.000000,687.000000) X=1, X%48=1, new x=46 -UGB: pmo=(0.000000,687.000000) X=0, X%48=0, new x=47 -UGB: pmo=(-1.000000,687.000000) X=-1, X%48=15, new x=1 -UGB: pmo=(-2.000000,686.000000) X=-2, X%48=14, new x=2 -UGB: pmo=(-3.000000,686.000000) X=-3, X%48=13, new x=3 - -Problem with changing grid size causes x/y origin to be shown incorrectly: -UGB: pmo=(10.000000,812.000000) X=10, X%12=10, new x=2 -UGB: pmo=(10.000000,812.000000) X=10, X%4=2, new x=2 -UGB: pmo=(3.333333,818.666667) X=3, X%48=3, new x=45 -UGB: pmo=(39.000000,782.000000) X=39, X%48=39, new x=9 <-- MMB move is here -UGB: pmo=(39.000000,781.000000) X=39, X%48=39, new x=9 - - - +most of the time, unless you use a power of 2. :-P So what we do here is just +take the modulus of the negation, which means we don't have to worry about +mirroring it later. + +The positive case looks gruesome (and it is) but it boils down to this: We take +the modulus of the X coordinate, then mirror it by subtraction from the +maximum (in this case, gridPixels). This gives us a number in the range of 1 to +gridPixels. But we need the case where the result equalling gridPixels to be +zero; so we do another modulus operation on the result to achieve this. */ -//printf("UGB: pmo=(%f,%f) X=%i, X%%%i=%i, ", pixmapOrigin.x, pixmapOrigin.y, x, BG_BRUSH_SPAN, x % BG_BRUSH_SPAN); -// x = (x < 0 ? 0 : BG_BRUSH_SPAN - 1) - (x % BG_BRUSH_SPAN); -// y = (y < 0 ? 0 : BG_BRUSH_SPAN - 1) - (y % BG_BRUSH_SPAN); -// x = (BG_BRUSH_SPAN - 1) - (x % BG_BRUSH_SPAN); -// y = (BG_BRUSH_SPAN - 1) - (y % BG_BRUSH_SPAN); -// x = (x < 0 ? 0 : BG_BRUSH_SPAN - 1) - ((x < 0 ? -x : x) % BG_BRUSH_SPAN); if (x < 0) - x = -x % BG_BRUSH_SPAN; + x = -x % gridPixels; else - x = (BG_BRUSH_SPAN - (x % BG_BRUSH_SPAN)) % BG_BRUSH_SPAN; + x = (gridPixels - (x % gridPixels)) % gridPixels; -// y = (y < 0 ? 0 : BG_BRUSH_SPAN - 1) - ((y < 0 ? -y : y) % BG_BRUSH_SPAN); if (y < 0) - y = -y % BG_BRUSH_SPAN; + y = -y % gridPixels; else - y = (BG_BRUSH_SPAN - (y % BG_BRUSH_SPAN)) % BG_BRUSH_SPAN; -//printf("new x=%i\n", x); + y = (gridPixels - (y % gridPixels)) % gridPixels; // Here we grab a section of the bigger pixmap, so that the background // *looks* like it's scrolling... - QPixmap pm = gridBackground.copy(x, y, BG_BRUSH_SPAN, BG_BRUSH_SPAN); + QPixmap pm = gridBackground.copy(x, y, gridPixels, gridPixels); QPalette pal = palette(); pal.setBrush(backgroundRole(), QBrush(pm)); setAutoFillBackground(true); @@ -398,11 +376,9 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) } -void DrawingView::resizeEvent(QResizeEvent * event) +void DrawingView::resizeEvent(QResizeEvent * /*event*/) { Painter::screenSize = Vector(size().width(), size().height()); -// Painter::screenSize = Vector(event->size().width(), event->size().height()); -//printf("DrawingView::resizeEvent: new size: UpdateGridBackground(); } diff --git a/src/painter.cpp b/src/painter.cpp index 2a5ed33..6cfd91f 100644 --- a/src/painter.cpp +++ b/src/painter.cpp @@ -119,32 +119,22 @@ void Painter::DrawAngledText(Vector center, double angle, QString text, double s // We may need this stuff... If dimension text is large enough. // int textWidth = QFontMetrics(painter->font()).width(text); // int textHeight = QFontMetrics(painter->font()).height(); -// NOTE: SCREEN_ZOOM is a kludge to make things look right at screen resolution... -// QRectF textBox(-100.0 * zoom * SCREEN_ZOOM, -100.0 * zoom * SCREEN_ZOOM, 200.0 * zoom * SCREEN_ZOOM, 200.0 * zoom * SCREEN_ZOOM); // x, y, w, h; x/y = upper left corner QRectF textBox(-100.0 * zoom * size, -100.0 * zoom * size, 200.0 * zoom * size, 200.0 * zoom * size); // x, y, w, h; x/y = upper left corner // This is in pixels. Might not render correctly at all zoom levels. - // Need to figure out if dimensions are always rendered at one size regardless of zoom, - // or if they have a definite size, and are thus zoomable. - // If zoomable, this is incorrect: - // (Added zoom, so this is correct now :-) -// float yOffset = -12.0 * zoom * SCREEN_ZOOM; + // Need to figure out if dimensions are always rendered at one size + // regardless of zoom, or if they have a definite size, and are thus + // zoomable. float yOffset = -12.0 * zoom * size; // Fix text so it isn't upside down... if ((angle > PI * 0.5) && (angle < PI * 1.5)) { angle += PI; -// yOffset = 12.0 * zoom * SCREEN_ZOOM; yOffset = 12.0 * zoom * size; } -#if 0 - Vector offset = CartesianToQtCoords(Vector(0, yOffset)); - textBox.translate(offset.x, offset.y); -#else textBox.translate(0, yOffset); -#endif painter->save(); painter->translate(center.x, center.y); // Angles are backwards in the Qt coord system, so we flip ours... @@ -258,16 +248,9 @@ void Painter::DrawArrowhead(Vector head, Vector tail, double size) Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle)); Vector unit = Vector(head - tail).Unit(); -#if 0 -// NOTE: SCREEN_ZOOM is a kludge to make things look right at scale... - Point p1 = head - (unit * 9.0 * SCREEN_ZOOM); - Point p2 = p1 + (orthogonal * 3.0 * SCREEN_ZOOM); - Point p3 = p1 - (orthogonal * 3.0 * SCREEN_ZOOM); -#else Point p1 = head - (unit * 9.0 * size); Point p2 = p1 + (orthogonal * 3.0 * size); Point p3 = p1 - (orthogonal * 3.0 * size); -#endif Point p4 = CartesianToQtCoords(head); Point p5 = CartesianToQtCoords(p2); diff --git a/src/vector.cpp b/src/vector.cpp index e992bbf..ab1433f 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -11,6 +11,7 @@ // JLH 09/19/2006 Created this file // JLH 03/22/2011 Moved implementation of constructor from header to here // JLH 04/02/2011 Fixed divide-by-zero bug in Unit(), added Angle() function +// JLH 08/04/2013 Added Parameter() function // #include "vector.h" @@ -18,17 +19,18 @@ #include // For sqrt() #include "mathconstants.h" - // Vector implementation Vector::Vector(double xx/*= 0*/, double yy/*= 0*/, double zz/*= 0*/): x(xx), y(yy), z(zz) { } + Vector::Vector(Vector head, Vector tail): x(head.x - tail.x), y(head.y - tail.y), z(head.z - tail.z) { } + Vector Vector::operator=(Vector const v) { x = v.x, y = v.y, z = v.z; @@ -36,16 +38,19 @@ Vector Vector::operator=(Vector const v) return *this; } + Vector Vector::operator+(Vector const v) { return Vector(x + v.x, y + v.y, z + v.z); } + Vector Vector::operator-(Vector const v) { return Vector(x - v.x, y - v.y, z - v.z); } + // Unary negation Vector Vector::operator-(void) @@ -53,6 +58,7 @@ Vector Vector::operator-(void) return Vector(-x, -y, -z); } + // Vector x constant Vector Vector::operator*(double const v) @@ -60,6 +66,7 @@ Vector Vector::operator*(double const v) return Vector(x * v, y * v, z * v); } + // Vector x constant Vector Vector::operator*(float const v) @@ -67,6 +74,7 @@ Vector Vector::operator*(float const v) return Vector(x * v, y * v, z * v); } + // Vector / constant Vector Vector::operator/(double const v) @@ -74,6 +82,7 @@ Vector Vector::operator/(double const v) return Vector(x / v, y / v, z / v); } + // Vector / constant Vector Vector::operator/(float const v) @@ -81,6 +90,7 @@ Vector Vector::operator/(float const v) return Vector(x / v, y / v, z / v); } + // Vector (cross) product Vector Vector::operator*(Vector const v) @@ -89,6 +99,7 @@ Vector Vector::operator*(Vector const v) return Vector((y * v.z) - (z * v.y), (z * v.x) - (x * v.z), (x * v.y) - (y * v.x)); } + // Dot product double Vector::Dot(Vector const v) @@ -106,6 +117,7 @@ Vector& Vector::operator*=(double const v) return *this; } + // Vector / constant, self assigned Vector& Vector::operator/=(double const v) @@ -124,6 +136,7 @@ Vector& Vector::operator+=(Vector const v) return *this; } + // Vector + constant, self assigned Vector& Vector::operator+=(double const v) @@ -133,6 +146,7 @@ Vector& Vector::operator+=(double const v) return *this; } + // Vector - vector, self assigned Vector& Vector::operator-=(Vector const v) @@ -142,6 +156,7 @@ Vector& Vector::operator-=(Vector const v) return *this; } + // Vector - constant, self assigned Vector& Vector::operator-=(double const v) @@ -151,18 +166,21 @@ Vector& Vector::operator-=(double const v) return *this; } + // Check for equality bool Vector::operator==(Vector const v) { return (x == v.x && y == v.y && z == v.z ? true : false); } + // Check for inequality bool Vector::operator!=(Vector const v) { return (x != v.x || y != v.y || z != v.z ? true : false); } + Vector Vector::Unit(void) { double mag = Magnitude(); @@ -174,11 +192,13 @@ Vector Vector::Unit(void) return Vector(x / mag, y / mag, z / mag); } + double Vector::Magnitude(void) { return sqrt(x * x + y * y + z * z); } + double Vector::Angle(void) { // acos returns a value between zero and PI, which means we don't know which @@ -190,6 +210,7 @@ double Vector::Angle(void) return correctedAngle; } + bool Vector::isZero(double epsilon/*= 1e-6*/) { return (fabs(x) < epsilon && fabs(y) < epsilon && fabs(z) < epsilon ? true : false); @@ -203,6 +224,7 @@ double Vector::Dot(Vector v1, Vector v2) return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z); } + double Vector::Magnitude(Vector v1, Vector v2) { double xx = v1.x - v2.x; @@ -210,3 +232,23 @@ double Vector::Magnitude(Vector v1, Vector v2) double zz = v1.z - v2.z; return sqrt(xx * xx + yy * yy + zz * zz); } + + +// Returns the parameter of a point in space to this vector. If the parameter +// is between 0 and 1, the normal of the vector to the point is on the vector. +double Vector::Parameter(Vector v1, Vector v2, Vector p) +{ + // Geometric interpretation: + // The parameterized point on the vector lineSegment is where the normal of + // the lineSegment to the point intersects lineSegment. If the pp < 0, then + // the perpendicular lies beyond the 1st endpoint. If pp > 1, then the + // perpendicular lies beyond the 2nd endpoint. + + Vector lineSegment = v2 - v1; + double magnitude = lineSegment.Magnitude(); + Vector pointSegment = p - v1; + double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude); + + return t; +} + diff --git a/src/vector.h b/src/vector.h index 6f11a32..0e7fc86 100644 --- a/src/vector.h +++ b/src/vector.h @@ -47,6 +47,7 @@ class Vector static double Dot(Vector v1, Vector v2); static double Magnitude(Vector v1, Vector v2); + static double Parameter(Vector v1, Vector v2, Vector p); public: double x, y, z; -- 2.37.2