As the title says. Currently user is able to change geometry if OVP is set on labels. This is because `doEnforceControlParameters` reads mouse position every mouse move and calculates angle from it, resulting in a new angle every time mouse is moved. So, this patch basically reads the position before it was set, and once it is set, locks the position of the mouse and calculates angle from it which will be maintained until user cleans the OVP or makes a new primitive.
2841 lines
127 KiB
C++
2841 lines
127 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2022 Abdullah Tahiri <abdullah.tahiri.yo@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 *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef SKETCHERGUI_DrawSketchHandlerRectangle_H
|
|
#define SKETCHERGUI_DrawSketchHandlerRectangle_H
|
|
|
|
#include <QApplication>
|
|
|
|
#include <Gui/BitmapFactory.h>
|
|
#include <Gui/Notifications.h>
|
|
#include <Gui/Command.h>
|
|
#include <Gui/CommandT.h>
|
|
#include <Gui/InputHint.h>
|
|
#include <Mod/Sketcher/App/SketchObject.h>
|
|
|
|
#include "DrawSketchDefaultWidgetController.h"
|
|
#include "DrawSketchControllableHandler.h"
|
|
|
|
#include "GeometryCreationMode.h"
|
|
#include "Utils.h"
|
|
|
|
namespace SketcherGui
|
|
{
|
|
|
|
extern GeometryCreationMode geometryCreationMode; // defined in CommandCreateGeo.cpp
|
|
|
|
class DrawSketchHandlerRectangle;
|
|
|
|
namespace ConstructionMethods
|
|
{
|
|
|
|
enum class RectangleConstructionMethod
|
|
{
|
|
Diagonal,
|
|
CenterAndCorner,
|
|
ThreePoints,
|
|
CenterAnd3Points,
|
|
End // Must be the last one
|
|
};
|
|
|
|
}
|
|
|
|
using DSHRectangleController = DrawSketchDefaultWidgetController<
|
|
DrawSketchHandlerRectangle,
|
|
StateMachines::FiveSeekEnd,
|
|
/*PAutoConstraintSize =*/3,
|
|
/*OnViewParametersT =*/OnViewParameters<6, 6, 8, 8>, // NOLINT
|
|
/*WidgetParametersT =*/WidgetParameters<0, 0, 0, 0>, // NOLINT
|
|
/*WidgetCheckboxesT =*/WidgetCheckboxes<2, 2, 2, 2>, // NOLINT
|
|
/*WidgetComboboxesT =*/WidgetComboboxes<1, 1, 1, 1>, // NOLINT
|
|
ConstructionMethods::RectangleConstructionMethod,
|
|
/*bool PFirstComboboxIsConstructionMethod =*/true>;
|
|
|
|
using DSHRectangleControllerBase = DSHRectangleController::ControllerBase;
|
|
|
|
using DrawSketchHandlerRectangleBase = DrawSketchControllableHandler<DSHRectangleController>;
|
|
|
|
|
|
class DrawSketchHandlerRectangle: public DrawSketchHandlerRectangleBase
|
|
{
|
|
// Allow specialisations of controllers access to private members
|
|
friend DSHRectangleController;
|
|
friend DSHRectangleControllerBase;
|
|
|
|
public:
|
|
DrawSketchHandlerRectangle(ConstructionMethod constrMethod = ConstructionMethod::Diagonal,
|
|
bool roundcorners = false,
|
|
bool frame = false)
|
|
: DrawSketchHandlerRectangleBase(constrMethod)
|
|
, roundCorners(roundcorners)
|
|
, makeFrame(frame)
|
|
, cornersReversed(false)
|
|
, radius(0.0)
|
|
, length(0.0)
|
|
, width(0.0)
|
|
, thickness(0.)
|
|
, radiusFrame(0.0)
|
|
, angle(0.0)
|
|
, angle123(0.0)
|
|
, angle412(0.0)
|
|
, firstCurve(Sketcher::GeoEnum::GeoUndef)
|
|
, constructionPointOneId(Sketcher::GeoEnum::GeoUndef)
|
|
, constructionPointTwoId(Sketcher::GeoEnum::GeoUndef)
|
|
, constructionPointThreeId(Sketcher::GeoEnum::GeoUndef)
|
|
, centerPointId(Sketcher::GeoEnum::GeoUndef)
|
|
, side(0)
|
|
, lengthSign(0)
|
|
, widthSign(0)
|
|
{}
|
|
|
|
~DrawSketchHandlerRectangle() override = default;
|
|
|
|
private:
|
|
std::list<Gui::InputHint> getToolHints() const override
|
|
{
|
|
using State = std::pair<ConstructionMethod, SelectMode>;
|
|
using enum Gui::InputHint::UserInput;
|
|
|
|
const Gui::InputHint switchHint {.message = tr("%1 switch mode"), .sequences = {KeyM}};
|
|
const Gui::InputHint roundedCornersHint {.message = tr("%1 toggle rounded corners"),
|
|
.sequences = {KeyU}};
|
|
const Gui::InputHint frameHint {.message = tr("%1 toggle frame"), .sequences = {KeyJ}};
|
|
|
|
return Gui::lookupHints<State>(
|
|
{constructionMethod(), state()},
|
|
{
|
|
// Diagonal method
|
|
{.state = {ConstructionMethod::Diagonal, SelectMode::SeekFirst},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick first corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::Diagonal, SelectMode::SeekSecond},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick opposite corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::Diagonal, SelectMode::SeekThird},
|
|
.hints =
|
|
{
|
|
{tr("%1 set corner radius or frame thickness"), {MouseMove}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::Diagonal, SelectMode::SeekFourth},
|
|
.hints =
|
|
{
|
|
{tr("%1 set frame thickness"), {MouseMove}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
|
|
// CenterAndCorner method
|
|
{.state = {ConstructionMethod::CenterAndCorner, SelectMode::SeekFirst},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick center"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::CenterAndCorner, SelectMode::SeekSecond},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::CenterAndCorner, SelectMode::SeekThird},
|
|
.hints =
|
|
{
|
|
{tr("%1 set corner radius or frame thickness"), {MouseMove}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::CenterAndCorner, SelectMode::SeekFourth},
|
|
.hints =
|
|
{
|
|
{tr("%1 set frame thickness"), {MouseMove}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
|
|
// ThreePoints method
|
|
{.state = {ConstructionMethod::ThreePoints, SelectMode::SeekFirst},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick first corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::ThreePoints, SelectMode::SeekSecond},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick second corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::ThreePoints, SelectMode::SeekThird},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick third corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::ThreePoints, SelectMode::SeekFourth},
|
|
.hints =
|
|
{
|
|
{tr("%1 set corner radius or frame thickness"), {MouseMove}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
|
|
// CenterAnd3Points method
|
|
{.state = {ConstructionMethod::CenterAnd3Points, SelectMode::SeekFirst},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick center"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::CenterAnd3Points, SelectMode::SeekSecond},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick first corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::CenterAnd3Points, SelectMode::SeekThird},
|
|
.hints =
|
|
{
|
|
{tr("%1 pick second corner"), {MouseLeft}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
{.state = {ConstructionMethod::CenterAnd3Points, SelectMode::SeekFourth},
|
|
.hints =
|
|
{
|
|
{tr("%1 set corner radius or frame thickness"), {MouseMove}},
|
|
switchHint,
|
|
roundedCornersHint,
|
|
frameHint,
|
|
}},
|
|
});
|
|
}
|
|
|
|
private:
|
|
void updateDataAndDrawToPosition(Base::Vector2d onSketchPos) override
|
|
{
|
|
using std::numbers::pi;
|
|
|
|
switch (state()) {
|
|
case SelectMode::SeekFirst: {
|
|
toolWidgetManager.drawPositionAtCursor(onSketchPos);
|
|
|
|
if (constructionMethod() == ConstructionMethod::Diagonal
|
|
|| constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
corner1 = onSketchPos;
|
|
}
|
|
else { //(constructionMethod == ConstructionMethod::CenterAndCorner)
|
|
center = onSketchPos;
|
|
}
|
|
|
|
seekAndRenderAutoConstraint(sugConstraints[0],
|
|
onSketchPos,
|
|
Base::Vector2d(0.f, 0.f));
|
|
} break;
|
|
case SelectMode::SeekSecond: {
|
|
if (constructionMethod() == ConstructionMethod::Diagonal) {
|
|
toolWidgetManager.drawDirectionAtCursor(onSketchPos, corner1);
|
|
|
|
// Note : we swap corner2 and 4 to make sure the corners are CCW.
|
|
// making things easier down the line.
|
|
corner3 = onSketchPos;
|
|
if ((corner3.x - corner1.x) * (corner3.y - corner1.y) > 0) {
|
|
corner2 = Base::Vector2d(onSketchPos.x, corner1.y);
|
|
corner4 = Base::Vector2d(corner1.x, onSketchPos.y);
|
|
cornersReversed = false;
|
|
}
|
|
else {
|
|
corner4 = Base::Vector2d(onSketchPos.x, corner1.y);
|
|
corner2 = Base::Vector2d(corner1.x, onSketchPos.y);
|
|
cornersReversed = true;
|
|
}
|
|
angle123 = pi / 2;
|
|
angle412 = pi / 2;
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
toolWidgetManager.drawDirectionAtCursor(onSketchPos, center);
|
|
|
|
corner1 = center - (onSketchPos - center);
|
|
corner3 = onSketchPos;
|
|
if (Base::sgn(corner3.x - corner1.x) * Base::sgn(corner3.y - corner1.y) > 0) {
|
|
corner2 = Base::Vector2d(onSketchPos.x, corner1.y);
|
|
corner4 = Base::Vector2d(corner1.x, onSketchPos.y);
|
|
cornersReversed = false;
|
|
}
|
|
else {
|
|
corner4 = Base::Vector2d(onSketchPos.x, corner1.y);
|
|
corner2 = Base::Vector2d(corner1.x, onSketchPos.y);
|
|
cornersReversed = true;
|
|
}
|
|
angle123 = pi / 2;
|
|
angle412 = pi / 2;
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
toolWidgetManager.drawDirectionAtCursor(onSketchPos, corner1);
|
|
|
|
corner2 = onSketchPos;
|
|
Base::Vector2d perpendicular;
|
|
perpendicular.x = -(corner2 - corner1).y;
|
|
perpendicular.y = (corner2 - corner1).x;
|
|
corner3 = corner2 + perpendicular;
|
|
corner4 = corner1 + perpendicular;
|
|
angle123 = pi / 2;
|
|
angle412 = pi / 2;
|
|
corner2Initial = corner2;
|
|
side = getPointSideOfVector(corner3, corner2 - corner1, corner1);
|
|
}
|
|
else {
|
|
toolWidgetManager.drawDirectionAtCursor(onSketchPos, center);
|
|
|
|
corner1 = onSketchPos;
|
|
corner3 = center - (onSketchPos - center);
|
|
Base::Vector2d perpendicular;
|
|
perpendicular.x = -(onSketchPos - center).y;
|
|
perpendicular.y = (onSketchPos - center).x;
|
|
corner2 = center + perpendicular;
|
|
corner4 = center - perpendicular;
|
|
angle123 = pi / 2;
|
|
angle412 = pi / 2;
|
|
side = getPointSideOfVector(corner2, corner3 - corner1, corner1);
|
|
}
|
|
|
|
if (roundCorners) {
|
|
length = (corner2 - corner1).Length();
|
|
width = (corner4 - corner1).Length();
|
|
radius = std::min(length, width) / 6; // NOLINT
|
|
}
|
|
else {
|
|
radius = 0.;
|
|
}
|
|
|
|
try {
|
|
CreateAndDrawShapeGeometry();
|
|
|
|
toolWidgetManager.drawWidthHeightAtCursor(onSketchPos, length, width);
|
|
}
|
|
catch (const Base::ValueError&) {
|
|
} // equal points while hovering raise an objection that can be safely ignored
|
|
|
|
seekAndRenderAutoConstraint(sugConstraints[1],
|
|
onSketchPos,
|
|
Base::Vector2d(0.0, 0.0));
|
|
} break;
|
|
case SelectMode::SeekThird: {
|
|
if (constructionMethod() == ConstructionMethod::Diagonal
|
|
|| constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (roundCorners) {
|
|
calculateRadius(onSketchPos);
|
|
toolWidgetManager.drawDoubleAtCursor(onSketchPos, radius);
|
|
}
|
|
else { // Normal rectangle with frame.
|
|
calculateThickness(onSketchPos);
|
|
toolWidgetManager.drawDoubleAtCursor(onSketchPos, thickness);
|
|
}
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
corner2 = corner2Initial;
|
|
corner3 = onSketchPos;
|
|
if (side == getPointSideOfVector(corner3, corner2 - corner1, corner1)) {
|
|
corner4 = corner1 + (corner3 - corner2);
|
|
cornersReversed = false;
|
|
}
|
|
else {
|
|
corner4 = corner2;
|
|
corner2 = corner1 + (corner3 - corner4);
|
|
cornersReversed = true;
|
|
}
|
|
Base::Vector2d a = corner1 - corner2;
|
|
Base::Vector2d b = corner3 - corner2;
|
|
if (fabs((sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y)))
|
|
> Precision::Confusion()) {
|
|
angle123 =
|
|
acos((a.x * b.x + a.y * b.y)
|
|
/ (sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y)));
|
|
}
|
|
angle412 = pi - angle123;
|
|
if (roundCorners) {
|
|
radius = std::min(length, width) / 6 // NOLINT
|
|
* std::min(sqrt(1 - cos(angle412) * cos(angle412)),
|
|
sqrt(1 - cos(angle123) * cos(angle123)));
|
|
}
|
|
else {
|
|
radius = 0.;
|
|
}
|
|
|
|
toolWidgetManager.drawWidthHeightAtCursor(onSketchPos, length, width);
|
|
}
|
|
else {
|
|
corner2 = onSketchPos;
|
|
corner4 = center - (onSketchPos - center);
|
|
cornersReversed = false;
|
|
if (side != getPointSideOfVector(corner2, corner3 - corner1, corner1)) {
|
|
corner4 = onSketchPos;
|
|
corner2 = center - (onSketchPos - center);
|
|
cornersReversed = true;
|
|
}
|
|
Base::Vector2d a = corner4 - corner1;
|
|
Base::Vector2d b = corner2 - corner1;
|
|
if (fabs((sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y)))
|
|
> Precision::Confusion()) {
|
|
angle412 =
|
|
acos((a.x * b.x + a.y * b.y)
|
|
/ (sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y)));
|
|
}
|
|
angle123 = pi - angle412;
|
|
if (roundCorners) {
|
|
radius = std::min(length, width) / 6 // NOLINT
|
|
* std::min(sqrt(1 - cos(angle412) * cos(angle412)),
|
|
sqrt(1 - cos(angle123) * cos(angle123)));
|
|
}
|
|
else {
|
|
radius = 0.;
|
|
}
|
|
|
|
toolWidgetManager.drawWidthHeightAtCursor(onSketchPos, length, width);
|
|
}
|
|
|
|
try {
|
|
CreateAndDrawShapeGeometry();
|
|
}
|
|
catch (const Base::ValueError&) {
|
|
} // equal points while hovering raise an objection that can be safely ignored
|
|
|
|
if ((constructionMethod() == ConstructionMethod::ThreePoints
|
|
|| constructionMethod() == ConstructionMethod::CenterAnd3Points)) {
|
|
seekAndRenderAutoConstraint(sugConstraints[2],
|
|
onSketchPos,
|
|
Base::Vector2d(0.0, 0.0));
|
|
}
|
|
} break;
|
|
case SelectMode::SeekFourth: {
|
|
if (constructionMethod() == ConstructionMethod::Diagonal
|
|
|| constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
calculateThickness(onSketchPos);
|
|
toolWidgetManager.drawDoubleAtCursor(onSketchPos, thickness);
|
|
}
|
|
else {
|
|
if (roundCorners) {
|
|
calculateRadius(onSketchPos);
|
|
toolWidgetManager.drawDoubleAtCursor(onSketchPos, radius);
|
|
}
|
|
else {
|
|
calculateThickness(onSketchPos);
|
|
toolWidgetManager.drawDoubleAtCursor(onSketchPos, thickness);
|
|
}
|
|
}
|
|
|
|
CreateAndDrawShapeGeometry();
|
|
} break;
|
|
case SelectMode::SeekFifth: {
|
|
calculateThickness(onSketchPos);
|
|
toolWidgetManager.drawDoubleAtCursor(onSketchPos, thickness);
|
|
|
|
CreateAndDrawShapeGeometry();
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void executeCommands() override
|
|
{
|
|
try {
|
|
firstCurve = getHighestCurveIndex() + 1;
|
|
|
|
createShape(false);
|
|
|
|
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add sketch box"));
|
|
|
|
commandAddShapeGeometryAndConstraints();
|
|
|
|
Gui::Command::commitCommand();
|
|
}
|
|
catch (const Base::Exception&) {
|
|
Gui::NotifyError(sketchgui,
|
|
QT_TRANSLATE_NOOP("Notifications", "Error"),
|
|
QT_TRANSLATE_NOOP("Notifications", "Failed to add box"));
|
|
|
|
Gui::Command::abortCommand();
|
|
THROWM(Base::RuntimeError,
|
|
QT_TRANSLATE_NOOP(
|
|
"Notifications",
|
|
"Tool execution aborted") "\n") // This prevents constraints from being
|
|
// applied on non existing geometry
|
|
}
|
|
|
|
thickness = 0.;
|
|
}
|
|
|
|
void generateAutoConstraints() override
|
|
{
|
|
|
|
if (constructionMethod() == ConstructionMethod::Diagonal) {
|
|
// add auto constraints at the start of the first side
|
|
if (radius > Precision::Confusion()) {
|
|
if (!sugConstraints[0].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[0],
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
if (!sugConstraints[1].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
}
|
|
else {
|
|
if (!sugConstraints[0].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[0],
|
|
firstCurve,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
if (!sugConstraints[1].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
firstCurve + 1,
|
|
Sketcher::PointPos::end);
|
|
}
|
|
}
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
// add auto constraints at center
|
|
if (!sugConstraints[0].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[0],
|
|
centerPointId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
// add auto constraints for the line segment end
|
|
if (!sugConstraints[1].empty()) {
|
|
if (radius > Precision::Confusion()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
else {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
firstCurve + 1,
|
|
Sketcher::PointPos::end);
|
|
}
|
|
}
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
if (radius > Precision::Confusion()) {
|
|
if (!sugConstraints[0].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[0],
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
if (!sugConstraints[1].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
if (!sugConstraints[2].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[2],
|
|
constructionPointThreeId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
}
|
|
else {
|
|
if (!sugConstraints[0].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[0],
|
|
firstCurve,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
if (!sugConstraints[1].empty()) {
|
|
if (!cornersReversed) {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
firstCurve + 1,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
else {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
firstCurve + 3,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
}
|
|
|
|
if (!sugConstraints[2].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[2],
|
|
firstCurve + 2,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
}
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
// add auto constraints at center
|
|
if (!sugConstraints[0].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[0],
|
|
centerPointId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
// add auto constraints for the line segment end
|
|
if (radius > Precision::Confusion()) {
|
|
if (!sugConstraints[1].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
if (!sugConstraints[2].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[2],
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
}
|
|
else {
|
|
if (!sugConstraints[1].empty()) {
|
|
generateAutoConstraintsOnElement(sugConstraints[1],
|
|
firstCurve,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
if (!sugConstraints[2].empty()) {
|
|
if (!cornersReversed) {
|
|
generateAutoConstraintsOnElement(sugConstraints[2],
|
|
firstCurve + 1,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
else {
|
|
generateAutoConstraintsOnElement(sugConstraints[2],
|
|
firstCurve + 3,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ensure temporary autoconstraints do not generate a redundancy and that the geometry
|
|
// parameters are accurate This is particularly important for adding widget mandated
|
|
// constraints.
|
|
removeRedundantAutoConstraints();
|
|
}
|
|
|
|
void createAutoConstraints() override
|
|
{
|
|
createGeneratedAutoConstraints(true);
|
|
|
|
sugConstraints[0].clear();
|
|
sugConstraints[1].clear();
|
|
}
|
|
|
|
std::string getToolName() const override
|
|
{
|
|
return "DSH_Rectangle";
|
|
}
|
|
|
|
QString getCrosshairCursorSVGName() const override
|
|
{
|
|
if (!roundCorners && !makeFrame) {
|
|
if (constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
return QStringLiteral("Sketcher_Pointer_Create_Box_Center");
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
return QStringLiteral("Sketcher_Pointer_Create_Box_3Points");
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
return QStringLiteral("Sketcher_Pointer_Create_Box_3Points_Center");
|
|
}
|
|
else {
|
|
return QStringLiteral("Sketcher_Pointer_Create_Box");
|
|
}
|
|
}
|
|
else if (roundCorners && !makeFrame) {
|
|
if (constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
return QStringLiteral("Sketcher_Pointer_Oblong_Center");
|
|
}
|
|
else {
|
|
return QStringLiteral("Sketcher_Pointer_Oblong");
|
|
}
|
|
}
|
|
else if (!roundCorners && makeFrame) {
|
|
if (constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
return QStringLiteral("Sketcher_Pointer_Create_Frame_Center");
|
|
}
|
|
else {
|
|
return QStringLiteral("Sketcher_Pointer_Create_Frame");
|
|
}
|
|
}
|
|
else { // both roundCorners and makeFrame
|
|
if (constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
return QStringLiteral("Sketcher_Pointer_Oblong_Frame_Center");
|
|
}
|
|
else {
|
|
return QStringLiteral("Sketcher_Pointer_Oblong_Frame");
|
|
}
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<QWidget> createWidget() const override
|
|
{
|
|
return std::make_unique<SketcherToolDefaultWidget>();
|
|
}
|
|
|
|
bool isWidgetVisible() const override
|
|
{
|
|
return true;
|
|
};
|
|
|
|
QPixmap getToolIcon() const override
|
|
{
|
|
return Gui::BitmapFactory().pixmap("Sketcher_CreateRectangle");
|
|
}
|
|
|
|
QString getToolWidgetText() const override
|
|
{
|
|
return QString(tr("Rectangle Parameters"));
|
|
}
|
|
|
|
void angleSnappingControl() override
|
|
{
|
|
if ((constructionMethod() == ConstructionMethod::ThreePoints)
|
|
&& state() == SelectMode::SeekSecond) {
|
|
setAngleSnapping(true, corner1);
|
|
}
|
|
else if ((constructionMethod() == ConstructionMethod::CenterAnd3Points)
|
|
&& state() == SelectMode::SeekSecond) {
|
|
setAngleSnapping(true, center);
|
|
}
|
|
else if ((constructionMethod() == ConstructionMethod::ThreePoints)
|
|
&& state() == SelectMode::SeekThird) {
|
|
setAngleSnapping(true, cornersReversed ? corner4 : corner2);
|
|
}
|
|
else if ((constructionMethod() == ConstructionMethod::CenterAnd3Points)
|
|
&& state() == SelectMode::SeekThird) {
|
|
setAngleSnapping(true, corner1);
|
|
}
|
|
|
|
else {
|
|
setAngleSnapping(false);
|
|
}
|
|
}
|
|
|
|
bool canGoToNextMode() override
|
|
{
|
|
if (state() == SelectMode::SeekSecond
|
|
&& (length < Precision::Confusion() || width < Precision::Confusion())) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// reimplement because if not radius then it's 2 steps
|
|
void onButtonPressed(Base::Vector2d onSketchPos) override
|
|
{
|
|
this->updateDataAndDrawToPosition(onSketchPos);
|
|
|
|
if (canGoToNextMode()) {
|
|
if (constructionMethod() == ConstructionMethod::Diagonal
|
|
|| constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (state() == SelectMode::SeekSecond && !roundCorners && !makeFrame) {
|
|
setState(SelectMode::End);
|
|
}
|
|
else if ((state() == SelectMode::SeekThird && roundCorners && !makeFrame)
|
|
|| (state() == SelectMode::SeekThird && !roundCorners && makeFrame)) {
|
|
setState(SelectMode::End);
|
|
}
|
|
else if (state() == SelectMode::SeekFourth) {
|
|
setState(SelectMode::End);
|
|
}
|
|
else {
|
|
this->moveToNextMode();
|
|
}
|
|
}
|
|
else {
|
|
if (state() == SelectMode::SeekThird && !roundCorners && !makeFrame) {
|
|
setState(SelectMode::End);
|
|
}
|
|
else if ((state() == SelectMode::SeekFourth && roundCorners && !makeFrame)
|
|
|| (state() == SelectMode::SeekFourth && !roundCorners && makeFrame)) {
|
|
setState(SelectMode::End);
|
|
}
|
|
else {
|
|
this->moveToNextMode();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void onReset() override
|
|
{
|
|
thickness = 0.;
|
|
lengthSign = 0;
|
|
widthSign = 0;
|
|
toolWidgetManager.resetControls();
|
|
}
|
|
|
|
private:
|
|
Base::Vector2d center, corner1, corner2, corner3, corner4, frameCorner1, frameCorner2,
|
|
frameCorner3, frameCorner4, corner2Initial;
|
|
Base::Vector3d center1, center2, center3, center4;
|
|
bool roundCorners, makeFrame, cornersReversed;
|
|
double radius, length, width, thickness, radiusFrame, angle, angle123, angle412;
|
|
int firstCurve, constructionPointOneId, constructionPointTwoId, constructionPointThreeId,
|
|
centerPointId, side;
|
|
|
|
// Sign tracking for OVP lock fix (issue #23459)
|
|
// These store the direction sign when OVP is first set to prevent sign flipping
|
|
int lengthSign, widthSign;
|
|
|
|
void createShape(bool onlyeditoutline) override
|
|
{
|
|
ShapeGeometry.clear();
|
|
|
|
Base::Vector2d vecL = corner2 - corner1;
|
|
Base::Vector2d vecW = corner4 - corner1;
|
|
length = vecL.Length();
|
|
width = vecW.Length();
|
|
angle = vecL.Angle();
|
|
if (length < Precision::Confusion() || width < Precision::Confusion()
|
|
|| fmod(fabs(angle123), std::numbers::pi) < Precision::Confusion()) {
|
|
return;
|
|
}
|
|
|
|
vecL = vecL / length;
|
|
vecW = vecW / width;
|
|
double L1 = radius;
|
|
double L2 = radius;
|
|
if (cos(angle123 / 2) != 1 && cos(angle412 / 2) != 1) {
|
|
L1 = radius / sqrt(1 - cos(angle123 / 2) * cos(angle123 / 2));
|
|
L2 = radius / sqrt(1 - cos(angle412 / 2) * cos(angle412 / 2));
|
|
}
|
|
|
|
createFirstRectangleGeometries(vecL, vecW, L1, L2);
|
|
|
|
bool thicknessNotZero = fabs(thickness) > Precision::Confusion();
|
|
bool negThicknessEqualRadius = fabs(radius + thickness) < Precision::Confusion();
|
|
if (makeFrame && state() != SelectMode::SeekSecond && thicknessNotZero) {
|
|
createSecondRectangleGeometries(vecL, vecW, L1, L2);
|
|
}
|
|
|
|
if (!onlyeditoutline) {
|
|
ShapeConstraints.clear();
|
|
|
|
if (radius > Precision::Confusion()) {
|
|
finishOblongCreation(thicknessNotZero, negThicknessEqualRadius);
|
|
}
|
|
else { // cases of normal rectangles and normal frames
|
|
finishRectangleCreation(thicknessNotZero);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
createFirstRectangleGeometries(Base::Vector2d vecL, Base::Vector2d vecW, double L1, double L2)
|
|
{
|
|
createFirstRectangleLines(vecL, vecW, L1, L2);
|
|
|
|
if (roundCorners && radius > Precision::Confusion()) {
|
|
createFirstRectangleFillets(vecL, vecW, L1, L2);
|
|
}
|
|
}
|
|
|
|
void createFirstRectangleLines(Base::Vector2d vecL, Base::Vector2d vecW, double L1, double L2)
|
|
{
|
|
addLineToShapeGeometry(toVector3d(corner1 + vecL * L2 * cos(angle412 / 2)),
|
|
toVector3d(corner2 - vecL * L1 * cos(angle123 / 2)),
|
|
isConstructionMode());
|
|
addLineToShapeGeometry(toVector3d(corner2 + vecW * L1 * cos(angle123 / 2)),
|
|
toVector3d(corner3 - vecW * L2 * cos(angle412 / 2)),
|
|
isConstructionMode());
|
|
addLineToShapeGeometry(toVector3d(corner3 - vecL * L2 * cos(angle412 / 2)),
|
|
toVector3d(corner4 + vecL * L1 * cos(angle123 / 2)),
|
|
isConstructionMode());
|
|
addLineToShapeGeometry(toVector3d(corner4 - vecW * L1 * cos(angle123 / 2)),
|
|
toVector3d(corner1 + vecW * L2 * cos(angle412 / 2)),
|
|
isConstructionMode());
|
|
}
|
|
|
|
void createFirstRectangleFillets(Base::Vector2d vecL, Base::Vector2d vecW, double L1, double L2)
|
|
{
|
|
using std::numbers::pi;
|
|
|
|
// center points required later for special case of round corner frame with
|
|
// radiusFrame = 0.
|
|
double end = angle - pi / 2;
|
|
|
|
Base::Vector2d b1 = (vecL + vecW) / (vecL + vecW).Length();
|
|
Base::Vector2d b2 = (vecL - vecW) / (vecL - vecW).Length();
|
|
center1 = toVector3d(corner1 + b1 * L2);
|
|
center2 = toVector3d(corner2 - b2 * L1);
|
|
center3 = toVector3d(corner3 - b1 * L2);
|
|
center4 = toVector3d(corner4 + b2 * L1);
|
|
|
|
addArcToShapeGeometry(center1, end - pi + angle412, end, radius, isConstructionMode());
|
|
addArcToShapeGeometry(center2, end, end - pi - angle123, radius, isConstructionMode());
|
|
addArcToShapeGeometry(center3, end + angle412, end - pi, radius, isConstructionMode());
|
|
addArcToShapeGeometry(center4, end - pi, end - angle123, radius, isConstructionMode());
|
|
}
|
|
|
|
void
|
|
createSecondRectangleGeometries(Base::Vector2d vecL, Base::Vector2d vecW, double L1, double L2)
|
|
{
|
|
using std::numbers::pi;
|
|
|
|
double end = angle - pi / 2;
|
|
|
|
if (radius < Precision::Confusion()) {
|
|
radiusFrame = 0.;
|
|
}
|
|
else {
|
|
radiusFrame = radius + thickness;
|
|
if (radiusFrame < 0.) {
|
|
radiusFrame = 0.;
|
|
}
|
|
}
|
|
|
|
Base::Vector2d vecLF = frameCorner2 - frameCorner1;
|
|
Base::Vector2d vecWF = frameCorner4 - frameCorner1;
|
|
double lengthF = vecLF.Length();
|
|
double widthF = vecWF.Length();
|
|
|
|
double L1F = 0.;
|
|
double L2F = 0.;
|
|
if (radius > Precision::Confusion()) {
|
|
L1F = L1 * radiusFrame / radius;
|
|
L2F = L2 * radiusFrame / radius;
|
|
}
|
|
|
|
addLineToShapeGeometry(toVector3d(frameCorner1 + vecLF / lengthF * L2F * cos(angle412 / 2)),
|
|
toVector3d(frameCorner2 - vecLF / lengthF * L1F * cos(angle123 / 2)),
|
|
isConstructionMode());
|
|
addLineToShapeGeometry(toVector3d(frameCorner2 + vecWF / widthF * L1F * cos(angle123 / 2)),
|
|
toVector3d(frameCorner3 - vecWF / widthF * L2F * cos(angle412 / 2)),
|
|
isConstructionMode());
|
|
addLineToShapeGeometry(toVector3d(frameCorner3 - vecLF / lengthF * L2F * cos(angle412 / 2)),
|
|
toVector3d(frameCorner4 + vecLF / lengthF * L1F * cos(angle123 / 2)),
|
|
isConstructionMode());
|
|
addLineToShapeGeometry(toVector3d(frameCorner4 - vecWF / widthF * L1F * cos(angle123 / 2)),
|
|
toVector3d(frameCorner1 + vecWF / widthF * L2F * cos(angle412 / 2)),
|
|
isConstructionMode());
|
|
|
|
if (roundCorners && radiusFrame > Precision::Confusion()) {
|
|
Base::Vector2d b1 = (vecL + vecW) / (vecL + vecW).Length();
|
|
Base::Vector2d b2 = (vecL - vecW) / (vecL - vecW).Length();
|
|
|
|
addArcToShapeGeometry(toVector3d(frameCorner1 + b1 * L2F),
|
|
end - pi + angle412,
|
|
end,
|
|
radiusFrame,
|
|
isConstructionMode());
|
|
addArcToShapeGeometry(toVector3d(frameCorner2 - b2 * L1F),
|
|
end,
|
|
end - pi - angle123,
|
|
radiusFrame,
|
|
isConstructionMode());
|
|
addArcToShapeGeometry(toVector3d(frameCorner3 - b1 * L2F),
|
|
end + angle412,
|
|
end - pi,
|
|
radiusFrame,
|
|
isConstructionMode());
|
|
addArcToShapeGeometry(toVector3d(frameCorner4 + b2 * L1F),
|
|
end - pi,
|
|
end - angle123,
|
|
radiusFrame,
|
|
isConstructionMode());
|
|
}
|
|
}
|
|
|
|
|
|
void finishOblongCreation(bool thicknessNotZero, bool negThicknessEqualRadius)
|
|
{
|
|
addTangentCoincidences(firstCurve);
|
|
|
|
addAlignmentConstraints();
|
|
|
|
addArcEqualities();
|
|
|
|
if (thicknessNotZero) {
|
|
// There are 3 cases possible:
|
|
// 1 - Thickness is negative and -thickness == radius.
|
|
// In this case the inner rectangle is a normal rectangle and its corner
|
|
// match the centers of the outer arcs.
|
|
// 2 - Thickness is negative and radius < -thickness.
|
|
// In this case it's a normal rectangle but we need construction
|
|
// lines to constraint it.
|
|
// 3 - Thickness is either positive or negative and radius > -thickness.
|
|
// In this case the second rectangle is also round-cornered
|
|
if (radiusFrame < Precision::Confusion()) {
|
|
addRectangleCoincidences(firstCurve + 8); // NOLINT
|
|
|
|
// Case 1
|
|
if (negThicknessEqualRadius) {
|
|
finishOblongFrameCase1();
|
|
}
|
|
else {
|
|
finishOblongFrameCase2();
|
|
}
|
|
}
|
|
else { // case 3: inner rectangle is rounded rectangle
|
|
finishOblongFrameCase3();
|
|
}
|
|
}
|
|
|
|
if (constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
finishOblongThreePoints(thicknessNotZero, negThicknessEqualRadius);
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
finishOblongCenterAnd3Points(thicknessNotZero, negThicknessEqualRadius);
|
|
}
|
|
else if (constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
finishOblongCenterAndCorner(thicknessNotZero, negThicknessEqualRadius);
|
|
}
|
|
else {
|
|
finishOblongDiagonal(thicknessNotZero, negThicknessEqualRadius);
|
|
}
|
|
}
|
|
|
|
void finishOblongFrameCase1()
|
|
{
|
|
// In this case the corners of the second rectangle are coincident
|
|
// with the centers of the arcs of the first rectangle.
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 8, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 4, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 9, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 5, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 10, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 6, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 11, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 7, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
}
|
|
|
|
void finishOblongFrameCase2()
|
|
{
|
|
// case 2: add construction lines +12, +13, +14, +15
|
|
|
|
addFrameAlignmentConstraints(firstCurve + 8);
|
|
|
|
addLineToShapeGeometry(center1, Base::Vector3d(frameCorner1.x, frameCorner1.y, 0.), true);
|
|
addLineToShapeGeometry(center2, Base::Vector3d(frameCorner2.x, frameCorner2.y, 0.), true);
|
|
addLineToShapeGeometry(center3, Base::Vector3d(frameCorner3.x, frameCorner3.y, 0.), true);
|
|
addLineToShapeGeometry(center4, Base::Vector3d(frameCorner4.x, frameCorner4.y, 0.), true);
|
|
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 12, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 4, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 12, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 8, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 13, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 5, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 13, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 9, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 14, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 6, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 14, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 10, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 15, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 7, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 15, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 11, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
|
|
addToShapeConstraints(Sketcher::Perpendicular,
|
|
firstCurve + 12, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 13); // NOLINT
|
|
addToShapeConstraints(Sketcher::Perpendicular,
|
|
firstCurve + 13, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 14); // NOLINT
|
|
addToShapeConstraints(Sketcher::Perpendicular,
|
|
firstCurve + 14, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 15); // NOLINT
|
|
}
|
|
|
|
void finishOblongFrameCase3()
|
|
{
|
|
addTangentCoincidences(firstCurve + 8);
|
|
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 4, // NOLINT
|
|
Sketcher::PointPos::mid,
|
|
firstCurve + 12, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 5, // NOLINT
|
|
Sketcher::PointPos::mid,
|
|
firstCurve + 13, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 6, // NOLINT
|
|
Sketcher::PointPos::mid,
|
|
firstCurve + 14, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 7, // NOLINT
|
|
Sketcher::PointPos::mid,
|
|
firstCurve + 15, // NOLINT
|
|
Sketcher::PointPos::mid);
|
|
|
|
addFrameAlignmentConstraints(firstCurve + 8, false);
|
|
}
|
|
|
|
void finishOblongThreePoints(bool thicknessNotZero, bool negThicknessEqualRadius)
|
|
{
|
|
if (thicknessNotZero) {
|
|
if (negThicknessEqualRadius) {
|
|
constructionPointOneId = firstCurve + 12; // NOLINT
|
|
constructionPointTwoId = firstCurve + 13; // NOLINT
|
|
constructionPointThreeId = firstCurve + 14; // NOLINT
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 16; // NOLINT
|
|
constructionPointTwoId = firstCurve + 17; // NOLINT
|
|
constructionPointThreeId = firstCurve + 18; // NOLINT
|
|
}
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 8; // NOLINT
|
|
constructionPointTwoId = firstCurve + 9; // NOLINT
|
|
constructionPointThreeId = firstCurve + 10; // NOLINT
|
|
}
|
|
|
|
addPointToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.), true);
|
|
if (!cornersReversed) {
|
|
addPointToShapeGeometry(Base::Vector3d(corner2.x, corner2.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 1);
|
|
}
|
|
else {
|
|
addPointToShapeGeometry(Base::Vector3d(corner4.x, corner4.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 2);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 3);
|
|
}
|
|
addPointToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 3);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointThreeId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 1);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointThreeId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 2);
|
|
}
|
|
|
|
void finishOblongCenterAnd3Points(bool thicknessNotZero, bool negThicknessEqualRadius)
|
|
{
|
|
if (thicknessNotZero) {
|
|
if (negThicknessEqualRadius) {
|
|
constructionPointOneId = firstCurve + 12; // NOLINT
|
|
constructionPointTwoId = firstCurve + 13; // NOLINT
|
|
centerPointId = firstCurve + 14; // NOLINT
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 16; // NOLINT
|
|
constructionPointTwoId = firstCurve + 17; // NOLINT
|
|
centerPointId = firstCurve + 18; // NOLINT
|
|
}
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 8; // NOLINT
|
|
constructionPointTwoId = firstCurve + 9; // NOLINT
|
|
centerPointId = firstCurve + 10; // NOLINT
|
|
}
|
|
|
|
addPointToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.), true);
|
|
if (!cornersReversed) {
|
|
addPointToShapeGeometry(Base::Vector3d(corner2.x, corner2.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 1);
|
|
}
|
|
else {
|
|
addPointToShapeGeometry(Base::Vector3d(corner4.x, corner4.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 2);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 3);
|
|
}
|
|
addPointToShapeGeometry(Base::Vector3d(center.x, center.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::Symmetric,
|
|
firstCurve + 2,
|
|
Sketcher::PointPos::start,
|
|
firstCurve,
|
|
Sketcher::PointPos::start,
|
|
centerPointId,
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 3); // NOLINT
|
|
}
|
|
|
|
void finishOblongCenterAndCorner(bool thicknessNotZero, bool negThicknessEqualRadius)
|
|
{
|
|
if (thicknessNotZero) {
|
|
if (negThicknessEqualRadius) {
|
|
constructionPointOneId = firstCurve + 12; // NOLINT
|
|
centerPointId = firstCurve + 13; // NOLINT
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 16; // NOLINT
|
|
centerPointId = firstCurve + 17; // NOLINT
|
|
}
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 8; // NOLINT
|
|
centerPointId = firstCurve + 9; // NOLINT
|
|
}
|
|
|
|
addPointToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.), true);
|
|
addPointToShapeGeometry(Base::Vector3d(center.x, center.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::Symmetric,
|
|
firstCurve + 2,
|
|
Sketcher::PointPos::start,
|
|
firstCurve,
|
|
Sketcher::PointPos::start,
|
|
centerPointId,
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 1);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 2);
|
|
}
|
|
|
|
void finishOblongDiagonal(bool thicknessNotZero, bool negThicknessEqualRadius)
|
|
{
|
|
if (thicknessNotZero) {
|
|
if (negThicknessEqualRadius) {
|
|
constructionPointOneId = firstCurve + 12; // NOLINT
|
|
constructionPointTwoId = firstCurve + 13; // NOLINT
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 16; // NOLINT
|
|
constructionPointTwoId = firstCurve + 17; // NOLINT
|
|
}
|
|
}
|
|
else {
|
|
constructionPointOneId = firstCurve + 8; // NOLINT
|
|
constructionPointTwoId = firstCurve + 9; // NOLINT
|
|
}
|
|
|
|
addPointToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.), true);
|
|
addPointToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointOneId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 3);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 1);
|
|
addToShapeConstraints(Sketcher::PointOnObject,
|
|
constructionPointTwoId,
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 2);
|
|
}
|
|
|
|
void addTangentCoincidences(int geoId)
|
|
{
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId,
|
|
Sketcher::PointPos::start,
|
|
geoId + 4, // NOLINT
|
|
Sketcher::PointPos::end);
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId,
|
|
Sketcher::PointPos::end,
|
|
geoId + 5, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId + 1, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
geoId + 5, // NOLINT
|
|
Sketcher::PointPos::end);
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId + 1, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
geoId + 6, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId + 2, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
geoId + 6, // NOLINT
|
|
Sketcher::PointPos::end);
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId + 2, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
geoId + 7, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId + 3, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
geoId + 7, // NOLINT
|
|
Sketcher::PointPos::end);
|
|
addToShapeConstraints(Sketcher::Tangent,
|
|
geoId + 3, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
geoId + 4, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
void addArcEqualities()
|
|
{
|
|
addToShapeConstraints(Sketcher::Equal,
|
|
firstCurve + 4, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 5); // NOLINT
|
|
addToShapeConstraints(Sketcher::Equal,
|
|
firstCurve + 5, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 6); // NOLINT
|
|
addToShapeConstraints(Sketcher::Equal,
|
|
firstCurve + 6, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 7); // NOLINT
|
|
}
|
|
|
|
void finishRectangleCreation(bool thicknessNotZero)
|
|
{
|
|
addRectangleCoincidences(firstCurve);
|
|
|
|
addAlignmentConstraints();
|
|
|
|
if (thicknessNotZero) {
|
|
finishRectangleFrameCreation();
|
|
}
|
|
|
|
if (constructionMethod() == ConstructionMethod::CenterAndCorner
|
|
|| constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
finishCenteredRectangleCreation(thicknessNotZero);
|
|
}
|
|
}
|
|
|
|
void addRectangleCoincidences(int geoId)
|
|
{
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
geoId,
|
|
Sketcher::PointPos::end,
|
|
geoId + 1,
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
geoId + 1,
|
|
Sketcher::PointPos::end,
|
|
geoId + 2,
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
geoId + 2,
|
|
Sketcher::PointPos::end,
|
|
geoId + 3,
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
geoId + 3,
|
|
Sketcher::PointPos::end,
|
|
geoId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
void addAlignmentConstraints()
|
|
{
|
|
Sketcher::ConstraintType typeA = Sketcher::Horizontal;
|
|
Sketcher::ConstraintType typeB = Sketcher::Vertical;
|
|
if (Base::sgn(corner3.x - corner1.x) * Base::sgn(corner3.y - corner1.y) < 0) {
|
|
typeA = Sketcher::Vertical;
|
|
typeB = Sketcher::Horizontal;
|
|
}
|
|
|
|
if (fabs(angle) < Precision::Confusion()
|
|
|| constructionMethod() == ConstructionMethod::Diagonal
|
|
|| constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
addToShapeConstraints(typeA, firstCurve);
|
|
addToShapeConstraints(typeA, firstCurve + 2);
|
|
addToShapeConstraints(typeB, firstCurve + 1);
|
|
addToShapeConstraints(typeB, firstCurve + 3);
|
|
}
|
|
else {
|
|
addToShapeConstraints(Sketcher::Parallel,
|
|
firstCurve,
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 2);
|
|
addToShapeConstraints(Sketcher::Parallel,
|
|
firstCurve + 1,
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 3);
|
|
if (fabs(angle123 - std::numbers::pi / 2) < Precision::Confusion()) {
|
|
addToShapeConstraints(Sketcher::Perpendicular,
|
|
firstCurve,
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void finishRectangleFrameCreation()
|
|
{
|
|
addRectangleCoincidences(firstCurve + 4);
|
|
|
|
addFrameAlignmentConstraints(firstCurve + 4);
|
|
|
|
addRectangleFrameConstructionLines();
|
|
}
|
|
|
|
void addFrameAlignmentConstraints(int geoId, bool addLast = true)
|
|
{
|
|
Sketcher::ConstraintType typeA = Sketcher::Horizontal;
|
|
Sketcher::ConstraintType typeB = Sketcher::Vertical;
|
|
if (Base::sgn(corner3.x - corner1.x) * Base::sgn(corner3.y - corner1.y) < 0) {
|
|
typeA = Sketcher::Vertical;
|
|
typeB = Sketcher::Horizontal;
|
|
}
|
|
|
|
if (fabs(angle) < Precision::Confusion()
|
|
|| constructionMethod() == ConstructionMethod::Diagonal
|
|
|| constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
addToShapeConstraints(typeA, geoId); // NOLINT
|
|
addToShapeConstraints(typeA, geoId + 2); // NOLINT
|
|
addToShapeConstraints(typeB, geoId + 1); // NOLINT
|
|
if (addLast) {
|
|
addToShapeConstraints(typeB, geoId + 3); // NOLINT
|
|
}
|
|
}
|
|
else {
|
|
addToShapeConstraints(Sketcher::Parallel,
|
|
geoId, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
geoId + 2); // NOLINT
|
|
addToShapeConstraints(Sketcher::Parallel,
|
|
geoId + 1, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
geoId + 3); // NOLINT
|
|
addToShapeConstraints(Sketcher::Parallel,
|
|
firstCurve,
|
|
Sketcher::PointPos::none,
|
|
geoId); // NOLINT
|
|
if (addLast) {
|
|
addToShapeConstraints(Sketcher::Parallel,
|
|
firstCurve + 1, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
geoId + 1); // NOLINT
|
|
}
|
|
}
|
|
}
|
|
|
|
void addRectangleFrameConstructionLines()
|
|
{
|
|
addLineToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.),
|
|
Base::Vector3d(frameCorner1.x, frameCorner1.y, 0.),
|
|
true);
|
|
addLineToShapeGeometry(Base::Vector3d(corner2.x, corner2.y, 0.),
|
|
Base::Vector3d(frameCorner2.x, frameCorner2.y, 0.),
|
|
true);
|
|
addLineToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.),
|
|
Base::Vector3d(frameCorner3.x, frameCorner3.y, 0.),
|
|
true);
|
|
addLineToShapeGeometry(Base::Vector3d(corner4.x, corner4.y, 0.),
|
|
Base::Vector3d(frameCorner4.x, frameCorner4.y, 0.),
|
|
true);
|
|
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 8, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve,
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 8, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 4, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 9, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 1, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 9, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 5, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 10, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 2, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 10, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 6, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 11, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve + 3, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
addToShapeConstraints(Sketcher::Coincident,
|
|
firstCurve + 11, // NOLINT
|
|
Sketcher::PointPos::end,
|
|
firstCurve + 7, // NOLINT
|
|
Sketcher::PointPos::start);
|
|
|
|
addToShapeConstraints(Sketcher::Perpendicular,
|
|
firstCurve + 8, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 9); // NOLINT
|
|
addToShapeConstraints(Sketcher::Perpendicular,
|
|
firstCurve + 9, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 10); // NOLINT
|
|
addToShapeConstraints(Sketcher::Perpendicular,
|
|
firstCurve + 10, // NOLINT
|
|
Sketcher::PointPos::none,
|
|
firstCurve + 11); // NOLINT
|
|
}
|
|
|
|
void finishCenteredRectangleCreation(bool thicknessNotZero)
|
|
{
|
|
if (thicknessNotZero) {
|
|
centerPointId = firstCurve + 12; // NOLINT
|
|
}
|
|
else {
|
|
centerPointId = firstCurve + 4; // NOLINT
|
|
}
|
|
|
|
addPointToShapeGeometry(Base::Vector3d(center.x, center.y, 0.), true);
|
|
addToShapeConstraints(Sketcher::Symmetric,
|
|
firstCurve + 2, // NOLINT
|
|
Sketcher::PointPos::start,
|
|
firstCurve,
|
|
Sketcher::PointPos::start,
|
|
centerPointId,
|
|
Sketcher::PointPos::start);
|
|
}
|
|
|
|
|
|
int getPointSideOfVector(Base::Vector2d pointToCheck,
|
|
Base::Vector2d separatingVector,
|
|
Base::Vector2d pointOnVector)
|
|
{
|
|
Base::Vector2d secondPointOnVec = pointOnVector + separatingVector;
|
|
double d = (pointToCheck.x - pointOnVector.x) * (secondPointOnVec.y - pointOnVector.y)
|
|
- (pointToCheck.y - pointOnVector.y) * (secondPointOnVec.x - pointOnVector.x);
|
|
if (abs(d) < Precision::Confusion()) {
|
|
return 0;
|
|
}
|
|
else if (d < 0) {
|
|
return -1;
|
|
}
|
|
else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void calculateRadius(Base::Vector2d onSketchPos)
|
|
{
|
|
Base::Vector2d u = (corner2 - corner1) / (corner2 - corner1).Length();
|
|
Base::Vector2d v = (corner4 - corner1) / (corner4 - corner1).Length();
|
|
Base::Vector2d e = onSketchPos - corner1;
|
|
double du = (v.y * e.x - v.x * e.y) / (u.x * v.y - u.y * v.x);
|
|
double dv = (-u.y * e.x + u.x * e.y) / (u.x * v.y - u.y * v.x);
|
|
|
|
if (-Precision::Confusion() < du && du < 0) {
|
|
du = 0.0;
|
|
}
|
|
if (-Precision::Confusion() < dv && dv < 0) {
|
|
dv = 0.0;
|
|
}
|
|
|
|
if (du < 0.0 || du > length || dv < 0.0 || dv > width) {
|
|
radius = 0.;
|
|
}
|
|
else {
|
|
if (du < length - du && dv < width - dv) {
|
|
radius = (du + dv
|
|
+ std::max(2 * sqrt(du * dv) * sin(angle412 / 2),
|
|
-2 * sqrt(du * dv) * sin(angle412 / 2)))
|
|
* tan(angle412 / 2);
|
|
}
|
|
else if (du > length - du && dv < width - dv) {
|
|
du = length - du;
|
|
radius = (du + dv
|
|
+ std::max(2 * sqrt(du * dv) * sin(angle123 / 2),
|
|
-2 * sqrt(du * dv) * sin(angle123 / 2)))
|
|
* tan(angle123 / 2);
|
|
}
|
|
else if (du < length - du && dv > width - dv) {
|
|
dv = width - dv;
|
|
radius = (du + dv
|
|
+ std::max(2 * sqrt(du * dv) * sin(angle123 / 2),
|
|
-2 * sqrt(du * dv) * sin(angle123 / 2)))
|
|
* tan(angle123 / 2);
|
|
}
|
|
else {
|
|
du = length - du;
|
|
dv = width - dv;
|
|
radius = (du + dv
|
|
+ std::max(2 * sqrt(du * dv) * sin(angle412 / 2),
|
|
-2 * sqrt(du * dv) * sin(angle412 / 2)))
|
|
* tan(angle412 / 2);
|
|
}
|
|
radius = std::min(
|
|
radius,
|
|
std::min(length * 0.999, width * 0.999) // NOLINT
|
|
/ (cos(angle412 / 2) / sqrt(1 - cos(angle412 / 2) * cos(angle412 / 2))
|
|
+ cos(angle123 / 2) / sqrt(1 - cos(angle123 / 2) * cos(angle123 / 2))));
|
|
}
|
|
}
|
|
|
|
void calculateThickness(Base::Vector2d onSketchPos)
|
|
{
|
|
|
|
Base::Vector2d u = (corner2 - corner1) / (corner2 - corner1).Length();
|
|
Base::Vector2d v = (corner4 - corner1) / (corner4 - corner1).Length();
|
|
Base::Vector2d e = onSketchPos - corner1;
|
|
double obliqueThickness = 0.;
|
|
double du = (v.y * e.x - v.x * e.y) / (u.x * v.y - u.y * v.x);
|
|
double dv = (-u.y * e.x + u.x * e.y) / (u.x * v.y - u.y * v.x);
|
|
if (du > 0 && du < length && !(dv > 0 && dv < width)) {
|
|
obliqueThickness = std::min(fabs(dv), fabs(width - dv));
|
|
}
|
|
else if (dv > 0 && dv < width && !(du > 0 && du < length)) {
|
|
obliqueThickness = std::min(fabs(du), fabs(length - du));
|
|
}
|
|
else if (du > 0 && du < length && dv > 0 && dv < width) {
|
|
obliqueThickness = -std::min(std::min(fabs(du), fabs(length - du)),
|
|
std::min(fabs(dv), fabs(width - dv)));
|
|
}
|
|
else {
|
|
obliqueThickness = std::max(std::min(fabs(du), fabs(length - du)),
|
|
std::min(fabs(dv), fabs(width - dv)));
|
|
}
|
|
|
|
|
|
frameCorner1 = corner1 - u * obliqueThickness - v * obliqueThickness;
|
|
frameCorner2 = corner2 + u * obliqueThickness - v * obliqueThickness;
|
|
frameCorner3 = corner3 + u * obliqueThickness + v * obliqueThickness;
|
|
frameCorner4 = corner4 - u * obliqueThickness + v * obliqueThickness;
|
|
|
|
thickness = obliqueThickness * sin(angle412);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
auto DSHRectangleControllerBase::getState(int labelindex) const
|
|
{
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
switch (labelindex) {
|
|
case OnViewParameter::First:
|
|
case OnViewParameter::Second:
|
|
return SelectMode::SeekFirst;
|
|
break;
|
|
case OnViewParameter::Third:
|
|
case OnViewParameter::Fourth:
|
|
return SelectMode::SeekSecond;
|
|
break;
|
|
case OnViewParameter::Fifth:
|
|
if (handler->roundCorners) {
|
|
return SelectMode::SeekThird;
|
|
}
|
|
else {
|
|
return SelectMode::End;
|
|
}
|
|
break;
|
|
case OnViewParameter::Sixth:
|
|
if (handler->makeFrame) {
|
|
if (!handler->roundCorners) {
|
|
return SelectMode::SeekThird;
|
|
}
|
|
else {
|
|
return SelectMode::SeekFourth;
|
|
}
|
|
}
|
|
else {
|
|
return SelectMode::End;
|
|
}
|
|
break;
|
|
default:
|
|
THROWM(Base::ValueError, "Parameter index without an associated machine state")
|
|
}
|
|
}
|
|
else {
|
|
switch (labelindex) {
|
|
case OnViewParameter::First:
|
|
case OnViewParameter::Second:
|
|
return SelectMode::SeekFirst;
|
|
break;
|
|
case OnViewParameter::Third:
|
|
case OnViewParameter::Fourth:
|
|
return SelectMode::SeekSecond;
|
|
break;
|
|
case OnViewParameter::Fifth:
|
|
case OnViewParameter::Sixth:
|
|
return SelectMode::SeekThird;
|
|
break;
|
|
case OnViewParameter::Seventh:
|
|
if (handler->roundCorners) {
|
|
return SelectMode::SeekFourth;
|
|
}
|
|
else {
|
|
return SelectMode::End;
|
|
}
|
|
break;
|
|
case OnViewParameter::Eighth:
|
|
if (handler->makeFrame) {
|
|
if (!handler->roundCorners) {
|
|
return SelectMode::SeekFourth;
|
|
}
|
|
else {
|
|
return SelectMode::SeekFifth;
|
|
}
|
|
}
|
|
else {
|
|
return SelectMode::End;
|
|
}
|
|
break;
|
|
default:
|
|
THROWM(Base::ValueError, "Parameter index without an associated machine state")
|
|
}
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void DSHRectangleController::configureToolWidget()
|
|
{
|
|
if (!init) { // Code to be executed only upon initialisation
|
|
QStringList names = {
|
|
QApplication::translate("TaskSketcherTool_c1_rectangle", "Corner, width, height"),
|
|
QApplication::translate("TaskSketcherTool_c1_rectangle", "Center, width, height"),
|
|
QApplication::translate("TaskSketcherTool_c1_rectangle", "3 corners"),
|
|
QApplication::translate("TaskSketcherTool_c1_rectangle", "Center, 2 corners")};
|
|
toolWidget->setComboboxElements(WCombobox::FirstCombo, names);
|
|
|
|
toolWidget->setCheckboxLabel(
|
|
WCheckbox::FirstBox,
|
|
QApplication::translate("TaskSketcherTool_c1_rectangle", "Rounded corners (U)"));
|
|
toolWidget->setCheckboxToolTip(
|
|
WCheckbox::FirstBox,
|
|
QApplication::translate("TaskSketcherTool_c1_rectangle",
|
|
"Create a rectangle with rounded corners."));
|
|
syncCheckboxToHandler(WCheckbox::FirstBox, handler->roundCorners);
|
|
|
|
toolWidget->setCheckboxLabel(
|
|
WCheckbox::SecondBox,
|
|
QApplication::translate("TaskSketcherTool_c2_rectangle", "Frame (J)"));
|
|
toolWidget->setCheckboxToolTip(
|
|
WCheckbox::SecondBox,
|
|
QApplication::translate("TaskSketcherTool_c2_rectangle",
|
|
"Create two rectangles with a constant offset."));
|
|
syncCheckboxToHandler(WCheckbox::SecondBox, handler->makeFrame);
|
|
|
|
if (isConstructionMode()) {
|
|
toolWidget->setComboboxItemIcon(
|
|
WCombobox::FirstCombo,
|
|
0,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle_Constr"));
|
|
toolWidget->setComboboxItemIcon(
|
|
WCombobox::FirstCombo,
|
|
1,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle_Center_Constr"));
|
|
toolWidget->setComboboxItemIcon(
|
|
WCombobox::FirstCombo,
|
|
2,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle3Points_Constr"));
|
|
toolWidget->setComboboxItemIcon(WCombobox::FirstCombo,
|
|
3,
|
|
Gui::BitmapFactory().iconFromTheme(
|
|
"Sketcher_CreateRectangle3Points_Center_Constr"));
|
|
|
|
toolWidget->setCheckboxIcon(
|
|
WCheckbox::FirstBox,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateOblong_Constr"));
|
|
toolWidget->setCheckboxIcon(
|
|
WCheckbox::SecondBox,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateFrame_Constr"));
|
|
}
|
|
else {
|
|
toolWidget->setComboboxItemIcon(
|
|
WCombobox::FirstCombo,
|
|
0,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle"));
|
|
toolWidget->setComboboxItemIcon(
|
|
WCombobox::FirstCombo,
|
|
1,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle_Center"));
|
|
toolWidget->setComboboxItemIcon(
|
|
WCombobox::FirstCombo,
|
|
2,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle3Points"));
|
|
toolWidget->setComboboxItemIcon(
|
|
WCombobox::FirstCombo,
|
|
3,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle3Points_Center"));
|
|
|
|
toolWidget->setCheckboxIcon(
|
|
WCheckbox::FirstBox,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateOblong"));
|
|
toolWidget->setCheckboxIcon(WCheckbox::SecondBox,
|
|
Gui::BitmapFactory().iconFromTheme("Sketcher_CreateFrame"));
|
|
}
|
|
}
|
|
|
|
onViewParameters[OnViewParameter::First]->setLabelType(Gui::SoDatumLabel::DISTANCEX);
|
|
onViewParameters[OnViewParameter::Second]->setLabelType(Gui::SoDatumLabel::DISTANCEY);
|
|
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
onViewParameters[OnViewParameter::Third]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCEX,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Fourth]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCEY,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Fifth]->setLabelType(
|
|
Gui::SoDatumLabel::RADIUS,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Sixth]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
}
|
|
else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
onViewParameters[OnViewParameter::Third]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Fourth]->setLabelType(
|
|
Gui::SoDatumLabel::ANGLE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Fifth]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Sixth]->setLabelType(
|
|
Gui::SoDatumLabel::ANGLE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Seventh]->setLabelType(
|
|
Gui::SoDatumLabel::RADIUS,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Eighth]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
}
|
|
else if (handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
onViewParameters[OnViewParameter::Third]->setLabelType(Gui::SoDatumLabel::DISTANCEX);
|
|
onViewParameters[OnViewParameter::Fourth]->setLabelType(Gui::SoDatumLabel::DISTANCEY);
|
|
onViewParameters[OnViewParameter::Fifth]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Sixth]->setLabelType(
|
|
Gui::SoDatumLabel::ANGLE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Seventh]->setLabelType(
|
|
Gui::SoDatumLabel::RADIUS,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
onViewParameters[OnViewParameter::Eighth]->setLabelType(
|
|
Gui::SoDatumLabel::DISTANCE,
|
|
Gui::EditableDatumLabel::Function::Dimensioning);
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void DSHRectangleController::adaptDrawingToCheckboxChange(int checkboxindex, bool value)
|
|
{
|
|
Q_UNUSED(checkboxindex);
|
|
|
|
switch (checkboxindex) {
|
|
case WCheckbox::FirstBox:
|
|
handler->roundCorners = value;
|
|
break;
|
|
case WCheckbox::SecondBox:
|
|
handler->makeFrame = value;
|
|
break;
|
|
}
|
|
|
|
handler->updateCursor();
|
|
}
|
|
|
|
template<>
|
|
void DSHRectangleControllerBase::doEnforceControlParameters(Base::Vector2d& onSketchPos)
|
|
{
|
|
switch (handler->state()) {
|
|
case SelectMode::SeekFirst: {
|
|
if (onViewParameters[OnViewParameter::First]->isSet) {
|
|
onSketchPos.x = onViewParameters[OnViewParameter::First]->getValue();
|
|
}
|
|
|
|
if (onViewParameters[OnViewParameter::Second]->isSet) {
|
|
onSketchPos.y = onViewParameters[OnViewParameter::Second]->getValue();
|
|
}
|
|
} break;
|
|
case SelectMode::SeekSecond: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (onViewParameters[OnViewParameter::Third]->isSet) {
|
|
double length = onViewParameters[OnViewParameter::Third]->getValue();
|
|
if (fabs(length) < Precision::Confusion()
|
|
&& onViewParameters[OnViewParameter::Third]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Third].get());
|
|
handler->lengthSign = 0;
|
|
return;
|
|
}
|
|
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal) {
|
|
if (handler->lengthSign == 0) {
|
|
handler->lengthSign =
|
|
(onSketchPos.x - handler->corner1.x) >= 0 ? 1 : -1;
|
|
}
|
|
onSketchPos.x = handler->corner1.x + handler->lengthSign * length;
|
|
}
|
|
else {
|
|
onSketchPos.x = handler->center.x + length / 2;
|
|
}
|
|
}
|
|
if (onViewParameters[OnViewParameter::Fourth]->isSet) {
|
|
double width = onViewParameters[OnViewParameter::Fourth]->getValue();
|
|
if (fabs(width) < Precision::Confusion()
|
|
&& onViewParameters[OnViewParameter::Fourth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Fourth].get());
|
|
handler->widthSign = 0;
|
|
return;
|
|
}
|
|
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal) {
|
|
if (handler->widthSign == 0) {
|
|
handler->widthSign = (onSketchPos.y - handler->corner1.y) >= 0 ? 1 : -1;
|
|
}
|
|
onSketchPos.y = handler->corner1.y + handler->widthSign * width;
|
|
}
|
|
else {
|
|
onSketchPos.y = handler->center.y + width / 2;
|
|
}
|
|
}
|
|
}
|
|
else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
Base::Vector2d dir = onSketchPos - handler->corner1;
|
|
if (dir.Length() < Precision::Confusion()) {
|
|
dir.x = 1.0; // if direction null, default to (1,0)
|
|
}
|
|
double length = dir.Length();
|
|
|
|
if (onViewParameters[OnViewParameter::Third]->isSet) {
|
|
length = onViewParameters[OnViewParameter::Third]->getValue();
|
|
if (length < Precision::Confusion()
|
|
&& onViewParameters[OnViewParameter::Third]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Third].get());
|
|
return;
|
|
}
|
|
|
|
onSketchPos = handler->corner1 + length * dir.Normalize();
|
|
}
|
|
|
|
if (onViewParameters[OnViewParameter::Fourth]->isSet) {
|
|
double angle =
|
|
Base::toRadians(onViewParameters[OnViewParameter::Fourth]->getValue());
|
|
onSketchPos.x = handler->corner1.x + cos(angle) * length;
|
|
onSketchPos.y = handler->corner1.y + sin(angle) * length;
|
|
}
|
|
}
|
|
else {
|
|
if (onViewParameters[OnViewParameter::Third]->isSet) {
|
|
onSketchPos.x = onViewParameters[OnViewParameter::Third]->getValue();
|
|
}
|
|
|
|
if (onViewParameters[OnViewParameter::Fourth]->isSet) {
|
|
onSketchPos.y = onViewParameters[OnViewParameter::Fourth]->getValue();
|
|
}
|
|
if (onViewParameters[OnViewParameter::Third]->hasFinishedEditing
|
|
&& onViewParameters[OnViewParameter::Fourth]->hasFinishedEditing
|
|
&& (onSketchPos - handler->center).Length() < Precision::Confusion()) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Third].get());
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Fourth].get());
|
|
}
|
|
}
|
|
} break;
|
|
case SelectMode::SeekThird: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (handler->roundCorners) {
|
|
if (onViewParameters[OnViewParameter::Fifth]->isSet) {
|
|
Base::Vector2d vecL = (handler->corner2 - handler->corner1).Normalize();
|
|
onSketchPos = handler->corner1
|
|
+ vecL * onViewParameters[OnViewParameter::Fifth]->getValue();
|
|
}
|
|
}
|
|
else {
|
|
if (onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
double thickness = onViewParameters[OnViewParameter::Sixth]->getValue();
|
|
if (thickness <= -std::min(handler->width, handler->length) / 2
|
|
&& onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get());
|
|
return;
|
|
}
|
|
|
|
Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize();
|
|
Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize();
|
|
onSketchPos = handler->corner1 - u * thickness - v * thickness;
|
|
}
|
|
}
|
|
}
|
|
else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
Base::Vector2d dir = onSketchPos - handler->corner2Initial;
|
|
if (dir.Length() < Precision::Confusion()) {
|
|
dir.x = 1.0; // if direction null, default to (1,0)
|
|
}
|
|
double width = dir.Length();
|
|
|
|
if (onViewParameters[OnViewParameter::Fifth]->isSet) {
|
|
width = onViewParameters[OnViewParameter::Fifth]->getValue();
|
|
if (width < Precision::Confusion()
|
|
&& onViewParameters[OnViewParameter::Fifth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Fifth].get());
|
|
return;
|
|
}
|
|
|
|
onSketchPos = handler->corner2Initial + width * dir.Normalize();
|
|
}
|
|
if (onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
double angle =
|
|
Base::toRadians(onViewParameters[OnViewParameter::Sixth]->getValue());
|
|
if (fmod(angle, std::numbers::pi) < Precision::Confusion()
|
|
&& onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get());
|
|
return;
|
|
}
|
|
|
|
int sign1 =
|
|
handler->getPointSideOfVector(onSketchPos,
|
|
handler->corner2Initial - handler->corner1,
|
|
handler->corner1);
|
|
|
|
int sign = handler->side != sign1 ? 1 : -1;
|
|
|
|
double angle123 = (handler->corner2Initial - handler->corner1).Angle()
|
|
+ std::numbers::pi + sign * angle;
|
|
|
|
onSketchPos.x = handler->corner2Initial.x + cos(angle123) * width;
|
|
onSketchPos.y = handler->corner2Initial.y + sin(angle123) * width;
|
|
}
|
|
}
|
|
else {
|
|
Base::Vector2d dir = onSketchPos - handler->corner1;
|
|
if (dir.Length() < Precision::Confusion()) {
|
|
dir.x = 1.0; // if direction null, default to (1,0)
|
|
}
|
|
double width = dir.Length();
|
|
if (onViewParameters[OnViewParameter::Fifth]->isSet) {
|
|
width = onViewParameters[OnViewParameter::Fifth]->getValue();
|
|
if (width < Precision::Confusion()
|
|
&& onViewParameters[OnViewParameter::Fifth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Fifth].get());
|
|
return;
|
|
}
|
|
|
|
onSketchPos = handler->corner1 + width * dir.Normalize();
|
|
}
|
|
if (onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
double c =
|
|
Base::toRadians(onViewParameters[OnViewParameter::Sixth]->getValue());
|
|
if (fmod(c, std::numbers::pi) < Precision::Confusion()
|
|
&& onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get());
|
|
return;
|
|
}
|
|
|
|
double a = asin(width * sin(std::numbers::pi - c)
|
|
/ (handler->corner3 - handler->corner1).Length());
|
|
|
|
int sign1 = handler->getPointSideOfVector(onSketchPos,
|
|
handler->corner3 - handler->corner1,
|
|
handler->corner1);
|
|
|
|
int sign = handler->side != sign1 ? 1 : -1;
|
|
|
|
double angle = (handler->center - handler->corner1).Angle() + sign * (c - a);
|
|
|
|
onSketchPos.x = handler->corner1.x + cos(angle) * width;
|
|
onSketchPos.y = handler->corner1.y + sin(angle) * width;
|
|
}
|
|
}
|
|
} break;
|
|
case SelectMode::SeekFourth: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
|
|
if (onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
double thickness = onViewParameters[OnViewParameter::Sixth]->getValue();
|
|
if (thickness <= -std::min(handler->width, handler->length) / 2
|
|
&& onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get());
|
|
return;
|
|
}
|
|
|
|
Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize();
|
|
Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize();
|
|
onSketchPos = handler->corner1 - u * thickness - v * thickness;
|
|
}
|
|
}
|
|
else {
|
|
if (handler->roundCorners) {
|
|
if (onViewParameters[OnViewParameter::Seventh]->isSet) {
|
|
double angleToUse = handler->angle412 / 2;
|
|
if (handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
angleToUse = handler->angle123 / 2;
|
|
}
|
|
Base::Vector2d vecL =
|
|
(handler->corner2Initial - handler->corner1).Normalize();
|
|
double L2 = onViewParameters[OnViewParameter::Seventh]->getValue()
|
|
/ sqrt(1 - cos(angleToUse) * cos(angleToUse));
|
|
onSketchPos = handler->corner1 + vecL * L2 * cos(angleToUse);
|
|
}
|
|
}
|
|
else {
|
|
if (onViewParameters[OnViewParameter::Eighth]->isSet) {
|
|
double thickness = onViewParameters[OnViewParameter::Eighth]->getValue();
|
|
if (thickness <= -std::min(handler->width, handler->length) / 2
|
|
&& onViewParameters[OnViewParameter::Eighth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Eighth].get());
|
|
return;
|
|
}
|
|
|
|
Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize();
|
|
Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize();
|
|
Base::Vector2d dir = (u + v).Normalize();
|
|
double angle = u.GetAngle(v) / 2;
|
|
double sinAngle = fabs(sin(angle));
|
|
if (sinAngle < Precision::Confusion()) {
|
|
sinAngle = 1; // protection against division by 0
|
|
}
|
|
double tr = thickness / sinAngle;
|
|
|
|
onSketchPos = handler->corner1 - dir * tr;
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
case SelectMode::SeekFifth: {
|
|
if (onViewParameters[OnViewParameter::Eighth]->isSet) {
|
|
double thickness = onViewParameters[OnViewParameter::Eighth]->getValue();
|
|
if (thickness <= -std::min(handler->width, handler->length) / 2
|
|
&& onViewParameters[OnViewParameter::Eighth]->hasFinishedEditing) {
|
|
unsetOnViewParameter(onViewParameters[OnViewParameter::Eighth].get());
|
|
return;
|
|
}
|
|
|
|
Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize();
|
|
Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize();
|
|
Base::Vector2d dir = (u + v).Normalize();
|
|
double angle = u.GetAngle(v) / 2;
|
|
double sinAngle = fabs(sin(angle));
|
|
if (sinAngle < Precision::Confusion()) {
|
|
sinAngle = 1; // protection against division by 0
|
|
}
|
|
double tr = thickness / sinAngle;
|
|
|
|
onSketchPos = handler->corner1 - dir * tr;
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void DSHRectangleController::adaptParameters(Base::Vector2d onSketchPos)
|
|
{
|
|
|
|
// If checkboxes need synchronisation (they were changed by the DSH, e.g. by using 'M' to switch
|
|
// construction method), synchronise them and return.
|
|
if (syncCheckboxToHandler(WCheckbox::FirstBox, handler->roundCorners)) {
|
|
return;
|
|
}
|
|
|
|
if (syncCheckboxToHandler(WCheckbox::SecondBox, handler->makeFrame)) {
|
|
return;
|
|
}
|
|
|
|
switch (handler->state()) {
|
|
case SelectMode::SeekFirst: {
|
|
if (!onViewParameters[OnViewParameter::First]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::First, onSketchPos.x);
|
|
}
|
|
|
|
if (!onViewParameters[OnViewParameter::Second]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Second, onSketchPos.y);
|
|
}
|
|
|
|
bool sameSign = onSketchPos.x * onSketchPos.y > 0.;
|
|
onViewParameters[OnViewParameter::First]->setLabelAutoDistanceReverse(!sameSign);
|
|
onViewParameters[OnViewParameter::Second]->setLabelAutoDistanceReverse(sameSign);
|
|
onViewParameters[OnViewParameter::First]->setPoints(Base::Vector3d(),
|
|
toVector3d(onSketchPos));
|
|
onViewParameters[OnViewParameter::Second]->setPoints(Base::Vector3d(),
|
|
toVector3d(onSketchPos));
|
|
} break;
|
|
case SelectMode::SeekSecond: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (!onViewParameters[OnViewParameter::Third]->isSet) {
|
|
double length = handler->cornersReversed ? handler->width : handler->length;
|
|
setOnViewParameterValue(OnViewParameter::Third, length);
|
|
}
|
|
|
|
if (!onViewParameters[OnViewParameter::Fourth]->isSet) {
|
|
double width = handler->cornersReversed ? handler->length : handler->width;
|
|
setOnViewParameterValue(OnViewParameter::Fourth, width);
|
|
}
|
|
|
|
Base::Vector3d start = toVector3d(handler->corner1);
|
|
Base::Vector3d vec = toVector3d(onSketchPos) - start;
|
|
bool sameSign = vec.x * vec.y > 0.;
|
|
|
|
onViewParameters[OnViewParameter::Third]->setLabelAutoDistanceReverse(sameSign);
|
|
onViewParameters[OnViewParameter::Fourth]->setLabelAutoDistanceReverse(!sameSign);
|
|
|
|
onViewParameters[OnViewParameter::Third]->setPoints(
|
|
start,
|
|
toVector3d(handler->cornersReversed ? handler->corner4 : handler->corner2));
|
|
onViewParameters[OnViewParameter::Fourth]->setPoints(
|
|
start,
|
|
toVector3d(handler->cornersReversed ? handler->corner2 : handler->corner4));
|
|
}
|
|
else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
if (!onViewParameters[OnViewParameter::Third]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Third, handler->length);
|
|
}
|
|
|
|
onViewParameters[OnViewParameter::Third]->setPoints(toVector3d(handler->corner4),
|
|
toVector3d(handler->corner3));
|
|
|
|
if (!onViewParameters[OnViewParameter::Fourth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Fourth,
|
|
Base::toDegrees(handler->angle),
|
|
Base::Unit::Angle);
|
|
}
|
|
|
|
onViewParameters[OnViewParameter::Fourth]->setPoints(toVector3d(handler->corner1),
|
|
Base::Vector3d());
|
|
onViewParameters[OnViewParameter::Fourth]->setLabelRange(
|
|
(handler->corner2 - handler->corner1).Angle());
|
|
}
|
|
else {
|
|
if (!onViewParameters[OnViewParameter::Third]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Third, onSketchPos.x);
|
|
}
|
|
|
|
if (!onViewParameters[OnViewParameter::Fourth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Fourth, onSketchPos.y);
|
|
}
|
|
|
|
bool sameSign = onSketchPos.x * onSketchPos.y > 0.;
|
|
onViewParameters[OnViewParameter::Third]->setLabelAutoDistanceReverse(!sameSign);
|
|
onViewParameters[OnViewParameter::Fourth]->setLabelAutoDistanceReverse(sameSign);
|
|
onViewParameters[OnViewParameter::Third]->setPoints(Base::Vector3d(),
|
|
toVector3d(onSketchPos));
|
|
onViewParameters[OnViewParameter::Fourth]->setPoints(Base::Vector3d(),
|
|
toVector3d(onSketchPos));
|
|
}
|
|
} break;
|
|
case SelectMode::SeekThird: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (handler->roundCorners) {
|
|
if (!onViewParameters[OnViewParameter::Fifth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Fifth, handler->radius);
|
|
}
|
|
|
|
Base::Vector3d center = handler->center3;
|
|
Base::Vector3d end = toVector3d(handler->corner3);
|
|
|
|
if (handler->radius != 0.0) {
|
|
Base::Vector3d vec = (end - center).Normalize();
|
|
end = center + vec * handler->radius;
|
|
}
|
|
|
|
onViewParameters[OnViewParameter::Fifth]->setPoints(center, end);
|
|
}
|
|
else {
|
|
if (!onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Sixth, handler->thickness);
|
|
}
|
|
|
|
Base::Vector3d start = toVector3d(handler->corner3);
|
|
Base::Vector3d end =
|
|
Base::Vector3d(handler->corner3.x, handler->frameCorner3.y, 0.0);
|
|
onViewParameters[OnViewParameter::Sixth]->setPoints(start, end);
|
|
}
|
|
}
|
|
else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
onViewParameters[OnViewParameter::Third]->setPoints(toVector3d(handler->corner4),
|
|
toVector3d(handler->corner3));
|
|
|
|
bool reversed = handler->cornersReversed;
|
|
|
|
if (!onViewParameters[OnViewParameter::Fifth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Fifth,
|
|
reversed ? handler->length : handler->width);
|
|
}
|
|
|
|
Base::Vector3d start = toVector3d(handler->corner1);
|
|
onViewParameters[OnViewParameter::Fifth]->setLabelAutoDistanceReverse(reversed);
|
|
onViewParameters[OnViewParameter::Fifth]->setPoints(
|
|
start,
|
|
toVector3d(reversed ? handler->corner2 : handler->corner4));
|
|
|
|
|
|
if (!onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
double val = Base::toDegrees(handler->angle123);
|
|
setOnViewParameterValue(OnViewParameter::Sixth, val, Base::Unit::Angle);
|
|
}
|
|
|
|
onViewParameters[OnViewParameter::Sixth]->setPoints(
|
|
toVector3d(reversed ? handler->corner4 : handler->corner2),
|
|
Base::Vector3d());
|
|
double startAngle = reversed ? (handler->corner1 - handler->corner4).Angle()
|
|
: (handler->corner3 - handler->corner2).Angle();
|
|
onViewParameters[OnViewParameter::Sixth]->setLabelStartAngle(startAngle);
|
|
onViewParameters[OnViewParameter::Sixth]->setLabelRange(handler->angle123);
|
|
}
|
|
else {
|
|
bool reversed = handler->cornersReversed;
|
|
|
|
if (!onViewParameters[OnViewParameter::Fifth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Fifth,
|
|
reversed ? handler->width : handler->length);
|
|
}
|
|
|
|
Base::Vector3d start = toVector3d(handler->corner1);
|
|
onViewParameters[OnViewParameter::Fifth]->setLabelAutoDistanceReverse(true);
|
|
onViewParameters[OnViewParameter::Fifth]->setPoints(
|
|
start,
|
|
toVector3d(reversed ? handler->corner4 : handler->corner2));
|
|
|
|
|
|
if (!onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
double val = Base::toDegrees(handler->angle412);
|
|
setOnViewParameterValue(OnViewParameter::Sixth, val, Base::Unit::Angle);
|
|
}
|
|
|
|
onViewParameters[OnViewParameter::Sixth]->setPoints(toVector3d(handler->corner1),
|
|
Base::Vector3d());
|
|
double startAngle = (handler->corner2 - handler->corner1).Angle();
|
|
onViewParameters[OnViewParameter::Sixth]->setLabelStartAngle(startAngle);
|
|
onViewParameters[OnViewParameter::Sixth]->setLabelRange(handler->angle412);
|
|
}
|
|
|
|
} break;
|
|
case SelectMode::SeekFourth: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (!onViewParameters[OnViewParameter::Sixth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Sixth, handler->thickness);
|
|
}
|
|
|
|
Base::Vector3d start = toVector3d(handler->corner3);
|
|
Base::Vector3d end =
|
|
Base::Vector3d(handler->corner3.x, handler->frameCorner3.y, 0.0);
|
|
onViewParameters[OnViewParameter::Sixth]->setPoints(start, end);
|
|
}
|
|
else {
|
|
if (handler->roundCorners) {
|
|
if (!onViewParameters[OnViewParameter::Seventh]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Seventh, handler->radius);
|
|
}
|
|
|
|
Base::Vector3d center = handler->center3;
|
|
Base::Vector3d end = toVector3d(handler->corner3);
|
|
|
|
if (handler->radius != 0.0) {
|
|
Base::Vector3d vec = (end - center).Normalize();
|
|
end = center + vec * handler->radius;
|
|
}
|
|
|
|
onViewParameters[OnViewParameter::Seventh]->setPoints(center, end);
|
|
}
|
|
else {
|
|
if (!onViewParameters[OnViewParameter::Eighth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Eighth, handler->thickness);
|
|
}
|
|
|
|
Base::Vector3d start = toVector3d(handler->corner3);
|
|
Base::Vector3d vec =
|
|
toVector3d((handler->corner3 - handler->corner2).Normalize());
|
|
Base::Vector3d end = start + handler->thickness * vec;
|
|
onViewParameters[OnViewParameter::Eighth]->setPoints(start, end);
|
|
}
|
|
}
|
|
} break;
|
|
case SelectMode::SeekFifth: {
|
|
if (!onViewParameters[OnViewParameter::Eighth]->isSet) {
|
|
setOnViewParameterValue(OnViewParameter::Eighth, handler->thickness);
|
|
}
|
|
|
|
Base::Vector3d start = toVector3d(handler->corner3);
|
|
Base::Vector3d vec = toVector3d((handler->corner3 - handler->corner2).Normalize());
|
|
Base::Vector3d end = start + handler->thickness * vec;
|
|
onViewParameters[OnViewParameter::Eighth]->setPoints(start, end);
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void DSHRectangleController::computeNextDrawSketchHandlerMode()
|
|
{
|
|
switch (handler->state()) {
|
|
case SelectMode::SeekFirst: {
|
|
if (onViewParameters[OnViewParameter::First]->hasFinishedEditing
|
|
&& onViewParameters[OnViewParameter::Second]->hasFinishedEditing) {
|
|
|
|
handler->setNextState(SelectMode::SeekSecond);
|
|
}
|
|
} break;
|
|
case SelectMode::SeekSecond: {
|
|
if (onViewParameters[OnViewParameter::Third]->hasFinishedEditing
|
|
&& onViewParameters[OnViewParameter::Fourth]->hasFinishedEditing) {
|
|
|
|
if (handler->roundCorners || handler->makeFrame
|
|
|| handler->constructionMethod() == ConstructionMethod::ThreePoints
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
|
|
handler->setNextState(SelectMode::SeekThird);
|
|
}
|
|
else {
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
}
|
|
} break;
|
|
case SelectMode::SeekThird: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (handler->roundCorners
|
|
&& onViewParameters[OnViewParameter::Fifth]->hasFinishedEditing) {
|
|
|
|
if (handler->makeFrame) {
|
|
handler->setNextState(SelectMode::SeekFourth);
|
|
}
|
|
else {
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
}
|
|
else if (handler->makeFrame
|
|
&& onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) {
|
|
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
}
|
|
else {
|
|
if (onViewParameters[OnViewParameter::Fifth]->hasFinishedEditing
|
|
&& onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) {
|
|
if (handler->roundCorners || handler->makeFrame) {
|
|
handler->setNextState(SelectMode::SeekFourth);
|
|
}
|
|
else {
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
case SelectMode::SeekFourth: {
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAndCorner) {
|
|
if (onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) {
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
}
|
|
else {
|
|
if (handler->roundCorners
|
|
&& onViewParameters[OnViewParameter::Seventh]->hasFinishedEditing) {
|
|
|
|
if (handler->makeFrame) {
|
|
handler->setNextState(SelectMode::SeekFifth);
|
|
}
|
|
else {
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
}
|
|
else if (handler->makeFrame
|
|
&& onViewParameters[OnViewParameter::Eighth]->hasFinishedEditing) {
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
}
|
|
} break;
|
|
case SelectMode::SeekFifth: {
|
|
if (handler->makeFrame
|
|
&& onViewParameters[OnViewParameter::Eighth]->hasFinishedEditing) {
|
|
handler->setNextState(SelectMode::End);
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void DSHRectangleController::addConstraints()
|
|
{
|
|
using std::numbers::pi;
|
|
|
|
App::DocumentObject* obj = handler->sketchgui->getObject();
|
|
|
|
int firstCurve = handler->firstCurve;
|
|
bool reverse = handler->cornersReversed;
|
|
if (handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
reverse = !reverse;
|
|
}
|
|
|
|
auto x0 = onViewParameters[OnViewParameter::First]->getValue();
|
|
auto y0 = onViewParameters[OnViewParameter::Second]->getValue();
|
|
auto length = onViewParameters[OnViewParameter::Third]->getValue();
|
|
auto width = onViewParameters[OnViewParameter::Fourth]->getValue();
|
|
auto radius = onViewParameters[OnViewParameter::Fifth]->getValue();
|
|
auto thickness = onViewParameters[OnViewParameter::Sixth]->getValue();
|
|
|
|
auto x0set = onViewParameters[OnViewParameter::First]->isSet;
|
|
auto y0set = onViewParameters[OnViewParameter::Second]->isSet;
|
|
auto lengthSet = onViewParameters[OnViewParameter::Third]->isSet;
|
|
auto widthSet = onViewParameters[OnViewParameter::Fourth]->isSet;
|
|
auto radiusSet = onViewParameters[OnViewParameter::Fifth]->isSet;
|
|
auto thicknessSet = onViewParameters[OnViewParameter::Sixth]->isSet;
|
|
|
|
auto corner1x = onViewParameters[OnViewParameter::Third]->getValue();
|
|
auto corner1y = onViewParameters[OnViewParameter::Fourth]->getValue();
|
|
auto angle = Base::toRadians(onViewParameters[OnViewParameter::Fourth]->getValue());
|
|
auto innerAngle = Base::toRadians(onViewParameters[OnViewParameter::Sixth]->getValue());
|
|
|
|
auto corner1xSet = onViewParameters[OnViewParameter::Third]->isSet;
|
|
auto corner1ySet = onViewParameters[OnViewParameter::Fourth]->isSet;
|
|
auto angleSet = onViewParameters[OnViewParameter::Fourth]->isSet;
|
|
auto innerAngleSet = onViewParameters[OnViewParameter::Sixth]->isSet;
|
|
|
|
if (handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
lengthSet = false;
|
|
}
|
|
if (handler->constructionMethod() == ConstructionMethod::ThreePoints
|
|
|| handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
width = onViewParameters[OnViewParameter::Fifth]->getValue();
|
|
radius = onViewParameters[OnViewParameter::Seventh]->getValue();
|
|
thickness = onViewParameters[OnViewParameter::Eighth]->getValue();
|
|
|
|
widthSet = onViewParameters[OnViewParameter::Fifth]->isSet;
|
|
radiusSet = onViewParameters[OnViewParameter::Seventh]->isSet;
|
|
thicknessSet = onViewParameters[OnViewParameter::Eighth]->isSet;
|
|
}
|
|
|
|
using namespace Sketcher;
|
|
|
|
int firstPointId = firstCurve;
|
|
if (handler->constructionMethod() == ConstructionMethod::Diagonal
|
|
|| handler->constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
if (handler->radius > Precision::Confusion()) {
|
|
firstPointId = handler->constructionPointOneId;
|
|
}
|
|
}
|
|
else {
|
|
firstPointId = handler->centerPointId;
|
|
}
|
|
|
|
auto constraintx0 = [&]() {
|
|
ConstraintToAttachment(GeoElementId(firstPointId, PointPos::start),
|
|
GeoElementId::VAxis,
|
|
x0,
|
|
obj);
|
|
};
|
|
|
|
auto constrainty0 = [&]() {
|
|
ConstraintToAttachment(GeoElementId(firstPointId, PointPos::start),
|
|
GeoElementId::HAxis,
|
|
y0,
|
|
obj);
|
|
};
|
|
|
|
auto constraintlength = [&]() {
|
|
int curveId = reverse ? firstCurve : firstCurve + 1;
|
|
|
|
Gui::cmdAppObjectArgs(obj,
|
|
"addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f)) ",
|
|
curveId,
|
|
1,
|
|
curveId + 2,
|
|
2,
|
|
fabs(length));
|
|
};
|
|
|
|
auto constraintwidth = [&]() {
|
|
int curveId = reverse ? firstCurve + 1 : firstCurve;
|
|
|
|
Gui::cmdAppObjectArgs(obj,
|
|
"addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f)) ",
|
|
curveId,
|
|
1,
|
|
curveId + 2,
|
|
2,
|
|
fabs(width));
|
|
};
|
|
|
|
// NOTE: if AutoConstraints is empty, we can add constraints directly without any diagnose. No
|
|
// diagnose was run.
|
|
if (handler->AutoConstraints.empty()) {
|
|
if (x0set) {
|
|
constraintx0();
|
|
}
|
|
|
|
if (y0set) {
|
|
constrainty0();
|
|
}
|
|
|
|
if (lengthSet) {
|
|
constraintlength();
|
|
}
|
|
|
|
if (widthSet) {
|
|
constraintwidth();
|
|
}
|
|
}
|
|
else { // There is a valid diagnose.
|
|
auto firstpointinfo = handler->getPointInfo(GeoElementId(firstPointId, PointPos::start));
|
|
|
|
if (x0set && firstpointinfo.isXDoF()) {
|
|
constraintx0();
|
|
|
|
handler->diagnoseWithAutoConstraints(); // ensure we have recalculated parameters after
|
|
// each constraint addition
|
|
|
|
firstpointinfo = handler->getPointInfo(
|
|
GeoElementId(firstPointId, PointPos::start)); // get updated point position
|
|
}
|
|
|
|
if (y0set && firstpointinfo.isYDoF()) {
|
|
constrainty0();
|
|
|
|
handler->diagnoseWithAutoConstraints(); // ensure we have recalculated parameters after
|
|
// each constraint addition
|
|
}
|
|
|
|
if (lengthSet) {
|
|
int curveId = reverse ? firstCurve : firstCurve + 1;
|
|
auto startpointinfo = handler->getPointInfo(GeoElementId(curveId, PointPos::start));
|
|
auto endpointinfo = handler->getPointInfo(GeoElementId(curveId + 2, PointPos::end));
|
|
|
|
int DoFs = startpointinfo.getDoFs();
|
|
DoFs += endpointinfo.getDoFs();
|
|
|
|
if (DoFs > 0) {
|
|
constraintlength();
|
|
}
|
|
|
|
handler->diagnoseWithAutoConstraints();
|
|
}
|
|
|
|
if (widthSet) {
|
|
int curveId = reverse ? firstCurve + 1 : firstCurve;
|
|
auto startpointinfo = handler->getPointInfo(GeoElementId(curveId, PointPos::start));
|
|
auto endpointinfo = handler->getPointInfo(GeoElementId(curveId + 2, PointPos::end));
|
|
|
|
int DoFs = startpointinfo.getDoFs();
|
|
DoFs += endpointinfo.getDoFs();
|
|
|
|
if (DoFs > 0) {
|
|
constraintwidth();
|
|
}
|
|
}
|
|
}
|
|
|
|
// NOTE: As of today, there are no autoconstraints on the radius or on the frame thickness,
|
|
// therefore, they are necessarily constrainable were applicable.
|
|
|
|
if (handler->constructionMethod() == ConstructionMethod::ThreePoints) {
|
|
if (angleSet) {
|
|
ConstraintLineByAngle(firstCurve, angle, obj);
|
|
}
|
|
if (innerAngleSet) {
|
|
if (fabs(innerAngle - pi / 2) > Precision::Confusion()) {
|
|
// if 90? then perpendicular already created.
|
|
Gui::cmdAppObjectArgs(obj,
|
|
"addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f)) ",
|
|
firstCurve + 1,
|
|
1,
|
|
firstCurve,
|
|
2,
|
|
innerAngle);
|
|
}
|
|
}
|
|
}
|
|
else if (handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) {
|
|
if (corner1xSet) {
|
|
ConstraintToAttachment(GeoElementId(firstCurve, PointPos::start),
|
|
GeoElementId::VAxis,
|
|
corner1x,
|
|
obj);
|
|
}
|
|
if (corner1ySet) {
|
|
ConstraintToAttachment(GeoElementId(firstCurve, PointPos::start),
|
|
GeoElementId::HAxis,
|
|
corner1y,
|
|
obj);
|
|
}
|
|
if (innerAngleSet) {
|
|
if (fabs(innerAngle - pi / 2) > Precision::Confusion()) {
|
|
// if 90? then perpendicular already created.
|
|
Gui::cmdAppObjectArgs(obj,
|
|
"addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f)) ",
|
|
firstCurve,
|
|
1,
|
|
firstCurve + 3,
|
|
2,
|
|
innerAngle);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (radiusSet && radius > Precision::Confusion()) {
|
|
Gui::cmdAppObjectArgs(obj,
|
|
"addConstraint(Sketcher.Constraint('Radius',%d,%f)) ",
|
|
firstCurve + 5, // NOLINT
|
|
radius);
|
|
}
|
|
|
|
bool negThicknessEqualRadius = fabs(radius + thickness) < Precision::Confusion();
|
|
// in the case where negative thickness = radius, the inner rectangle has its corner
|
|
// constrained to the mid of the arcs of the outer rectangle. So thickness would be redundant
|
|
if (thicknessSet && !negThicknessEqualRadius) {
|
|
Gui::cmdAppObjectArgs(obj,
|
|
"addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f)) ",
|
|
firstCurve + (handler->roundCorners == true ? 8 : 4), // NOLINT
|
|
1,
|
|
firstCurve,
|
|
fabs(thickness));
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void DSHRectangleController::doConstructionMethodChanged()
|
|
{
|
|
handler->updateHint();
|
|
}
|
|
|
|
} // namespace SketcherGui
|
|
|
|
|
|
#endif // SKETCHERGUI_DrawSketchHandlerRectangle_H
|