Files
create/src/Mod/TechDraw/Gui/QGIBreakLine.cpp

271 lines
8.9 KiB
C++

// SPDX-License-Identifier: LGPL-2.0-or-later
/***************************************************************************
* Copyright (c) 2024 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 *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QGraphicsScene>
# include <QPainter>
# include <QPainterPath>
# include <QStyleOptionGraphicsItem>
#endif
#include <App/Application.h>
#include <Base/Console.h>
#include <Base/Parameter.h>
#include <Base/Tools.h>
#include <Mod/TechDraw/App/Preferences.h>
#include <Mod/TechDraw/App/DrawUtil.h>
#include "QGIBreakLine.h"
#include "PreferencesGui.h"
using namespace TechDrawGui;
using namespace TechDraw;
using DU = DrawUtil;
constexpr double zigzagWidth{30.0};
constexpr double segments{8};
QGIBreakLine::QGIBreakLine()
{
setFlag(QGraphicsItem::ItemIsSelectable, false);
setFlag(QGraphicsItem::ItemIsMovable, false);
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
m_background = new QGraphicsRectItem();
addToGroup(m_background);
m_line0 = new QGraphicsPathItem();
addToGroup(m_line0);
m_line1 = new QGraphicsPathItem();
addToGroup(m_line1);
setColor(PreferencesGui::sectionLineQColor());
m_brush.setStyle(Qt::SolidPattern);
}
void QGIBreakLine::draw()
{
if (breakType() == DrawBrokenView::BreakType::NONE) {
// none
m_background->hide();
m_line0->hide();
m_line1->hide();
}
if (breakType() == DrawBrokenView::BreakType::ZIGZAG) {
drawLargeZigZag();
m_background->show();
m_line0->show();
m_line1->show();
}
if (breakType() == DrawBrokenView::BreakType::SIMPLE) {
// simple line from pref
drawSimpleLines();
m_background->hide();
m_line0->show();
m_line1->show();
}
update();
}
void QGIBreakLine::drawLargeZigZag()
{
Base::Vector3d horizontal{1.0, 0.0, 0.0};
prepareGeometryChange();
double offset = zigzagWidth / 2.0;
if (DU::fpCompare(fabs(m_direction.Dot(horizontal)), 1.0, EWTOLERANCE)) {
// m_direction connects the two cut points. The zigzags have
// to be perpendicular to m_direction
// 2x vertical zigzag
Base::Vector3d start = Base::Vector3d(m_left - offset, m_bottom, 0.0);
m_line0->setPath(makeVerticalZigZag(start));
start = Base::Vector3d(m_right - offset, m_bottom, 0.0);
m_line1->setPath(makeVerticalZigZag(start));
} else {
// m_top is lower than m_bottom due to Qt Y+ down coords
// the higher break line
// 2x horizontal zigszags
Base::Vector3d start = Base::Vector3d(m_left, m_bottom - offset, 0.0);
m_line0->setPath(makeHorizontalZigZag(start));
// the lower break line
start = Base::Vector3d(m_left, m_top - offset, 0.0);
m_line1->setPath(makeHorizontalZigZag(start));
}
QRectF backgroundRect(m_left - offset, m_bottom - offset,
std::fabs(m_right - m_left + zigzagWidth),
std::fabs(m_top - m_bottom + zigzagWidth));
m_background->setRect(backgroundRect);
}
// start needs to be Rez'd and +Y up
QPainterPath QGIBreakLine::makeHorizontalZigZag(Base::Vector3d start) const
{
// Base::Console().message("QGIBL::makeHorizontalZigZag(%s)\n", DU::formatVector(start).c_str());
QPainterPath pPath;
double step = (m_right - m_left) / segments;
Base::Vector3d xOffset = Base::Vector3d(step, 0.0, 0.0); // 1/2 wave length
Base::Vector3d yOffset = Base::Vector3d(0.0, zigzagWidth, 0.0); // amplitude
pPath.moveTo(DU::toQPointF(start));
Base::Vector3d current = start;
int iSegment = 0;
double flipflop = 1.0;
for (; iSegment < segments; iSegment++) {
current = current + xOffset;
current = current + yOffset * flipflop;
pPath.lineTo(DU::toQPointF(current));
flipflop *= -1.0;
}
return pPath;
}
QPainterPath QGIBreakLine::makeVerticalZigZag(Base::Vector3d start) const
{
// Base::Console().message("QGIBL::makeVerticalZigZag(%s)\n", DU::formatVector(start).c_str());
QPainterPath pPath;
double step = (m_top - m_bottom) / segments;
Base::Vector3d xOffset = Base::Vector3d(zigzagWidth, 0.0, 0.0); // amplitude
Base::Vector3d yOffset = Base::Vector3d(0.0, step, 0.0); // 1/2 wave length
pPath.moveTo(DU::toQPointF(start));
Base::Vector3d current = start;
int iSegment = 0;
double flipflop = 1.0;
for (; iSegment < segments; iSegment++) {
current = current + xOffset * flipflop;
current = current + yOffset;
pPath.lineTo(DU::toQPointF(current));
flipflop *= -1.0;
}
return pPath;
}
void QGIBreakLine::drawSimpleLines()
{
Base::Vector3d horizontal{1.0, 0.0, 0.0};
prepareGeometryChange();
if (DU::fpCompare(fabs(m_direction.Dot(horizontal)), 1.0, EWTOLERANCE)) {
// m_direction connects the two cut points. The break lines have
// to be perpendicular to m_direction
Base::Vector3d start = Base::Vector3d(m_left, m_bottom, 0.0);
Base::Vector3d end = Base::Vector3d(m_left, m_top, 0.0);
m_line0->setPath(pathFromPoints(start, end));
start = Base::Vector3d(m_right, m_bottom, 0.0);
end = Base::Vector3d(m_right, m_top, 0.0);
m_line1->setPath(pathFromPoints(start, end));
} else {
// m_top is lower than m_bottom due to Qt Y+ down coords
// the higher break line
// 2x horizontal zigszags
Base::Vector3d start = Base::Vector3d(m_left, m_bottom, 0.0);
Base::Vector3d end = Base::Vector3d(m_right, m_bottom, 0.0);
m_line0->setPath(pathFromPoints(start, end));
// the lower break line
start = Base::Vector3d(m_left, m_top, 0.0);
end = Base::Vector3d(m_right, m_top, 0.0);
m_line1->setPath(pathFromPoints(start, end));
}
}
QPainterPath QGIBreakLine::pathFromPoints(Base::Vector3d start, Base::Vector3d end)
{
QPainterPath result(DU::toQPointF(start));
result.lineTo(DU::toQPointF(end));
return result;
}
void QGIBreakLine::setBounds(double left, double top, double right, double bottom)
{
// Base::Console().message("QGIBL::setBounds(%.3f, %.3f, %.3f, %.3f\n", left, top, right, bottom);
m_left = left;
m_right = right;
m_top = top;
m_bottom = bottom;
}
void QGIBreakLine::setBounds(Base::Vector3d topLeft, Base::Vector3d bottomRight)
{
double left = std::min(topLeft.x, bottomRight.x);
double right = std::max(topLeft.x, bottomRight.x);
double bottom = std::min(topLeft.y, bottomRight.y);
double top = std::max(topLeft.y, bottomRight.y);
setBounds(left, top, right, bottom);
}
void QGIBreakLine::setDirection(Base::Vector3d dir)
{
m_direction = dir;
}
void QGIBreakLine::setBreakColor(QColor c)
{
setColor(c);
}
void QGIBreakLine::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
QStyleOptionGraphicsItem myOption(*option);
myOption.state &= ~QStyle::State_Selected;
setTools();
// painter->setPen(Qt::blue);
// painter->drawRect(boundingRect()); //good for debugging
QGIDecoration::paint (painter, &myOption, widget);
}
void QGIBreakLine::setTools()
{
m_brush.setColor(PreferencesGui::pageQColor());
m_line0->setPen(m_pen);
m_line0->setBrush(Qt::NoBrush);
m_line1->setPen(m_pen);
m_line1->setBrush(Qt::NoBrush);
m_background->setBrush(m_brush);
m_background->setPen(Qt::NoPen);
}
void QGIBreakLine::setLinePen(QPen isoPen)
{
m_pen = isoPen;
}