=======================================
Refactor:
- Substitute the use of variadic templates with parameter packs.
- Use recently incorporated external library "fmt" to handle printf like formating.
- Extensive cleaning of pragmas and unnecessary forward declarations.
- Parameter packs and libfmt provide a much stronger type checking now, so
conversions that are by standard implicit as bool to int need an explicit static_cast
to avoid compilation warnings.
Extension:
- Include a notifier field, so that the originator of the message can be provided. E.g. Document#DocumentObject
- Include a new type of message called CriticalMessage, this message is intended to have
special behaviour in the future. Namely, it will be used to notify forward compatilibity issues.
It will be used to substitute the current signal/slot mechanism.
- Include two new types of messages for user notifications (Notification and TranslatedNotification). This messages
will be use to convey UI notifications intended for the user (such as non-intrusive message about the usage of a tool). There
are two versions to mark whether the string provided as a message is already translated or not. When using the console system for
notifications, these notifications may originate from the App or the Gui. In the former, it is generally the case that the strings
of messages are not (yet) translated (but they can be marked with QT_TRANSLATE_NOOP). In the latter, often the messages to be provided
are already translated.
Python support for CriticalMessage, Notification and TranslatedNofification, including shortcuts:
Crt = FreeCAD.Console.PrintCritical
Ntf = FreeCAD.Console.PrintNotification
Tnf = FreeCAD.Console.PrintTranslatedNotification
1306 lines
52 KiB
C++
1306 lines
52 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2013 Luke Parry <l.parry@warwick.ac.uk> *
|
|
* *
|
|
* 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 <cmath>
|
|
|
|
#include <QPainterPath>
|
|
#include <qmath.h>
|
|
#endif// #ifndef _PreComp_
|
|
|
|
#include <App/Application.h>
|
|
#include <App/Document.h>
|
|
#include <Base/Console.h>
|
|
#include <Base/Parameter.h>
|
|
#include <Base/Vector3D.h>
|
|
#include <Mod/TechDraw/App/Cosmetic.h>
|
|
#include <Mod/TechDraw/App/DrawComplexSection.h>
|
|
#include <Mod/TechDraw/App/DrawGeomHatch.h>
|
|
#include <Mod/TechDraw/App/DrawHatch.h>
|
|
#include <Mod/TechDraw/App/DrawUtil.h>
|
|
#include <Mod/TechDraw/App/DrawViewDetail.h>
|
|
#include <Mod/TechDraw/App/DrawViewPart.h>
|
|
#include <Mod/TechDraw/App/DrawViewSection.h>
|
|
#include <Mod/TechDraw/App/Geometry.h>
|
|
|
|
#include "MDIViewPage.h"
|
|
#include "PreferencesGui.h"
|
|
#include "QGICMark.h"
|
|
#include "QGICenterLine.h"
|
|
#include "QGIEdge.h"
|
|
#include "QGIFace.h"
|
|
#include "QGIHighlight.h"
|
|
#include "QGIMatting.h"
|
|
#include "QGISectionLine.h"
|
|
#include "QGIVertex.h"
|
|
#include "QGIViewPart.h"
|
|
#include "Rez.h"
|
|
#include "ViewProviderGeomHatch.h"
|
|
#include "ViewProviderHatch.h"
|
|
#include "ViewProviderViewPart.h"
|
|
#include "ZVALUE.h"
|
|
|
|
|
|
using namespace TechDraw;
|
|
using namespace TechDrawGui;
|
|
using namespace std;
|
|
using DU = DrawUtil;
|
|
|
|
#define GEOMETRYEDGE 0
|
|
#define COSMETICEDGE 1
|
|
#define CENTERLINE 2
|
|
|
|
|
|
const float lineScaleFactor = Rez::guiX(1.);// temp fiddle for devel
|
|
|
|
QGIViewPart::QGIViewPart() : m_isExporting(false)
|
|
{
|
|
setCacheMode(QGraphicsItem::NoCache);
|
|
setHandlesChildEvents(false);
|
|
setAcceptHoverEvents(true);
|
|
setFlag(QGraphicsItem::ItemIsSelectable, true);
|
|
setFlag(QGraphicsItem::ItemIsMovable, true);
|
|
setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
|
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
|
|
|
showSection = false;
|
|
}
|
|
|
|
QGIViewPart::~QGIViewPart() { tidy(); }
|
|
|
|
QVariant QGIViewPart::itemChange(GraphicsItemChange change, const QVariant& value)
|
|
{
|
|
if (change == ItemSelectedHasChanged && scene()) {
|
|
//There's nothing special for QGIVP to do when selection changes!
|
|
}
|
|
else if (change == ItemSceneChange && scene()) {
|
|
tidy();
|
|
}
|
|
return QGIView::itemChange(change, value);
|
|
}
|
|
|
|
//obs?
|
|
void QGIViewPart::tidy()
|
|
{
|
|
//Delete any leftover items
|
|
for (QList<QGraphicsItem*>::iterator it = deleteItems.begin(); it != deleteItems.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
deleteItems.clear();
|
|
}
|
|
|
|
void QGIViewPart::setViewPartFeature(TechDraw::DrawViewPart* obj)
|
|
{
|
|
if (!obj)
|
|
return;
|
|
|
|
setViewFeature(static_cast<TechDraw::DrawView*>(obj));
|
|
}
|
|
|
|
QPainterPath QGIViewPart::drawPainterPath(TechDraw::BaseGeomPtr baseGeom) const
|
|
{
|
|
double rot = getViewObject()->Rotation.getValue();
|
|
return geomToPainterPath(baseGeom, rot);
|
|
}
|
|
|
|
|
|
QPainterPath QGIViewPart::geomToPainterPath(BaseGeomPtr baseGeom, double rot)
|
|
{
|
|
Q_UNUSED(rot);
|
|
QPainterPath path;
|
|
|
|
if (!baseGeom)
|
|
return path;
|
|
|
|
switch (baseGeom->getGeomType()) {
|
|
case CIRCLE: {
|
|
TechDraw::CirclePtr geom = std::static_pointer_cast<TechDraw::Circle>(baseGeom);
|
|
|
|
double x = geom->center.x - geom->radius;
|
|
double y = geom->center.y - geom->radius;
|
|
|
|
path.addEllipse(Rez::guiX(x), Rez::guiX(y), Rez::guiX(geom->radius * 2),
|
|
Rez::guiX(geom->radius * 2));//topleft@(x, y) radx, rady
|
|
} break;
|
|
case ARCOFCIRCLE: {
|
|
TechDraw::AOCPtr geom = std::static_pointer_cast<TechDraw::AOC>(baseGeom);
|
|
if (baseGeom->getReversed()) {
|
|
path.moveTo(Rez::guiX(geom->endPnt.x), Rez::guiX(geom->endPnt.y));
|
|
pathArc(path, Rez::guiX(geom->radius), Rez::guiX(geom->radius), 0., geom->largeArc,
|
|
!geom->cw, Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y),
|
|
Rez::guiX(geom->endPnt.x), Rez::guiX(geom->endPnt.y));
|
|
}
|
|
else {
|
|
path.moveTo(Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y));
|
|
pathArc(path, Rez::guiX(geom->radius), Rez::guiX(geom->radius), 0., geom->largeArc,
|
|
geom->cw, Rez::guiX(geom->endPnt.x), Rez::guiX(geom->endPnt.y),
|
|
Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y));
|
|
}
|
|
} break;
|
|
case TechDraw::ELLIPSE: {
|
|
TechDraw::AOEPtr geom = std::static_pointer_cast<TechDraw::AOE>(baseGeom);
|
|
|
|
// Calculate start and end points as ellipse with theta = 0 and pi
|
|
double startX = geom->center.x + geom->major * cos(geom->angle),
|
|
startY = geom->center.y + geom->major * sin(geom->angle),
|
|
endX = geom->center.x - geom->major * cos(geom->angle),
|
|
endY = geom->center.y - geom->major * sin(geom->angle);
|
|
|
|
pathArc(path, Rez::guiX(geom->major), Rez::guiX(geom->minor), geom->angle, false, false,
|
|
Rez::guiX(endX), Rez::guiX(endY), Rez::guiX(startX), Rez::guiX(startY));
|
|
|
|
pathArc(path, Rez::guiX(geom->major), Rez::guiX(geom->minor), geom->angle, false, false,
|
|
Rez::guiX(startX), Rez::guiX(startY), Rez::guiX(endX), Rez::guiX(endY));
|
|
} break;
|
|
case TechDraw::ARCOFELLIPSE: {
|
|
TechDraw::AOEPtr geom = std::static_pointer_cast<TechDraw::AOE>(baseGeom);
|
|
if (baseGeom->getReversed()) {
|
|
path.moveTo(Rez::guiX(geom->endPnt.x), Rez::guiX(geom->endPnt.y));
|
|
pathArc(path, Rez::guiX(geom->major), Rez::guiX(geom->minor), geom->angle,
|
|
geom->largeArc, !geom->cw, Rez::guiX(geom->startPnt.x),
|
|
Rez::guiX(geom->startPnt.y), Rez::guiX(geom->endPnt.x),
|
|
Rez::guiX(geom->endPnt.y));
|
|
}
|
|
else {
|
|
path.moveTo(Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y));
|
|
pathArc(path, Rez::guiX(geom->major), Rez::guiX(geom->minor), geom->angle,
|
|
geom->largeArc, geom->cw, Rez::guiX(geom->endPnt.x),
|
|
Rez::guiX(geom->endPnt.y), Rez::guiX(geom->startPnt.x),
|
|
Rez::guiX(geom->startPnt.y));
|
|
}
|
|
} break;
|
|
case TechDraw::BEZIER: {
|
|
TechDraw::BezierSegmentPtr geom =
|
|
std::static_pointer_cast<TechDraw::BezierSegment>(baseGeom);
|
|
if (baseGeom->getReversed()) {
|
|
if (!geom->pnts.empty()) {
|
|
Base::Vector3d rStart = geom->pnts.back();
|
|
path.moveTo(Rez::guiX(rStart.x), Rez::guiX(rStart.y));
|
|
}
|
|
if (geom->poles == 2) {
|
|
// Degree 1 bezier = straight line...
|
|
path.lineTo(Rez::guiX(geom->pnts[0].x), Rez::guiX(geom->pnts[0].y));
|
|
}
|
|
else if (geom->poles == 3) {
|
|
path.quadTo(Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y),
|
|
Rez::guiX(geom->pnts[0].x), Rez::guiX(geom->pnts[0].y));
|
|
}
|
|
else if (geom->poles == 4) {
|
|
path.cubicTo(Rez::guiX(geom->pnts[2].x), Rez::guiX(geom->pnts[2].y),
|
|
Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y),
|
|
Rez::guiX(geom->pnts[0].x), Rez::guiX(geom->pnts[0].y));
|
|
}
|
|
else {//can only handle lines, quads, cubes
|
|
Base::Console().Error("Bad pole count (%d) for BezierSegment\n", geom->poles);
|
|
auto itBez = geom->pnts.begin() + 1;
|
|
for (; itBez != geom->pnts.end(); itBez++) {
|
|
path.lineTo(Rez::guiX((*itBez).x),
|
|
Rez::guiX((*itBez).y));//show something for debugging
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Move painter to the beginning
|
|
path.moveTo(Rez::guiX(geom->pnts[0].x), Rez::guiX(geom->pnts[0].y));
|
|
|
|
if (geom->poles == 2) {
|
|
// Degree 1 bezier = straight line...
|
|
path.lineTo(Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y));
|
|
}
|
|
else if (geom->poles == 3) {
|
|
path.quadTo(Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y),
|
|
Rez::guiX(geom->pnts[2].x), Rez::guiX(geom->pnts[2].y));
|
|
}
|
|
else if (geom->poles == 4) {
|
|
path.cubicTo(Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y),
|
|
Rez::guiX(geom->pnts[2].x), Rez::guiX(geom->pnts[2].y),
|
|
Rez::guiX(geom->pnts[3].x), Rez::guiX(geom->pnts[3].y));
|
|
}
|
|
else {//can only handle lines, quads, cubes
|
|
Base::Console().Error("Bad pole count (%d) for BezierSegment\n", geom->poles);
|
|
auto itBez = geom->pnts.begin() + 1;
|
|
for (; itBez != geom->pnts.end(); itBez++) {
|
|
path.lineTo(Rez::guiX((*itBez).x),
|
|
Rez::guiX((*itBez).y));//show something for debugging
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
case TechDraw::BSPLINE: {
|
|
TechDraw::BSplinePtr geom = std::static_pointer_cast<TechDraw::BSpline>(baseGeom);
|
|
if (baseGeom->getReversed()) {
|
|
// Move painter to the end of our last segment
|
|
std::vector<TechDraw::BezierSegment>::const_reverse_iterator it =
|
|
geom->segments.rbegin();
|
|
Base::Vector3d rStart = it->pnts.back();
|
|
path.moveTo(Rez::guiX(rStart.x), Rez::guiX(rStart.y));
|
|
|
|
for (; it != geom->segments.rend(); ++it) {
|
|
// At this point, the painter is either at the beginning
|
|
// of the first segment, or end of the last
|
|
if (it->poles == 2) {
|
|
// Degree 1 bezier = straight line...
|
|
path.lineTo(Rez::guiX(it->pnts[0].x), Rez::guiX(it->pnts[0].y));
|
|
}
|
|
else if (it->poles == 3) {
|
|
path.quadTo(Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y),
|
|
Rez::guiX(it->pnts[0].x), Rez::guiX(it->pnts[0].y));
|
|
}
|
|
else if (it->poles == 4) {
|
|
path.cubicTo(Rez::guiX(it->pnts[2].x), Rez::guiX(it->pnts[2].y),
|
|
Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y),
|
|
Rez::guiX(it->pnts[0].x), Rez::guiX(it->pnts[0].y));
|
|
}
|
|
else {//can only handle lines, quads, cubes
|
|
Base::Console().Error(
|
|
"Bad pole count (%d) for BezierSegment of B-spline geometry\n",
|
|
it->poles);
|
|
path.lineTo(it->pnts[1].x, it->pnts[1].y);//show something for debugging
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Move painter to the beginning of our first segment
|
|
std::vector<TechDraw::BezierSegment>::const_iterator it = geom->segments.begin();
|
|
path.moveTo(Rez::guiX(it->pnts[0].x), Rez::guiX(it->pnts[0].y));
|
|
|
|
for (; it != geom->segments.end(); ++it) {
|
|
// At this point, the painter is either at the beginning
|
|
// of the first segment, or end of the last
|
|
if (it->poles == 2) {
|
|
// Degree 1 bezier = straight line...
|
|
path.lineTo(Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y));
|
|
}
|
|
else if (it->poles == 3) {
|
|
path.quadTo(Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y),
|
|
Rez::guiX(it->pnts[2].x), Rez::guiX(it->pnts[2].y));
|
|
}
|
|
else if (it->poles == 4) {
|
|
path.cubicTo(Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y),
|
|
Rez::guiX(it->pnts[2].x), Rez::guiX(it->pnts[2].y),
|
|
Rez::guiX(it->pnts[3].x), Rez::guiX(it->pnts[3].y));
|
|
}
|
|
else {
|
|
Base::Console().Error(
|
|
"Bad pole count (%d) for BezierSegment of B-spline geometry\n",
|
|
it->poles);
|
|
path.lineTo(it->pnts[1].x, it->pnts[1].y);//show something for debugging
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
case TechDraw::GENERIC: {
|
|
TechDraw::GenericPtr geom = std::static_pointer_cast<TechDraw::Generic>(baseGeom);
|
|
if (baseGeom->getReversed()) {
|
|
if (!geom->points.empty()) {
|
|
Base::Vector3d rStart = geom->points.back();
|
|
path.moveTo(Rez::guiX(rStart.x), Rez::guiX(rStart.y));
|
|
}
|
|
std::vector<Base::Vector3d>::const_reverse_iterator it = geom->points.rbegin();
|
|
for (++it; it != geom->points.rend(); ++it) {
|
|
path.lineTo(Rez::guiX((*it).x), Rez::guiX((*it).y));
|
|
}
|
|
}
|
|
else {
|
|
path.moveTo(Rez::guiX(geom->points[0].x), Rez::guiX(geom->points[0].y));
|
|
std::vector<Base::Vector3d>::const_iterator it = geom->points.begin();
|
|
for (++it; it != geom->points.end(); ++it) {
|
|
path.lineTo(Rez::guiX((*it).x), Rez::guiX((*it).y));
|
|
}
|
|
}
|
|
} break;
|
|
default: {
|
|
Base::Console().Error("Error - geomToPainterPath - UNKNOWN geomType: %d\n",
|
|
static_cast<int>(baseGeom->getGeomType()));
|
|
} break;
|
|
}//sb end of switch
|
|
|
|
//old rotate path logic. now done on App side.
|
|
// if (rot != 0.0) {
|
|
// QTransform t;
|
|
// t.rotate(-rot);
|
|
// path = t.map(path);
|
|
// }
|
|
|
|
return path;
|
|
}
|
|
|
|
void QGIViewPart::updateView(bool update)
|
|
{
|
|
// Base::Console().Message("QGIVP::updateView() - %s\n", getViewObject()->getNameInDocument());
|
|
auto viewPart(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
|
|
if (!viewPart)
|
|
return;
|
|
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
|
|
if (!vp)
|
|
return;
|
|
|
|
if (update)
|
|
draw();
|
|
QGIView::updateView(update);
|
|
}
|
|
|
|
void QGIViewPart::draw()
|
|
{
|
|
if (!isVisible())
|
|
return;
|
|
|
|
drawViewPart();
|
|
drawMatting();
|
|
//this is old C/L
|
|
drawCenterLines(true);//have to draw centerlines after border to get size correct.
|
|
drawAllSectionLines();//same for section lines
|
|
}
|
|
|
|
void QGIViewPart::drawViewPart()
|
|
{
|
|
auto viewPart(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
|
|
if (!viewPart)
|
|
return;
|
|
// Base::Console().Message("QGIVP::DVP() - %s / %s\n", viewPart->getNameInDocument(), viewPart->Label.getValue());
|
|
if (!viewPart->hasGeometry()) {
|
|
removePrimitives();//clean the slate
|
|
removeDecorations();
|
|
return;
|
|
}
|
|
|
|
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
|
|
if (!vp)
|
|
return;
|
|
|
|
float lineWidth = vp->LineWidth.getValue() * lineScaleFactor; //thick
|
|
float lineWidthHid = vp->HiddenWidth.getValue() * lineScaleFactor;//thin
|
|
float lineWidthIso = vp->IsoWidth.getValue() * lineScaleFactor; //graphic
|
|
// float lineWidthExtra = viewPart->ExtraWidth.getValue() * lineScaleFactor; //extra
|
|
bool showAll = vp->ShowAllEdges.getValue();
|
|
|
|
prepareGeometryChange();
|
|
removePrimitives();//clean the slate
|
|
removeDecorations();
|
|
|
|
if (viewPart->handleFaces() && !viewPart->CoarseView.getValue()) {
|
|
// Draw Faces
|
|
std::vector<TechDraw::DrawHatch*> hatchObjs = viewPart->getHatches();
|
|
std::vector<TechDraw::DrawGeomHatch*> geomObjs = viewPart->getGeomHatches();
|
|
const std::vector<TechDraw::FacePtr>& faceGeoms = viewPart->getFaceGeometry();
|
|
std::vector<TechDraw::FacePtr>::const_iterator fit = faceGeoms.begin();
|
|
for (int i = 0; fit != faceGeoms.end(); fit++, i++) {
|
|
QGIFace* newFace = drawFace(*fit, i);
|
|
newFace->isHatched(false);
|
|
newFace->setFillMode(QGIFace::PlainFill);
|
|
TechDraw::DrawHatch* fHatch = faceIsHatched(i, hatchObjs);
|
|
TechDraw::DrawGeomHatch* fGeom = faceIsGeomHatched(i, geomObjs);
|
|
if (fGeom) {
|
|
const std::vector<std::string>& sourceNames = fGeom->Source.getSubValues();
|
|
if (!sourceNames.empty()) {
|
|
std::vector<LineSet> lineSets = fGeom->getTrimmedLines(i);
|
|
if (!lineSets.empty()) {
|
|
newFace->clearLineSets();
|
|
for (auto& ls : lineSets) {
|
|
newFace->addLineSet(ls);
|
|
}
|
|
newFace->isHatched(true);
|
|
newFace->setFillMode(QGIFace::GeomHatchFill);
|
|
double hatchScale = fGeom->ScalePattern.getValue();
|
|
if (hatchScale > 0.0) {
|
|
newFace->setHatchScale(fGeom->ScalePattern.getValue());
|
|
}
|
|
newFace->setHatchRotation(fGeom->PatternRotation.getValue());
|
|
newFace->setHatchOffset(fGeom->PatternOffset.getValue());
|
|
newFace->setHatchFile(fGeom->PatIncluded.getValue());
|
|
Gui::ViewProvider* gvp = QGIView::getViewProvider(fGeom);
|
|
ViewProviderGeomHatch* geomVp = dynamic_cast<ViewProviderGeomHatch*>(gvp);
|
|
if (geomVp) {
|
|
newFace->setHatchColor(geomVp->ColorPattern.getValue());
|
|
newFace->setLineWeight(geomVp->WeightPattern.getValue());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (fHatch) {
|
|
Gui::ViewProvider* gvp = QGIView::getViewProvider(fHatch);
|
|
ViewProviderHatch* hatchVp = dynamic_cast<ViewProviderHatch*>(gvp);
|
|
if (fHatch->isSvgHatch()) {
|
|
if (!fHatch->SvgIncluded.isEmpty()) {
|
|
if (getExporting()) {
|
|
newFace->hideSvg(true);
|
|
}
|
|
else {
|
|
newFace->hideSvg(false);
|
|
}
|
|
newFace->isHatched(true);
|
|
newFace->setFillMode(QGIFace::SvgFill);
|
|
newFace->setHatchFile(fHatch->SvgIncluded.getValue());
|
|
// Gui::ViewProvider* gvp = QGIView::getViewProvider(fHatch);
|
|
// ViewProviderHatch* hatchVp = dynamic_cast<ViewProviderHatch*>(gvp);
|
|
if (hatchVp) {
|
|
double hatchScale = hatchVp->HatchScale.getValue();
|
|
if (hatchScale > 0.0) {
|
|
newFace->setHatchScale(hatchVp->HatchScale.getValue());
|
|
}
|
|
newFace->setHatchColor(hatchVp->HatchColor.getValue());
|
|
newFace->setHatchRotation(hatchVp->HatchRotation.getValue());
|
|
newFace->setHatchOffset(hatchVp->HatchOffset.getValue());
|
|
}
|
|
}
|
|
}
|
|
else {//bitmap hatch
|
|
newFace->isHatched(true);
|
|
newFace->setFillMode(QGIFace::BitmapFill);
|
|
newFace->setHatchFile(fHatch->SvgIncluded.getValue());
|
|
if (hatchVp) {
|
|
newFace->setHatchRotation(hatchVp->HatchRotation.getValue());
|
|
}
|
|
}
|
|
}
|
|
bool drawEdges = prefFaceEdges();
|
|
newFace->setDrawEdges(drawEdges);//pref. for debugging only
|
|
newFace->setZValue(ZVALUE::FACE);
|
|
newFace->setPrettyNormal();
|
|
newFace->draw();
|
|
}
|
|
}
|
|
|
|
// Draw Edges
|
|
QColor edgeColor = PreferencesGui::getAccessibleQColor(PreferencesGui::normalQColor());
|
|
const TechDraw::BaseGeomPtrVector& geoms = viewPart->getEdgeGeometry();
|
|
TechDraw::BaseGeomPtrVector::const_iterator itGeom = geoms.begin();
|
|
QGIEdge* item;
|
|
for (int i = 0; itGeom != geoms.end(); itGeom++, i++) {
|
|
bool showEdge = false;
|
|
if ((*itGeom)->getHlrVisible()) {
|
|
if (((*itGeom)->getClassOfEdge() == ecHARD) || ((*itGeom)->getClassOfEdge() == ecOUTLINE)
|
|
|| (((*itGeom)->getClassOfEdge() == ecSMOOTH) && viewPart->SmoothVisible.getValue())
|
|
|| (((*itGeom)->getClassOfEdge() == ecSEAM) && viewPart->SeamVisible.getValue())
|
|
|| (((*itGeom)->getClassOfEdge() == ecUVISO) && viewPart->IsoVisible.getValue())) {
|
|
showEdge = true;
|
|
}
|
|
}
|
|
else {
|
|
if ((((*itGeom)->getClassOfEdge() == ecHARD) && (viewPart->HardHidden.getValue()))
|
|
|| (((*itGeom)->getClassOfEdge() == ecOUTLINE) && (viewPart->HardHidden.getValue()))
|
|
|| (((*itGeom)->getClassOfEdge() == ecSMOOTH) && (viewPart->SmoothHidden.getValue()))
|
|
|| (((*itGeom)->getClassOfEdge() == ecSEAM) && (viewPart->SeamHidden.getValue()))
|
|
|| (((*itGeom)->getClassOfEdge() == ecUVISO) && (viewPart->IsoHidden.getValue()))) {
|
|
showEdge = true;
|
|
}
|
|
}
|
|
bool showItem = true;
|
|
if (showEdge) {//based on hard/seam/hidden/etc
|
|
item = new QGIEdge(i);
|
|
item->setWidth(lineWidth);
|
|
item->setNormalColor(edgeColor);
|
|
item->setStyle(Qt::SolidLine);
|
|
if ((*itGeom)->getCosmetic()) {
|
|
int source = (*itGeom)->source();
|
|
if (source == COSMETICEDGE) {
|
|
std::string cTag = (*itGeom)->getCosmeticTag();
|
|
showItem = formatGeomFromCosmetic(cTag, item);
|
|
}
|
|
else if (source == CENTERLINE) {
|
|
std::string cTag = (*itGeom)->getCosmeticTag();
|
|
showItem = formatGeomFromCenterLine(cTag, item);
|
|
}
|
|
else {
|
|
Base::Console().Message("QGIVP::drawVP - edge: %d is confused - source: %d\n",
|
|
i, source);
|
|
}
|
|
}
|
|
else {
|
|
TechDraw::GeomFormat* gf = viewPart->getGeomFormatBySelection(i);
|
|
if (gf) {
|
|
App::Color color = Preferences::getAccessibleColor(gf->m_format.m_color);
|
|
item->setNormalColor(color.asValue<QColor>());
|
|
item->setWidth(gf->m_format.m_weight * lineScaleFactor);
|
|
item->setStyle(gf->m_format.m_style);
|
|
showItem = gf->m_format.m_visible;
|
|
}
|
|
}
|
|
|
|
addToGroup(item); //item is at scene(0, 0), not group(0, 0)
|
|
item->setPos(0.0, 0.0);//now at group(0, 0)
|
|
item->setPath(drawPainterPath(*itGeom));
|
|
item->setZValue(ZVALUE::EDGE);
|
|
if (!(*itGeom)->getHlrVisible()) {
|
|
item->setWidth(lineWidthHid);
|
|
item->setHiddenEdge(true);
|
|
item->setZValue(ZVALUE::HIDEDGE);
|
|
}
|
|
if ((*itGeom)->getClassOfEdge() == ecUVISO) {
|
|
item->setWidth(lineWidthIso);
|
|
}
|
|
item->setPrettyNormal();
|
|
if (!showAll) { //view level "show" status
|
|
if (!showItem) {//individual edge "show" status
|
|
item->hide();
|
|
}
|
|
}
|
|
//debug a path
|
|
// QPainterPath edgePath=drawPainterPath(*itGeom);
|
|
// std::stringstream edgeId;
|
|
// edgeId << "QGIVP.edgePath" << i;
|
|
// dumpPath(edgeId.str().c_str(), edgePath);
|
|
}
|
|
}
|
|
|
|
|
|
// Draw Vertexs:
|
|
Base::Reference<ParameterGrp> hGrp = App::GetApplication()
|
|
.GetUserParameter()
|
|
.GetGroup("BaseApp")
|
|
->GetGroup("Preferences")
|
|
->GetGroup("Mod/TechDraw/General");
|
|
double vertexScaleFactor = hGrp->GetFloat("VertexScale", 3.0);
|
|
QColor vertexColor = PreferencesGui::getAccessibleQColor(PreferencesGui::vertexQColor());
|
|
bool showVertices = true;
|
|
bool showCenterMarks = true;
|
|
if (getFrameState()) {//frames are on
|
|
if (viewPart->CoarseView.getValue()) {
|
|
showVertices = false;
|
|
}
|
|
if (!vp->ArcCenterMarks.getValue()) {
|
|
showCenterMarks = false;
|
|
}
|
|
}
|
|
else {//frames are off
|
|
showVertices = false;
|
|
if (!prefPrintCenters()) {//based on preference (!frame && !pref)
|
|
showCenterMarks = false;
|
|
}
|
|
if (!vp->ArcCenterMarks.getValue()) {//based on property (!frame && !prop)
|
|
showCenterMarks = false;
|
|
}
|
|
}
|
|
|
|
const std::vector<TechDraw::VertexPtr>& verts = viewPart->getVertexGeometry();
|
|
std::vector<TechDraw::VertexPtr>::const_iterator vert = verts.begin();
|
|
double cAdjust = vp->CenterScale.getValue();
|
|
|
|
for (int i = 0; vert != verts.end(); ++vert, i++) {
|
|
if ((*vert)->isCenter()) {
|
|
if (showCenterMarks) {
|
|
QGICMark* cmItem = new QGICMark(i);
|
|
addToGroup(cmItem);
|
|
cmItem->setPos(Rez::guiX((*vert)->x()), Rez::guiX((*vert)->y()));
|
|
cmItem->setThick(0.5 * lineWidth);//need minimum?
|
|
cmItem->setSize(cAdjust * lineWidth * vertexScaleFactor);
|
|
cmItem->setPrettyNormal();
|
|
cmItem->setZValue(ZVALUE::VERTEX);
|
|
}
|
|
}
|
|
else {//regular Vertex
|
|
if (showVertices) {
|
|
QGIVertex* item = new QGIVertex(i);
|
|
addToGroup(item);
|
|
item->setPos(Rez::guiX((*vert)->x()), Rez::guiX((*vert)->y()));
|
|
item->setNormalColor(vertexColor);
|
|
item->setFillColor(vertexColor);
|
|
item->setRadius(lineWidth * vertexScaleFactor);
|
|
item->setPrettyNormal();
|
|
item->setZValue(ZVALUE::VERTEX);
|
|
}
|
|
}
|
|
}
|
|
|
|
//draw detail highlights
|
|
auto drefs = viewPart->getDetailRefs();
|
|
for (auto& r : drefs) {
|
|
drawHighlight(r, true);
|
|
}
|
|
}
|
|
|
|
bool QGIViewPart::formatGeomFromCosmetic(std::string cTag, QGIEdge* item)
|
|
{
|
|
// Base::Console().Message("QGIVP::formatGeomFromCosmetic(%s)\n", cTag.c_str());
|
|
bool result = true;
|
|
auto partFeat(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
|
|
TechDraw::CosmeticEdge* ce = partFeat ? partFeat->getCosmeticEdge(cTag) : nullptr;
|
|
if (ce) {
|
|
App::Color color = Preferences::getAccessibleColor(ce->m_format.m_color);
|
|
item->setNormalColor(color.asValue<QColor>());
|
|
item->setWidth(ce->m_format.m_weight * lineScaleFactor);
|
|
item->setStyle(ce->m_format.m_style);
|
|
result = ce->m_format.m_visible;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
bool QGIViewPart::formatGeomFromCenterLine(std::string cTag, QGIEdge* item)
|
|
{
|
|
// Base::Console().Message("QGIVP::formatGeomFromCenterLine(%d)\n", sourceIndex);
|
|
bool result = true;
|
|
auto partFeat(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
|
|
TechDraw::CenterLine* cl = partFeat ? partFeat->getCenterLine(cTag) : nullptr;
|
|
if (cl) {
|
|
App::Color color = Preferences::getAccessibleColor(cl->m_format.m_color);
|
|
item->setNormalColor(color.asValue<QColor>());
|
|
item->setWidth(cl->m_format.m_weight * lineScaleFactor);
|
|
item->setStyle(cl->m_format.m_style);
|
|
result = cl->m_format.m_visible;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QGIFace* QGIViewPart::drawFace(TechDraw::FacePtr f, int idx)
|
|
{
|
|
// Base::Console().Message("QGIVP::drawFace - %d\n", idx);
|
|
std::vector<TechDraw::Wire*> fWires = f->wires;
|
|
QPainterPath facePath;
|
|
for (std::vector<TechDraw::Wire*>::iterator wire = fWires.begin(); wire != fWires.end();
|
|
++wire) {
|
|
TechDraw::BaseGeomPtrVector geoms = (*wire)->geoms;
|
|
if (geoms.empty())
|
|
continue;
|
|
|
|
TechDraw::BaseGeomPtr firstGeom = geoms.front();
|
|
QPainterPath wirePath;
|
|
//QPointF startPoint(firstGeom->getStartPoint().x, firstGeom->getStartPoint().y);
|
|
//wirePath.moveTo(startPoint);
|
|
QPainterPath firstSeg = drawPainterPath(firstGeom);
|
|
wirePath.connectPath(firstSeg);
|
|
for (TechDraw::BaseGeomPtrVector::iterator edge = ((*wire)->geoms.begin()) + 1;
|
|
edge != (*wire)->geoms.end(); ++edge) {
|
|
QPainterPath edgePath = drawPainterPath(*edge);
|
|
//handle section faces differently
|
|
if (idx == -1) {
|
|
QPointF wEnd = wirePath.currentPosition();
|
|
auto element = edgePath.elementAt(0);
|
|
QPointF eStart(element.x, element.y);
|
|
QPointF eEnd = edgePath.currentPosition();
|
|
QPointF sVec = wEnd - eStart;
|
|
QPointF eVec = wEnd - eEnd;
|
|
double sDist2 = sVec.x() * sVec.x() + sVec.y() * sVec.y();
|
|
double eDist2 = eVec.x() * eVec.x() + eVec.y() * eVec.y();
|
|
if (sDist2 > eDist2) {
|
|
edgePath = edgePath.toReversed();
|
|
}
|
|
}
|
|
wirePath.connectPath(edgePath);
|
|
}
|
|
// dumpPath("wirePath:", wirePath);
|
|
facePath.addPath(wirePath);
|
|
}
|
|
facePath.setFillRule(Qt::OddEvenFill);
|
|
|
|
QGIFace* gFace = new QGIFace(idx);
|
|
addToGroup(gFace);
|
|
gFace->setPos(0.0, 0.0);
|
|
gFace->setOutline(facePath);
|
|
//debug a path
|
|
//std::stringstream faceId;
|
|
//faceId << "facePath " << idx;
|
|
//dumpPath(faceId.str().c_str(), facePath);
|
|
|
|
return gFace;
|
|
}
|
|
|
|
//! Remove all existing QGIPrimPath items(Vertex, Edge, Face)
|
|
//note this triggers scene selectionChanged signal if vertex/edge/face is selected
|
|
void QGIViewPart::removePrimitives()
|
|
{
|
|
QList<QGraphicsItem*> children = childItems();
|
|
MDIViewPage* mdi = getMDIViewPage();
|
|
if (mdi) {
|
|
getMDIViewPage()->blockSceneSelection(true);
|
|
}
|
|
for (auto& c : children) {
|
|
QGIPrimPath* prim = dynamic_cast<QGIPrimPath*>(c);
|
|
if (prim) {
|
|
prim->hide();
|
|
scene()->removeItem(prim);
|
|
delete prim;
|
|
}
|
|
}
|
|
if (mdi) {
|
|
getMDIViewPage()->blockSceneSelection(false);
|
|
}
|
|
}
|
|
|
|
//! Remove all existing QGIDecoration items(SectionLine, SectionMark, ...)
|
|
void QGIViewPart::removeDecorations()
|
|
{
|
|
QList<QGraphicsItem*> children = childItems();
|
|
for (auto& c : children) {
|
|
QGIDecoration* decor = dynamic_cast<QGIDecoration*>(c);
|
|
QGIMatting* mat = dynamic_cast<QGIMatting*>(c);
|
|
if (decor) {
|
|
decor->hide();
|
|
scene()->removeItem(decor);
|
|
delete decor;
|
|
}
|
|
else if (mat) {
|
|
mat->hide();
|
|
scene()->removeItem(mat);
|
|
delete mat;
|
|
}
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::drawAllSectionLines()
|
|
{
|
|
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
|
|
if (!viewPart)
|
|
return;
|
|
|
|
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
|
|
if (!vp)
|
|
return;
|
|
if (vp->ShowSectionLine.getValue()) {
|
|
auto refs = viewPart->getSectionRefs();
|
|
for (auto& r : refs) {
|
|
if (r->isDerivedFrom(DrawComplexSection::getClassTypeId())) {
|
|
drawComplexSectionLine(r, true);
|
|
}
|
|
else {
|
|
drawSectionLine(r, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::drawSectionLine(TechDraw::DrawViewSection* viewSection, bool b)
|
|
{
|
|
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
|
|
if (!viewPart)
|
|
return;
|
|
if (!viewSection)
|
|
return;
|
|
|
|
if (!viewSection->hasGeometry())
|
|
return;
|
|
|
|
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
|
|
if (!vp) {
|
|
return;
|
|
}
|
|
float lineWidthThin = vp->HiddenWidth.getValue() * lineScaleFactor;//thin
|
|
|
|
if (b) {
|
|
QGISectionLine* sectionLine = new QGISectionLine();
|
|
addToGroup(sectionLine);
|
|
sectionLine->setSymbol(const_cast<char*>(viewSection->SectionSymbol.getValue()));
|
|
sectionLine->setSectionStyle(vp->SectionLineStyle.getValue());
|
|
App::Color color = Preferences::getAccessibleColor(vp->SectionLineColor.getValue());
|
|
sectionLine->setSectionColor(color.asValue<QColor>());
|
|
sectionLine->setPathMode(false);
|
|
|
|
//find the ends of the section line
|
|
double scale = viewPart->getScale();
|
|
std::pair<Base::Vector3d, Base::Vector3d> sLineEnds = viewSection->sectionLineEnds();
|
|
Base::Vector3d l1 = Rez::guiX(sLineEnds.first) * scale;
|
|
Base::Vector3d l2 = Rez::guiX(sLineEnds.second) * scale;
|
|
//make the section line a little longer
|
|
double fudge = 2.0 * Preferences::dimFontSizeMM();
|
|
Base::Vector3d lineDir = l2 - l1;
|
|
lineDir.Normalize();
|
|
sectionLine->setEnds(l1 - lineDir * Rez::guiX(fudge), l2 + lineDir * Rez::guiX(fudge));
|
|
|
|
//which way do the arrows point?
|
|
Base::Vector3d arrowDir = viewSection->SectionNormal.getValue();
|
|
arrowDir = -viewPart->projectPoint(arrowDir); //arrows point reverse of sectionNormal
|
|
sectionLine->setDirection(arrowDir.x, -arrowDir.y);//3d direction needs Y inversion
|
|
|
|
if (vp->SectionLineMarks.getValue()) {
|
|
ChangePointVector points = viewSection->getChangePointsFromSectionLine();
|
|
//extend the changePoint locations to match the fudged section line ends
|
|
QPointF location0 = points.front().getLocation() * scale;
|
|
location0 = location0 - DU::toQPointF(lineDir) * fudge;
|
|
QPointF location1 = points.back().getLocation() * scale;
|
|
location1 = location1 + DU::toQPointF(lineDir) * fudge;
|
|
//change points have Rez::guiX applied in sectionLine
|
|
points.front().setLocation(location0);
|
|
points.back().setLocation(location1);
|
|
sectionLine->setChangePoints(points);
|
|
}
|
|
else {
|
|
sectionLine->clearChangePoints();
|
|
}
|
|
|
|
//set the general parameters
|
|
sectionLine->setPos(0.0, 0.0);
|
|
sectionLine->setWidth(lineWidthThin);
|
|
double fontSize = Preferences::dimFontSizeMM();
|
|
sectionLine->setFont(getFont(), fontSize);
|
|
sectionLine->setZValue(ZVALUE::SECTIONLINE);
|
|
sectionLine->setRotation(-viewPart->Rotation.getValue());
|
|
sectionLine->draw();
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::drawComplexSectionLine(TechDraw::DrawViewSection* viewSection, bool b)
|
|
{
|
|
Q_UNUSED(b);
|
|
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
|
|
if (!viewPart)
|
|
return;
|
|
if (!viewSection)
|
|
return;
|
|
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
|
|
if (!vp) {
|
|
return;
|
|
}
|
|
float lineWidthThin = vp->HiddenWidth.getValue() * lineScaleFactor;//thin
|
|
|
|
auto dcs = static_cast<DrawComplexSection*>(viewSection);
|
|
BaseGeomPtrVector edges = dcs->makeSectionLineGeometry();
|
|
QPainterPath wirePath;
|
|
QPainterPath firstSeg = drawPainterPath(edges.front());
|
|
wirePath.connectPath(firstSeg);
|
|
int edgeCount = edges.size();
|
|
//NOTE: if the edges are not in nose to tail order, Qt will insert extra segments
|
|
//that will overlap the segments we add. for interrupted line styles, this
|
|
//will make the line look continuous. This is prevented in
|
|
//DrawComplexSection::makeSectionLineGeometry by calling makeNoseToTailWire
|
|
for (int i = 1; i < edgeCount; i++) {
|
|
QPainterPath edgePath = drawPainterPath(edges.at(i));
|
|
wirePath.connectPath(edgePath);
|
|
}
|
|
|
|
std::pair<Base::Vector3d, Base::Vector3d> ends = dcs->sectionLineEnds();
|
|
Base::Vector3d vStart = Rez::guiX(ends.first);//already scaled by dcs
|
|
Base::Vector3d vEnd = Rez::guiX(ends.second);
|
|
|
|
QGISectionLine* sectionLine = new QGISectionLine();
|
|
addToGroup(sectionLine);
|
|
sectionLine->setSymbol(const_cast<char*>(viewSection->SectionSymbol.getValue()));
|
|
sectionLine->setSectionStyle(vp->SectionLineStyle.getValue());
|
|
App::Color color = Preferences::getAccessibleColor(vp->SectionLineColor.getValue());
|
|
sectionLine->setSectionColor(color.asValue<QColor>());
|
|
sectionLine->setPathMode(true);
|
|
sectionLine->setPath(wirePath);
|
|
sectionLine->setEnds(vStart, vEnd);
|
|
if (vp->SectionLineMarks.getValue()) {
|
|
sectionLine->setChangePoints(dcs->getChangePointsFromSectionLine());
|
|
}
|
|
else {
|
|
sectionLine->clearChangePoints();
|
|
}
|
|
if (dcs->ProjectionStrategy.isValue("Offset")) {
|
|
Base::Vector3d arrowDirOffset = viewSection->SectionNormal.getValue();
|
|
arrowDirOffset =
|
|
-viewPart->projectPoint(arrowDirOffset);//arrows are opposite section normal
|
|
sectionLine->setDirection(arrowDirOffset.x, -arrowDirOffset.y);//invert y for Qt
|
|
}
|
|
else {
|
|
std::pair<Base::Vector3d, Base::Vector3d> dirsAligned = dcs->sectionArrowDirs();
|
|
dirsAligned.first = DrawUtil::invertY(dirsAligned.first);
|
|
dirsAligned.second = DrawUtil::invertY(dirsAligned.second);
|
|
sectionLine->setArrowDirections(dirsAligned.first, dirsAligned.second);
|
|
}
|
|
|
|
//set the general parameters
|
|
sectionLine->setPos(0.0, 0.0);
|
|
sectionLine->setWidth(lineWidthThin);
|
|
double fontSize = Preferences::dimFontSizeMM();
|
|
sectionLine->setFont(getFont(), fontSize);
|
|
sectionLine->setZValue(ZVALUE::SECTIONLINE);
|
|
sectionLine->setRotation(-viewPart->Rotation.getValue());
|
|
sectionLine->draw();
|
|
}
|
|
|
|
//TODO: use Cosmetic::CenterLine object for this to make it usable for dims.
|
|
void QGIViewPart::drawCenterLines(bool b)
|
|
{
|
|
TechDraw::DrawViewPart* viewPart = dynamic_cast<TechDraw::DrawViewPart*>(getViewObject());
|
|
if (!viewPart)
|
|
return;
|
|
|
|
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
|
|
if (!vp)
|
|
return;
|
|
|
|
if (b) {
|
|
bool horiz = vp->HorizCenterLine.getValue();
|
|
bool vert = vp->VertCenterLine.getValue();
|
|
|
|
QGICenterLine* centerLine;
|
|
double sectionSpan;
|
|
double sectionFudge = Rez::guiX(10.0);
|
|
double xVal, yVal;
|
|
if (horiz) {
|
|
centerLine = new QGICenterLine();
|
|
addToGroup(centerLine);
|
|
centerLine->setPos(0.0, 0.0);
|
|
double width = Rez::guiX(viewPart->getBoxX());
|
|
sectionSpan = width + sectionFudge;
|
|
xVal = sectionSpan / 2.0;
|
|
yVal = 0.0;
|
|
centerLine->setIntersection(horiz && vert);
|
|
centerLine->setBounds(-xVal, -yVal, xVal, yVal);
|
|
centerLine->setWidth(Rez::guiX(vp->HiddenWidth.getValue()));
|
|
centerLine->setZValue(ZVALUE::SECTIONLINE);
|
|
centerLine->draw();
|
|
}
|
|
if (vert) {
|
|
centerLine = new QGICenterLine();
|
|
addToGroup(centerLine);
|
|
centerLine->setPos(0.0, 0.0);
|
|
double height = Rez::guiX(viewPart->getBoxY());
|
|
sectionSpan = height + sectionFudge;
|
|
xVal = 0.0;
|
|
yVal = sectionSpan / 2.0;
|
|
centerLine->setIntersection(horiz && vert);
|
|
centerLine->setBounds(-xVal, -yVal, xVal, yVal);
|
|
centerLine->setWidth(Rez::guiX(vp->HiddenWidth.getValue()));
|
|
centerLine->setZValue(ZVALUE::SECTIONLINE);
|
|
centerLine->draw();
|
|
}
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::drawHighlight(TechDraw::DrawViewDetail* viewDetail, bool b)
|
|
{
|
|
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
|
|
if (!viewPart || !viewDetail) {
|
|
return;
|
|
}
|
|
|
|
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
|
|
if (!vp) {
|
|
return;
|
|
}
|
|
auto vpDetail = static_cast<ViewProviderViewPart*>(getViewProvider(viewDetail));
|
|
if (!vpDetail) {
|
|
return;
|
|
}
|
|
if (b) {
|
|
// double fontSize = getPrefFontSize();
|
|
double fontSize = Preferences::labelFontSizeMM();
|
|
QGIHighlight* highlight = new QGIHighlight();
|
|
scene()->addItem(highlight);
|
|
highlight->setReference(viewDetail->Reference.getValue());
|
|
highlight->setStyle((Qt::PenStyle)vp->HighlightLineStyle.getValue());
|
|
App::Color color = Preferences::getAccessibleColor(vp->HighlightLineColor.getValue());
|
|
highlight->setColor(color.asValue<QColor>());
|
|
highlight->setFeatureName(viewDetail->getNameInDocument());
|
|
highlight->setInteractive(true);
|
|
|
|
addToGroup(highlight);
|
|
highlight->setPos(0.0, 0.0);//sb setPos(center.x, center.y)?
|
|
|
|
Base::Vector3d center = viewDetail->AnchorPoint.getValue() * viewPart->getScale();
|
|
double rotationRad = viewPart->Rotation.getValue() * M_PI / 180.0;
|
|
center.RotateZ(rotationRad);
|
|
|
|
double radius = viewDetail->Radius.getValue() * viewPart->getScale();
|
|
highlight->setBounds(center.x - radius, center.y + radius, center.x + radius,
|
|
center.y - radius);
|
|
highlight->setWidth(Rez::guiX(vp->IsoWidth.getValue()));
|
|
highlight->setFont(getFont(), fontSize);
|
|
highlight->setZValue(ZVALUE::HIGHLIGHT);
|
|
highlight->setReferenceAngle(vpDetail->HighlightAdjust.getValue());
|
|
|
|
//handle conversion of apparent X,Y to rotated
|
|
QPointF rotCenter = highlight->mapFromParent(transformOriginPoint());
|
|
highlight->setTransformOriginPoint(rotCenter);
|
|
|
|
double rotation = viewPart->Rotation.getValue();
|
|
highlight->setRotation(rotation);
|
|
highlight->draw();
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::highlightMoved(QGIHighlight* highlight, QPointF newPos)
|
|
{
|
|
std::string highlightName = highlight->getFeatureName();
|
|
App::Document* doc = getViewObject()->getDocument();
|
|
App::DocumentObject* docObj = doc->getObject(highlightName.c_str());
|
|
auto detail = dynamic_cast<DrawViewDetail*>(docObj);
|
|
auto oldAnchor = detail->AnchorPoint.getValue();
|
|
if (detail) {
|
|
Base::Vector3d delta = Rez::appX(DrawUtil::toVector3d(newPos)) / getViewObject()->getScale();
|
|
delta = DrawUtil::invertY(delta);
|
|
detail->AnchorPoint.setValue(oldAnchor + delta);
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::drawMatting()
|
|
{
|
|
auto viewPart(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
|
|
TechDraw::DrawViewDetail* dvd = nullptr;
|
|
if (viewPart && viewPart->isDerivedFrom(TechDraw::DrawViewDetail::getClassTypeId())) {
|
|
dvd = static_cast<TechDraw::DrawViewDetail*>(viewPart);
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
|
|
double scale = dvd->getScale();
|
|
double radius = dvd->Radius.getValue() * scale;
|
|
QGIMatting* mat = new QGIMatting();
|
|
addToGroup(mat);
|
|
mat->setRadius(Rez::guiX(radius));
|
|
mat->setPos(0.0, 0.0);
|
|
mat->draw();
|
|
mat->show();
|
|
}
|
|
|
|
// As called by arc of ellipse case:
|
|
// pathArc(path, geom->major, geom->minor, geom->angle, geom->largeArc, geom->cw,
|
|
// geom->endPnt.x, geom->endPnt.y,
|
|
// geom->startPnt.x, geom->startPnt.y);
|
|
void QGIViewPart::pathArc(QPainterPath& path, double rx, double ry, double x_axis_rotation,
|
|
bool large_arc_flag, bool sweep_flag, double x, double y, double curx,
|
|
double cury)
|
|
{
|
|
double sin_th, cos_th;
|
|
double a00, a01, a10, a11;
|
|
double x0, y0, x1, y1, xc, yc;
|
|
double d, sfactor, sfactor_sq;
|
|
double th0, th1, th_arc;
|
|
int i, n_segs;
|
|
double dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
|
|
|
|
rx = qAbs(rx);
|
|
ry = qAbs(ry);
|
|
|
|
sin_th = qSin(x_axis_rotation);
|
|
cos_th = qCos(x_axis_rotation);
|
|
|
|
dx = (curx - x) / 2.0;
|
|
dy = (cury - y) / 2.0;
|
|
dx1 = cos_th * dx + sin_th * dy;
|
|
dy1 = -sin_th * dx + cos_th * dy;
|
|
Pr1 = rx * rx;
|
|
Pr2 = ry * ry;
|
|
Px = dx1 * dx1;
|
|
Py = dy1 * dy1;
|
|
/* Spec : check if radii are large enough */
|
|
check = Px / Pr1 + Py / Pr2;
|
|
if (check > 1) {
|
|
rx = rx * qSqrt(check);
|
|
ry = ry * qSqrt(check);
|
|
}
|
|
|
|
a00 = cos_th / rx;
|
|
a01 = sin_th / rx;
|
|
a10 = -sin_th / ry;
|
|
a11 = cos_th / ry;
|
|
x0 = a00 * curx + a01 * cury;
|
|
y0 = a10 * curx + a11 * cury;
|
|
x1 = a00 * x + a01 * y;
|
|
y1 = a10 * x + a11 * y;
|
|
/* (x0, y0) is current point in transformed coordinate space.
|
|
(x1, y1) is new point in transformed coordinate space.
|
|
|
|
The arc fits a unit-radius circle in this space.
|
|
*/
|
|
d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
|
|
sfactor_sq = 1.0 / d - 0.25;
|
|
if (sfactor_sq < 0)
|
|
sfactor_sq = 0;
|
|
|
|
sfactor = qSqrt(sfactor_sq);
|
|
|
|
if (sweep_flag == large_arc_flag)
|
|
sfactor = -sfactor;
|
|
|
|
xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
|
|
yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
|
|
/* (xc, yc) is center of the circle. */
|
|
|
|
th0 = qAtan2(y0 - yc, x0 - xc);
|
|
th1 = qAtan2(y1 - yc, x1 - xc);
|
|
|
|
th_arc = th1 - th0;
|
|
if (th_arc < 0 && sweep_flag)
|
|
th_arc += 2 * M_PI;
|
|
else if (th_arc > 0 && !sweep_flag)
|
|
th_arc -= 2 * M_PI;
|
|
|
|
n_segs = qCeil(qAbs(th_arc / (M_PI * 0.5 + 0.001)));
|
|
|
|
path.moveTo(curx, cury);
|
|
|
|
for (i = 0; i < n_segs; i++) {
|
|
pathArcSegment(path, xc, yc, th0 + i * th_arc / n_segs, th0 + (i + 1) * th_arc / n_segs, rx,
|
|
ry, x_axis_rotation);
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::pathArcSegment(QPainterPath& path, double xc, double yc, double th0, double th1,
|
|
double rx, double ry, double xAxisRotation)
|
|
{
|
|
double sinTh, cosTh;
|
|
double a00, a01, a10, a11;
|
|
double x1, y1, x2, y2, x3, y3;
|
|
double t;
|
|
double thHalf;
|
|
|
|
sinTh = qSin(xAxisRotation);
|
|
cosTh = qCos(xAxisRotation);
|
|
|
|
a00 = cosTh * rx;
|
|
a01 = -sinTh * ry;
|
|
a10 = sinTh * rx;
|
|
a11 = cosTh * ry;
|
|
|
|
thHalf = 0.5 * (th1 - th0);
|
|
t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf);
|
|
x1 = xc + qCos(th0) - t * qSin(th0);
|
|
y1 = yc + qSin(th0) + t * qCos(th0);
|
|
x3 = xc + qCos(th1);
|
|
y3 = yc + qSin(th1);
|
|
x2 = x3 + t * qSin(th1);
|
|
y2 = y3 - t * qCos(th1);
|
|
|
|
path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
|
|
a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
|
|
}
|
|
|
|
void QGIViewPart::toggleCache(bool state)
|
|
{
|
|
QList<QGraphicsItem*> items = childItems();
|
|
for (QList<QGraphicsItem*>::iterator it = items.begin(); it != items.end(); it++) {
|
|
//(*it)->setCacheMode((state)? DeviceCoordinateCache : NoCache); //TODO: fiddle cache settings if req'd for performance
|
|
Q_UNUSED(state);
|
|
(*it)->setCacheMode(NoCache);
|
|
(*it)->update();
|
|
}
|
|
}
|
|
|
|
void QGIViewPart::toggleCosmeticLines(bool state)
|
|
{
|
|
QList<QGraphicsItem*> items = childItems();
|
|
for (QList<QGraphicsItem*>::iterator it = items.begin(); it != items.end(); it++) {
|
|
QGIEdge* edge = dynamic_cast<QGIEdge*>(*it);
|
|
if (edge) {
|
|
edge->setCosmetic(state);
|
|
}
|
|
}
|
|
}
|
|
|
|
//get hatchObj for face i if it exists
|
|
TechDraw::DrawHatch* QGIViewPart::faceIsHatched(int i,
|
|
std::vector<TechDraw::DrawHatch*> hatchObjs) const
|
|
{
|
|
TechDraw::DrawHatch* result = nullptr;
|
|
bool found = false;
|
|
for (auto& h : hatchObjs) {
|
|
const std::vector<std::string>& sourceNames = h->Source.getSubValues();
|
|
for (auto& s : sourceNames) {
|
|
int fdx = TechDraw::DrawUtil::getIndexFromName(s);
|
|
if (fdx == i) {
|
|
result = h;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
TechDraw::DrawGeomHatch*
|
|
QGIViewPart::faceIsGeomHatched(int i, std::vector<TechDraw::DrawGeomHatch*> geomObjs) const
|
|
{
|
|
TechDraw::DrawGeomHatch* result = nullptr;
|
|
bool found = false;
|
|
for (auto& h : geomObjs) {
|
|
const std::vector<std::string>& sourceNames = h->Source.getSubValues();
|
|
for (auto& sn : sourceNames) {
|
|
int fdx = TechDraw::DrawUtil::getIndexFromName(sn);
|
|
if (fdx == i) {
|
|
result = h;
|
|
found = true;
|
|
break;
|
|
}
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
void QGIViewPart::dumpPath(const char* text, QPainterPath path)
|
|
{
|
|
QPainterPath::Element elem;
|
|
Base::Console().Message(">>>%s has %d elements\n", text, path.elementCount());
|
|
char* typeName;
|
|
for (int iElem = 0; iElem < path.elementCount(); iElem++) {
|
|
elem = path.elementAt(iElem);
|
|
if (elem.isMoveTo()) {
|
|
typeName = "MoveTo";
|
|
}
|
|
else if (elem.isLineTo()) {
|
|
typeName = "LineTo";
|
|
}
|
|
else if (elem.isCurveTo()) {
|
|
typeName = "CurveTo";
|
|
}
|
|
else {
|
|
typeName = "CurveData";
|
|
}
|
|
Base::Console().Message(">>>>> element %d: type:%d/%s pos(%.3f, %.3f) M:%d L:%d C:%d\n",
|
|
iElem, static_cast<int>(elem.type), typeName, elem.x, elem.y, static_cast<int>(elem.isMoveTo()),
|
|
static_cast<int>(elem.isLineTo()), static_cast<int>(elem.isCurveTo()));
|
|
}
|
|
}
|
|
|
|
QRectF QGIViewPart::boundingRect() const
|
|
{
|
|
// return childrenBoundingRect();
|
|
// return customChildrenBoundingRect();
|
|
return QGIView::boundingRect();
|
|
}
|
|
void QGIViewPart::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
|
{
|
|
QStyleOptionGraphicsItem myOption(*option);
|
|
myOption.state &= ~QStyle::State_Selected;
|
|
|
|
// painter->drawRect(boundingRect()); //good for debugging
|
|
|
|
QGIView::paint(painter, &myOption, widget);
|
|
}
|
|
|
|
//QGIViewPart derived classes do not need a rotate view method as rotation is handled on App side.
|
|
void QGIViewPart::rotateView() {}
|
|
|
|
bool QGIViewPart::prefFaceEdges()
|
|
{
|
|
bool result = false;
|
|
Base::Reference<ParameterGrp> hGrp = App::GetApplication()
|
|
.GetUserParameter()
|
|
.GetGroup("BaseApp")
|
|
->GetGroup("Preferences")
|
|
->GetGroup("Mod/TechDraw/General");
|
|
result = hGrp->GetBool("DrawFaceEdges", 0l);
|
|
return result;
|
|
}
|
|
|
|
bool QGIViewPart::prefPrintCenters()
|
|
{
|
|
Base::Reference<ParameterGrp> hGrp = App::GetApplication()
|
|
.GetUserParameter()
|
|
.GetGroup("BaseApp")
|
|
->GetGroup("Preferences")
|
|
->GetGroup("Mod/TechDraw/Decorations");
|
|
bool printCenters = hGrp->GetBool("PrintCenterMarks", false);//true matches v0.18 behaviour
|
|
return printCenters;
|
|
}
|