FreeCAD / src /Mod /TechDraw /Gui /Widgets /CompassDialWidget.cpp
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
/***************************************************************************
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
//largely based on a python widget from:
//https://github.com/tcalmant/demo-ipopo-qt/blob/master/pc/details/compass.py
#include <QtGui>
#include <Mod/TechDraw/TechDrawGlobal.h>
#include <Base/Console.h>
#include "CompassDialWidget.h"
using namespace TechDrawGui;
using CardinalMap = std::map<int, std::string>;
CompassDialWidget::CompassDialWidget(QWidget* parent) : QWidget(parent),
m_markInterval(15),
m_defaultSize(75),
m_defaultMargin(10),
m_designRadius(64)
{
setObjectName(QStringLiteral("Compass"));
m_rect = QRect(0, 0, m_defaultSize, m_defaultSize);
m_angle = 0.0;
m_margin = m_defaultMargin;
m_designDiameter = 2 * m_designRadius;
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
sizePolicy.setHorizontalStretch(1);
sizePolicy.setVerticalStretch(1);
setSizePolicy(sizePolicy);
repaint();
}
QSize CompassDialWidget::sizeHint() const
{
return m_rect.size();
}
QSize CompassDialWidget::minimumSizeHint() const
{
return QRect(0, 0, m_defaultSize, m_defaultSize).size();
}
void CompassDialWidget::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QPainter painter(this);
drawWidget(painter);
QWidget::paintEvent(event);
}
void CompassDialWidget::drawWidget(QPainter& painter)
{
painter.setRenderHint(QPainter::Antialiasing, true);
// Draw the background
drawBackground(painter);
//Draw the cardinal points
drawMarkings(painter);
//Draw the needle
drawNeedle(painter);
}
void CompassDialWidget::drawBackground(QPainter& painter)
{
painter.save();
//Move to the center of the compass
painter.translate(width() / 2, height() / 2);
double scale = std::min((float) width() / (float) (m_designDiameter + 2.0 * m_margin),
(float) height() / (float) (m_designDiameter + 2.0 * m_margin));
painter.scale(scale, scale);
painter.setPen(QPen(Qt::NoPen));
// Clear the background
int circleWidth = 2.0 * (m_designRadius + m_margin);
int circleHeight = 2.0 * (m_designRadius + m_margin);
QRect circleRect(-circleWidth / 2, -circleHeight / 2, circleWidth, circleHeight);
painter.drawEllipse(circleRect);
// QRect backRect(-m_rect.width() / 2, -m_rect.height() / 2, m_rect.width(), m_rect.height());
QPainterPath backPath;
backPath.addEllipse(circleRect);
painter.fillPath(backPath, palette().brush((QPalette::Window)));
// painter.fillRect(backRect, palette().brush((QPalette::Window)));
painter.restore();
}
//Draws the cardinal points on painter. This widget was designed such that
//the dial gradations extend to 50 units from center and the compass point text
//begins at 52 units from the center. With the font size set to 12 pixels, this
//gives a design area of a circle with a radius of approximately 64 units. All of
//the constants reflect this design size.
void CompassDialWidget::drawMarkings(QPainter& painter)
{
CardinalMap CompassPointText( { {0, "Y"}, {45, "XY"}, {90, "X"}, {135, "X-Y"}, {180, "-Y"},
{225, "-X-Y"}, {270, "-X"}, {315, "-XY"} } );
painter.save();
int markInterval(15);
//Move to the center of the compass
painter.translate(width() / 2, height() / 2);
double scale = std::min((float) width() / (float) (m_designDiameter + 2.0 * m_margin),
(float) height() / (float) (m_designDiameter + 2.0 * m_margin));
painter.scale(scale, scale);
// Setup the fonts and the painter
QFont widgetFont = font();
widgetFont.setPixelSize(12);
QFontMetrics metrics(widgetFont);
//outer circle
int circleWidth = 2.0 * (m_designRadius + m_margin);
int circleHeight = 2.0 * (m_designRadius + m_margin);
QRect circleRect(-circleWidth / 2, -circleHeight / 2, circleWidth, circleHeight);
painter.drawEllipse(circleRect);
painter.setFont(widgetFont);
painter.setPen(QPen(palette().color(QPalette::WindowText)));
int iDegree = 0;
while ( iDegree < 360 ) {
if (iDegree % 45 == 0) {
//Named direction (every 45°)
painter.drawLine(0, -40, 0, -50); //this has to depend on m_rect or size?
QString qPointText = QString::fromStdString(CompassPointText.at(iDegree));
painter.drawText(-metrics.boundingRect(qPointText).width() / 2.0, -52, qPointText);
// what is -52? line end point y = -50 + 2 for margin?
} else {
//Small line
painter.drawLine(0, -45, 0, -50);
}
//Next line (+15°)
painter.rotate(markInterval);
iDegree += markInterval;
}
painter.restore();
}
//Draws a needle on painter
void CompassDialWidget::drawNeedle(QPainter& painter)
{
painter.save();
//Move to the center of the compass
painter.translate(width() / 2, height() / 2);
//Rotate to the correct angle
painter.rotate(m_angle);
double scale = std::min((float) width() / (float) (m_designDiameter + 2.0 * m_margin),
(float) height() / (float) (m_designDiameter + 2.0 * m_margin));
painter.scale(scale, scale);
//Setup the painter
QPen needlePen(palette().color(QPalette::WindowText));
needlePen.setWidth(2);
needlePen.setStyle(Qt::DashDotLine);
painter.setPen(needlePen);
painter.setBrush(palette().color(QPalette::WindowText));
//Draw the section line
int sectionLineExtent(25);
painter.drawLine(0, sectionLineExtent, 0, -sectionLineExtent);
needlePen.setStyle(Qt::SolidLine);
painter.setPen(needlePen);
int viewDirectionExtent(15);
painter.drawLine(-viewDirectionExtent, sectionLineExtent, 0, sectionLineExtent);
painter.drawLine(-viewDirectionExtent, -sectionLineExtent, 0, -sectionLineExtent);
//Draw the arrowheads of the needle section line
needlePen.setWidth(1);
needlePen.setStyle(Qt::SolidLine);
painter.setPen(needlePen);
int arrowLength(5);
int arrowWidth(3); //actual 1/2 width
painter.drawPolygon(
QPolygon( { QPoint(0, sectionLineExtent),
QPoint(-arrowLength, sectionLineExtent + arrowWidth),
QPoint(-arrowLength, sectionLineExtent - arrowWidth),
QPoint(0, sectionLineExtent) } ) );
painter.drawPolygon(
QPolygon( { QPoint(0, -sectionLineExtent),
QPoint(-arrowLength, -(sectionLineExtent + arrowWidth)),
QPoint(-arrowLength, -(sectionLineExtent - arrowWidth)),
QPoint(0, -sectionLineExtent) } ) );
//draw the actual needle
needlePen.setStyle(Qt::SolidLine);
painter.setPen(needlePen);
painter.setBrush(palette().color(QPalette::BrightText));
int needleExtent(40);
painter.drawPolygon(
QPolygon( { QPoint(needleExtent, 0),
QPoint(0, 5),
QPoint(-15, 2),
QPoint(-15, -2),
QPoint(0, -5),
QPoint(needleExtent, 0) } ) );
//draw needle pivot
painter.setBrush(palette().color(QPalette::WindowText));
int pivotSize(4);
QRect pivotRect(-pivotSize / 2, -pivotSize / 2, pivotSize, pivotSize);
painter.drawEllipse(pivotRect);
//draw needle point
painter.setBrush(QBrush(Qt::red));
int pointLength(5);
int pointWidth(3);
painter.drawPolygon(
QPolygon( { QPoint(needleExtent, 0),
QPoint(needleExtent - pointLength, pointWidth),
QPoint(needleExtent - pointLength, -pointWidth),
QPoint(needleExtent, 0) } ) );
painter.restore();
}
//convert a conventional angle to a Qt angle and set the dial accordingly
void CompassDialWidget::setAngle(double newAngle)
{
m_angle = fmod(360.0 - newAngle, 360.0);
repaint();
}
void CompassDialWidget::setSize(int newSize)
{
m_rect = QRect(0, 0, newSize, newSize);
repaint();
}