TechDraw: Radius drawing refactored - ASME support

This commit is contained in:
Tomas Pavlicek
2019-08-21 21:43:08 +02:00
committed by WandererFan
parent 93b5481c68
commit 46c73062ff
9 changed files with 413 additions and 316 deletions

View File

@@ -65,6 +65,7 @@ public:
inline bool operator== (const Vector2d &rclVct) const;
inline Vector2d operator+ (const Vector2d &rclVct) const;
inline Vector2d operator- (const Vector2d &rclVct) const;
inline Vector2d operator* (double c) const;
inline Vector2d operator/ (double c) const;
inline void Set (double fPX, double fPY);
@@ -238,6 +239,16 @@ inline double Vector2d::operator* (const Vector2d &rclVct) const
return (x * rclVct.x) + (y * rclVct.y);
}
inline Vector2d operator* (double c, const Vector2d &rclVct)
{
return Vector2d(c * rclVct.x, c * rclVct.y);
}
inline Vector2d Vector2d::operator* (double c) const
{
return Vector2d(c * x, c * y);
}
inline Vector2d Vector2d::operator/ (double c) const
{
return Vector2d(x / c, y / c);

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TechDrawGui::DlgPrefsTechDraw2Imp</class>
<widget class="QWidget" name="TechDrawGui::DlgPrefsTechDraw2Imp">
@@ -305,6 +305,46 @@
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Dimensioning Standard and Style</string>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="Gui::PrefComboBox" name="pcbStandardAndStyle">
<property name="toolTip">
<string>Preferred standard and style of drawing dimensional values</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>StandardAndStyle</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>/Mod/TechDraw/Dimensions</cstring>
</property>
<item>
<property name="text">
<string>ISO Oriented</string>
</property>
</item>
<item>
<property name="text">
<string>ISO Levelled</string>
</property>
</item>
<item>
<property name="text">
<string>ASME Regular</string>
</property>
</item>
<item>
<property name="text">
<string>ASME Inlined</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>

View File

@@ -62,6 +62,7 @@ void DlgPrefsTechDraw2Imp::saveSettings()
leLineGroup->onSave();
pdsb_VertexScale->onSave();
pcb_VertexColor->onSave();
pcbStandardAndStyle->onSave();
}
void DlgPrefsTechDraw2Imp::loadSettings()
@@ -83,6 +84,7 @@ void DlgPrefsTechDraw2Imp::loadSettings()
leLineGroup->onRestore();
pdsb_VertexScale->onRestore();
pcb_VertexColor->onRestore();
pcbStandardAndStyle->onRestore();
}
/**

View File

@@ -70,8 +70,7 @@
#include "DrawGuiUtil.h"
#ifndef M_2PI
// #define M_2PI 6.283185307179586476925287
#define M_2PI (M_PI * 2.0)
#define M_2PI ((M_PI) * 2.0)
#endif
//TODO: hide the Qt coord system (+y down).
@@ -880,7 +879,7 @@ void QGIViewDimension::draw()
double gap = (gapMargin * scaler); //sb % of radius?
//offset of dimLine from getDimText()
double horizOffset = getDefaultTextHorizontalOffset(lblCenter.x > curveCenter.x);
double horizOffset = getDefaultTextHorizontalOffset(lblCenter.x > curveCenter.x ? -1.0 : +1.0);
double vertOffset = getDefaultTextVerticalOffset();
bool outerPlacement = false;
@@ -1175,13 +1174,7 @@ void QGIViewDimension::draw()
// dim->getViewPart()->addVertex(curveCenter,true);
// }
} else if(strcmp(dimType, "Radius") == 0) {
if (prefRadiusAligned() == 0) { //ISO
drawRadiusAligned(dim, vp);
} else if (prefRadiusAligned() == 1) { //ASME
drawRadiusUniform(dim, vp);
} else {
Base::Console().Error("QGIVD::draw - bad radiusAligned pref: %d\n", prefRadiusAligned());
}
drawRadius(dim, vp);
} else if( (strcmp(dimType, "Angle") == 0) ||
(strcmp(dimType, "Angle3Pt") == 0)) {
anglePoints pts = dim->getAnglePoints();
@@ -1379,28 +1372,22 @@ void QGIViewDimension::draw()
}
}
int QGIViewDimension::classifyPointToArcPosition(double pointDistance, double pointAngle,
double radius, double startAngle, double endAngle, bool clockwise) const
double QGIViewDimension::getIsoStandardLinePlacement(double labelAngle)
{
if (angleWithinSector(pointAngle, startAngle, endAngle, clockwise)) {
return pointDistance > radius ? OUTER_SECTOR : INNER_SECTOR;
}
if (angleWithinSector(addAngles(pointAngle, M_PI), startAngle, endAngle, clockwise)) {
return OPPOSITE_SECTOR;
}
return COMPLEMENT_SECTOR;
// According to ISO 129-1 Standard Figure 23, the bordering angle is 2/3 PI, resp. -1/3 PI
// As Qt Y axis points downwards, all signs are flipped
return labelAngle > +M_PI/3.0 || labelAngle < -2.0*M_PI/3.0
? -1.0 : +1.0;
}
double QGIViewDimension::computeLineAndLabelAngles(Base::Vector3d lineTarget, Base::Vector3d labelCenter,
double lineLabelDistance, double &lineAngle, double &labelAngle) const
double QGIViewDimension::computeLineAndLabelAngles(Base::Vector2d lineTarget, Base::Vector2d labelCenter,
double lineLabelDistance, double &lineAngle, double &labelAngle)
{
// By default horizontal line and no label rotation
lineAngle = 0.0;
labelAngle = 0.0;
Base::Vector3d rawDirection(labelCenter - lineTarget);
Base::Vector2d rawDirection(labelCenter - lineTarget);
double rawDistance = rawDirection.Length();
if (rawDistance < Precision::Confusion()) { // Almost single point, can't tell
return 0.0;
@@ -1415,7 +1402,7 @@ double QGIViewDimension::computeLineAndLabelAngles(Base::Vector3d lineTarget, Ba
}
// Rotate the line by angle between the label rectangle center and label bottom side center
double devAngle = getStandardLinePlacement(rawAngle)*asin(lineLabelDistance/rawDistance);
double devAngle = getIsoStandardLinePlacement(rawAngle)*asin(lineLabelDistance/rawDistance);
lineAngle = addAngles(lineAngle, devAngle);
labelAngle = devAngle > 0.0 ? lineAngle : addAngles(lineAngle, M_PI);
@@ -1423,30 +1410,75 @@ double QGIViewDimension::computeLineAndLabelAngles(Base::Vector3d lineTarget, Ba
return devAngle;
}
Base::Vector3d QGIViewDimension::computeLineOriginPoint(Base::Vector3d lineTarget, double projectedLabelDistance,
bool QGIViewDimension::computeLineRectangleExitPoint(const QRectF &rectangle, Base::Vector2d targetPoint,
Base::Vector2d &exitPoint) {
if (targetPoint.x > rectangle.left() && targetPoint.x < rectangle.right()
&& targetPoint.y > rectangle.top() && targetPoint.y < rectangle.bottom()) {
// Target point is inside the rectangle - no crossing at all
return false;
}
Base::Vector2d lineOrigin(rectangle.center().x(), rectangle.center().y());
Base::Vector2d direction = targetPoint - lineOrigin;
if (fabs(direction.y) >= Precision::Confusion()) {
// The line is not parallel with X axis
exitPoint.y = direction.y < 0 ? rectangle.top() : rectangle.bottom();
exitPoint.x = lineOrigin.x + direction.x*(exitPoint.y - lineOrigin.y)/direction.y;
if (exitPoint.x >= rectangle.left() && exitPoint.x <= rectangle.right()) {
return true;
}
}
if (fabs(direction.x) >= Precision::Confusion()) {
// The line is not parallel with Y axis
exitPoint.x = direction.x < 0 ? rectangle.left() : rectangle.right();
exitPoint.y = lineOrigin.y + direction.y*(exitPoint.x - lineOrigin.x)/direction.x;
if (exitPoint.y >= rectangle.top() && exitPoint.y <= rectangle.bottom()) {
return true;
}
}
return false;
}
Base::Vector2d QGIViewDimension::computeLineOriginPoint(Base::Vector2d lineTarget, double projectedLabelDistance,
double lineAngle, double labelWidth, double direction) const
{
return lineTarget + (projectedLabelDistance + direction*(0.5*labelWidth + getDefaultReferenceLineOverhang()))
*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
*Base::Vector2d(cos(lineAngle), sin(lineAngle));
}
//draw a Radius dimension using "aligned" convention (ISO)
void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
ViewProviderDimension *viewProvider) const
Base::Vector2d QGIViewDimension::getIsoJointPoint(Base::Vector2d labelCenter, double width, double dir) const
{
return Base::Vector2d(labelCenter.x + dir*(width*0.5 + getDefaultReferenceLineOverhang()),
labelCenter.y + getDefaultTextVerticalOffset());
}
Base::Vector2d QGIViewDimension::getAsmeJointPoint(Base::Vector2d labelCenter, double width, double dir) const
{
return Base::Vector2d(labelCenter.x + dir*(width*0.5 + getDefaultHorizontalLeaderLength()),
labelCenter.y + TextOffsetFudge);
}
void QGIViewDimension::drawRadius(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const
{
// Preferred terminology according to ISO 129-1 for Radius:
// Dimensional Value, Leader Line, Reference Line, Terminator
QPainterPath radiusPath;
datumLabel->setRotation(0.0);
aHead1->setRotation(0.0);
aHead1->setFlipped(false);
datumLabel->setRotation(0.0);
QRectF mappedRect = mapRectFromItem(datumLabel, datumLabel->boundingRect());
Base::Vector3d labelCenter = Base::Vector3d(mappedRect.center().x(), mappedRect.center().y(), 0.0);
Base::Vector2d labelCenter = Base::Vector2d(mappedRect.center().x(), mappedRect.center().y());
arcPoints curvePoints = dimension->getArcPoints();
Base::Vector3d curveCenter = Rez::guiX(curvePoints.center);
Base::Vector2d curveCenter = Rez::guiX(curvePoints.center, true);
double mappedRadius = Rez::guiX(curvePoints.radius);
double centerDistance = (labelCenter - curveCenter).Length();
@@ -1467,24 +1499,166 @@ void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
}
double labelAngle = 0.0;
Base::Vector3d arcPoint;
Base::Vector2d arcPoint;
double lineAngle;
//TODO: does this violate "Aligned" convention?
if (viewProvider->TiltText.getValue()) { // We may rotate the label so no reference line is needed
int standardStyle = viewProvider->StandardAndStyle.getValue();
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_LEVELLED
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REGULAR) {
// The dimensional value text must stay horizontal
Base::Vector2d leftJoint, rightJoint;
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_LEVELLED) {
leftJoint = getIsoJointPoint(labelCenter, mappedRect.width(), -1.0);
rightJoint = getIsoJointPoint(labelCenter, mappedRect.width(), +1.0);
}
else {
leftJoint = getAsmeJointPoint(labelCenter, mappedRect.width(), -1.0);
rightJoint = getAsmeJointPoint(labelCenter, mappedRect.width(), +1.0);
}
double leftAngle = atan2(leftJoint.y - curveCenter.y, leftJoint.x - curveCenter.x);
double rightAngle = atan2(rightJoint.y - curveCenter.y, rightJoint.x - curveCenter.x);
int leftPosition = classifyPointToArcPosition((leftJoint - curveCenter).Length(),
leftAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise);
int rightPosition = classifyPointToArcPosition((rightJoint - curveCenter).Length(),
rightAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise);
Base::Vector2d originPoint;
Base::Vector2d jointPoint;
Base::Vector2d targetPoint;
if (leftPosition <= OPPOSITE_SECTOR || rightPosition <= OPPOSITE_SECTOR) {
// At least from one of the reference line sides can run the leader line
// perpendicularly to the arc, i.e. in direction to the center
if (leftPosition <= OPPOSITE_SECTOR && rightPosition <= OPPOSITE_SECTOR) {
// Both are acceptable, so choose the more convenient one
double leftBend = leftPosition == INNER_SECTOR ? M_PI - fabs(leftAngle) : fabs(leftAngle);
double rightBend = rightPosition == INNER_SECTOR ? fabs(rightAngle) : M_PI - fabs(rightAngle);
// If right leader line bends less or does not cross the dimensional value,
// use it by marking left point as outlayer
if (leftBend <= M_PI_2 || rightBend <= M_PI_2
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REGULAR) {
// Either at least one line does not cross the text, or it is an ASME connection
// (vertically centered), which behaves the same going up or down
if (rightBend < leftBend) {
leftPosition = COMPLEMENT_SECTOR;
}
}
else { // ISO connection, but crosses the value - try to find the one pointing down (if exists)
bool leftDown = leftPosition == INNER_SECTOR ? leftAngle > 0.0 : leftAngle < 0.0;
bool rightDown = rightPosition == INNER_SECTOR ? rightAngle > 0.0 : rightAngle < 0.0;
if (leftDown == rightDown) { // Both lines go downwards or upwards
if (rightBend < leftBend) {
leftPosition = COMPLEMENT_SECTOR;
}
}
else if (rightDown) {
leftPosition = COMPLEMENT_SECTOR;
}
}
}
int resultPosition;
if (leftPosition <= OPPOSITE_SECTOR) {
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REGULAR) {
originPoint = Base::Vector2d(labelCenter.x + getDefaultTextHorizontalOffset(-1.0),
labelCenter.y + TextOffsetFudge);
}
else {
originPoint = rightJoint;
}
jointPoint = leftJoint;
lineAngle = leftAngle;
resultPosition = leftPosition;
}
else {
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REGULAR) {
originPoint = Base::Vector2d(labelCenter.x + getDefaultTextHorizontalOffset(+1.0),
labelCenter.y + TextOffsetFudge);
}
else {
originPoint = leftJoint;
}
jointPoint = rightJoint;
lineAngle = rightAngle;
resultPosition = rightPosition;
}
switch (resultPosition) {
case INNER_SECTOR:
arcPoint = curveCenter + mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
targetPoint = arcPoint;
break;
case OUTER_SECTOR:
arcPoint = curveCenter + mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
// If desired, extend the target point to the center
if (viewProvider->ExtendToCenter.getValue()) {
targetPoint = curveCenter;
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_LEVELLED) {
aHead1->flip();
}
}
else {
targetPoint = arcPoint;
aHead1->flip();
}
break;
case OPPOSITE_SECTOR:
arcPoint = curveCenter - mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
targetPoint = arcPoint;
aHead1->flip();
break;
}
}
else { // Both joint points lay outside the vertical angles
arcPoint = Rez::guiX(curvePoints.midArc, true);
if (labelCenter.x >= arcPoint.x) { // Place the dimensional value right
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REGULAR) {
originPoint = Base::Vector2d(mappedRect.left(), labelCenter.y);
}
else {
originPoint = rightJoint;
}
jointPoint = leftJoint;
}
else { // Place the dimensional value left
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REGULAR) {
originPoint = Base::Vector2d(mappedRect.right(), labelCenter.y);
}
else {
originPoint = leftJoint;
}
jointPoint = rightJoint;
}
targetPoint = arcPoint;
lineAngle = atan2(targetPoint.y - jointPoint.y, targetPoint.x - jointPoint.x);
}
radiusPath.moveTo(originPoint.x, originPoint.y);
radiusPath.lineTo(jointPoint.x, jointPoint.y);
radiusPath.lineTo(targetPoint.x, targetPoint.y);
}
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
// We may rotate the label so no reference line is needed
double devAngle = computeLineAndLabelAngles(curveCenter, labelCenter,
getDefaultTextVerticalOffset(), lineAngle, labelAngle);
// Correct the label center distance projected on the leader line
centerDistance *= cos(devAngle);
Base::Vector3d originPoint;
Base::Vector3d targetPoint;
Base::Vector2d originPoint;
Base::Vector2d targetPoint;
switch (classifyPointToArcPosition(centerDistance, lineAngle, mappedRadius,
arcStartAngle, arcEndAngle, arcClockwise)) {
case INNER_SECTOR: {
// The label is placed within the arc sector angle, there's always point
// on the arc where the leader line can cross it perpendicularly
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
arcPoint = curveCenter + mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
if (viewProvider->ExtendToCenter.getValue()) { // Start in the very center
originPoint = curveCenter;
@@ -1498,7 +1672,7 @@ void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
}
case OUTER_SECTOR: {
// Same situation as when on the inner side of sector
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
arcPoint = curveCenter + mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
aHead1->flip();
originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle,
@@ -1510,7 +1684,7 @@ void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
case OPPOSITE_SECTOR: {
// If the label is placed within the vertically opposite angle of the arc sector,
// the leader line passing through the arc center can mark a point on the arc
arcPoint = curveCenter - mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
arcPoint = curveCenter - mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
aHead1->flip();
originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle,
@@ -1520,7 +1694,7 @@ void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
}
default: {
// Label outside both arc wedges
arcPoint = Rez::guiX(curvePoints.midArc);
arcPoint = Rez::guiX(curvePoints.midArc, true);
aHead1->flip();
devAngle = computeLineAndLabelAngles(arcPoint, labelCenter,
getDefaultTextVerticalOffset(), lineAngle, labelAngle);
@@ -1537,104 +1711,82 @@ void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
radiusPath.moveTo(originPoint.x, originPoint.y);
radiusPath.lineTo(targetPoint.x, targetPoint.y);
}
else { // The dimensional value text must stay horizontal
Base::Vector3d leftJoint(mappedRect.left() - getDefaultReferenceLineOverhang(),
labelCenter.y + getDefaultTextVerticalOffset(), 0.0);
Base::Vector3d rightJoint(mappedRect.right() + getDefaultReferenceLineOverhang(),
labelCenter.y + getDefaultTextVerticalOffset(), 0.0);
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
// Text must remain horizontal, but it may split the leader line
Base::Vector2d lineDirection(labelCenter - curveCenter);
lineAngle = atan2(lineDirection.y, lineDirection.x);
double leftAngle = atan2(leftJoint.y - curveCenter.y, leftJoint.x - curveCenter.x);
double rightAngle = atan2(rightJoint.y - curveCenter.y, rightJoint.x - curveCenter.x);
Base::Vector2d exitPoint;
switch (classifyPointToArcPosition(centerDistance, lineAngle, mappedRadius,
arcStartAngle, arcEndAngle, arcClockwise)) {
case INNER_SECTOR: {
// The label is placed within the arc sector angle, there's always point
// on the arc where the leader line can cross it perpendicularly
arcPoint = curveCenter + mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
int leftPosition = classifyPointToArcPosition((leftJoint - curveCenter).Length(),
leftAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise);
int rightPosition = classifyPointToArcPosition((rightJoint - curveCenter).Length(),
rightAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise);
Base::Vector3d originPoint;
Base::Vector3d jointPoint;
Base::Vector3d targetPoint;
if (leftPosition >= OPPOSITE_SECTOR || rightPosition >= OPPOSITE_SECTOR) {
// At least from one of the reference line sides can run the leader line
// perpendicularly to the arc, i.e. in direction to the center
if (leftPosition >= OPPOSITE_SECTOR && rightPosition >= OPPOSITE_SECTOR) {
// Both are acceptable, so choose the more convenient one
double leftBend = leftPosition == INNER_SECTOR ? M_PI - fabs(leftAngle) : fabs(leftAngle);
double rightBend = rightPosition == INNER_SECTOR ? fabs(rightAngle) : M_PI - fabs(rightAngle);
// If right leader line bends less or does not cross the dimensional value,
// use it by marking left point as outlayer
if (leftBend <= M_PI_2 || rightBend <= M_PI_2) { // At least one line is not crossing the text
if (rightBend < leftBend) {
leftPosition = COMPLEMENT_SECTOR;
}
if (computeLineRectangleExitPoint(mappedRect, arcPoint, exitPoint)) {
radiusPath.moveTo(exitPoint.x, exitPoint.y);
radiusPath.lineTo(arcPoint.x, arcPoint.y);
}
else {
bool leftDown = leftPosition == INNER_SECTOR ? leftAngle > 0.0 : leftAngle < 0.0;
bool rightDown = rightPosition == INNER_SECTOR ? rightAngle > 0.0 : rightAngle < 0.0;
if (leftDown == rightDown) { // Both lines go downwards or upwards
if (rightBend < leftBend) {
leftPosition = COMPLEMENT_SECTOR;
}
}
else if (rightDown) {
leftPosition = COMPLEMENT_SECTOR;
}
if (viewProvider->ExtendToCenter.getValue()
&& computeLineRectangleExitPoint(mappedRect, curveCenter, exitPoint)) {
radiusPath.moveTo(exitPoint.x, exitPoint.y);
radiusPath.lineTo(curveCenter.x, curveCenter.y);
}
}
int resultPosition;
if (leftPosition >= OPPOSITE_SECTOR) {
originPoint = rightJoint;
jointPoint = leftJoint;
lineAngle = leftAngle;
resultPosition = leftPosition;
}
else {
originPoint = leftJoint;
jointPoint = rightJoint;
lineAngle = rightAngle;
resultPosition = rightPosition;
break;
}
case OUTER_SECTOR: {
// Same situation as when on the inner side of sector
arcPoint = curveCenter + mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
switch (resultPosition) {
case INNER_SECTOR:
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
targetPoint = arcPoint;
break;
case OUTER_SECTOR:
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
// If desired, extend the target point to the center
targetPoint = viewProvider->ExtendToCenter.getValue() ? curveCenter : arcPoint;
Base::Vector2d targetPoint(viewProvider->ExtendToCenter.getValue()
? curveCenter : arcPoint);
if (computeLineRectangleExitPoint(mappedRect, targetPoint, exitPoint)) {
radiusPath.moveTo(exitPoint.x, exitPoint.y);
radiusPath.lineTo(targetPoint.x, targetPoint.y);
}
if (!viewProvider->ExtendToCenter.getValue()) {
aHead1->flip();
break;
case OPPOSITE_SECTOR:
arcPoint = curveCenter - mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
targetPoint = arcPoint;
aHead1->flip();
break;
}
break;
}
case OPPOSITE_SECTOR: {
// If the label is placed within the vertically opposite angle of the arc sector,
// the leader line passing through the arc center can mark a point on the arc
arcPoint = curveCenter - mappedRadius*Base::Vector2d(cos(lineAngle), sin(lineAngle));
if (computeLineRectangleExitPoint(mappedRect, arcPoint, exitPoint)) {
radiusPath.moveTo(exitPoint.x, exitPoint.y);
radiusPath.lineTo(arcPoint.x, arcPoint.y);
}
aHead1->flip();
break;
}
default: {
// Label outside both arc wedges
arcPoint = Rez::guiX(curvePoints.midArc, true);
lineDirection = labelCenter - arcPoint;
lineAngle = atan2(lineDirection.y, lineDirection.x);
if (computeLineRectangleExitPoint(mappedRect, arcPoint, exitPoint)) {
radiusPath.moveTo(exitPoint.x, exitPoint.y);
radiusPath.lineTo(arcPoint.x, arcPoint.y);
}
aHead1->flip();
break;
}
}
else { // Both joint points lay outside the vertical angles
arcPoint = Rez::guiX(curvePoints.midArc);
if (labelCenter.x >= arcPoint.x) { // Place the dimensional value right
originPoint = rightJoint;
jointPoint = leftJoint;
}
else { // Place the dimensional value left
originPoint = leftJoint;
jointPoint = rightJoint;
}
targetPoint = arcPoint;
lineAngle = atan2(targetPoint.y - jointPoint.y, targetPoint.x - jointPoint.x);
}
radiusPath.moveTo(originPoint.x, originPoint.y);
radiusPath.lineTo(jointPoint.x, jointPoint.y);
radiusPath.lineTo(targetPoint.x, targetPoint.y);
}
else {
Base::Console().Error("QGIVD::drawRadius - this Standard&Style is not supported: %d\n", standardStyle);
return;
}
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().width()*0.5,
@@ -1644,7 +1796,6 @@ void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
dimLines->setPath(radiusPath);
aHead1->setPos(arcPoint.x, arcPoint.y);
aHead1->setRotation(0.0);
aHead1->setDirMode(true);
aHead1->setDirection(lineAngle);
if (viewProvider->FlipArrowheads.getValue()) {
@@ -1658,141 +1809,6 @@ void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
aHead2->hide();
}
//Draw a Radius dimension using "uniform" alignment convention (Ansi/Asme)
void QGIViewDimension::drawRadiusUniform(TechDraw::DrawViewDimension* dim,
TechDrawGui::ViewProviderDimension* viewProvider) const
{
// preferred terminology: Dimension Text, Dimension Line(s), Extension Lines, Arrowheads
// radius gets 1 dimension line from the dimension text to a point on the curve
aHead1->setFlipped(false);
Base::Vector3d pointOnCurve,curveCenter;
double radius;
arcPoints pts = dim->getArcPoints();
bool isArc = pts.isArc;
radius = Rez::guiX(pts.radius);
curveCenter = Rez::guiX(pts.center);
pointOnCurve = Rez::guiX(pts.onCurve.first);
QRectF mappedRect = mapRectFromItem(datumLabel, datumLabel->boundingRect());
Base::Vector3d lblCenter = Base::Vector3d(mappedRect.center().x(), mappedRect.center().y(), 0.0);
// Note Bounding Box size is not the same width or height as text (only used for finding center)
float bbX = datumLabel->boundingRect().width();
float bbY = datumLabel->boundingRect().height();
datumLabel->setTransformOriginPoint(bbX / 2, bbY /2);
datumLabel->setRotation(0.0); //label is always right side up & horizontal
//if inside the arc (len(DimLine < radius)) arrow goes from center to edge away from label
//if outside the arc arrow kinks, then goes to edge nearest label
bool outerPlacement = false;
if ((lblCenter - curveCenter).Length() > radius) { //label is outside circle
outerPlacement = true;
}
Base::Vector3d dirDimLine = (lblCenter - curveCenter).Normalize();
if (fabs(dirDimLine.Length()) < (Precision::Confusion())) {
dirDimLine = Base::Vector3d(-1.0,0.0,0.0);
}
// Base::Vector3d adjustDir = dirDimLine; //adjust line lengths for arrowheads
double dimLineAdjust = Rez::guiX(QGIArrow::getOverlapAdjust(QGIArrow::getPrefArrowStyle(),
QGIArrow::getPrefArrowSize()));
Base::Vector3d dLineStart;
Base::Vector3d dLineEnd; //?? radius draws line from text to curve?? (diam is curve to text!)
Base::Vector3d kinkPoint;
double margin = Rez::guiX(5.f); //space around label
double kinkLength = Rez::guiX(5.0); //sb % of horizontal dist(lblCenter,curveCenter)???
if (outerPlacement) {
double offset = getDefaultTextHorizontalOffset(lblCenter.x > curveCenter.x);
dLineStart.y = lblCenter.y;
dLineStart.x = lblCenter.x + offset; //start at right or left of label
kinkLength = (lblCenter.x < curveCenter.x) ? kinkLength : -kinkLength;
kinkPoint.y = dLineStart.y;
kinkPoint.x = dLineStart.x + kinkLength;
pointOnCurve = curveCenter + (kinkPoint - curveCenter).Normalize() * radius;
dLineEnd = pointOnCurve + (kinkPoint - curveCenter).Normalize() * dimLineAdjust;
if ((kinkPoint - curveCenter).Length() < radius) {
dirDimLine = (curveCenter - kinkPoint).Normalize();
} else {
dirDimLine = (kinkPoint - curveCenter).Normalize();
}
} else {
dLineStart = curveCenter - dirDimLine * margin; //just beyond centerpoint
pointOnCurve = curveCenter - dirDimLine * radius;
dLineEnd = pointOnCurve + dirDimLine * dimLineAdjust;
kinkPoint = dLineStart; //no kink
}
//handle partial arc weird cases
if (isArc) {
Base::Vector3d midPt = Rez::guiX(pts.midArc);
Base::Vector3d startPt = Rez::guiX(pts.arcEnds.first);
Base::Vector3d endPt = Rez::guiX(pts.arcEnds.second);
if (outerPlacement &&
!dim->leaderIntersectsArc(Rez::appX(curveCenter),Rez::appX(kinkPoint))) { //keep pathological case within arc
pointOnCurve = midPt;
} else if (!outerPlacement) {
if ((midPt - lblCenter).Length() > (midPt - curveCenter).Length()) { //label is farther than center
dirDimLine = dirDimLine * -1;
}
dLineStart = curveCenter + dirDimLine * margin;
pointOnCurve = curveCenter + dirDimLine * radius;
dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust;
kinkPoint = dLineStart;
if (!dim->leaderIntersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc
if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) {
if (!pts.arcCW ) {
pointOnCurve = endPt;
} else {
pointOnCurve = startPt;
}
} else {
if (!pts.arcCW ) {
pointOnCurve = startPt;
} else {
pointOnCurve = endPt;
}
}
dLineStart = curveCenter + (pointOnCurve - curveCenter).Normalize() * margin;
dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust;
kinkPoint = dLineStart;
}
}
}
QPainterPath dLinePath; //radius dimension line path
dLinePath.moveTo(dLineStart.x, dLineStart.y);
dLinePath.lineTo(kinkPoint.x, kinkPoint.y);
dLinePath.lineTo(dLineEnd.x, dLineEnd.y);
dimLines->setPath(dLinePath);
Base::Vector3d ar1Pos = pointOnCurve;
Base::Vector3d dirArrowLine = (pointOnCurve - kinkPoint).Normalize();
float arAngle = atan2(dirArrowLine.y, dirArrowLine.x) * 180 / M_PI;
//NOTE: in this case aHead1->dirMode is false and Qt rotation is used to point arrowhead
aHead1->setPos(ar1Pos.x, ar1Pos.y);
aHead1->setDirMode(false);
aHead1->setRotation(arAngle);
if (viewProvider->FlipArrowheads.getValue()) {
aHead1->flip();
}
aHead1->setStyle(QGIArrow::getPrefArrowStyle());
aHead1->setSize(QGIArrow::getPrefArrowSize());
aHead1->draw();
aHead1->show();
aHead2->hide();
// code for showCenterMark as attribute of Dimension instead of View
// if (dim->CentreLines.getValue()) {
// curveCenterMark->setPos(curveCenter.x,curveCenter.y);
// centerMark->show();
// dim->getViewPart()->addVertex(curveCenter,true);
// }
}
QColor QGIViewDimension::getNormalColor()
{
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
@@ -1896,12 +1912,9 @@ void QGIViewDimension::drawBorder(void)
const double QGIViewDimension::TextOffsetFudge = 2.0;
double QGIViewDimension::getDefaultTextHorizontalOffset(bool toLeft) const
double QGIViewDimension::getDefaultTextHorizontalOffset(double direction) const
{
double offset = datumLabel->boundingRect().width()*0.5 + TextOffsetFudge*2.0;
// return toLeft ? -offset - TextOffsetFudge*5.0: offset;
return toLeft ? -offset : offset;
return direction*(datumLabel->boundingRect().width()*0.5 + TextOffsetFudge*2.0);
}
double QGIViewDimension::getDefaultTextVerticalOffset() const
@@ -1922,12 +1935,11 @@ double QGIViewDimension::getDefaultReferenceLineOverhang() const
return 2.0*TextOffsetFudge;
}
double QGIViewDimension::getStandardLinePlacement(double labelAngle)
double QGIViewDimension::getDefaultHorizontalLeaderLength() const
{
// According to ISO 129-1 Standard Figure 23, the bordering angle is 2/3 PI, resp. -1/3 PI
// As Qt Y axis points downwards, all signs are flipped
return labelAngle > +M_PI/3.0 || labelAngle < -2.0*M_PI/3.0
? -1.0 : +1.0;
QFontMetrics fontMetrics(datumLabel->getFont());
return 1.5*fontMetrics.width(QChar::fromLatin1('M'));
}
bool QGIViewDimension::angleWithinSector(double testAngle, double startAngle, double endAngle, bool clockwise)
@@ -1961,6 +1973,20 @@ double QGIViewDimension::addAngles(double angle1, double angle2)
}
}
int QGIViewDimension::classifyPointToArcPosition(double pointDistance, double pointAngle,
double radius, double startAngle, double endAngle, bool clockwise)
{
if (angleWithinSector(pointAngle, startAngle, endAngle, clockwise)) {
return pointDistance > radius ? OUTER_SECTOR : INNER_SECTOR;
}
if (angleWithinSector(addAngles(pointAngle, M_PI), startAngle, endAngle, clockwise)) {
return OPPOSITE_SECTOR;
}
return COMPLEMENT_SECTOR;
}
//frame, border, caption are never shown in QGIVD, so shouldn't be in bRect
QRectF QGIViewDimension::boundingRect() const
{
@@ -2010,13 +2036,4 @@ void QGIViewDimension::setPens(void)
aHead2->setWidth(m_lineWidth);
}
int QGIViewDimension::prefRadiusAligned(void)
{
int result = 0;
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Standards");
result = hGrp->GetInt("RadiusAligned", 0); //default to ISO
return result;
}
#include <Mod/TechDraw/Gui/moc_QGIViewDimension.cpp>

View File

@@ -156,23 +156,19 @@ public Q_SLOTS:
protected:
static const int INNER_SECTOR = 3;
static const int OUTER_SECTOR = 2;
static const int OPPOSITE_SECTOR = 1;
static const int COMPLEMENT_SECTOR = 0;
static double getIsoStandardLinePlacement(double labelAngle);
static double computeLineAndLabelAngles(Base::Vector2d lineTarget, Base::Vector2d labelCenter,
double lineLabelDistance, double &lineAngle, double &labelAngle);
static bool computeLineRectangleExitPoint(const QRectF &rectangle, Base::Vector2d targetPoint,
Base::Vector2d &exitPoint);
int classifyPointToArcPosition(double pointDistance, double pointAngle,
double radius, double startAngle, double endAngle, bool clockwise) const;
double computeLineAndLabelAngles(Base::Vector3d lineTarget, Base::Vector3d labelCenter,
double lineLabelDistance, double &lineAngle, double &labelAngle) const;
Base::Vector3d computeLineOriginPoint(Base::Vector3d lineTarget, double projectedLabelDistance,
Base::Vector2d computeLineOriginPoint(Base::Vector2d lineTarget, double projectedLabelDistance,
double lineAngle, double labelWidth, double direction) const;
Base::Vector2d getIsoJointPoint(Base::Vector2d labelCenter, double width, double dir) const;
Base::Vector2d getAsmeJointPoint(Base::Vector2d labelCenter, double width, double dir) const;
void draw() override;
void drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
ViewProviderDimension *viewProvider) const;
void drawRadiusUniform(TechDraw::DrawViewDimension *dimension,
ViewProviderDimension *viewProvider) const;
void drawRadius(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const;
virtual QVariant itemChange( GraphicsItemChange change,
const QVariant &value ) override;
@@ -182,8 +178,6 @@ protected:
Base::Vector3d findIsoExt(Base::Vector3d isoDir);
QString getPrecision(void);
int prefRadiusAligned(void);
protected:
bool hasHover;
QGIDatumLabel* datumLabel; //dimension text
@@ -197,13 +191,21 @@ protected:
private:
static const double TextOffsetFudge;
double getDefaultTextHorizontalOffset(bool toLeft) const;
double getDefaultTextHorizontalOffset(double direction) const;
double getDefaultTextVerticalOffset() const;
double getDefaultReferenceLineOverhang() const;
double getDefaultHorizontalLeaderLength() const;
static double getStandardLinePlacement(double labelAngle);
static bool angleWithinSector(double testAngle, double startAngle, double endAngle, bool clockwise);
static double addAngles(double angle1, double angle2);
static const int INNER_SECTOR = 0;
static const int OUTER_SECTOR = 1;
static const int OPPOSITE_SECTOR = 2;
static const int COMPLEMENT_SECTOR = 3;
static int classifyPointToArcPosition(double pointDistance, double pointAngle,
double radius, double startAngle, double endAngle, bool clockwise);
};
} // namespace MDIViewPageGui

View File

@@ -61,6 +61,12 @@ Base::Vector3d Rez::guiX(Base::Vector3d v)
return result;
}
Base::Vector2d Rez::guiX(Base::Vector3d v, bool planar)
{
Q_UNUSED(planar);
return Base::Vector2d(guiX(v.x), guiX(v.y));
}
//turn Gui side value to App side value
double Rez::appX(double x)
{

View File

@@ -42,6 +42,7 @@ public:
//turn App side value to Gui side value
static double guiX(double x);
static Base::Vector3d guiX(Base::Vector3d v);
static Base::Vector2d guiX(Base::Vector3d v, bool planar);
//turn Gui side value to App side value
static double appX(double x);
static Base::Vector3d appX(Base::Vector3d v);

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
* Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de> *
* Copyright (c) 2012 Luke Parry <l.parry@warwick.ac.uk> *
* *
@@ -43,6 +43,9 @@
using namespace TechDrawGui;
const char *ViewProviderDimension::StandardAndStyleEnums[]=
{ "ISO Oriented", "ISO Levelled", "ASME Regular", "ASME Inlined", NULL };
PROPERTY_SOURCE(TechDrawGui::ViewProviderDimension, TechDrawGui::ViewProviderDrawingView)
//**************************************************************************
@@ -79,9 +82,12 @@ ViewProviderDimension::ViewProviderDimension()
fcColor.setPackedValue(hGrp->GetUnsigned("Color", 0x00000000));
ADD_PROPERTY_TYPE(Color,(fcColor),group,App::Prop_None,"The color of the Dimension");
ADD_PROPERTY_TYPE(FlipArrowheads, (false), group, App::Prop_None,"Reverse the normal direction of arrowheads on dimline");
ADD_PROPERTY_TYPE(TiltText, (true), group, App::Prop_None,"Rotate the text label so it is parallel with dimline");
int standardStyle = hGrp->GetInt("StandardAndStyle", STD_STYLE_ISO_ORIENTED);
ADD_PROPERTY_TYPE(StandardAndStyle, (standardStyle), group, App::Prop_None, "Specify the standard according to which this dimension is drawn");
StandardAndStyle.setEnums(StandardAndStyleEnums);
ADD_PROPERTY_TYPE(ExtendToCenter, (true), group, App::Prop_None,"Prolong the leader line right upto the center point");
ADD_PROPERTY_TYPE(FlipArrowheads, (false), group, App::Prop_None,"Reverse the normal direction of arrowheads on dimline");
}
ViewProviderDimension::~ViewProviderDimension()
@@ -132,9 +138,10 @@ void ViewProviderDimension::onChanged(const App::Property* p)
if ((p == &Font) ||
(p == &Fontsize) ||
(p == &LineWidth) ||
(p == &FlipArrowheads) ||
(p == &TiltText) ||
(p == &ExtendToCenter)) {
(p == &StandardAndStyle) ||
(p == &ExtendToCenter) ||
(p == &FlipArrowheads))
{
QGIView* qgiv = getQView();
if (qgiv) {
qgiv->updateView(true);

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
* Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de> *
* Copyright (c) 2012 Luke Parry <l.parry@warwick.ac.uk> *
* *
@@ -44,13 +44,19 @@ public:
/// destructor
virtual ~ViewProviderDimension();
App::PropertyFont Font;
App::PropertyLength Fontsize;
App::PropertyFloat LineWidth;
App::PropertyColor Color;
App::PropertyBool FlipArrowheads;
App::PropertyBool TiltText;
App::PropertyBool ExtendToCenter;
App::PropertyFont Font;
App::PropertyLength Fontsize;
App::PropertyFloat LineWidth;
App::PropertyColor Color;
static const int STD_STYLE_ISO_ORIENTED = 0;
static const int STD_STYLE_ISO_LEVELLED = 1;
static const int STD_STYLE_ASME_REGULAR = 2;
static const int STD_STYLE_ASME_INLINED = 3;
App::PropertyEnumeration StandardAndStyle;
App::PropertyBool ExtendToCenter;
App::PropertyBool FlipArrowheads;
virtual void attach(App::DocumentObject *);
virtual void setDisplayMode(const char* ModeName);
@@ -61,6 +67,11 @@ public:
virtual void onChanged(const App::Property* p);
virtual TechDraw::DrawViewDimension* getViewObject() const;
private:
static const char *StandardAndStyleEnums[];
};
} // namespace TechDrawGui