From 5600c564be627a8e6dc4e3bc13f4ce1f05f6a0fd Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Wed, 8 Mar 2023 17:58:50 +0100
Subject: [PATCH 01/53] Added MappedName class
---
src/App/CMakeLists.txt | 2 +
src/App/MappedName.cpp | 54 +++
src/App/MappedName.h | 615 +++++++++++++++++++++++++++++++++++
tests/src/App/CMakeLists.txt | 1 +
tests/src/App/MappedName.cpp | 16 +
5 files changed, 688 insertions(+)
create mode 100644 src/App/MappedName.cpp
create mode 100644 src/App/MappedName.h
create mode 100644 tests/src/App/MappedName.cpp
diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt
index 918ced0a6f..e4b096aedd 100644
--- a/src/App/CMakeLists.txt
+++ b/src/App/CMakeLists.txt
@@ -262,6 +262,7 @@ SET(FreeCADApp_CPP_SRCS
ComplexGeoDataPyImp.cpp
Enumeration.cpp
IndexedName.cpp
+ MappedName.cpp
Material.cpp
MaterialPyImp.cpp
Metadata.cpp
@@ -279,6 +280,7 @@ SET(FreeCADApp_HPP_SRCS
ComplexGeoData.h
Enumeration.h
IndexedName.h
+ MappedName.h
Material.h
Metadata.h
)
diff --git a/src/App/MappedName.cpp b/src/App/MappedName.cpp
new file mode 100644
index 0000000000..f7620ff7c8
--- /dev/null
+++ b/src/App/MappedName.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+ * Copyright (c) 2020 Zheng, Lei (realthunder) *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ****************************************************************************/
+
+#include "PreCompiled.h"
+
+#ifndef _PreComp_
+# include
+#endif
+
+//#include
+
+#include "MappedName.h"
+
+using namespace Data;
+
+
+void MappedName::compact() const
+{
+ auto self = const_cast(this);
+
+ if (this->raw) {
+ self->data = QByteArray(self->data.constData(), self->data.size());
+ self->raw = false;
+ }
+
+#if 0
+ static std::unordered_set PostfixSet;
+ if (this->postfix.size()) {
+ auto res = PostfixSet.insert(this->postfix);
+ if (!res.second)
+ self->postfix = *res.first;
+ }
+#endif
+}
+
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
new file mode 100644
index 0000000000..5bf15b1c89
--- /dev/null
+++ b/src/App/MappedName.h
@@ -0,0 +1,615 @@
+/****************************************************************************
+ * Copyright (c) 2020 Zheng, Lei (realthunder) *
+ * *
+ * 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 _AppMappedName_h_
+#define _AppMappedName_h_
+
+
+#include
+
+#include
+
+#include
+#include
+
+#include "ComplexGeoData.h"
+
+
+namespace Data
+{
+
+
+class AppExport MappedName
+{
+public:
+
+ explicit MappedName(const char * name, int size = -1)
+ : raw(false)
+ {
+ if (!name) return;
+ if (boost::starts_with(name, ComplexGeoData::elementMapPrefix()))
+ name += ComplexGeoData::elementMapPrefix().size();
+
+ data = size < 0 ? QByteArray(name) : QByteArray(name, size);
+ }
+
+ explicit MappedName(const std::string & name)
+ : raw(false)
+ {
+ int size = name.size();
+ const char *n = name.c_str();
+ if (boost::starts_with(name, ComplexGeoData::elementMapPrefix())) {
+ n += ComplexGeoData::elementMapPrefix().size();
+ size -= ComplexGeoData::elementMapPrefix().size();
+ }
+ data = QByteArray(n, size);
+ }
+/*
+ explicit MappedName(const IndexedName & element)
+ : data(element.getType()), raw(false)
+ {
+ if (element.getIndex() > 0)
+ data += QByteArray::number(element.getIndex());
+ }
+*/
+ MappedName()
+ : raw(false)
+ {}
+
+ MappedName(const MappedName & other)
+ : data(other.data), postfix(other.postfix), raw(other.raw)
+ {}
+
+ MappedName(const MappedName & other, int startpos, int size = -1)
+ : raw(false)
+ {
+ append(other, startpos, size);
+ }
+
+ MappedName(const MappedName & other, const char *postfix)
+ : data(other.data + other.postfix), postfix(postfix), raw(false)
+ {}
+
+#if QT_VERSION >= 0x050200
+ MappedName(MappedName &&other)
+ : data(std::move(other.data)), postfix(std::move(other.postfix)), raw(other.raw)
+ {}
+#endif
+
+ static MappedName fromRawData(const char * name, int size = -1)
+ {
+ MappedName res;
+ if (name) {
+ res.data = QByteArray::fromRawData(name, size>=0 ? size : qstrlen(name));
+ res.raw = true;
+ }
+ return res;
+ }
+
+ static MappedName fromRawData(const QByteArray & data)
+ {
+ return fromRawData(data.constData(), data.size());
+ }
+
+ static MappedName fromRawData(const MappedName &other, int startpos, int size = -1)
+ {
+ if (startpos < 0)
+ startpos = 0;
+
+ if (startpos >= other.size())
+ return MappedName();
+
+ if (startpos >= other.data.size())
+ return MappedName(other, startpos, size);
+
+ MappedName res;
+ res.raw = true;
+ if (size < 0)
+ size = other.size() - startpos;
+
+ if (size < other.data.size() - startpos) {
+ res.data = QByteArray::fromRawData(other.data.constData() + startpos, size);
+ }
+ else {
+ res.data = QByteArray::fromRawData(other.data.constData() + startpos, other.data.size() - startpos);
+ size -= other.data.size() - startpos;
+ if (size == other.postfix.size())
+ res.postfix = other.postfix;
+ else if (size)
+ res.postfix.append(other.postfix.constData(), size);
+ }
+ return res;
+ }
+
+ MappedName & operator=(const MappedName & other)
+ {
+ this->data = other.data;
+ this->postfix = other.postfix;
+ this->raw = other.raw;
+ return *this;
+ }
+
+ MappedName & operator=(const std::string & other)
+ {
+ *this = MappedName(other);
+ return *this;
+ }
+
+ MappedName & operator=(const char * other)
+ {
+ *this = MappedName(other);
+ return *this;
+ }
+
+
+#if QT_VERSION >= 0x050200
+ MappedName & operator=(MappedName &&other)
+ {
+ this->data = std::move(other.data);
+ this->postfix = std::move(other.postfix);
+ this->raw = other.raw;
+ return *this;
+ }
+#endif
+
+ friend std::ostream & operator<<(std::ostream & s, const MappedName & n)
+ {
+ s.write(n.data.constData(), n.data.size());
+ s.write(n.postfix.constData(), n.postfix.size());
+ return s;
+ }
+
+ bool operator==(const MappedName & other) const
+ {
+ if (this->size() != other.size()) {
+ return false;
+ }
+
+ if (this->data.size() == other.data.size()) {
+ return this->data == other.data && this->postfix == other.postfix;
+ }
+
+ const auto &smaller = this->data.size() < other.data.size() ? *this : other;
+ const auto &larger = this->data.size() < other.data.size() ? other: *this;
+
+ if (!larger.data.startsWith(smaller.data)) {
+ return false;
+ }
+
+ QByteArray tmp = QByteArray::fromRawData(
+ larger.data.constData() + smaller.data.size(),
+ larger.data.size() - smaller.data.size()
+ );
+
+ if (!smaller.postfix.startsWith(tmp)) {
+ return false;
+ }
+
+ tmp = QByteArray::fromRawData(
+ smaller.postfix.constData() + tmp.size(),
+ smaller.postfix.size() - tmp.size()
+ );
+
+ return tmp == larger.postfix;
+ }
+
+ bool operator!=(const MappedName & other) const
+ {
+ return !(this->operator==(other));
+ }
+
+ MappedName operator+(const MappedName & other) const
+ {
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName operator+(const char * other) const
+ {
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName operator+(const std::string & other) const
+ {
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName operator+(const QByteArray & other) const
+ {
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName & operator+=(const char * other)
+ {
+ if (other && other[0])
+ this->postfix.append(other, -1);
+ return *this;
+ }
+
+ MappedName & operator+=(const std::string & other)
+ {
+ if (other.size()) {
+ this->postfix.reserve(this->postfix.size() + other.size());
+ this->postfix.append(other.c_str(), other.size());
+ }
+ return *this;
+ }
+
+ MappedName & operator+=(const QByteArray & other)
+ {
+ this->postfix += other;
+ return *this;
+ }
+
+ MappedName & operator+=(const MappedName & other)
+ {
+ append(other);
+ return *this;
+ }
+
+ void append(const char * d, int size = -1)
+ {
+ if (d && size) {
+ if (size < 0)
+ size = qstrlen(d);
+ if (empty())
+ this->data.append(d, size);
+ else
+ this->postfix.append(d, size);
+ }
+ }
+
+ void append(const MappedName & other, int startpos = 0, int size = -1)
+ {
+ if (startpos < 0)
+ startpos = 0;
+ else if (startpos > other.size())
+ return;
+ if (size < 0 || size + startpos > other.size())
+ size = other.size() - startpos;
+
+ int count = size;
+ if (startpos < other.data.size()) {
+ if (count > other.data.size() - startpos)
+ count = other.data.size() - startpos;
+ if (startpos == 0 && count == other.data.size() && this->empty()) {
+ this->data = other.data;
+ this->raw = other.raw;
+ } else
+ append(other.data.constData() + startpos, count);
+ startpos = 0;
+ size -= count;
+ } else
+ startpos -= other.data.size();
+ if (size) {
+ if (startpos == 0 && size == other.postfix.size()) {
+ if (this->empty())
+ this->data = other.postfix;
+ else if (this->postfix.isEmpty())
+ this->postfix = other.postfix;
+ else
+ this->postfix += other.postfix;
+ } else
+ append(other.postfix.constData() + startpos, size);
+ }
+ }
+
+ std::string toString(int startpos, int len=-1) const
+ {
+ std::string res;
+ return toString(res, startpos, len);
+ }
+
+ const char * toString(std::string &s, int startpos=0, int len=-1) const
+ {
+ std::size_t offset = s.size();
+ int count = this->size();
+ if (startpos < 0)
+ startpos = 0;
+ else if (startpos >= count)
+ return s.c_str()+s.size();
+ if (len < 0 || len > count - startpos)
+ len = count - startpos;
+ s.reserve(s.size() + len);
+ if (startpos < this->data.size()) {
+ count = this->data.size() - startpos;
+ if (len < count)
+ count = len;
+ s.append(this->data.constData()+startpos, count);
+ len -= count;
+ }
+ s.append(this->postfix.constData(), len);
+ return s.c_str() + offset;
+ }
+
+ const char * toConstString(int offset, int &size) const
+ {
+ if (offset < 0)
+ offset = 0;
+ if (offset > this->data.size()) {
+ offset -= this->data.size();
+ if (offset > this->postfix.size()) {
+ size = 0;
+ return "";
+ }
+ size = this->postfix.size() - offset;
+ return this->postfix.constData() + offset;
+ }
+ size = this->data.size() - offset;
+ return this->data.constData() + offset;
+ }
+
+ QByteArray toRawBytes(int offset=0, int size=-1) const
+ {
+ if (offset < 0)
+ offset = 0;
+ if (offset >= this->size())
+ return QByteArray();
+ if (size < 0 || size > this->size() - offset)
+ size = this->size() - offset;
+ if (offset >= this->data.size()) {
+ offset -= this->data.size();
+ return QByteArray::fromRawData(this->postfix.constData()+offset, size);
+ }
+ if (size <= this->data.size() - offset)
+ return QByteArray::fromRawData(this->data.constData()+offset, size);
+
+ QByteArray res(this->data.constData()+offset, this->data.size()-offset);
+ res.append(this->postfix.constData(), size - this->data.size() + offset);
+ return res;
+ }
+
+ const QByteArray & dataBytes() const
+ {
+ return this->data;
+ }
+
+ const QByteArray & postfixBytes() const
+ {
+ return this->postfix;
+ }
+
+ const char * constPostfix() const
+ {
+ return this->postfix.constData();
+ }
+
+ // No constData() because 'data' is allow to contain raw data, which may
+ // not end with 0.
+#if 0
+ void char * constData() const
+ {
+ return this->data.constData();
+ }
+#endif
+
+ QByteArray toBytes() const
+ {
+ if (this->postfix.isEmpty())
+ return this->data;
+ if (this->data.isEmpty())
+ return this->postfix;
+ return this->data + this->postfix;
+ }
+/*
+ IndexedName toIndexedName() const
+ {
+ if (this->postfix.isEmpty())
+ return IndexedName(this->data);
+ return IndexedName();
+ }
+
+ std::string toPrefixedString() const
+ {
+ std::string res;
+ toPrefixedString(res);
+ return res;
+ }
+
+ const char *toPrefixedString(std::string &buf) const
+ {
+ if (!toIndexedName())
+ buf += ComplexGeoData::elementMapPrefix();
+ toString(buf);
+ return buf.c_str();
+ }
+*/
+ int compare(const MappedName &other) const
+ {
+ int asize = this->size();
+ int bsize = other.size();
+ for (int i=0, count=std::min(asize, bsize); ioperator[](i);
+ char b = other[i];
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ }
+ if (asize < bsize)
+ return -1;
+ if (asize > bsize)
+ return 1;
+ return 0;
+ }
+
+ bool operator<(const MappedName & other) const
+ {
+ return compare(other) < 0;
+ }
+
+ char operator[](int index) const
+ {
+ if (index >= this->data.size())
+ return this->postfix[index - this->data.size()];
+ return this->data[index];
+ }
+
+ int size() const
+ {
+ return this->data.size() + this->postfix.size();
+ }
+
+ bool empty() const
+ {
+ return this->data.isEmpty() && this->postfix.isEmpty();
+ }
+
+ bool isRaw() const
+ {
+ return this->raw;
+ }
+
+ MappedName copy() const
+ {
+ if (!this->raw)
+ return *this;
+ MappedName res;
+ res.data.append(this->data.constData(), this->data.size());
+ res.postfix = this->postfix;
+ return res;
+ }
+
+ void compact() const;
+
+ explicit operator bool() const
+ {
+ return !empty();
+ }
+
+ void clear()
+ {
+ this->data.clear();
+ this->postfix.clear();
+ this->raw = false;
+ }
+
+ int find(const char *d, int startpos = 0) const
+ {
+ if (!d)
+ return -1;
+ if (startpos < 0)
+ startpos = 0;
+ if (startpos < this->data.size()) {
+ int res = this->data.indexOf(d, startpos);
+ if (res >= 0)
+ return res;
+ startpos = 0;
+ } else
+ startpos -= this->data.size();
+ int res = this->postfix.indexOf(d, startpos);
+ if (res < 0)
+ return res;
+ return res + this->data.size();
+ }
+
+ int find(const std::string &d, int startpos = 0) const
+ {
+ return find(d.c_str(), startpos);
+ }
+
+ int rfind(const char *d, int startpos = -1) const
+ {
+ if (!d)
+ return -1;
+ if (startpos < 0 || startpos > this->postfix.size()) {
+ if (startpos > postfix.size())
+ startpos -= postfix.size();
+ int res = this->postfix.lastIndexOf(d, startpos);
+ if (res >= 0)
+ return res + this->data.size();
+ startpos = -1;
+ }
+ return this->data.lastIndexOf(d, startpos);
+ }
+
+ int rfind(const std::string &d, int startpos = -1) const
+ {
+ return rfind(d.c_str(), startpos);
+ }
+
+ bool endsWith(const char *s) const
+ {
+ if (!s)
+ return false;
+ if (this->postfix.size())
+ return this->postfix.endsWith(s);
+ return this->data.endsWith(s);
+ }
+
+ bool endsWith(const std::string &s) const
+ {
+ return endsWith(s.c_str());
+ }
+
+ bool startsWith(const QByteArray & s, int offset = 0) const
+ {
+ if (s.size() > size() - offset)
+ return false;
+ if (offset || (this->data.size() && this->data.size() < s.size()))
+ return toRawBytes(offset, s.size()) == s;
+ if (this->data.size())
+ return this->data.startsWith(s);
+ return this->postfix.startsWith(s);
+ }
+
+ bool startsWith(const char *s, int offset = 0) const
+ {
+ if (!s)
+ return false;
+ return startsWith(QByteArray::fromRawData(s, qstrlen(s)), offset);
+ }
+
+ bool startsWith(const std::string &s, int offset = 0) const
+ {
+ return startsWith(QByteArray::fromRawData(s.c_str(), s.size()), offset);
+ }
+
+ std::size_t hash() const
+ {
+#if QT_VERSION >= 0x050000
+ return qHash(data, qHash(postfix));
+#else
+ return qHash(data) ^ qHash(postfix);
+#endif
+ }
+
+private:
+ QByteArray data;
+ QByteArray postfix;
+ bool raw;
+};
+
+
+
+} //namespace Data
+
+
+#endif
\ No newline at end of file
diff --git a/tests/src/App/CMakeLists.txt b/tests/src/App/CMakeLists.txt
index fbde1bb2fa..c64ae328f5 100644
--- a/tests/src/App/CMakeLists.txt
+++ b/tests/src/App/CMakeLists.txt
@@ -5,5 +5,6 @@ target_sources(
${CMAKE_CURRENT_SOURCE_DIR}/Expression.cpp
${CMAKE_CURRENT_SOURCE_DIR}/IndexedName.cpp
${CMAKE_CURRENT_SOURCE_DIR}/License.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/MappedName.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Metadata.cpp
)
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
new file mode 100644
index 0000000000..436bf0c520
--- /dev/null
+++ b/tests/src/App/MappedName.cpp
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "gtest/gtest.h"
+
+#include "App/MappedName.h"
+
+
+// clang-format off
+TEST(MappedName, defaultConstruction)
+{
+
+}
+
+
+
+// clang-format on
\ No newline at end of file
From 62246b951a1a0086c06b4aadc0b3f7284509d75a Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Fri, 10 Mar 2023 20:11:04 +0100
Subject: [PATCH 02/53] Added initial tests to MappedName
---
src/App/MappedName.h | 29 +++++-
tests/src/App/MappedName.cpp | 194 +++++++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+), 5 deletions(-)
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
index 5bf15b1c89..89b6bf56ea 100644
--- a/src/App/MappedName.h
+++ b/src/App/MappedName.h
@@ -80,6 +80,9 @@ public:
: data(other.data), postfix(other.postfix), raw(other.raw)
{}
+ //FIXME if you pass a raw MappedName into these constructors they will
+ //reset raw to false and things will break. is this intended?
+
MappedName(const MappedName & other, int startpos, int size = -1)
: raw(false)
{
@@ -276,6 +279,7 @@ public:
void append(const char * d, int size = -1)
{
+ //FIXME raw not assigned?
if (d && size) {
if (size < 0)
size = qstrlen(d);
@@ -288,26 +292,41 @@ public:
void append(const MappedName & other, int startpos = 0, int size = -1)
{
+ // enforce 0 <= startpos <= other.size
if (startpos < 0)
startpos = 0;
else if (startpos > other.size())
return;
- if (size < 0 || size + startpos > other.size())
+
+ // enforce 0 <= size <= other.size - startpos
+ if (size < 0 || size > other.size() - startpos)
size = other.size() - startpos;
- int count = size;
- if (startpos < other.data.size()) {
- if (count > other.data.size() - startpos)
+
+ if (startpos < other.data.size()) // if starting inside data
+ {
+ int count = size;
+ //make sure count doesn't exceed data size and end up in postfix
+ if (count > other.data.size() - startpos)
count = other.data.size() - startpos;
+
+ //if this is empty append in data else append in postfix
if (startpos == 0 && count == other.data.size() && this->empty()) {
this->data = other.data;
this->raw = other.raw;
} else
append(other.data.constData() + startpos, count);
+
+ //setup startpos and count to contiune appending the remainder to postfix
startpos = 0;
size -= count;
- } else
+ }
+ else //else starting inside postfix
+ {
startpos -= other.data.size();
+ }
+
+ //if there is still data to be added to postfix
if (size) {
if (startpos == 0 && size == other.postfix.size()) {
if (this->empty())
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index 436bf0c520..dc3ae1b383 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -3,14 +3,208 @@
#include "gtest/gtest.h"
#include "App/MappedName.h"
+#include "App/ComplexGeoData.h"
+
+#include
+
// clang-format off
TEST(MappedName, defaultConstruction)
{
+ auto mappedName = Data::MappedName();
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), true);
+ EXPECT_EQ(mappedName.size(), 0);
+}
+
+TEST(MappedName, namedConstruction)
+{
+ auto mappedName = Data::MappedName("TEST");
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, namedConstructionWithMaxSize)
+{
+ auto mappedName = Data::MappedName("TEST", 2);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 2);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TE"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, namedConstructionDiscardPrefix)
+{
+ std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
+ auto mappedName = Data::MappedName(name.c_str());
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
}
+TEST(MappedName, stringNamedConstruction)
+{
+ auto mappedName = Data::MappedName(std::string("TEST"));
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, stringNamedConstructionDiscardPrefix)
+{
+ std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
+ auto mappedName = Data::MappedName(name);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+
+}
+
+TEST(MappedName, copyConstructor)
+{
+ auto temp = Data::MappedName("TEST");
+ auto mappedName = Data::MappedName(temp);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+
+}
+
+TEST(MappedName, copyConstructorWithPostfix)
+{
+ auto temp = Data::MappedName("TEST");
+ auto mappedName = Data::MappedName(temp, "POSTFIXTEST");
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 15);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
+}
+
+TEST(MappedName, constructorWithPostfixAndCopy)
+{
+ auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ auto mappedName = Data::MappedName(temp, "ANOTHERPOSTFIX");
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 29);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TESTPOSTFIXTEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("ANOTHERPOSTFIX"));
+}
+
+TEST(MappedName, copyConstructorStartpos)
+{
+ auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ auto mappedName = Data::MappedName(temp, 2, -1);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 13);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("ST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
+}
+
+TEST(MappedName, copyConstructorStartposAndSize)
+{
+ auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ auto mappedName = Data::MappedName(temp, 2, 6);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 6);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("ST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POST"));
+}
+
+#if QT_VERSION >= 0x050200
+TEST(MappedName, moveConstructor)
+{
+ auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ auto mappedName = Data::MappedName(std::move(temp));
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 15);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
+
+ EXPECT_EQ(temp.isRaw(), false);
+ EXPECT_EQ(temp.empty(), true);
+ EXPECT_EQ(temp.size(), 0);
+ EXPECT_EQ(temp.dataBytes(), QByteArray());
+ EXPECT_EQ(temp.postfixBytes(), QByteArray());
+}
+#endif
+
+TEST(MappedName, fromRawData)
+{
+ auto mappedName = Data::MappedName::fromRawData("TEST\0\0TEST", 10);
+ EXPECT_EQ(mappedName.isRaw(), true);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 10);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, fromRawDataQByteArray)
+{
+ auto mappedName = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.isRaw(), true);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 10);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, fromRawDataCopy)
+{
+ auto temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ temp.append("TESTPOSTFIX");
+ auto mappedName = Data::MappedName::fromRawData(temp, 0);
+ EXPECT_EQ(mappedName.isRaw(), true);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 21);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("TESTPOSTFIX"));
+}
+
+
+TEST(MappedName, fromRawDataCopyStartposAndSize)
+{
+ auto temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ temp.append("ABCDEFGHIJKLM"); //postfix
+/* This block is OK
+ EXPECT_EQ(temp.isRaw(), true);
+ EXPECT_EQ(temp.empty(), false);
+ EXPECT_EQ(temp.size(), 23);
+ EXPECT_EQ(temp.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(temp.postfixBytes(), QByteArray("ABCDEFGHIJKLM"));
+*/
+
+ auto mappedName = Data::MappedName::fromRawData(temp, 2, 13);
+ EXPECT_EQ(mappedName.isRaw(), true);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 13);
+ //next line fails with CDE\0TEST != ST\0\0TEST
+ //funny thing if i uncomment the block above, which does nothing, now the next line
+ //fails with CDE\0GHIJ != ST\0\0TEST
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("ST\0\0TEST", 8));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("ABCDE"));
+}
+
+//TODO raw postfix?
+
// clang-format on
\ No newline at end of file
From 1562179bdc3f10417a56d6e3a2333183b8e9b8ad Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Sat, 11 Mar 2023 15:48:12 +0100
Subject: [PATCH 03/53] MappedName unit tests almost complete
---
src/App/MappedName.h | 13 +-
tests/src/App/MappedName.cpp | 420 ++++++++++++++++++++++++++++++++---
2 files changed, 397 insertions(+), 36 deletions(-)
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
index 89b6bf56ea..89e95fd4ad 100644
--- a/src/App/MappedName.h
+++ b/src/App/MappedName.h
@@ -93,11 +93,9 @@ public:
: data(other.data + other.postfix), postfix(postfix), raw(false)
{}
-#if QT_VERSION >= 0x050200
MappedName(MappedName &&other)
: data(std::move(other.data)), postfix(std::move(other.postfix)), raw(other.raw)
{}
-#endif
static MappedName fromRawData(const char * name, int size = -1)
{
@@ -165,7 +163,6 @@ public:
}
-#if QT_VERSION >= 0x050200
MappedName & operator=(MappedName &&other)
{
this->data = std::move(other.data);
@@ -173,7 +170,6 @@ public:
this->raw = other.raw;
return *this;
}
-#endif
friend std::ostream & operator<<(std::ostream & s, const MappedName & n)
{
@@ -368,6 +364,8 @@ public:
return s.c_str() + offset;
}
+ //if offset is inside data return data, if offset is > data.size
+ //(ends up in postfix) return postfix
const char * toConstString(int offset, int &size) const
{
if (offset < 0)
@@ -486,6 +484,7 @@ public:
char operator[](int index) const
{
+ //FIXME overflow underflow checks?
if (index >= this->data.size())
return this->postfix[index - this->data.size()];
return this->data[index];
@@ -558,7 +557,7 @@ public:
{
if (!d)
return -1;
- if (startpos < 0 || startpos > this->postfix.size()) {
+ if (startpos < 0 || startpos > this->postfix.size()) { //FIXME should be this->data.size
if (startpos > postfix.size())
startpos -= postfix.size();
int res = this->postfix.lastIndexOf(d, startpos);
@@ -613,11 +612,7 @@ public:
std::size_t hash() const
{
-#if QT_VERSION >= 0x050000
return qHash(data, qHash(postfix));
-#else
- return qHash(data) ^ qHash(postfix);
-#endif
}
private:
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index dc3ae1b383..5ddee750d8 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -6,13 +6,14 @@
#include "App/ComplexGeoData.h"
#include
+#include
// clang-format off
TEST(MappedName, defaultConstruction)
{
- auto mappedName = Data::MappedName();
+ Data::MappedName mappedName = Data::MappedName();
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), true);
EXPECT_EQ(mappedName.size(), 0);
@@ -20,7 +21,7 @@ TEST(MappedName, defaultConstruction)
TEST(MappedName, namedConstruction)
{
- auto mappedName = Data::MappedName("TEST");
+ Data::MappedName mappedName = Data::MappedName("TEST");
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -30,7 +31,7 @@ TEST(MappedName, namedConstruction)
TEST(MappedName, namedConstructionWithMaxSize)
{
- auto mappedName = Data::MappedName("TEST", 2);
+ Data::MappedName mappedName = Data::MappedName("TEST", 2);
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 2);
@@ -41,7 +42,7 @@ TEST(MappedName, namedConstructionWithMaxSize)
TEST(MappedName, namedConstructionDiscardPrefix)
{
std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
- auto mappedName = Data::MappedName(name.c_str());
+ Data::MappedName mappedName = Data::MappedName(name.c_str());
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -52,7 +53,7 @@ TEST(MappedName, namedConstructionDiscardPrefix)
TEST(MappedName, stringNamedConstruction)
{
- auto mappedName = Data::MappedName(std::string("TEST"));
+ Data::MappedName mappedName = Data::MappedName(std::string("TEST"));
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -63,7 +64,7 @@ TEST(MappedName, stringNamedConstruction)
TEST(MappedName, stringNamedConstructionDiscardPrefix)
{
std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
- auto mappedName = Data::MappedName(name);
+ Data::MappedName mappedName = Data::MappedName(name);
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -74,8 +75,8 @@ TEST(MappedName, stringNamedConstructionDiscardPrefix)
TEST(MappedName, copyConstructor)
{
- auto temp = Data::MappedName("TEST");
- auto mappedName = Data::MappedName(temp);
+ Data::MappedName temp = Data::MappedName("TEST");
+ Data::MappedName mappedName = Data::MappedName(temp);
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -86,8 +87,8 @@ TEST(MappedName, copyConstructor)
TEST(MappedName, copyConstructorWithPostfix)
{
- auto temp = Data::MappedName("TEST");
- auto mappedName = Data::MappedName(temp, "POSTFIXTEST");
+ Data::MappedName temp = Data::MappedName("TEST");
+ Data::MappedName mappedName = Data::MappedName(temp, "POSTFIXTEST");
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 15);
@@ -97,8 +98,8 @@ TEST(MappedName, copyConstructorWithPostfix)
TEST(MappedName, constructorWithPostfixAndCopy)
{
- auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- auto mappedName = Data::MappedName(temp, "ANOTHERPOSTFIX");
+ Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName = Data::MappedName(temp, "ANOTHERPOSTFIX");
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 29);
@@ -108,8 +109,8 @@ TEST(MappedName, constructorWithPostfixAndCopy)
TEST(MappedName, copyConstructorStartpos)
{
- auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- auto mappedName = Data::MappedName(temp, 2, -1);
+ Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName = Data::MappedName(temp, 2, -1);
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 13);
@@ -119,8 +120,8 @@ TEST(MappedName, copyConstructorStartpos)
TEST(MappedName, copyConstructorStartposAndSize)
{
- auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- auto mappedName = Data::MappedName(temp, 2, 6);
+ Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName = Data::MappedName(temp, 2, 6);
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 6);
@@ -128,11 +129,10 @@ TEST(MappedName, copyConstructorStartposAndSize)
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POST"));
}
-#if QT_VERSION >= 0x050200
TEST(MappedName, moveConstructor)
{
- auto temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- auto mappedName = Data::MappedName(std::move(temp));
+ Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName = Data::MappedName(std::move(temp));
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 15);
@@ -145,11 +145,10 @@ TEST(MappedName, moveConstructor)
EXPECT_EQ(temp.dataBytes(), QByteArray());
EXPECT_EQ(temp.postfixBytes(), QByteArray());
}
-#endif
TEST(MappedName, fromRawData)
{
- auto mappedName = Data::MappedName::fromRawData("TEST\0\0TEST", 10);
+ Data::MappedName mappedName = Data::MappedName::fromRawData("TEST\0\0TEST", 10);
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 10);
@@ -159,7 +158,7 @@ TEST(MappedName, fromRawData)
TEST(MappedName, fromRawDataQByteArray)
{
- auto mappedName = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ Data::MappedName mappedName = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 10);
@@ -169,9 +168,9 @@ TEST(MappedName, fromRawDataQByteArray)
TEST(MappedName, fromRawDataCopy)
{
- auto temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
temp.append("TESTPOSTFIX");
- auto mappedName = Data::MappedName::fromRawData(temp, 0);
+ Data::MappedName mappedName = Data::MappedName::fromRawData(temp, 0);
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 21);
@@ -182,7 +181,7 @@ TEST(MappedName, fromRawDataCopy)
TEST(MappedName, fromRawDataCopyStartposAndSize)
{
- auto temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
temp.append("ABCDEFGHIJKLM"); //postfix
/* This block is OK
EXPECT_EQ(temp.isRaw(), true);
@@ -192,7 +191,7 @@ TEST(MappedName, fromRawDataCopyStartposAndSize)
EXPECT_EQ(temp.postfixBytes(), QByteArray("ABCDEFGHIJKLM"));
*/
- auto mappedName = Data::MappedName::fromRawData(temp, 2, 13);
+ Data::MappedName mappedName = Data::MappedName::fromRawData(temp, 2, 13);
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 13);
@@ -203,8 +202,375 @@ TEST(MappedName, fromRawDataCopyStartposAndSize)
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("ABCDE"));
}
-//TODO raw postfix?
+//TODO raw postfix? answer: apparently postfix will never be raw. See copy()
+
+TEST(MappedName, assignmentOperator)
+{
+ Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName = temp;
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 15);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
+}
+
+TEST(MappedName, assignmentOperatorString)
+{
+ Data::MappedName mappedName;
+ mappedName = std::string("TEST");
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, assignmentOperatorConstCharPtr)
+{
+ Data::MappedName mappedName;
+ mappedName = "TEST";
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, operatorEqualMove)
+{
+ Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName = std::move(temp);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 15);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
+
+ EXPECT_EQ(temp.isRaw(), false);
+ EXPECT_EQ(temp.empty(), true);
+ EXPECT_EQ(temp.size(), 0);
+ EXPECT_EQ(temp.dataBytes(), QByteArray());
+ EXPECT_EQ(temp.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, streamInsertionOperator)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 15);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
+
+ std::stringstream ss;
+ ss << mappedName;
+ EXPECT_EQ(ss.str(), std::string("TESTPOSTFIXTEST"));
+}
+TEST(MappedName, comparisonOperators)
+{
+ Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName2 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName3 = Data::MappedName(Data::MappedName("TESTPOST"), "FIXTEST");
+ Data::MappedName mappedName4 = Data::MappedName(Data::MappedName("THIS"), "ISDIFFERENT");
+
+ EXPECT_EQ(mappedName1 == mappedName1, true);
+ EXPECT_EQ(mappedName1 == mappedName2, true);
+ EXPECT_EQ(mappedName1 == mappedName3, true);
+ EXPECT_EQ(mappedName1 == mappedName4, false);
+
+ EXPECT_EQ(mappedName1 != mappedName1, false);
+ EXPECT_EQ(mappedName1 != mappedName2, false);
+ EXPECT_EQ(mappedName1 != mappedName3, false);
+ EXPECT_EQ(mappedName1 != mappedName4, true);
+}
+
+TEST(MappedName, additionOperators)
+{
+ Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ mappedName1 += "POST1";
+ mappedName1 += std::string("POST2");
+ mappedName1 += QByteArray("POST3");
+ mappedName1 += Data::MappedName("POST4");
+
+ EXPECT_EQ(mappedName1.isRaw(), false);
+ EXPECT_EQ(mappedName1.empty(), false);
+ EXPECT_EQ(mappedName1.size(), 35);
+ EXPECT_EQ(mappedName1.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName1.postfixBytes(), QByteArray("POSTFIXTESTPOST1POST2POST3POST4"));
+
+ mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ mappedName1 = mappedName1 + Data::MappedName("POST5");
+ mappedName1 = mappedName1 + "POST6";
+ mappedName1 = mappedName1 + std::string("POST7");
+ mappedName1 = mappedName1 + QByteArray("POST8");
+
+ EXPECT_EQ(mappedName1.isRaw(), false);
+ EXPECT_EQ(mappedName1.empty(), false);
+ EXPECT_EQ(mappedName1.size(), 35);
+ EXPECT_EQ(mappedName1.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName1.postfixBytes(), QByteArray("POSTFIXTESTPOST5POST6POST7POST8"));
+}
+
+
+TEST(MappedName, append)
+{
+ Data::MappedName mappedName = Data::MappedName();
+ mappedName.append("TEST");
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 4);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray(""));
+
+ mappedName.append("POSTFIX");
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 11);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIX"));
+
+ mappedName.append("ANOTHERPOSTFIX", 5);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 16);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXANOTH"));
+}
+
+
+TEST(MappedName, appendMappedNameObj)
+{
+ Data::MappedName mappedName = Data::MappedName();
+
+ mappedName.append(Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST"));
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 15);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
+
+ mappedName.append(Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST"), 2, 7);
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 22);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTESTSTPOSTF"));
+}
+
+TEST(MappedName, toString)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ EXPECT_EQ(mappedName.toString(0), "TESTPOSTFIXTEST");
+ EXPECT_EQ(mappedName.toString(0), std::string("TESTPOSTFIXTEST"));
+ EXPECT_EQ(mappedName.toString(2, 8), "STPOSTFI");
+ EXPECT_EQ(mappedName.toString(2, 8), std::string("STPOSTFI"));
+}
+
+
+TEST(MappedName, toConstString)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ int size;
+ const char *temp = mappedName.toConstString(0, size);
+ EXPECT_EQ(QByteArray(temp, size), QByteArray("TEST"));
+ EXPECT_EQ(size, 4);
+ const char *temp2 = mappedName.toConstString(7, size);
+ EXPECT_EQ(QByteArray(temp2, size), QByteArray("TFIXTEST"));
+ EXPECT_EQ(size, 8);
+}
+
+TEST(MappedName, toRawBytes)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ EXPECT_EQ(mappedName.toRawBytes(), QByteArray("TESTPOSTFIXTEST"));
+ EXPECT_EQ(mappedName.toRawBytes(3), QByteArray("TPOSTFIXTEST"));
+ EXPECT_EQ(mappedName.toRawBytes(7, 3), QByteArray("TFI"));
+ EXPECT_EQ(mappedName.toRawBytes(502, 5), QByteArray());
+}
+
+TEST(MappedName, toBytes)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ EXPECT_EQ(mappedName.toBytes(), QByteArray("TESTPOSTFIXTEST"));
+}
+
+
+TEST(MappedName, compare)
+{
+ Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName2 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName3 = Data::MappedName(Data::MappedName("TESTPOST"), "FIXTEST");
+ Data::MappedName mappedName4 = Data::MappedName(Data::MappedName("THIS"), "ISDIFFERENT");
+ Data::MappedName mappedName5 = Data::MappedName(Data::MappedName("SH"), "ORTHER");
+ Data::MappedName mappedName6 = Data::MappedName(Data::MappedName("VERYVERYVERY"), "VERYMUCHLONGER");
+
+ EXPECT_EQ(mappedName1.compare(mappedName1), 0);
+ EXPECT_EQ(mappedName1.compare(mappedName2), 0);
+ EXPECT_EQ(mappedName1.compare(mappedName3), 0);
+ EXPECT_EQ(mappedName1.compare(mappedName4), -1);
+ EXPECT_EQ(mappedName1.compare(mappedName5), 1);
+ EXPECT_EQ(mappedName1.compare(mappedName6), -1);
+
+ EXPECT_EQ(mappedName1 < mappedName1, false);
+ EXPECT_EQ(mappedName1 < mappedName2, false);
+ EXPECT_EQ(mappedName1 < mappedName3, false);
+ EXPECT_EQ(mappedName1 < mappedName4, true);
+ EXPECT_EQ(mappedName1 < mappedName5, false);
+ EXPECT_EQ(mappedName1 < mappedName6, true);
+}
+
+TEST(MappedName, indexOperator)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ EXPECT_EQ(mappedName[0], 'T');
+ EXPECT_EQ(mappedName[1], 'E');
+ EXPECT_EQ(mappedName[2], 'S');
+ EXPECT_EQ(mappedName[3], 'T');
+ EXPECT_EQ(mappedName[4], 'P');
+ EXPECT_EQ(mappedName[5], 'O');
+ EXPECT_EQ(mappedName[6], 'S');
+ EXPECT_EQ(mappedName[7], 'T');
+ EXPECT_EQ(mappedName[8], 'F');
+ EXPECT_EQ(mappedName[9], 'I');
+}
+
+TEST(MappedName, copy)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName2 = mappedName.copy();
+ EXPECT_EQ(mappedName, mappedName2);
+}
+
+
+TEST(MappedName, compact)
+{
+ Data::MappedName mappedName = Data::MappedName::fromRawData("TEST\0\0TEST", 10);
+ EXPECT_EQ(mappedName.isRaw(), true);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 10);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+
+ mappedName.compact();
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 10);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+}
+
+TEST(MappedName, boolOperator)
+{
+ Data::MappedName mappedName = Data::MappedName();
+ EXPECT_EQ((bool)mappedName, false);
+ mappedName.append("TEST");
+ EXPECT_EQ((bool)mappedName, true);
+}
+
+TEST(MappedName, clear)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ EXPECT_EQ(mappedName.empty(), false);
+ mappedName.clear();
+ EXPECT_EQ(mappedName.empty(), true);
+}
+
+TEST(MappedName, find)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ EXPECT_EQ(mappedName.find(nullptr), -1);
+ EXPECT_EQ(mappedName.find(""), 0);
+ EXPECT_EQ(mappedName.find("TEST"), 0);
+ EXPECT_EQ(mappedName.find("STPO"), -1); //sentence must be fully contained in data or postfix
+ EXPECT_EQ(mappedName.find("POST"), 4);
+ EXPECT_EQ(mappedName.find("ST", 3), 6); //found in postfix
+ EXPECT_EQ(mappedName.find("POST", 4), 4);
+ EXPECT_EQ(mappedName.find("POST", 5), -1);
+
+ EXPECT_EQ(mappedName.find(std::string("")), 0);
+}
+
+
+TEST(MappedName, rfind)
+{
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ EXPECT_EQ(mappedName.rfind(nullptr), -1);
+ EXPECT_EQ(mappedName.rfind(""), mappedName.size());
+ EXPECT_EQ(mappedName.rfind("TEST"), 11);
+ EXPECT_EQ(mappedName.rfind("STPO"), -1); //sentence must be fully contained in data or postfix
+ EXPECT_EQ(mappedName.rfind("POST"), 4);
+
+
+ //FIXME looks broken
+ EXPECT_EQ(mappedName.rfind("ST"), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 0), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 1), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 2), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 3), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 4), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 5), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 6), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 7), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 8), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 9), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 10), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 11), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 12), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 13), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 14), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 15), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 16), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 17), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 18), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 19), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 20), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 21), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 22), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 23), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 24), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 25), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 26), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 27), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 28), 2);
+ //EXPECT_EQ(mappedName.rfind("POST", 7), 4);
+ //EXPECT_EQ(mappedName.rfind("POST", 8), -1);
+
+ EXPECT_EQ(mappedName.rfind(std::string("")), mappedName.size());
+}
+
+TEST(MappedName, endswith)
+{
+ Data::MappedName mappedName = Data::MappedName("TEST");
+ EXPECT_EQ(mappedName.endsWith(nullptr), false);
+ EXPECT_EQ(mappedName.endsWith("TEST"), true);
+ EXPECT_EQ(mappedName.endsWith("WASD"), false);
+
+ EXPECT_EQ(mappedName.endsWith(std::string("TEST")), true);
+
+ mappedName.append("POSTFIX");
+
+ EXPECT_EQ(mappedName.endsWith(nullptr), false);
+ EXPECT_EQ(mappedName.endsWith("TEST"), false);
+ EXPECT_EQ(mappedName.endsWith("FIX"), true);
+}
+
+
+TEST(MappedName, startsWith)
+{
+ Data::MappedName mappedName = Data::MappedName("TEST");
+ EXPECT_EQ(mappedName.startsWith(QByteArray()), true);
+ EXPECT_EQ(mappedName.startsWith("TEST"), true);
+ EXPECT_EQ(mappedName.startsWith("WASD"), false);
+
+ EXPECT_EQ(mappedName.startsWith(nullptr), false);
+ EXPECT_EQ(mappedName.startsWith("TEST"), true);
+ EXPECT_EQ(mappedName.startsWith(std::string("TEST")), true);
+}
+
+//TODO test hash function
// clang-format on
\ No newline at end of file
From 6a6cda538fb70901a01ce56c1281af9271e561d8 Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Tue, 14 Mar 2023 02:11:15 +0100
Subject: [PATCH 04/53] Use AAA pattern in test suite
---
tests/src/App/MappedName.cpp | 304 ++++++++++++++++++++++++++---------
1 file changed, 229 insertions(+), 75 deletions(-)
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index 5ddee750d8..c5e176f540 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -13,15 +13,23 @@
// clang-format off
TEST(MappedName, defaultConstruction)
{
+ // Act
Data::MappedName mappedName = Data::MappedName();
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), true);
EXPECT_EQ(mappedName.size(), 0);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray());
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
}
TEST(MappedName, namedConstruction)
{
+ // Act
Data::MappedName mappedName = Data::MappedName("TEST");
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -31,7 +39,10 @@ TEST(MappedName, namedConstruction)
TEST(MappedName, namedConstructionWithMaxSize)
{
+ // Act
Data::MappedName mappedName = Data::MappedName("TEST", 2);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 2);
@@ -41,19 +52,26 @@ TEST(MappedName, namedConstructionWithMaxSize)
TEST(MappedName, namedConstructionDiscardPrefix)
{
+ // Arrange
std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
+
+ // Act
Data::MappedName mappedName = Data::MappedName(name.c_str());
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
-
}
TEST(MappedName, stringNamedConstruction)
{
+ // Act
Data::MappedName mappedName = Data::MappedName(std::string("TEST"));
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -63,43 +81,58 @@ TEST(MappedName, stringNamedConstruction)
TEST(MappedName, stringNamedConstructionDiscardPrefix)
{
+ // Arrange
std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
+
+ // Act
Data::MappedName mappedName = Data::MappedName(name);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
-
}
TEST(MappedName, copyConstructor)
{
+ // Arrange
Data::MappedName temp = Data::MappedName("TEST");
+
+ // Act
Data::MappedName mappedName = Data::MappedName(temp);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
-
}
TEST(MappedName, copyConstructorWithPostfix)
{
+ // Arrange
Data::MappedName temp = Data::MappedName("TEST");
+
+ // Act
Data::MappedName mappedName = Data::MappedName(temp, "POSTFIXTEST");
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 15);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
-}
-TEST(MappedName, constructorWithPostfixAndCopy)
-{
- Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- Data::MappedName mappedName = Data::MappedName(temp, "ANOTHERPOSTFIX");
+ // Arrange
+ temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
+ mappedName = Data::MappedName(temp, "ANOTHERPOSTFIX");
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 29);
@@ -109,8 +142,13 @@ TEST(MappedName, constructorWithPostfixAndCopy)
TEST(MappedName, copyConstructorStartpos)
{
+ // Arrange
Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
Data::MappedName mappedName = Data::MappedName(temp, 2, -1);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 13);
@@ -120,8 +158,13 @@ TEST(MappedName, copyConstructorStartpos)
TEST(MappedName, copyConstructorStartposAndSize)
{
+ // Arrange
Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
Data::MappedName mappedName = Data::MappedName(temp, 2, 6);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 6);
@@ -131,8 +174,13 @@ TEST(MappedName, copyConstructorStartposAndSize)
TEST(MappedName, moveConstructor)
{
+ // Arrange
Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
Data::MappedName mappedName = Data::MappedName(std::move(temp));
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 15);
@@ -148,66 +196,84 @@ TEST(MappedName, moveConstructor)
TEST(MappedName, fromRawData)
{
- Data::MappedName mappedName = Data::MappedName::fromRawData("TEST\0\0TEST", 10);
+ // Act
+ Data::MappedName mappedName = Data::MappedName::fromRawData("TESTTEST", 10);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 10);
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TESTTEST", 10));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
}
TEST(MappedName, fromRawDataQByteArray)
{
- Data::MappedName mappedName = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ // Act
+ Data::MappedName mappedName = Data::MappedName::fromRawData(QByteArray("TESTTEST", 10));
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 10);
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TESTTEST", 10));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
}
TEST(MappedName, fromRawDataCopy)
{
- Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ // Arrange
+ Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TESTTEST", 10));
temp.append("TESTPOSTFIX");
+
+ // Act
Data::MappedName mappedName = Data::MappedName::fromRawData(temp, 0);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 21);
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TESTTEST", 10));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("TESTPOSTFIX"));
}
-
-TEST(MappedName, fromRawDataCopyStartposAndSize)
+TEST(MappedName, fromRawDataCopyStartposAndSize) //FIXME
{
- Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TEST\0\0TEST", 10));
+ // Arrange
+ Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TESTTEST", 8));
temp.append("ABCDEFGHIJKLM"); //postfix
+
/* This block is OK
EXPECT_EQ(temp.isRaw(), true);
EXPECT_EQ(temp.empty(), false);
- EXPECT_EQ(temp.size(), 23);
- EXPECT_EQ(temp.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(temp.size(), 21);
+ EXPECT_EQ(temp.dataBytes(), QByteArray("TESTTEST", 8));
EXPECT_EQ(temp.postfixBytes(), QByteArray("ABCDEFGHIJKLM"));
*/
+ // Act
Data::MappedName mappedName = Data::MappedName::fromRawData(temp, 2, 13);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 13);
- //next line fails with CDE\0TEST != ST\0\0TEST
+ //next line fails with TEST\0T != STTEST
//funny thing if i uncomment the block above, which does nothing, now the next line
- //fails with CDE\0GHIJ != ST\0\0TEST
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("ST\0\0TEST", 8));
- EXPECT_EQ(mappedName.postfixBytes(), QByteArray("ABCDE"));
+ //fails with TEST\0H != STTEST
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("STTEST", 6));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("ABCDEFG"));
}
-//TODO raw postfix? answer: apparently postfix will never be raw. See copy()
-
TEST(MappedName, assignmentOperator)
{
+ // Arrange
Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
Data::MappedName mappedName = temp;
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 15);
@@ -217,8 +283,13 @@ TEST(MappedName, assignmentOperator)
TEST(MappedName, assignmentOperatorString)
{
+ // Arrange
Data::MappedName mappedName;
+
+ // Act
mappedName = std::string("TEST");
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -228,8 +299,13 @@ TEST(MappedName, assignmentOperatorString)
TEST(MappedName, assignmentOperatorConstCharPtr)
{
+ // Arrange
Data::MappedName mappedName;
+
+ // Act
mappedName = "TEST";
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
@@ -237,10 +313,15 @@ TEST(MappedName, assignmentOperatorConstCharPtr)
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
}
-TEST(MappedName, operatorEqualMove)
+TEST(MappedName, assignmentOperatorMove)
{
+ // Arrange
Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
Data::MappedName mappedName = std::move(temp);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 15);
@@ -256,27 +337,26 @@ TEST(MappedName, operatorEqualMove)
TEST(MappedName, streamInsertionOperator)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- EXPECT_EQ(mappedName.isRaw(), false);
- EXPECT_EQ(mappedName.empty(), false);
- EXPECT_EQ(mappedName.size(), 15);
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
- EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
-
+ // Act
std::stringstream ss;
ss << mappedName;
+
+ // Assert
EXPECT_EQ(ss.str(), std::string("TESTPOSTFIXTEST"));
}
-
TEST(MappedName, comparisonOperators)
{
+ // Arrange
Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
Data::MappedName mappedName2 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
Data::MappedName mappedName3 = Data::MappedName(Data::MappedName("TESTPOST"), "FIXTEST");
Data::MappedName mappedName4 = Data::MappedName(Data::MappedName("THIS"), "ISDIFFERENT");
-
+
+ // Act & Assert
EXPECT_EQ(mappedName1 == mappedName1, true);
EXPECT_EQ(mappedName1 == mappedName2, true);
EXPECT_EQ(mappedName1 == mappedName3, true);
@@ -290,50 +370,68 @@ TEST(MappedName, comparisonOperators)
TEST(MappedName, additionOperators)
{
- Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- mappedName1 += "POST1";
- mappedName1 += std::string("POST2");
- mappedName1 += QByteArray("POST3");
- mappedName1 += Data::MappedName("POST4");
+ // Arrange
+ Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
+ mappedName += "POST1";
+ mappedName += std::string("POST2");
+ mappedName += QByteArray("POST3");
+ mappedName += Data::MappedName("POST4");
+
+ // Assert
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 35);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTESTPOST1POST2POST3POST4"));
- EXPECT_EQ(mappedName1.isRaw(), false);
- EXPECT_EQ(mappedName1.empty(), false);
- EXPECT_EQ(mappedName1.size(), 35);
- EXPECT_EQ(mappedName1.dataBytes(), QByteArray("TEST"));
- EXPECT_EQ(mappedName1.postfixBytes(), QByteArray("POSTFIXTESTPOST1POST2POST3POST4"));
+ // Arrange
+ mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- mappedName1 = mappedName1 + Data::MappedName("POST5");
- mappedName1 = mappedName1 + "POST6";
- mappedName1 = mappedName1 + std::string("POST7");
- mappedName1 = mappedName1 + QByteArray("POST8");
-
- EXPECT_EQ(mappedName1.isRaw(), false);
- EXPECT_EQ(mappedName1.empty(), false);
- EXPECT_EQ(mappedName1.size(), 35);
- EXPECT_EQ(mappedName1.dataBytes(), QByteArray("TEST"));
- EXPECT_EQ(mappedName1.postfixBytes(), QByteArray("POSTFIXTESTPOST5POST6POST7POST8"));
+ // Act
+ mappedName = mappedName + Data::MappedName("POST5");
+ mappedName = mappedName + "POST6";
+ mappedName = mappedName + std::string("POST7");
+ mappedName = mappedName + QByteArray("POST8");
+
+ // Assert
+ EXPECT_EQ(mappedName.isRaw(), false);
+ EXPECT_EQ(mappedName.empty(), false);
+ EXPECT_EQ(mappedName.size(), 35);
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
+ EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTESTPOST5POST6POST7POST8"));
}
-
TEST(MappedName, append)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName();
+
+ // Act
mappedName.append("TEST");
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 4);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray(""));
+ // Act
mappedName.append("POSTFIX");
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 11);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIX"));
+ // Act
mappedName.append("ANOTHERPOSTFIX", 5);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 16);
@@ -341,19 +439,26 @@ TEST(MappedName, append)
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXANOTH"));
}
-
TEST(MappedName, appendMappedNameObj)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName();
+ Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- mappedName.append(Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST"));
+ // Act
+ mappedName.append(temp);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 15);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
- mappedName.append(Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST"), 2, 7);
+ // Act
+ mappedName.append(temp, 2, 7);
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 22);
@@ -363,29 +468,43 @@ TEST(MappedName, appendMappedNameObj)
TEST(MappedName, toString)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName.toString(0), "TESTPOSTFIXTEST");
EXPECT_EQ(mappedName.toString(0), std::string("TESTPOSTFIXTEST"));
EXPECT_EQ(mappedName.toString(2, 8), "STPOSTFI");
EXPECT_EQ(mappedName.toString(2, 8), std::string("STPOSTFI"));
}
-
TEST(MappedName, toConstString)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
int size;
+
+ // Act
const char *temp = mappedName.toConstString(0, size);
+
+ // Assert
EXPECT_EQ(QByteArray(temp, size), QByteArray("TEST"));
EXPECT_EQ(size, 4);
+
+ // Act
const char *temp2 = mappedName.toConstString(7, size);
+
+ // Assert
EXPECT_EQ(QByteArray(temp2, size), QByteArray("TFIXTEST"));
EXPECT_EQ(size, 8);
}
TEST(MappedName, toRawBytes)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName.toRawBytes(), QByteArray("TESTPOSTFIXTEST"));
EXPECT_EQ(mappedName.toRawBytes(3), QByteArray("TPOSTFIXTEST"));
EXPECT_EQ(mappedName.toRawBytes(7, 3), QByteArray("TFI"));
@@ -394,20 +513,24 @@ TEST(MappedName, toRawBytes)
TEST(MappedName, toBytes)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName.toBytes(), QByteArray("TESTPOSTFIXTEST"));
}
-
TEST(MappedName, compare)
{
+ // Arrange
Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
Data::MappedName mappedName2 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
Data::MappedName mappedName3 = Data::MappedName(Data::MappedName("TESTPOST"), "FIXTEST");
Data::MappedName mappedName4 = Data::MappedName(Data::MappedName("THIS"), "ISDIFFERENT");
Data::MappedName mappedName5 = Data::MappedName(Data::MappedName("SH"), "ORTHER");
Data::MappedName mappedName6 = Data::MappedName(Data::MappedName("VERYVERYVERY"), "VERYMUCHLONGER");
-
+
+ // Act & Assert
EXPECT_EQ(mappedName1.compare(mappedName1), 0);
EXPECT_EQ(mappedName1.compare(mappedName2), 0);
EXPECT_EQ(mappedName1.compare(mappedName3), 0);
@@ -423,9 +546,12 @@ TEST(MappedName, compare)
EXPECT_EQ(mappedName1 < mappedName6, true);
}
-TEST(MappedName, indexOperator)
+TEST(MappedName, subscriptOperator)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName[0], 'T');
EXPECT_EQ(mappedName[1], 'E');
EXPECT_EQ(mappedName[2], 'S');
@@ -440,48 +566,65 @@ TEST(MappedName, indexOperator)
TEST(MappedName, copy)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act
Data::MappedName mappedName2 = mappedName.copy();
+
+ // Assert
EXPECT_EQ(mappedName, mappedName2);
}
-
TEST(MappedName, compact)
{
- Data::MappedName mappedName = Data::MappedName::fromRawData("TEST\0\0TEST", 10);
- EXPECT_EQ(mappedName.isRaw(), true);
- EXPECT_EQ(mappedName.empty(), false);
- EXPECT_EQ(mappedName.size(), 10);
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
- EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
+ // Arrange
+ Data::MappedName mappedName = Data::MappedName::fromRawData("TESTTEST", 10);
+ // Act
mappedName.compact();
+
+ // Assert
EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 10);
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST\0\0TEST", 10));
+ EXPECT_EQ(mappedName.dataBytes(), QByteArray("TESTTEST", 10));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
}
TEST(MappedName, boolOperator)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName();
+
+ // Act & Assert
EXPECT_EQ((bool)mappedName, false);
+
+ // Arrange
mappedName.append("TEST");
+
+ // Act & Assert
EXPECT_EQ((bool)mappedName, true);
}
TEST(MappedName, clear)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- EXPECT_EQ(mappedName.empty(), false);
+
+ // Act
mappedName.clear();
+
+ // Assert
EXPECT_EQ(mappedName.empty(), true);
}
TEST(MappedName, find)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName.find(nullptr), -1);
EXPECT_EQ(mappedName.find(""), 0);
EXPECT_EQ(mappedName.find("TEST"), 0);
@@ -494,10 +637,12 @@ TEST(MappedName, find)
EXPECT_EQ(mappedName.find(std::string("")), 0);
}
-
TEST(MappedName, rfind)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName.rfind(nullptr), -1);
EXPECT_EQ(mappedName.rfind(""), mappedName.size());
EXPECT_EQ(mappedName.rfind("TEST"), 11);
@@ -544,24 +689,31 @@ TEST(MappedName, rfind)
TEST(MappedName, endswith)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName("TEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName.endsWith(nullptr), false);
EXPECT_EQ(mappedName.endsWith("TEST"), true);
EXPECT_EQ(mappedName.endsWith("WASD"), false);
EXPECT_EQ(mappedName.endsWith(std::string("TEST")), true);
+ // Arrange
mappedName.append("POSTFIX");
-
+
+ // Act & Assert
EXPECT_EQ(mappedName.endsWith(nullptr), false);
EXPECT_EQ(mappedName.endsWith("TEST"), false);
EXPECT_EQ(mappedName.endsWith("FIX"), true);
}
-
TEST(MappedName, startsWith)
{
+ // Arrange
Data::MappedName mappedName = Data::MappedName("TEST");
+
+ // Act & Assert
EXPECT_EQ(mappedName.startsWith(QByteArray()), true);
EXPECT_EQ(mappedName.startsWith("TEST"), true);
EXPECT_EQ(mappedName.startsWith("WASD"), false);
@@ -572,5 +724,7 @@ TEST(MappedName, startsWith)
}
//TODO test hash function
+//TODO test indexedName functions
+
// clang-format on
\ No newline at end of file
From cd6c70adcc1a8a2302e1a2f8091672b6a96c850c Mon Sep 17 00:00:00 2001
From: Chris Hennes
Date: Wed, 15 Mar 2023 22:09:17 -0500
Subject: [PATCH 05/53] App/Toponaming: MappedName clang-tidy cleanup
---
src/App/MappedName.h | 670 +++++++++++++++++++++++--------------------
1 file changed, 363 insertions(+), 307 deletions(-)
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
index 89e95fd4ad..6a84b19a42 100644
--- a/src/App/MappedName.h
+++ b/src/App/MappedName.h
@@ -21,8 +21,8 @@
****************************************************************************/
-#ifndef _AppMappedName_h_
-#define _AppMappedName_h_
+#ifndef APP_MAPPED_NAME_H
+#define APP_MAPPED_NAME_H
#include
@@ -33,152 +33,164 @@
#include
#include "ComplexGeoData.h"
+#include "IndexedName.h"
namespace Data
{
+// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
class AppExport MappedName
{
public:
-
- explicit MappedName(const char * name, int size = -1)
- : raw(false)
- {
- if (!name) return;
- if (boost::starts_with(name, ComplexGeoData::elementMapPrefix()))
+ explicit MappedName(const char* name, int size = -1)
+ : raw(false)
+ {
+ if (!name) {
+ return;
+ }
+ if (boost::starts_with(name, ComplexGeoData::elementMapPrefix())) {
name += ComplexGeoData::elementMapPrefix().size();
+ }
data = size < 0 ? QByteArray(name) : QByteArray(name, size);
}
- explicit MappedName(const std::string & name)
- : raw(false)
+ explicit MappedName(const std::string& nameString)
+ : raw(false)
{
- int size = name.size();
- const char *n = name.c_str();
- if (boost::starts_with(name, ComplexGeoData::elementMapPrefix())) {
- n += ComplexGeoData::elementMapPrefix().size();
+ auto size = nameString.size();
+ const char* name = nameString.c_str();
+ if (boost::starts_with(nameString, ComplexGeoData::elementMapPrefix())) {
+ name += ComplexGeoData::elementMapPrefix().size();
size -= ComplexGeoData::elementMapPrefix().size();
}
- data = QByteArray(n, size);
+ data = QByteArray(name, static_cast(size));
}
-/*
- explicit MappedName(const IndexedName & element)
- : data(element.getType()), raw(false)
+
+ explicit MappedName(const IndexedName& element)
+ : data(element.getType()),
+ raw(false)
{
- if (element.getIndex() > 0)
+ if (element.getIndex() > 0) {
data += QByteArray::number(element.getIndex());
+ }
}
-*/
+
MappedName()
: raw(false)
{}
- MappedName(const MappedName & other)
- : data(other.data), postfix(other.postfix), raw(other.raw)
- {}
+ MappedName(const MappedName& other) = default;
- //FIXME if you pass a raw MappedName into these constructors they will
- //reset raw to false and things will break. is this intended?
+ // FIXME if you pass a raw MappedName into these constructors they will
+ // reset raw to false and things will break. is this intended?
- MappedName(const MappedName & other, int startpos, int size = -1)
+ MappedName(const MappedName& other, int startPosition, int size = -1)
: raw(false)
{
- append(other, startpos, size);
+ append(other, startPosition, size);
}
- MappedName(const MappedName & other, const char *postfix)
- : data(other.data + other.postfix), postfix(postfix), raw(false)
- {}
-
- MappedName(MappedName &&other)
- : data(std::move(other.data)), postfix(std::move(other.postfix)), raw(other.raw)
+ MappedName(const MappedName& other, const char* postfix)
+ : data(other.data + other.postfix),
+ postfix(postfix),
+ raw(false)
{}
- static MappedName fromRawData(const char * name, int size = -1)
+ MappedName(MappedName&& other) noexcept
+ : data(std::move(other.data)),
+ postfix(std::move(other.postfix)),
+ raw(other.raw)
+ {}
+
+ ~MappedName() = default;
+
+ static MappedName fromRawData(const char* name, int size = -1)
{
MappedName res;
if (name) {
- res.data = QByteArray::fromRawData(name, size>=0 ? size : qstrlen(name));
+ res.data =
+ QByteArray::fromRawData(name, size >= 0 ? size : static_cast(qstrlen(name)));
res.raw = true;
}
return res;
}
- static MappedName fromRawData(const QByteArray & data)
+ static MappedName fromRawData(const QByteArray& data)
{
return fromRawData(data.constData(), data.size());
}
- static MappedName fromRawData(const MappedName &other, int startpos, int size = -1)
+ static MappedName fromRawData(const MappedName& other, int startPosition, int size = -1)
{
- if (startpos < 0)
- startpos = 0;
+ if (startPosition < 0) {
+ startPosition = 0;
+ }
- if (startpos >= other.size())
- return MappedName();
+ if (startPosition >= other.size()) {
+ return {};
+ }
- if (startpos >= other.data.size())
- return MappedName(other, startpos, size);
+ if (startPosition >= other.data.size()) {
+ return {other, startPosition, size};
+ }
MappedName res;
res.raw = true;
- if (size < 0)
- size = other.size() - startpos;
+ if (size < 0) {
+ size = other.size() - startPosition;
+ }
- if (size < other.data.size() - startpos) {
- res.data = QByteArray::fromRawData(other.data.constData() + startpos, size);
+ if (size < other.data.size() - startPosition) {
+ res.data = QByteArray::fromRawData(other.data.constData() + startPosition, size);
}
else {
- res.data = QByteArray::fromRawData(other.data.constData() + startpos, other.data.size() - startpos);
- size -= other.data.size() - startpos;
- if (size == other.postfix.size())
+ res.data = QByteArray::fromRawData(other.data.constData() + startPosition,
+ other.data.size() - startPosition);
+ size -= other.data.size() - startPosition;
+ if (size == other.postfix.size()) {
res.postfix = other.postfix;
- else if (size)
+ }
+ else if (size != 0) {
res.postfix.append(other.postfix.constData(), size);
+ }
}
return res;
}
- MappedName & operator=(const MappedName & other)
+ MappedName& operator=(const MappedName& other) = default;
+
+ MappedName& operator=(const std::string& other)
{
- this->data = other.data;
- this->postfix = other.postfix;
+ *this = MappedName(other);
+ return *this;
+ }
+
+ MappedName& operator=(const char* other)
+ {
+ *this = MappedName(other);
+ return *this;
+ }
+
+
+ MappedName& operator=(MappedName&& other) noexcept
+ {
+ this->data = std::move(other.data);
+ this->postfix = std::move(other.postfix);
this->raw = other.raw;
return *this;
}
- MappedName & operator=(const std::string & other)
+ friend std::ostream& operator<<(std::ostream& stream, const MappedName& mappedName)
{
- *this = MappedName(other);
- return *this;
+ stream.write(mappedName.data.constData(), mappedName.data.size());
+ stream.write(mappedName.postfix.constData(), mappedName.postfix.size());
+ return stream;
}
- MappedName & operator=(const char * other)
- {
- *this = MappedName(other);
- return *this;
- }
-
-
- MappedName & operator=(MappedName &&other)
- {
- this->data = std::move(other.data);
- this->postfix = std::move(other.postfix);
- this->raw = other.raw;
- return *this;
- }
-
- friend std::ostream & operator<<(std::ostream & s, const MappedName & n)
- {
- s.write(n.data.constData(), n.data.size());
- s.write(n.postfix.constData(), n.postfix.size());
- return s;
- }
-
- bool operator==(const MappedName & other) const
+ bool operator==(const MappedName& other) const
{
if (this->size() != other.size()) {
return false;
@@ -188,188 +200,204 @@ public:
return this->data == other.data && this->postfix == other.postfix;
}
- const auto &smaller = this->data.size() < other.data.size() ? *this : other;
- const auto &larger = this->data.size() < other.data.size() ? other: *this;
-
+ const auto& smaller = this->data.size() < other.data.size() ? *this : other;
+ const auto& larger = this->data.size() < other.data.size() ? other : *this;
+
if (!larger.data.startsWith(smaller.data)) {
return false;
}
- QByteArray tmp = QByteArray::fromRawData(
- larger.data.constData() + smaller.data.size(),
- larger.data.size() - smaller.data.size()
- );
-
+ QByteArray tmp = QByteArray::fromRawData(larger.data.constData() + smaller.data.size(),
+ larger.data.size() - smaller.data.size());
+
if (!smaller.postfix.startsWith(tmp)) {
return false;
}
- tmp = QByteArray::fromRawData(
- smaller.postfix.constData() + tmp.size(),
- smaller.postfix.size() - tmp.size()
- );
+ tmp = QByteArray::fromRawData(smaller.postfix.constData() + tmp.size(),
+ smaller.postfix.size() - tmp.size());
return tmp == larger.postfix;
}
- bool operator!=(const MappedName & other) const
+ bool operator!=(const MappedName& other) const
{
return !(this->operator==(other));
}
- MappedName operator+(const MappedName & other) const
- {
- MappedName res(*this);
- res += other;
- return res;
- }
-
- MappedName operator+(const char * other) const
- {
- MappedName res(*this);
- res += other;
- return res;
- }
-
- MappedName operator+(const std::string & other) const
- {
- MappedName res(*this);
- res += other;
- return res;
- }
-
- MappedName operator+(const QByteArray & other) const
- {
- MappedName res(*this);
- res += other;
- return res;
- }
-
- MappedName & operator+=(const char * other)
- {
- if (other && other[0])
- this->postfix.append(other, -1);
- return *this;
- }
-
- MappedName & operator+=(const std::string & other)
- {
- if (other.size()) {
- this->postfix.reserve(this->postfix.size() + other.size());
- this->postfix.append(other.c_str(), other.size());
- }
- return *this;
- }
-
- MappedName & operator+=(const QByteArray & other)
- {
- this->postfix += other;
- return *this;
- }
-
- MappedName & operator+=(const MappedName & other)
- {
- append(other);
- return *this;
- }
-
- void append(const char * d, int size = -1)
+ MappedName operator+(const MappedName& other) const
{
- //FIXME raw not assigned?
- if (d && size) {
- if (size < 0)
- size = qstrlen(d);
- if (empty())
- this->data.append(d, size);
- else
- this->postfix.append(d, size);
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName operator+(const char* other) const
+ {
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName operator+(const std::string& other) const
+ {
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName operator+(const QByteArray& other) const
+ {
+ MappedName res(*this);
+ res += other;
+ return res;
+ }
+
+ MappedName& operator+=(const char* other)
+ {
+ if (other && (other[0] != 0)) {
+ this->postfix.append(other, -1);
+ }
+ return *this;
+ }
+
+ MappedName& operator+=(const std::string& other)
+ {
+ if (!other.empty()) {
+ this->postfix.reserve(this->postfix.size() + static_cast(other.size()));
+ this->postfix.append(other.c_str(), static_cast(other.size()));
+ }
+ return *this;
+ }
+
+ MappedName& operator+=(const QByteArray& other)
+ {
+ this->postfix += other;
+ return *this;
+ }
+
+ MappedName& operator+=(const MappedName& other)
+ {
+ append(other);
+ return *this;
+ }
+
+ void append(const char* dataToAppend, int size = -1)
+ {
+ // FIXME raw not assigned?
+ if (dataToAppend && (size != 0)) {
+ if (size < 0) {
+ size = static_cast(qstrlen(dataToAppend));
+ }
+ if (empty()) {
+ this->data.append(dataToAppend, size);
+ }
+ else {
+ this->postfix.append(dataToAppend, size);
+ }
}
}
- void append(const MappedName & other, int startpos = 0, int size = -1)
+ void append(const MappedName& other, int startPosition = 0, int size = -1)
{
- // enforce 0 <= startpos <= other.size
- if (startpos < 0)
- startpos = 0;
- else if (startpos > other.size())
+ // enforce 0 <= startPosition <= other.size
+ if (startPosition < 0) {
+ startPosition = 0;
+ }
+ else if (startPosition > other.size()) {
return;
+ }
- // enforce 0 <= size <= other.size - startpos
- if (size < 0 || size > other.size() - startpos)
- size = other.size() - startpos;
+ // enforce 0 <= size <= other.size - startPosition
+ if (size < 0 || size > other.size() - startPosition) {
+ size = other.size() - startPosition;
+ }
-
- if (startpos < other.data.size()) // if starting inside data
- {
+
+ if (startPosition < other.data.size())// if starting inside data
+ {
int count = size;
- //make sure count doesn't exceed data size and end up in postfix
- if (count > other.data.size() - startpos)
- count = other.data.size() - startpos;
-
- //if this is empty append in data else append in postfix
- if (startpos == 0 && count == other.data.size() && this->empty()) {
+ // make sure count doesn't exceed data size and end up in postfix
+ if (count > other.data.size() - startPosition) {
+ count = other.data.size() - startPosition;
+ }
+
+ // if this is empty append in data else append in postfix
+ if (startPosition == 0 && count == other.data.size() && this->empty()) {
this->data = other.data;
this->raw = other.raw;
- } else
- append(other.data.constData() + startpos, count);
+ }
+ else {
+ append(other.data.constData() + startPosition, count);
+ }
- //setup startpos and count to contiune appending the remainder to postfix
- startpos = 0;
+ // setup startPosition and count to continue appending the remainder to postfix
+ startPosition = 0;
size -= count;
- }
- else //else starting inside postfix
+ }
+ else// else starting inside postfix
{
- startpos -= other.data.size();
+ startPosition -= other.data.size();
}
- //if there is still data to be added to postfix
- if (size) {
- if (startpos == 0 && size == other.postfix.size()) {
- if (this->empty())
+ // if there is still data to be added to postfix
+ if (size != 0) {
+ if (startPosition == 0 && size == other.postfix.size()) {
+ if (this->empty()) {
this->data = other.postfix;
- else if (this->postfix.isEmpty())
+ }
+ else if (this->postfix.isEmpty()) {
this->postfix = other.postfix;
- else
+ }
+ else {
this->postfix += other.postfix;
- } else
- append(other.postfix.constData() + startpos, size);
+ }
+ }
+ else {
+ append(other.postfix.constData() + startPosition, size);
+ }
}
}
- std::string toString(int startpos, int len=-1) const
+ std::string toString(int startPosition, int len = -1) const
{
std::string res;
- return toString(res, startpos, len);
+ return toString(res, startPosition, len);
}
- const char * toString(std::string &s, int startpos=0, int len=-1) const
+ const char* toString(std::string& buffer, int startPosition = 0, int len = -1) const
{
- std::size_t offset = s.size();
+ std::size_t offset = buffer.size();
int count = this->size();
- if (startpos < 0)
- startpos = 0;
- else if (startpos >= count)
- return s.c_str()+s.size();
- if (len < 0 || len > count - startpos)
- len = count - startpos;
- s.reserve(s.size() + len);
- if (startpos < this->data.size()) {
- count = this->data.size() - startpos;
- if (len < count)
+ if (startPosition < 0) {
+ startPosition = 0;
+ }
+ else if (startPosition >= count) {
+ return buffer.c_str() + buffer.size();
+ }
+ if (len < 0 || len > count - startPosition) {
+ len = count - startPosition;
+ }
+ buffer.reserve(buffer.size() + len);
+ if (startPosition < this->data.size()) {
+ count = this->data.size() - startPosition;
+ if (len < count) {
count = len;
- s.append(this->data.constData()+startpos, count);
+ }
+ buffer.append(this->data.constData() + startPosition, count);
len -= count;
}
- s.append(this->postfix.constData(), len);
- return s.c_str() + offset;
+ buffer.append(this->postfix.constData(), len);
+ return buffer.c_str() + offset;
}
- //if offset is inside data return data, if offset is > data.size
+ // if offset is inside data return data, if offset is > data.size
//(ends up in postfix) return postfix
- const char * toConstString(int offset, int &size) const
+ const char* toConstString(int offset, int& size) const
{
- if (offset < 0)
+ if (offset < 0) {
offset = 0;
+ }
if (offset > this->data.size()) {
offset -= this->data.size();
if (offset > this->postfix.size()) {
@@ -383,63 +411,63 @@ public:
return this->data.constData() + offset;
}
- QByteArray toRawBytes(int offset=0, int size=-1) const
+ QByteArray toRawBytes(int offset = 0, int size = -1) const
{
- if (offset < 0)
+ if (offset < 0) {
offset = 0;
- if (offset >= this->size())
- return QByteArray();
- if (size < 0 || size > this->size() - offset)
+ }
+ if (offset >= this->size()) {
+ return {};
+ }
+ if (size < 0 || size > this->size() - offset) {
size = this->size() - offset;
+ }
if (offset >= this->data.size()) {
offset -= this->data.size();
- return QByteArray::fromRawData(this->postfix.constData()+offset, size);
+ return QByteArray::fromRawData(this->postfix.constData() + offset, size);
+ }
+ if (size <= this->data.size() - offset) {
+ return QByteArray::fromRawData(this->data.constData() + offset, size);
}
- if (size <= this->data.size() - offset)
- return QByteArray::fromRawData(this->data.constData()+offset, size);
- QByteArray res(this->data.constData()+offset, this->data.size()-offset);
+ QByteArray res(this->data.constData() + offset, this->data.size() - offset);
res.append(this->postfix.constData(), size - this->data.size() + offset);
return res;
}
- const QByteArray & dataBytes() const
+ const QByteArray& dataBytes() const
{
return this->data;
}
- const QByteArray & postfixBytes() const
+ const QByteArray& postfixBytes() const
{
return this->postfix;
}
- const char * constPostfix() const
+ const char* constPostfix() const
{
return this->postfix.constData();
}
- // No constData() because 'data' is allow to contain raw data, which may
- // not end with 0.
-#if 0
- void char * constData() const
- {
- return this->data.constData();
- }
-#endif
+ // No constData() because 'data' is allowed to contain raw data, which may not end with 0.
QByteArray toBytes() const
{
- if (this->postfix.isEmpty())
+ if (this->postfix.isEmpty()) {
return this->data;
- if (this->data.isEmpty())
+ }
+ if (this->data.isEmpty()) {
return this->postfix;
+ }
return this->data + this->postfix;
}
-/*
+
IndexedName toIndexedName() const
{
- if (this->postfix.isEmpty())
+ if (this->postfix.isEmpty()) {
return IndexedName(this->data);
+ }
return IndexedName();
}
@@ -450,52 +478,58 @@ public:
return res;
}
- const char *toPrefixedString(std::string &buf) const
+ const char* toPrefixedString(std::string& buf) const
{
- if (!toIndexedName())
+ if (!toIndexedName()) {
buf += ComplexGeoData::elementMapPrefix();
+ }
toString(buf);
return buf.c_str();
}
-*/
- int compare(const MappedName &other) const
+
+ int compare(const MappedName& other) const
{
- int asize = this->size();
- int bsize = other.size();
- for (int i=0, count=std::min(asize, bsize); ioperator[](i);
- char b = other[i];
- if (a < b)
+ int thisSize = this->size();
+ int otherSize = other.size();
+ for (int i = 0, count = std::min(thisSize, otherSize); i < count; ++i) {
+ char thisChar = this->operator[](i);
+ char otherChar = other[i];
+ if (thisChar < otherChar) {
return -1;
- if (a > b)
+ }
+ if (thisChar > otherChar) {
return 1;
+ }
}
- if (asize < bsize)
+ if (thisSize < otherSize) {
return -1;
- if (asize > bsize)
+ }
+ if (thisSize > otherSize) {
return 1;
+ }
return 0;
}
- bool operator<(const MappedName & other) const
+ bool operator<(const MappedName& other) const
{
return compare(other) < 0;
}
- char operator[](int index) const
- {
- //FIXME overflow underflow checks?
- if (index >= this->data.size())
+ char operator[](int index) const
+ {
+ // FIXME overflow underflow checks?
+ if (index >= this->data.size()) {
return this->postfix[index - this->data.size()];
- return this->data[index];
- }
+ }
+ return this->data[index];
+ }
- int size() const
+ int size() const
{
return this->data.size() + this->postfix.size();
}
- bool empty() const
+ bool empty() const
{
return this->data.isEmpty() && this->postfix.isEmpty();
}
@@ -507,8 +541,9 @@ public:
MappedName copy() const
{
- if (!this->raw)
+ if (!this->raw) {
return *this;
+ }
MappedName res;
res.data.append(this->data.constData(), this->data.size());
res.postfix = this->postfix;
@@ -522,92 +557,112 @@ public:
return !empty();
}
- void clear()
+ void clear()
{
this->data.clear();
this->postfix.clear();
this->raw = false;
}
- int find(const char *d, int startpos = 0) const
+ int find(const char* searchTarget, int startPosition = 0) const
{
- if (!d)
+ if (!searchTarget) {
return -1;
- if (startpos < 0)
- startpos = 0;
- if (startpos < this->data.size()) {
- int res = this->data.indexOf(d, startpos);
- if (res >= 0)
+ }
+ if (startPosition < 0) {
+ startPosition = 0;
+ }
+ if (startPosition < this->data.size()) {
+ int res = this->data.indexOf(searchTarget, startPosition);
+ if (res >= 0) {
return res;
- startpos = 0;
- } else
- startpos -= this->data.size();
- int res = this->postfix.indexOf(d, startpos);
- if (res < 0)
+ }
+ startPosition = 0;
+ }
+ else {
+ startPosition -= this->data.size();
+ }
+ int res = this->postfix.indexOf(searchTarget, startPosition);
+ if (res < 0) {
return res;
+ }
return res + this->data.size();
}
- int find(const std::string &d, int startpos = 0) const
+ int find(const std::string& searchTarget, int startPosition = 0) const
{
- return find(d.c_str(), startpos);
+ return find(searchTarget.c_str(), startPosition);
}
- int rfind(const char *d, int startpos = -1) const
+ int rfind(const char* searchTarget, int startPosition = -1) const
{
- if (!d)
+ if (!searchTarget) {
return -1;
- if (startpos < 0 || startpos > this->postfix.size()) { //FIXME should be this->data.size
- if (startpos > postfix.size())
- startpos -= postfix.size();
- int res = this->postfix.lastIndexOf(d, startpos);
- if (res >= 0)
- return res + this->data.size();
- startpos = -1;
}
- return this->data.lastIndexOf(d, startpos);
+ if (startPosition < 0
+ || startPosition > this->postfix.size()) {// FIXME should be this->data.size
+ if (startPosition > postfix.size()) {
+ startPosition -= postfix.size();
+ }
+ int res = this->postfix.lastIndexOf(searchTarget, startPosition);
+ if (res >= 0) {
+ return res + this->data.size();
+ }
+ startPosition = -1;
+ }
+ return this->data.lastIndexOf(searchTarget, startPosition);
}
- int rfind(const std::string &d, int startpos = -1) const
+ int rfind(const std::string& searchTarget, int startPosition = -1) const
{
- return rfind(d.c_str(), startpos);
+ return rfind(searchTarget.c_str(), startPosition);
}
- bool endsWith(const char *s) const
+ bool endsWith(const char* searchTarget) const
{
- if (!s)
+ if (!searchTarget) {
return false;
- if (this->postfix.size())
- return this->postfix.endsWith(s);
- return this->data.endsWith(s);
+ }
+ if (this->postfix.size() != 0) {
+ return this->postfix.endsWith(searchTarget);
+ }
+ return this->data.endsWith(searchTarget);
}
- bool endsWith(const std::string &s) const
+ bool endsWith(const std::string& searchTarget) const
{
- return endsWith(s.c_str());
+ return endsWith(searchTarget.c_str());
}
- bool startsWith(const QByteArray & s, int offset = 0) const
+ bool startsWith(const QByteArray& searchTarget, int offset = 0) const
{
- if (s.size() > size() - offset)
+ if (searchTarget.size() > size() - offset) {
return false;
- if (offset || (this->data.size() && this->data.size() < s.size()))
- return toRawBytes(offset, s.size()) == s;
- if (this->data.size())
- return this->data.startsWith(s);
- return this->postfix.startsWith(s);
+ }
+ if ((offset != 0)
+ || ((this->data.size() != 0) && this->data.size() < searchTarget.size())) {
+ return toRawBytes(offset, searchTarget.size()) == searchTarget;
+ }
+ if (this->data.size() != 0) {
+ return this->data.startsWith(searchTarget);
+ }
+ return this->postfix.startsWith(searchTarget);
}
- bool startsWith(const char *s, int offset = 0) const
+ bool startsWith(const char* searchTarget, int offset = 0) const
{
- if (!s)
+ if (!searchTarget) {
return false;
- return startsWith(QByteArray::fromRawData(s, qstrlen(s)), offset);
+ }
+ return startsWith(
+ QByteArray::fromRawData(searchTarget, static_cast(qstrlen(searchTarget))), offset);
}
- bool startsWith(const std::string &s, int offset = 0) const
+ bool startsWith(const std::string& searchTarget, int offset = 0) const
{
- return startsWith(QByteArray::fromRawData(s.c_str(), s.size()), offset);
+ return startsWith(
+ QByteArray::fromRawData(searchTarget.c_str(), static_cast(searchTarget.size())),
+ offset);
}
std::size_t hash() const
@@ -616,14 +671,15 @@ public:
}
private:
- QByteArray data;
- QByteArray postfix;
+ QByteArray data;
+ QByteArray postfix;
bool raw;
};
+// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-} //namespace Data
+}// namespace Data
-#endif
\ No newline at end of file
+#endif// APP_MAPPED_NAME_H
\ No newline at end of file
From c02aeafad037a66c72222fc19795efc4fa7c4f34 Mon Sep 17 00:00:00 2001
From: Chris Hennes
Date: Thu, 16 Mar 2023 19:54:29 -0500
Subject: [PATCH 06/53] App/Toponaming: Begin adding Doxygen comments
---
src/App/MappedName.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
index 6a84b19a42..77e51dabf5 100644
--- a/src/App/MappedName.h
+++ b/src/App/MappedName.h
@@ -44,6 +44,12 @@ namespace Data
class AppExport MappedName
{
public:
+ /// Create a MappedName from a C string, optionally prefixed by an element map prefix, which
+ /// will be omitted from the stored MappedName.
+ ///
+ /// \param name The new name. A deep copy is made.
+ /// \param size Optional, the length of the name string. If not provided, the string must be
+ /// null-terminated.
explicit MappedName(const char* name, int size = -1)
: raw(false)
{
@@ -57,6 +63,10 @@ public:
data = size < 0 ? QByteArray(name) : QByteArray(name, size);
}
+ /// Create a MappedName from a C++ std::string, optionally prefixed by an element map prefix,
+ /// which will be omitted from the stored MappedName.
+ ///
+ /// \param name The new name. A deep copy is made.
explicit MappedName(const std::string& nameString)
: raw(false)
{
@@ -69,6 +79,9 @@ public:
data = QByteArray(name, static_cast(size));
}
+ /// Create a MappedName from an IndexedName. If non-zero, the numerical part of the IndexedName
+ /// is appended as text to the MappedName. In that case the memory is *not* shared between the
+ /// original IndexedName and the MappedName.
explicit MappedName(const IndexedName& element)
: data(element.getType()),
raw(false)
@@ -87,6 +100,11 @@ public:
// FIXME if you pass a raw MappedName into these constructors they will
// reset raw to false and things will break. is this intended?
+ /// Copy constructor with start position offset and optional size. The data is *not* reused.
+ ///
+ /// \param other The MappedName to copy
+ /// \param startPosition an integer offset to start the copy from
+ /// \param size the number of bytes to copy. If not specified
MappedName(const MappedName& other, int startPosition, int size = -1)
: raw(false)
{
From 25031a74ee41268fd8564697b86da5f974cf1e8b Mon Sep 17 00:00:00 2001
From: Uwe
Date: Sat, 18 Mar 2023 05:45:01 +0100
Subject: [PATCH 07/53] [App] [skip ci] register PropertyVelocity
- was forgotten once the property was implemented some days ago
---
src/App/Application.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/App/Application.cpp b/src/App/Application.cpp
index 30bd322fad..ef0e383782 100644
--- a/src/App/Application.cpp
+++ b/src/App/Application.cpp
@@ -2009,6 +2009,7 @@ void Application::initTypes()
App::PropertyTime ::init();
App::PropertyUltimateTensileStrength ::init();
App::PropertyVacuumPermittivity ::init();
+ App::PropertyVelocity ::init();
App::PropertyVolume ::init();
App::PropertyVolumeFlowRate ::init();
App::PropertyVolumetricThermalExpansionCoefficient::init();
From 7cc3fe480c79e203fc2621d56410ce4660e924d4 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sat, 18 Mar 2023 06:07:35 +0100
Subject: [PATCH 08/53] ElementsWidget: Move Delegate to implementation
===============================================
Only moving code from header to implementation.
---
src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 24 +++++++++++++++++++
src/Mod/Sketcher/Gui/TaskSketcherElements.h | 20 ----------------
2 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
index 7baf45f4a3..cb942082e6 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
+++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
@@ -74,6 +74,29 @@ void ElementView::FUNC(){ \
namespace SketcherGui {
+
+class ElementItemDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ explicit ElementItemDelegate(ElementView* parent);
+ ~ElementItemDelegate() override;
+
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+ bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override;
+
+ ElementItem* getElementtItem(const QModelIndex& index) const;
+
+ const int border = 1; //1px, looks good around buttons.
+ const int leftMargin = 4; //4px on the left of icons, looks good.
+ mutable int customIconsMargin = 4;
+ const int textBottomMargin = 5; //5px center the text.
+
+Q_SIGNALS:
+ void itemHovered(QModelIndex);
+ void itemChecked(QModelIndex, Qt::CheckState state);
+};
+
// helper class to store additional information about the listWidget entry.
class ElementItem : public QListWidgetItem
{
@@ -1465,3 +1488,4 @@ void TaskSketcherElements::onSettingsExtendedInformationChanged()
}
#include "moc_TaskSketcherElements.cpp"
+#include "TaskSketcherElements.moc" // For Delegate as it is QOBJECT
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.h b/src/Mod/Sketcher/Gui/TaskSketcherElements.h
index 7efa0a7158..ede72efd5a 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherElements.h
+++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.h
@@ -55,27 +55,7 @@ enum class SubElementType {
none
};
-class ElementItemDelegate : public QStyledItemDelegate
-{
- Q_OBJECT
-public:
- explicit ElementItemDelegate(ElementView* parent);
- ~ElementItemDelegate() override;
- void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
- bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override;
-
- ElementItem* getElementtItem(const QModelIndex& index) const;
-
- const int border = 1; //1px, looks good around buttons.
- const int leftMargin = 4; //4px on the left of icons, looks good.
- mutable int customIconsMargin = 4;
- const int textBottomMargin = 5; //5px center the text.
-
-Q_SIGNALS:
- void itemHovered(QModelIndex);
- void itemChecked(QModelIndex, Qt::CheckState state);
-};
class ElementView : public QListWidget
{
From 5242f6d048334553d5f6099f452a206684b0e924 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sat, 18 Mar 2023 06:14:23 +0100
Subject: [PATCH 09/53] ElementsWidget: Move ElementFilterList to
implementation
========================================================
Only moving code from header to implementation.
---
src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 35 +++++++++++++++++++
src/Mod/Sketcher/Gui/TaskSketcherElements.h | 35 +------------------
2 files changed, 36 insertions(+), 34 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
index cb942082e6..a851f342d2 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
+++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
@@ -667,6 +667,41 @@ ElementItem* ElementItemDelegate::getElementtItem(const QModelIndex& index) cons
}
/* Filter element list widget ------------------------------------------------------ */
+namespace SketcherGui {
+class ElementFilterList : public QListWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ElementFilterList(QWidget* parent = nullptr);
+ ~ElementFilterList() override;
+
+protected:
+ void changeEvent(QEvent* e) override;
+ virtual void languageChange();
+
+private:
+ using filterItemRepr = std::pair; // {filter item text, filter item level}
+ inline static const std::vector filterItems = {
+ {QT_TR_NOOP("Normal"),0},
+ {QT_TR_NOOP("Construction"),0},
+ {QT_TR_NOOP("Internal"),0},
+ {QT_TR_NOOP("External"),0},
+ {QT_TR_NOOP("All types"),0},
+ {QT_TR_NOOP("Point"),1},
+ {QT_TR_NOOP("Line"),1},
+ {QT_TR_NOOP("Circle"),1},
+ {QT_TR_NOOP("Ellipse"),1},
+ {QT_TR_NOOP("Arc of circle"),1},
+ {QT_TR_NOOP("Arc of ellipse"),1},
+ {QT_TR_NOOP("Arc of hyperbola"),1},
+ {QT_TR_NOOP("Arc of parabola"),1},
+ {QT_TR_NOOP("B-Spline"),1}
+ };
+
+};
+} // namespace SketcherGui
+
enum class GeoFilterType {
NormalGeos,
ConstructionGeos,
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.h b/src/Mod/Sketcher/Gui/TaskSketcherElements.h
index ede72efd5a..5392d0fe85 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherElements.h
+++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.h
@@ -55,8 +55,6 @@ enum class SubElementType {
none
};
-
-
class ElementView : public QListWidget
{
Q_OBJECT
@@ -111,38 +109,7 @@ private:
void changeLayer(int layer);
};
-class ElementFilterList : public QListWidget
-{
- Q_OBJECT
-
-public:
- explicit ElementFilterList(QWidget* parent = nullptr);
- ~ElementFilterList() override;
-
-protected:
- void changeEvent(QEvent* e) override;
- virtual void languageChange();
-
-private:
- using filterItemRepr = std::pair; // {filter item text, filter item level}
- inline static const std::vector filterItems = {
- {QT_TR_NOOP("Normal"),0},
- {QT_TR_NOOP("Construction"),0},
- {QT_TR_NOOP("Internal"),0},
- {QT_TR_NOOP("External"),0},
- {QT_TR_NOOP("All types"),0},
- {QT_TR_NOOP("Point"),1},
- {QT_TR_NOOP("Line"),1},
- {QT_TR_NOOP("Circle"),1},
- {QT_TR_NOOP("Ellipse"),1},
- {QT_TR_NOOP("Arc of circle"),1},
- {QT_TR_NOOP("Arc of ellipse"),1},
- {QT_TR_NOOP("Arc of hyperbola"),1},
- {QT_TR_NOOP("Arc of parabola"),1},
- {QT_TR_NOOP("B-Spline"),1}
- };
-
-};
+class ElementFilterList;
class TaskSketcherElements : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
{
From 3f19bcbeef467afe0f7cd27ab8a634efbf72e17e Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sat, 18 Mar 2023 06:49:23 +0100
Subject: [PATCH 10/53] Sketcher: Elements Widget - Fix crash when moving
external geometry to another layer
====================================================================================
As reported:
https://forum.freecad.org/viewtopic.php?p=667426#p667426
Support for moving external geometry to another layer will come in the future.
---
src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
index a851f342d2..0da222ab49 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
+++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
@@ -41,6 +41,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -386,12 +387,19 @@ void ElementView::changeLayer(int layer)
bool anychanged = false;
for(auto geoid : geoids) {
- auto currentlayer = getSafeGeomLayerId(geometry[geoid]);
- if( currentlayer != layer) {
- auto geo = geometry[geoid]->clone();
- setSafeGeomLayerId(geo, layer);
- newgeometry[geoid] = geo;
- anychanged = true;
+ if(geoid >= 0) { // currently only internal geometry can be changed from one layer to another
+ auto currentlayer = getSafeGeomLayerId(geometry[geoid]);
+ if( currentlayer != layer) {
+ auto geo = geometry[geoid]->clone();
+ setSafeGeomLayerId(geo, layer);
+ newgeometry[geoid] = geo;
+ anychanged = true;
+ }
+ }
+ else {
+ Gui::TranslatedNotification(sketchobject,
+ QObject::tr("Unsupported visual layer operation"),
+ QObject::tr("It is currently unsupported to move external geometry to another visual layer. External geometry will be omitted"));
}
}
@@ -700,7 +708,7 @@ private:
};
};
-} // namespace SketcherGui
+}
enum class GeoFilterType {
NormalGeos,
From 45401e30ce29c8a8c66bced6d2db216c96227289 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sat, 18 Mar 2023 08:19:19 +0100
Subject: [PATCH 11/53] Notifications: Extend translated notification to
include caption
===============================================================
For translated notifications now the caption is included in the
message, as the translation is already done, and this improves
the semantics of existing messages.
---
src/Gui/Notifications.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Gui/Notifications.h b/src/Gui/Notifications.h
index d805f38bf0..8c55d514bf 100644
--- a/src/Gui/Notifications.h
+++ b/src/Gui/Notifications.h
@@ -153,7 +153,7 @@ inline void Gui::Notify(TNotifier && notifier, TCaption && caption, TMessage &&
if constexpr( type == Base::LogStyle::TranslatedNotification) {
// trailing newline is necessary as this may be shown too in a console requiring them (depending on the configuration).
- auto msg = message.append(QStringLiteral("\n")); // QString
+ auto msg = QStringLiteral("%1. %2\n").arg(caption).arg(message); // QString
if constexpr( std::is_base_of_v::type>> ) {
Base::Console().Send(notifier->getFullLabel(), msg.toUtf8());
From 522679321c325e893ad8a2bc6e0a64320436320f Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sat, 18 Mar 2023 09:18:20 +0100
Subject: [PATCH 12/53] ElementWidget: reorganise implementation class
declarations
---
src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 67 +++++++++----------
1 file changed, 33 insertions(+), 34 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
index 0da222ab49..1eb88e910c 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
+++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
@@ -168,6 +168,39 @@ class ElementItem : public QListWidgetItem
const Part::Geometry * geo;
};
+
+class ElementFilterList : public QListWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ElementFilterList(QWidget* parent = nullptr);
+ ~ElementFilterList() override;
+
+protected:
+ void changeEvent(QEvent* e) override;
+ virtual void languageChange();
+
+private:
+ using filterItemRepr = std::pair; // {filter item text, filter item level}
+ inline static const std::vector filterItems = {
+ {QT_TR_NOOP("Normal"),0},
+ {QT_TR_NOOP("Construction"),0},
+ {QT_TR_NOOP("Internal"),0},
+ {QT_TR_NOOP("External"),0},
+ {QT_TR_NOOP("All types"),0},
+ {QT_TR_NOOP("Point"),1},
+ {QT_TR_NOOP("Line"),1},
+ {QT_TR_NOOP("Circle"),1},
+ {QT_TR_NOOP("Ellipse"),1},
+ {QT_TR_NOOP("Arc of circle"),1},
+ {QT_TR_NOOP("Arc of ellipse"),1},
+ {QT_TR_NOOP("Arc of hyperbola"),1},
+ {QT_TR_NOOP("Arc of parabola"),1},
+ {QT_TR_NOOP("B-Spline"),1}
+ };
+
+};
} // SketcherGui
class ElementWidgetIcons {
@@ -675,40 +708,6 @@ ElementItem* ElementItemDelegate::getElementtItem(const QModelIndex& index) cons
}
/* Filter element list widget ------------------------------------------------------ */
-namespace SketcherGui {
-class ElementFilterList : public QListWidget
-{
- Q_OBJECT
-
-public:
- explicit ElementFilterList(QWidget* parent = nullptr);
- ~ElementFilterList() override;
-
-protected:
- void changeEvent(QEvent* e) override;
- virtual void languageChange();
-
-private:
- using filterItemRepr = std::pair; // {filter item text, filter item level}
- inline static const std::vector filterItems = {
- {QT_TR_NOOP("Normal"),0},
- {QT_TR_NOOP("Construction"),0},
- {QT_TR_NOOP("Internal"),0},
- {QT_TR_NOOP("External"),0},
- {QT_TR_NOOP("All types"),0},
- {QT_TR_NOOP("Point"),1},
- {QT_TR_NOOP("Line"),1},
- {QT_TR_NOOP("Circle"),1},
- {QT_TR_NOOP("Ellipse"),1},
- {QT_TR_NOOP("Arc of circle"),1},
- {QT_TR_NOOP("Arc of ellipse"),1},
- {QT_TR_NOOP("Arc of hyperbola"),1},
- {QT_TR_NOOP("Arc of parabola"),1},
- {QT_TR_NOOP("B-Spline"),1}
- };
-
-};
-}
enum class GeoFilterType {
NormalGeos,
From 64eb85b1eaade8f876529727492c1dd9cb48d61e Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sat, 18 Mar 2023 09:41:58 +0100
Subject: [PATCH 13/53] ElementWidget: remove unnecesary element pointer
================================================
This should fix this (I cannot reproduce it):
https://forum.freecad.org/viewtopic.php?p=667579#p667579
Lately I added the geometry pointer to the item. This has indeed
the potential for an already deleted pointer being accessed.
This PR removes the geometry pointer from the item and relies on the
ViewProvider to indirectly access an updated pointer.
---
src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 30 +++++++++++++------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
index 1eb88e910c..dc8e52e1f4 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
+++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp
@@ -117,7 +117,7 @@ class ElementItem : public QListWidgetItem
};
ElementItem(int elementnr, int startingVertex, int midVertex, int endVertex,
- Base::Type geometryType, GeometryState state, const QString & lab, const Part::Geometry * geo) :
+ Base::Type geometryType, GeometryState state, const QString & lab, ViewProviderSketch *sketchView) :
ElementNbr(elementnr)
, StartingVertex(startingVertex)
, MidVertex(midVertex)
@@ -132,7 +132,7 @@ class ElementItem : public QListWidgetItem
, hovered(SubElementType::none)
, rightClicked(false)
, label(lab)
- , geo(geo)
+ , sketchView(sketchView)
{
}
@@ -141,9 +141,20 @@ class ElementItem : public QListWidgetItem
}
bool isVisible() {
- auto layer = getSafeGeomLayerId(geo);
- return layer != static_cast(Layer::Hidden);
+ if(State != GeometryState::External) {
+ const auto geo = sketchView->getSketchObject()->getGeometry(ElementNbr);
+ if(geo) {
+ auto layer = getSafeGeomLayerId(geo);
+
+ return layer != static_cast(Layer::Hidden);
+ }
+ }
+
+ // 1. external geometry currently is always visible.
+ // 2. if internal and ElementNbr is out of range, the element
+ // needs to be updated and the return value is not important.
+ return true;
}
int ElementNbr;
@@ -166,7 +177,8 @@ class ElementItem : public QListWidgetItem
QString label;
- const Part::Geometry * geo;
+ private:
+ ViewProviderSketch *sketchView;
};
class ElementFilterList : public QListWidget
@@ -1369,8 +1381,8 @@ void TaskSketcherElements::slotElementsChanged(void)
(isNamingBoxChecked ?
(tr("Other") + IdInformation()) +
(construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) :
- (QString::fromLatin1("%1-").arg(i) + tr("Other")))
- , (*it) // geometry
+ (QString::fromLatin1("%1-").arg(i) + tr("Other"))),
+ sketchView
);
ui->listWidgetElements->addItem(itemN);
@@ -1461,8 +1473,8 @@ void TaskSketcherElements::slotElementsChanged(void)
(QString::fromLatin1("%1-").arg(i - 2) + tr("BSpline"))) :
(isNamingBoxChecked ?
(tr("Other") + linkname) :
- (QString::fromLatin1("%1-").arg(i - 2) + tr("Other")))
- , (*it) // geometry
+ (QString::fromLatin1("%1-").arg(i - 2) + tr("Other"))),
+ sketchView
);
ui->listWidgetElements->addItem(itemN);
From 376c94f72fc2306534a9469c9cc6e8f25ebafe2b Mon Sep 17 00:00:00 2001
From: Chris Hennes
Date: Fri, 17 Mar 2023 14:45:41 -0500
Subject: [PATCH 14/53] App/Toponaming: Finish Doxygen comments
---
src/App/MappedName.h | 257 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 229 insertions(+), 28 deletions(-)
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
index 77e51dabf5..0d16018a5b 100644
--- a/src/App/MappedName.h
+++ b/src/App/MappedName.h
@@ -1,25 +1,26 @@
-/****************************************************************************
- * Copyright (c) 2020 Zheng, Lei (realthunder) *
- * *
- * 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 *
- * *
- ****************************************************************************/
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * Copyright (c) 2022 Zheng, Lei (realthunder) *
+ * Copyright (c) 2023 FreeCAD Project Association *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
#ifndef APP_MAPPED_NAME_H
#define APP_MAPPED_NAME_H
@@ -41,6 +42,11 @@ namespace Data
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+/// The MappedName class maintains a two-part name: the first part ("data") is considered immutable
+/// once created, while the second part ("postfix") can be modified/appended to by later operations.
+/// It uses shared data when possible (see the fromRawData() members). Despite storing data and
+/// postfix separately, they can be accessed via calls to size(), operator[], etc. as though they
+/// were a single array.
class AppExport MappedName
{
public:
@@ -104,19 +110,25 @@ public:
///
/// \param other The MappedName to copy
/// \param startPosition an integer offset to start the copy from
- /// \param size the number of bytes to copy. If not specified
+ /// \param size the number of bytes to copy.
+ /// \see append() for details about how the copy behaves for various sizes and start positions
MappedName(const MappedName& other, int startPosition, int size = -1)
: raw(false)
{
append(other, startPosition, size);
}
+ /// Copy constructor with additional postfix
+ ///
+ /// \param other The mapped name to copy. Its data and postfix become the new MappedName's data
+ /// \param postfix The postfix for the new MappedName
MappedName(const MappedName& other, const char* postfix)
: data(other.data + other.postfix),
postfix(postfix),
raw(false)
{}
+ /// Move constructor
MappedName(MappedName&& other) noexcept
: data(std::move(other.data)),
postfix(std::move(other.postfix)),
@@ -125,6 +137,12 @@ public:
~MappedName() = default;
+ /// Construct a MappedName from raw character data (including null characters, if size is
+ /// provided). No copy is made: the data is used in place.
+ ///
+ /// \param name The raw data to use.
+ /// \param size The number of bytes to access. If omitted, name must be null-terminated.
+ /// \return a new MappedName with name as its data.
static MappedName fromRawData(const char* name, int size = -1)
{
MappedName res;
@@ -136,11 +154,25 @@ public:
return res;
}
+ /// Construct a MappedName from QByteArray data (including any embedded null characters).
+ ///
+ /// \param data The original data. No copy is made, the data is shared with the other instance.
+ /// \return a new MappedName with data as its data.
static MappedName fromRawData(const QByteArray& data)
{
return fromRawData(data.constData(), data.size());
}
+ /// Construct a MappedName from another MappedName
+ ///
+ /// \param other The MappedName to copy from. The data is usually not copied, but in some
+ /// cases a partial copy may be made to support a slice that extends across other's data into
+ /// its postfix.
+ /// \param startPosition The position to start the reference at.
+ /// \param size The number of bytes to access. If omitted, continues from startPosition
+ /// to the end of available data (including postfix).
+ /// \return a new MappedName sharing (possibly a subset of) data with other.
+ /// \see append() for details about how the copy behaves for various sizes and start positions
static MappedName fromRawData(const MappedName& other, int startPosition, int size = -1)
{
if (startPosition < 0) {
@@ -178,14 +210,17 @@ public:
return res;
}
+ /// Share data with another MappedName
MappedName& operator=(const MappedName& other) = default;
+ /// Create a new MappedName from a std::string: the string's data is copied.
MappedName& operator=(const std::string& other)
{
*this = MappedName(other);
return *this;
}
+ /// Create a new MappedName from a const char *. The character data is copied.
MappedName& operator=(const char* other)
{
*this = MappedName(other);
@@ -193,6 +228,7 @@ public:
}
+ /// Move-construct a MappedName
MappedName& operator=(MappedName&& other) noexcept
{
this->data = std::move(other.data);
@@ -201,6 +237,8 @@ public:
return *this;
}
+ /// Write to a stream as the name with postfix directly appended to it. Note that there is no
+ /// special handling for null or non-ASCII characters, they are simply written to the stream.
friend std::ostream& operator<<(std::ostream& stream, const MappedName& mappedName)
{
stream.write(mappedName.data.constData(), mappedName.data.size());
@@ -208,6 +246,8 @@ public:
return stream;
}
+ /// Two MappedNames are equal if the concatenation of their data and postfix is equal. The
+ /// individual data and postfix may NOT be equal in this case.
bool operator==(const MappedName& other) const
{
if (this->size() != other.size()) {
@@ -243,6 +283,8 @@ public:
return !(this->operator==(other));
}
+ /// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
+ /// argument's postfix with the RHS argument's data and postfix appended to it.
MappedName operator+(const MappedName& other) const
{
MappedName res(*this);
@@ -250,6 +292,8 @@ public:
return res;
}
+ /// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
+ /// argument's postfix with the RHS argument appended to it. The character data is copied.
MappedName operator+(const char* other) const
{
MappedName res(*this);
@@ -257,6 +301,8 @@ public:
return res;
}
+ /// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
+ /// argument's postfix with the RHS argument appended to it. The character data is copied.
MappedName operator+(const std::string& other) const
{
MappedName res(*this);
@@ -264,6 +310,8 @@ public:
return res;
}
+ /// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
+ /// argument's postfix with the RHS argument appended to it.
MappedName operator+(const QByteArray& other) const
{
MappedName res(*this);
@@ -271,6 +319,8 @@ public:
return res;
}
+ /// Appends other to this instance's postfix. other must be a null-terminated C string. The
+ /// character data from the string is copied.
MappedName& operator+=(const char* other)
{
if (other && (other[0] != 0)) {
@@ -279,6 +329,7 @@ public:
return *this;
}
+ /// Appends other to this instance's postfix. The character data from the string is copied.
MappedName& operator+=(const std::string& other)
{
if (!other.empty()) {
@@ -288,18 +339,29 @@ public:
return *this;
}
+ /// Appends other to this instance's postfix. The data may be either copied or shared, depending
+ /// on whether this->postfix is empty (in which case the data is shared) or non-empty (in which
+ /// case it is copied).
MappedName& operator+=(const QByteArray& other)
{
this->postfix += other;
return *this;
}
+ /// Appends other to this instance's postfix, unless this is empty, in which case this acts
+ /// like operator=, and makes this instance's data equal to other's data, and this instance's
+ /// postfix equal to the other instance's postfix.
MappedName& operator+=(const MappedName& other)
{
append(other);
return *this;
}
+ /// Add dataToAppend to this MappedName. If the current name is empty, this becomes the new
+ /// data element. If this MappedName already has data, then the data is appended to the postfix.
+ ///
+ /// \param dataToAppend The data to add. A deep copy is made.
+ /// \param size The number of bytes to copy. If omitted, dataToAppend must be null-terminated.
void append(const char* dataToAppend, int size = -1)
{
// FIXME raw not assigned?
@@ -316,6 +378,20 @@ public:
}
}
+ /// Treating both this and other as single continuous byte arrays, append other to this. If this
+ /// is empty, then other's data is shared with this instance's data beginning at startPosition.
+ /// If this is *not* empty, then all data is appended to the postfix. If the copy crosses the
+ /// boundary between other's data and its postfix, then if this instance was empty, the new
+ /// data stops where other's data stops, and the remainder of the copy is placed in the suffix.
+ /// Otherwise the copy simply continues as though there was no distinction between other's
+ /// data and suffix.
+ ///
+ /// \param other The MappedName to obtain the data from. The data is shared when possible,
+ /// depending on the details of startPosition, size, and this->empty().
+ /// \param startPosition The byte to start the copy at. Must be a positive non-zero integer less
+ /// than the length of other's combined data + postfix.
+ /// \param size The number of bytes to copy. Must not overrun the end of other's combined data
+ /// storage when taking startPosition into consideration.
void append(const MappedName& other, int startPosition = 0, int size = -1)
{
// enforce 0 <= startPosition <= other.size
@@ -377,13 +453,32 @@ public:
}
}
- std::string toString(int startPosition, int len = -1) const
+ /// Create a std::string from this instance, starting at startPosition, and extending len bytes.
+ ///
+ /// \param startPosition The offset into the data
+ /// \param len The number of bytes to output
+ /// \return A new std::string containing the bytes copied from this instance's data and postfix
+ /// (depending on startPosition and len).
+ /// \note No effort is made to ensure that these are valid ASCII characters, and it is possible
+ /// the data includes embedded null characters, non-ASCII data, etc.
+ std::string toString(int startPosition = 0, int len = -1) const
{
std::string res;
- return toString(res, startPosition, len);
+ return appendToBuffer(res, startPosition, len);
}
- const char* toString(std::string& buffer, int startPosition = 0, int len = -1) const
+ /// Given a (possibly non-empty) std::string buffer, append this instance to it, starting at a
+ /// specified position, and continuing for a specified number of bytes.
+ ///
+ /// \param buffer The string buffer to append to.
+ /// \param startPosition The position in this instance's data/postfix to start at (defaults to
+ /// zero). Must be less than the total length of the data plus the postfix.
+ /// \param len The number of bytes to append. If omitted, defaults to appending all available
+ /// data starting at startPosition.
+ /// \return A pointer to the beginning of the appended data within buffer.
+ /// \note No effort is made to ensure that these are valid ASCII characters, and it is possible
+ /// the data includes embedded null characters, non-ASCII data, etc.
+ const char* appendToBuffer(std::string& buffer, int startPosition = 0, int len = -1) const
{
std::size_t offset = buffer.size();
int count = this->size();
@@ -429,6 +524,16 @@ public:
return this->data.constData() + offset;
}
+ /// Get access to raw byte data. When possible, data is shared between this instance and the
+ /// returned QByteArray. If the combination of offset and size results in data that crosses the
+ /// boundary between this->data and this->postfix, the data must be copied in order to provide
+ /// access as a continuous array of bytes.
+ ///
+ /// \param offset The start position of the raw data access.
+ /// \param size The number of bytes to access. If omitted, the resulting QByteArray includes
+ /// everything starting from offset to the end, including any postfix data.
+ /// \return A new QByteArray that shares data with this instance if possible, or is a new copy
+ /// if required by offset and size.
QByteArray toRawBytes(int offset = 0, int size = -1) const
{
if (offset < 0) {
@@ -453,16 +558,19 @@ public:
return res;
}
+ /// Direct access to the stored QByteArray of data. A copy is never made.
const QByteArray& dataBytes() const
{
return this->data;
}
+ /// Direct access to the stored QByteArray of postfix. A copy is never made.
const QByteArray& postfixBytes() const
{
return this->postfix;
}
+ /// Convenience function providing access to the pointer to the beginning of the postfix data.
const char* constPostfix() const
{
return this->postfix.constData();
@@ -470,6 +578,10 @@ public:
// No constData() because 'data' is allowed to contain raw data, which may not end with 0.
+ /// Provide access to the content of this instance. If either postfix or data is empty, no copy
+ /// is made and the original QByteArray is returned, sharing data with this instance. If this
+ /// instance contains both data and postfix, a new QByteArray is created and stores a copy of
+ /// the data and postfix concatenated together.
QByteArray toBytes() const
{
if (this->postfix.isEmpty()) {
@@ -481,6 +593,13 @@ public:
return this->data + this->postfix;
}
+ /// Create an IndexedName from the data portion of this MappedName. If this data has a postfix,
+ /// the function returns an empty IndexedName. The function will fail if this->data contains
+ /// anything other than the ASCII letter a-z, A-Z, and the underscore, with an optional integer
+ /// suffix, returning an empty IndexedName (e.g. an IndexedName that evaluates to boolean
+ /// false and isNull() == true).
+ ///
+ /// \return a new IndexedName that shares its data with this instance's data member.
IndexedName toIndexedName() const
{
if (this->postfix.isEmpty()) {
@@ -489,22 +608,33 @@ public:
return IndexedName();
}
+ /// Create and return a string version of this MappedName prefixed by the ComplexGeoData element
+ /// map prefix, if this MappedName cannot be converted to an indexed name.
std::string toPrefixedString() const
{
std::string res;
- toPrefixedString(res);
+ appendToBufferWithPrefix(res);
return res;
}
- const char* toPrefixedString(std::string& buf) const
+ /// Append this MappedName to a provided string buffer, including the ComplexGeoData element
+ /// map prefix if the MappedName cannot be converted to an IndexedName.
+ ///
+ /// \param buf A (possibly non-empty) string to append this MappedName to.
+ /// \return A pointer to the beginning of the buffer.
+ const char* appendToBufferWithPrefix(std::string& buf) const
{
if (!toIndexedName()) {
buf += ComplexGeoData::elementMapPrefix();
}
- toString(buf);
+ appendToBuffer(buf);
return buf.c_str();
}
+ /// Equivalent to C++20 operator<=>. Performs byte-by-byte comparison of this and other,
+ /// starting at the first byte and continuing through both data and postfix, ignoring which is
+ /// which. If the combined data and postfix members are of unequal size but start with the same
+ /// data, the shorter array is considered "less than" the longer.
int compare(const MappedName& other) const
{
int thisSize = this->size();
@@ -528,11 +658,14 @@ public:
return 0;
}
+ /// \see compare()
bool operator<(const MappedName& other) const
{
return compare(other) < 0;
}
+ /// Treat this MappedName as a single continuous array of bytes, beginning with data and
+ /// continuing through postfix. No bounds checking is performed when compiled in release mode.
char operator[](int index) const
{
// FIXME overflow underflow checks?
@@ -542,21 +675,29 @@ public:
return this->data[index];
}
+ /// Treat this MappedName as a single continuous array of bytes, returning the combined size
+ /// of the data and postfix.
int size() const
{
return this->data.size() + this->postfix.size();
}
+ /// Treat this MappedName as a single continuous array of bytes, returning true only if both
+ /// data and prefix are empty.
bool empty() const
{
return this->data.isEmpty() && this->postfix.isEmpty();
}
+ /// Returns true if this is shared data, or false if a unique copy has been made.
bool isRaw() const
{
return this->raw;
}
+ /// If this is shared data, a new unshared copy is made and returned. If it is already unshared
+ /// no new copy is made, a new instance is returned that shares is data with the current
+ /// instance.
MappedName copy() const
{
if (!this->raw) {
@@ -568,13 +709,17 @@ public:
return res;
}
+ /// Ensure that this data is unshared, making a copy if necessary.
void compact() const;
+ /// Boolean conversion is the inverse of empty(), returning true if there is data in either the
+ /// data or postfix, and false if there is nothing in either.
explicit operator bool() const
{
return !empty();
}
+ /// Reset this instance, clearing anything in data and postfix.
void clear()
{
this->data.clear();
@@ -582,6 +727,12 @@ public:
this->raw = false;
}
+ /// Find a string of characters in this MappedName. The bytes must occur either entirely in the
+ /// data, or entirely in the postfix: a string that overlaps the two will not be found.
+ ///
+ /// \param searchTarget A null-terminated C string to search for.
+ /// \param startPosition A byte offset to start the search at.
+ /// \return The position of the target in this instance, or -1 if the target is not found.
int find(const char* searchTarget, int startPosition = 0) const
{
if (!searchTarget) {
@@ -607,11 +758,25 @@ public:
return res + this->data.size();
}
+ /// Find a string of characters in this MappedName. The bytes must occur either entirely in the
+ /// data, or entirely in the postfix: a string that overlaps the two will not be found.
+ ///
+ /// \param searchTarget A string to search for.
+ /// \param startPosition A byte offset to start the search at.
+ /// \return The position of the target in this instance, or -1 if the target is not found.
int find(const std::string& searchTarget, int startPosition = 0) const
{
return find(searchTarget.c_str(), startPosition);
}
+ /// Find a string of characters in this MappedName, starting at the back of postfix and
+ /// proceeding in reverse through the data. The bytes must occur either entirely in the
+ /// data, or entirely in the postfix: a string that overlaps the two will not be found.
+ ///
+ /// \param searchTarget A null-terminated C string to search for.
+ /// \param startPosition A byte offset to start the search at. Negative numbers are supported
+ /// and count back from the end of the concatenated data (as in QByteArray::lastIndexOf()).
+ /// \return The position of the target in this instance, or -1 if the target is not found.
int rfind(const char* searchTarget, int startPosition = -1) const
{
if (!searchTarget) {
@@ -631,11 +796,22 @@ public:
return this->data.lastIndexOf(searchTarget, startPosition);
}
+ /// Find a string in this MappedName, starting at the back of postfix and proceeding in reverse
+ /// through the data. The bytes must occur either entirely in the data, or entirely in the
+ /// postfix: a string that overlaps the two will not be found.
+ ///
+ /// \param searchTarget A null-terminated C string to search for.
+ /// \param startPosition A byte offset to start the search at. Negative numbers are supported
+ /// and count back from the end of the concatenated data (as in QByteArray::lastIndexOf()).
+ /// \return The position of the target in this instance, or -1 if the target is not found.
int rfind(const std::string& searchTarget, int startPosition = -1) const
{
return rfind(searchTarget.c_str(), startPosition);
}
+ /// Returns true if this MappedName ends with the search target. If there is a postfix, only the
+ /// postfix is considered. If not, then only the data is considered. A search string that
+ /// overlaps the two will not be found.
bool endsWith(const char* searchTarget) const
{
if (!searchTarget) {
@@ -647,11 +823,21 @@ public:
return this->data.endsWith(searchTarget);
}
+ /// Returns true if this MappedName ends with the search target. If there is a postfix, only the
+ /// postfix is considered. If not, then only the data is considered. A search string that
+ /// overlaps the two will not be found.
bool endsWith(const std::string& searchTarget) const
{
return endsWith(searchTarget.c_str());
}
+ /// Returns true if this MappedName starts with the search target. If there is a postfix, only
+ /// the postfix is considered. If not, then only the data is considered. A search string that
+ /// overlaps the two will not be found.
+ ///
+ /// \param searchTarget An array of bytes to match
+ /// \param offset An offset to perform the match at
+ /// \return True if this MappedName begins with the target bytes
bool startsWith(const QByteArray& searchTarget, int offset = 0) const
{
if (searchTarget.size() > size() - offset) {
@@ -667,6 +853,13 @@ public:
return this->postfix.startsWith(searchTarget);
}
+ /// Returns true if this MappedName starts with the search target. If there is a postfix, only
+ /// the postfix is considered. If not, then only the data is considered. A search string that
+ /// overlaps the two will not be found.
+ ///
+ /// \param searchTarget An array of bytes to match
+ /// \param offset An offset to perform the match at
+ /// \return True if this MappedName begins with the target bytes
bool startsWith(const char* searchTarget, int offset = 0) const
{
if (!searchTarget) {
@@ -676,6 +869,13 @@ public:
QByteArray::fromRawData(searchTarget, static_cast(qstrlen(searchTarget))), offset);
}
+ /// Returns true if this MappedName starts with the search target. If there is a postfix, only
+ /// the postfix is considered. If not, then only the data is considered. A search string that
+ /// overlaps the two will not be found.
+ ///
+ /// \param searchTarget A string to match
+ /// \param offset An offset to perform the match at
+ /// \return True if this MappedName begins with the target bytes
bool startsWith(const std::string& searchTarget, int offset = 0) const
{
return startsWith(
@@ -683,6 +883,7 @@ public:
offset);
}
+ /// Get a hash for this MappedName
std::size_t hash() const
{
return qHash(data, qHash(postfix));
From 992dec2c6b9e96f7c1ec78b0c4fa21e96f6aa4d8 Mon Sep 17 00:00:00 2001
From: Alexander Golubev
Date: Fri, 10 Mar 2023 04:59:45 +0300
Subject: [PATCH 15/53] Gui: Prevent UiLoader from loading 3rd-party Qt
plugins.
Due to a flaw in the QUiLoader, UiLoader were loading all designer plugins
it can find in QApplication::libraryPaths(). This in general a bad
practice and leads to bugs due to some plugins may perform some unexpected
actions upon load which may interfere with FreeCAD's functionality.
To avoid such problems reset the libraryPaths before creation of a
UiLoader object.
Also move setLanguageChangeEnabled(true) into constructor due to it's
called every time it's being instanced anyway.
See: https://github.com/FreeCAD/FreeCAD/issues/8708
---
src/Gui/PropertyPage.cpp | 7 ++---
src/Gui/TaskView/TaskDialogPython.cpp | 5 ++--
src/Gui/UiLoader.cpp | 41 +++++++++++++++++----------
src/Gui/UiLoader.h | 25 ++++++++++++++--
src/Gui/WidgetFactory.cpp | 5 ++--
5 files changed, 56 insertions(+), 27 deletions(-)
diff --git a/src/Gui/PropertyPage.cpp b/src/Gui/PropertyPage.cpp
index b5e92d6ae0..16c09c7711 100644
--- a/src/Gui/PropertyPage.cpp
+++ b/src/Gui/PropertyPage.cpp
@@ -119,12 +119,11 @@ void PreferencePage::changeEvent(QEvent *e)
PreferenceUiForm::PreferenceUiForm(const QString& fn, QWidget* parent)
: PreferencePage(parent), form(nullptr)
{
- UiLoader loader;
- loader.setLanguageChangeEnabled(true);
- loader.setWorkingDirectory(QFileInfo(fn).absolutePath());
+ auto loader = UiLoader::newInstance();
+ loader->setWorkingDirectory(QFileInfo(fn).absolutePath());
QFile file(fn);
if (file.open(QFile::ReadOnly))
- form = loader.load(&file, this);
+ form = loader->load(&file, this);
file.close();
if (form) {
this->setWindowTitle(form->windowTitle());
diff --git a/src/Gui/TaskView/TaskDialogPython.cpp b/src/Gui/TaskView/TaskDialogPython.cpp
index 7d05b12411..795b7cf43a 100644
--- a/src/Gui/TaskView/TaskDialogPython.cpp
+++ b/src/Gui/TaskView/TaskDialogPython.cpp
@@ -544,8 +544,7 @@ TaskDialogPython::~TaskDialogPython()
bool TaskDialogPython::tryLoadUiFile()
{
if (dlg.hasAttr(std::string("ui"))) {
- UiLoader loader;
- loader.setLanguageChangeEnabled(true);
+ auto loader = UiLoader::newInstance();
QString fn, icon;
Py::String ui(dlg.getAttr(std::string("ui")));
std::string path = static_cast(ui);
@@ -554,7 +553,7 @@ bool TaskDialogPython::tryLoadUiFile()
QFile file(fn);
QWidget* form = nullptr;
if (file.open(QFile::ReadOnly))
- form = loader.load(&file, nullptr);
+ form = loader->load(&file, nullptr);
file.close();
if (form) {
appendForm(form, QPixmap(icon));
diff --git a/src/Gui/UiLoader.cpp b/src/Gui/UiLoader.cpp
index 002f9affbe..20db81ce55 100644
--- a/src/Gui/UiLoader.cpp
+++ b/src/Gui/UiLoader.cpp
@@ -24,6 +24,7 @@
#ifndef _PreComp_
# include
# include
+# include
# include
# include
# include
@@ -488,10 +489,20 @@ QString QUiLoader::errorString() const
UiLoader::UiLoader(QObject* parent)
: QUiLoader(parent)
{
- // do not use the plugins for additional widgets as we don't need them and
- // the application may crash under Linux (tested on Ubuntu 7.04 & 7.10).
- clearPluginPaths();
this->cw = availableWidgets();
+ setLanguageChangeEnabled(true);
+}
+
+std::unique_ptr UiLoader::newInstance(QObject *parent)
+{
+ QCoreApplication *app=QCoreApplication::instance();
+ QStringList libPaths= app->libraryPaths();
+
+ app->setLibraryPaths(QStringList{}); //< backup library paths, so QUiLoader won't load plugins by default
+ std::unique_ptr rv{new UiLoader{parent}};
+ app->setLibraryPaths(libPaths);
+
+ return rv;
}
UiLoader::~UiLoader()
@@ -544,8 +555,8 @@ void UiLoaderPy::init_type()
}
UiLoaderPy::UiLoaderPy()
+ : loader{UiLoader::newInstance()}
{
- loader.setLanguageChangeEnabled(true);
}
UiLoaderPy::~UiLoaderPy()
@@ -592,7 +603,7 @@ Py::Object UiLoaderPy::load(const Py::Tuple& args)
}
if (device) {
- QWidget* widget = loader.load(device, parent);
+ QWidget* widget = loader->load(device, parent);
if (widget) {
wrap.loadGuiModule();
wrap.loadWidgetsModule();
@@ -613,7 +624,7 @@ Py::Object UiLoaderPy::load(const Py::Tuple& args)
Py::Object UiLoaderPy::createWidget(const Py::Tuple& args)
{
- return wrapFromWidgetFactory(args, std::bind(&UiLoader::createWidget, &loader,
+ return wrapFromWidgetFactory(args, std::bind(&UiLoader::createWidget, loader.get(),
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3));
@@ -625,7 +636,7 @@ Py::Object UiLoaderPy::addPluginPath(const Py::Tuple& args)
if (wrap.loadCoreModule()) {
std::string fn;
if (wrap.toCString(args[0], fn)) {
- loader.addPluginPath(QString::fromStdString(fn));
+ loader->addPluginPath(QString::fromStdString(fn));
}
}
return Py::None();
@@ -633,13 +644,13 @@ Py::Object UiLoaderPy::addPluginPath(const Py::Tuple& args)
Py::Object UiLoaderPy::clearPluginPaths(const Py::Tuple& /*args*/)
{
- loader.clearPluginPaths();
+ loader->clearPluginPaths();
return Py::None();
}
Py::Object UiLoaderPy::pluginPaths(const Py::Tuple& /*args*/)
{
- auto list = loader.pluginPaths();
+ auto list = loader->pluginPaths();
Py::List py;
for (const auto& it : list) {
py.append(Py::String(it.toStdString()));
@@ -649,7 +660,7 @@ Py::Object UiLoaderPy::pluginPaths(const Py::Tuple& /*args*/)
Py::Object UiLoaderPy::availableWidgets(const Py::Tuple& /*args*/)
{
- auto list = loader.availableWidgets();
+ auto list = loader->availableWidgets();
Py::List py;
for (const auto& it : list) {
py.append(Py::String(it.toStdString()));
@@ -665,17 +676,17 @@ Py::Object UiLoaderPy::availableWidgets(const Py::Tuple& /*args*/)
Py::Object UiLoaderPy::errorString(const Py::Tuple& /*args*/)
{
- return Py::String(loader.errorString().toStdString());
+ return Py::String(loader->errorString().toStdString());
}
Py::Object UiLoaderPy::isLanguageChangeEnabled(const Py::Tuple& /*args*/)
{
- return Py::Boolean(loader.isLanguageChangeEnabled());
+ return Py::Boolean(loader->isLanguageChangeEnabled());
}
Py::Object UiLoaderPy::setLanguageChangeEnabled(const Py::Tuple& args)
{
- loader.setLanguageChangeEnabled(Py::Boolean(args[0]));
+ loader->setLanguageChangeEnabled(Py::Boolean(args[0]));
return Py::None();
}
@@ -685,7 +696,7 @@ Py::Object UiLoaderPy::setWorkingDirectory(const Py::Tuple& args)
if (wrap.loadCoreModule()) {
std::string fn;
if (wrap.toCString(args[0], fn)) {
- loader.setWorkingDirectory(QString::fromStdString(fn));
+ loader->setWorkingDirectory(QString::fromStdString(fn));
}
}
return Py::None();
@@ -693,7 +704,7 @@ Py::Object UiLoaderPy::setWorkingDirectory(const Py::Tuple& args)
Py::Object UiLoaderPy::workingDirectory(const Py::Tuple& /*args*/)
{
- QDir dir = loader.workingDirectory();
+ QDir dir = loader->workingDirectory();
QString path = dir.absolutePath();
return Py::String(path.toStdString());
}
diff --git a/src/Gui/UiLoader.h b/src/Gui/UiLoader.h
index 112138bd57..94a7ab16dc 100644
--- a/src/Gui/UiLoader.h
+++ b/src/Gui/UiLoader.h
@@ -106,8 +106,29 @@ private:
*/
class UiLoader : public QUiLoader
{
-public:
+protected:
+ /**
+ * A protected construct for UiLoader.
+ * To create an instance of UiLoader @see UiLoader::newInstance()
+ */
explicit UiLoader(QObject* parent=nullptr);
+
+public:
+ /**
+ * Creates a new instance of a UiLoader.
+ *
+ * Due to its flaw the QUiLoader upon creation loads every available Qt
+ * designer plugin it can find in QApplication::libraryPaths(). Some of
+ * those plugins may perform some unexpected actions upon load which may
+ * interfere with FreeCAD's functionality. Only way to avoid such behaviour
+ * is to reset QApplication::libraryPaths, create a QUiLoader and then
+ * restore the libs paths. Hence need for this function to wrap
+ * construction.
+ *
+ * @see https://github.com/FreeCAD/FreeCAD/issues/8708
+ */
+ static std::unique_ptr newInstance(QObject *parent=0);
+
~UiLoader() override;
/**
@@ -149,7 +170,7 @@ private:
static PyObject *PyMake(struct _typeobject *, PyObject *, PyObject *);
private:
- UiLoader loader;
+ std::unique_ptr loader;
};
} // namespace Gui
diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp
index 298ab3b02f..6c2503b904 100644
--- a/src/Gui/WidgetFactory.cpp
+++ b/src/Gui/WidgetFactory.cpp
@@ -461,11 +461,10 @@ void PyResource::load(const char* name)
QWidget* w=nullptr;
try {
- UiLoader loader;
- loader.setLanguageChangeEnabled(true);
+ auto loader = UiLoader::newInstance();
QFile file(fn);
if (file.open(QFile::ReadOnly))
- w = loader.load(&file, QApplication::activeWindow());
+ w = loader->load(&file, QApplication::activeWindow());
file.close();
}
catch (...) {
From 57f2f06fe22bbac6b74b04413aba991ddbd1016e Mon Sep 17 00:00:00 2001
From: Alexander Golubev
Date: Fri, 10 Mar 2023 05:25:20 +0300
Subject: [PATCH 16/53] Gui: add a tooltip about how to modify shortcuts into
DlgKeyboard
---
src/Gui/DlgKeyboard.ui | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/Gui/DlgKeyboard.ui b/src/Gui/DlgKeyboard.ui
index 5e2d77ca5e..8ff9076675 100644
--- a/src/Gui/DlgKeyboard.ui
+++ b/src/Gui/DlgKeyboard.ui
@@ -103,6 +103,9 @@
-
+
+ To change a current shortcut enter the new shortcut in the field below and press 'Assign'.
+
true
From 5090cf343614a5ac6c22cd91928a603f539fe7e4 Mon Sep 17 00:00:00 2001
From: Paddle
Date: Tue, 14 Mar 2023 14:43:02 +0100
Subject: [PATCH 17/53] Sketcher: Constraint Widget: Change showHideButton from
QPushButton to QToolButton to avoid style problems.
---
src/Mod/Sketcher/Gui/TaskSketcherConstraints.ui | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstraints.ui b/src/Mod/Sketcher/Gui/TaskSketcherConstraints.ui
index be68c34d72..0c72fdb6c7 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherConstraints.ui
+++ b/src/Mod/Sketcher/Gui/TaskSketcherConstraints.ui
@@ -70,7 +70,7 @@
-
-
+
0
From 13d175e891a2781828995c51bddfadfedb63b170 Mon Sep 17 00:00:00 2001
From: Paddle
Date: Wed, 15 Mar 2023 11:46:50 +0100
Subject: [PATCH 18/53] Sketcher: Stylesheets: Taskbox buttons revert margin
and padding.
---
src/Gui/Stylesheets/Behave-dark.qss | 2 --
src/Gui/Stylesheets/Dark-blue.qss | 2 --
src/Gui/Stylesheets/Dark-contrast.qss | 2 --
src/Gui/Stylesheets/Dark-green.qss | 2 --
src/Gui/Stylesheets/Dark-orange.qss | 2 --
src/Gui/Stylesheets/Darker-blue.qss | 2 --
src/Gui/Stylesheets/Darker-green.qss | 2 --
src/Gui/Stylesheets/Darker-orange.qss | 2 --
src/Gui/Stylesheets/Light-blue.qss | 2 --
src/Gui/Stylesheets/Light-green.qss | 2 --
src/Gui/Stylesheets/Light-orange.qss | 2 --
src/Gui/Stylesheets/ProDark.qss | 2 --
12 files changed, 24 deletions(-)
diff --git a/src/Gui/Stylesheets/Behave-dark.qss b/src/Gui/Stylesheets/Behave-dark.qss
index 13ef21cb80..4c27d8f89b 100644
--- a/src/Gui/Stylesheets/Behave-dark.qss
+++ b/src/Gui/Stylesheets/Behave-dark.qss
@@ -1662,9 +1662,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Dark-blue.qss b/src/Gui/Stylesheets/Dark-blue.qss
index 12f8edb93f..de33c11dfb 100644
--- a/src/Gui/Stylesheets/Dark-blue.qss
+++ b/src/Gui/Stylesheets/Dark-blue.qss
@@ -1629,9 +1629,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Dark-contrast.qss b/src/Gui/Stylesheets/Dark-contrast.qss
index acf351997c..5e3e49f824 100644
--- a/src/Gui/Stylesheets/Dark-contrast.qss
+++ b/src/Gui/Stylesheets/Dark-contrast.qss
@@ -1629,9 +1629,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Dark-green.qss b/src/Gui/Stylesheets/Dark-green.qss
index ed6ab3923b..b772ce1d62 100644
--- a/src/Gui/Stylesheets/Dark-green.qss
+++ b/src/Gui/Stylesheets/Dark-green.qss
@@ -1628,9 +1628,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Dark-orange.qss b/src/Gui/Stylesheets/Dark-orange.qss
index 4e1432f149..bb2a7cdad9 100644
--- a/src/Gui/Stylesheets/Dark-orange.qss
+++ b/src/Gui/Stylesheets/Dark-orange.qss
@@ -1629,9 +1629,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Darker-blue.qss b/src/Gui/Stylesheets/Darker-blue.qss
index 31fc761cb5..cef6ef16e5 100644
--- a/src/Gui/Stylesheets/Darker-blue.qss
+++ b/src/Gui/Stylesheets/Darker-blue.qss
@@ -1629,9 +1629,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Darker-green.qss b/src/Gui/Stylesheets/Darker-green.qss
index 004d55c3e7..970445870b 100644
--- a/src/Gui/Stylesheets/Darker-green.qss
+++ b/src/Gui/Stylesheets/Darker-green.qss
@@ -1629,9 +1629,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Darker-orange.qss b/src/Gui/Stylesheets/Darker-orange.qss
index e19faeb6cc..6e0b70b8cc 100644
--- a/src/Gui/Stylesheets/Darker-orange.qss
+++ b/src/Gui/Stylesheets/Darker-orange.qss
@@ -1623,9 +1623,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Light-blue.qss b/src/Gui/Stylesheets/Light-blue.qss
index cbb3ee70e1..c5ac31173d 100644
--- a/src/Gui/Stylesheets/Light-blue.qss
+++ b/src/Gui/Stylesheets/Light-blue.qss
@@ -1626,9 +1626,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Light-green.qss b/src/Gui/Stylesheets/Light-green.qss
index 6567b974e0..125fc5b725 100644
--- a/src/Gui/Stylesheets/Light-green.qss
+++ b/src/Gui/Stylesheets/Light-green.qss
@@ -1626,9 +1626,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/Light-orange.qss b/src/Gui/Stylesheets/Light-orange.qss
index 3d3eee57f2..17b718b95a 100644
--- a/src/Gui/Stylesheets/Light-orange.qss
+++ b/src/Gui/Stylesheets/Light-orange.qss
@@ -1626,9 +1626,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
diff --git a/src/Gui/Stylesheets/ProDark.qss b/src/Gui/Stylesheets/ProDark.qss
index d29ae2c954..668ccadd1f 100644
--- a/src/Gui/Stylesheets/ProDark.qss
+++ b/src/Gui/Stylesheets/ProDark.qss
@@ -1815,9 +1815,7 @@ QSint--ActionGroup QToolButton::menu-button {
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
- padding: 2px;
padding-right: 20px; /* make way for the popup button */
- margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
From 5e5719a43597ec99ba60b8e51fe2b8f75bd60a6b Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Sat, 18 Mar 2023 19:44:18 +0100
Subject: [PATCH 19/53] Fixed tests
---
src/App/MappedName.h | 12 ++++----
tests/src/App/MappedName.cpp | 56 +++++++++++-------------------------
2 files changed, 21 insertions(+), 47 deletions(-)
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
index 0d16018a5b..90172b9c99 100644
--- a/src/App/MappedName.h
+++ b/src/App/MappedName.h
@@ -103,9 +103,6 @@ public:
MappedName(const MappedName& other) = default;
- // FIXME if you pass a raw MappedName into these constructors they will
- // reset raw to false and things will break. is this intended?
-
/// Copy constructor with start position offset and optional size. The data is *not* reused.
///
/// \param other The MappedName to copy
@@ -364,7 +361,6 @@ public:
/// \param size The number of bytes to copy. If omitted, dataToAppend must be null-terminated.
void append(const char* dataToAppend, int size = -1)
{
- // FIXME raw not assigned?
if (dataToAppend && (size != 0)) {
if (size < 0) {
size = static_cast(qstrlen(dataToAppend));
@@ -690,6 +686,8 @@ public:
}
/// Returns true if this is shared data, or false if a unique copy has been made.
+ /// It is safe to access data only if it has been copied prior. To force a copy
+ /// please \see compact()
bool isRaw() const
{
return this->raw;
@@ -783,9 +781,9 @@ public:
return -1;
}
if (startPosition < 0
- || startPosition > this->postfix.size()) {// FIXME should be this->data.size
- if (startPosition > postfix.size()) {
- startPosition -= postfix.size();
+ || startPosition >= this->data.size()) {
+ if (startPosition >= data.size()) {
+ startPosition -= data.size();
}
int res = this->postfix.lastIndexOf(searchTarget, startPosition);
if (res >= 0) {
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index c5e176f540..9ebeb7d41b 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -237,19 +237,12 @@ TEST(MappedName, fromRawDataCopy)
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("TESTPOSTFIX"));
}
-TEST(MappedName, fromRawDataCopyStartposAndSize) //FIXME
+TEST(MappedName, fromRawDataCopyStartposAndSize)
{
// Arrange
Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TESTTEST", 8));
temp.append("ABCDEFGHIJKLM"); //postfix
-
-/* This block is OK
- EXPECT_EQ(temp.isRaw(), true);
- EXPECT_EQ(temp.empty(), false);
- EXPECT_EQ(temp.size(), 21);
- EXPECT_EQ(temp.dataBytes(), QByteArray("TESTTEST", 8));
- EXPECT_EQ(temp.postfixBytes(), QByteArray("ABCDEFGHIJKLM"));
-*/
+ temp.compact(); //Always call compact before accessing data!
// Act
Data::MappedName mappedName = Data::MappedName::fromRawData(temp, 2, 13);
@@ -258,9 +251,6 @@ TEST(MappedName, fromRawDataCopyStartposAndSize) //FIXME
EXPECT_EQ(mappedName.isRaw(), true);
EXPECT_EQ(mappedName.empty(), false);
EXPECT_EQ(mappedName.size(), 13);
- //next line fails with TEST\0T != STTEST
- //funny thing if i uncomment the block above, which does nothing, now the next line
- //fails with TEST\0H != STTEST
EXPECT_EQ(mappedName.dataBytes(), QByteArray("STTEST", 6));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("ABCDEFG"));
}
@@ -649,40 +639,26 @@ TEST(MappedName, rfind)
EXPECT_EQ(mappedName.rfind("STPO"), -1); //sentence must be fully contained in data or postfix
EXPECT_EQ(mappedName.rfind("POST"), 4);
-
- //FIXME looks broken
EXPECT_EQ(mappedName.rfind("ST"), 13);
EXPECT_EQ(mappedName.rfind("ST", 0), -1);
EXPECT_EQ(mappedName.rfind("ST", 1), -1);
EXPECT_EQ(mappedName.rfind("ST", 2), 2);
EXPECT_EQ(mappedName.rfind("ST", 3), 2);
EXPECT_EQ(mappedName.rfind("ST", 4), 2);
- EXPECT_EQ(mappedName.rfind("ST", 5), -1);
- EXPECT_EQ(mappedName.rfind("ST", 6), -1);
- EXPECT_EQ(mappedName.rfind("ST", 7), -1);
- EXPECT_EQ(mappedName.rfind("ST", 8), -1);
- EXPECT_EQ(mappedName.rfind("ST", 9), -1);
- EXPECT_EQ(mappedName.rfind("ST", 10), -1);
- EXPECT_EQ(mappedName.rfind("ST", 11), -1);
- EXPECT_EQ(mappedName.rfind("ST", 12), 2);
- EXPECT_EQ(mappedName.rfind("ST", 13), 6);
- EXPECT_EQ(mappedName.rfind("ST", 14), 6);
- EXPECT_EQ(mappedName.rfind("ST", 15), 6);
- EXPECT_EQ(mappedName.rfind("ST", 16), 6);
- EXPECT_EQ(mappedName.rfind("ST", 17), 6);
- EXPECT_EQ(mappedName.rfind("ST", 18), 6);
- EXPECT_EQ(mappedName.rfind("ST", 19), 6);
- EXPECT_EQ(mappedName.rfind("ST", 20), 13);
- EXPECT_EQ(mappedName.rfind("ST", 21), 13);
- EXPECT_EQ(mappedName.rfind("ST", 22), 13);
- EXPECT_EQ(mappedName.rfind("ST", 23), 2);
- EXPECT_EQ(mappedName.rfind("ST", 24), 2);
- EXPECT_EQ(mappedName.rfind("ST", 25), 2);
- EXPECT_EQ(mappedName.rfind("ST", 26), 2);
- EXPECT_EQ(mappedName.rfind("ST", 27), 2);
- EXPECT_EQ(mappedName.rfind("ST", 28), 2);
- //EXPECT_EQ(mappedName.rfind("POST", 7), 4);
- //EXPECT_EQ(mappedName.rfind("POST", 8), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 5), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 6), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 7), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 8), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 9), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 10), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 11), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 12), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 13), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 14), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 15), 13);
+
+ EXPECT_EQ(mappedName.rfind("POST", 4), 4);
+ EXPECT_EQ(mappedName.rfind("POST", 3), -1);
EXPECT_EQ(mappedName.rfind(std::string("")), mappedName.size());
}
From 3ed781ce1e5306cb98359fc620e59d379700f48b Mon Sep 17 00:00:00 2001
From: wmayer
Date: Sat, 18 Mar 2023 17:11:20 +0100
Subject: [PATCH 20/53] Gui: solves #8939: timers are moved between
non-QThreads
For more details see: https://github.com/FreeCAD/FreeCAD/issues/8939#issuecomment-1474888902
---
src/Gui/Tree.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp
index f13015e066..7cf6c32644 100644
--- a/src/Gui/Tree.cpp
+++ b/src/Gui/Tree.cpp
@@ -33,6 +33,7 @@
# include
# include
# include
+# include
# include
# include
# include
@@ -757,6 +758,12 @@ void TreeWidget::updateStatus(bool delay) {
}
void TreeWidget::_updateStatus(bool delay) {
+ // When running from a different thread Qt will raise a warning
+ // when trying to start the QTimer
+ if (Q_UNLIKELY(thread() != QThread::currentThread())) {
+ return;
+ }
+
if (!delay) {
if (!ChangedObjects.empty() || !NewObjects.empty())
onUpdateStatus();
From c585a9f4306e4707e36c5a4c2c68a2f987a66a21 Mon Sep 17 00:00:00 2001
From: wmayer
Date: Sat, 18 Mar 2023 14:48:03 +0100
Subject: [PATCH 21/53] TD: move all XML query handling to a single function
---
src/Mod/TechDraw/App/CMakeLists.txt | 2 +
src/Mod/TechDraw/App/DrawSVGTemplate.cpp | 123 ++++++++++-------------
src/Mod/TechDraw/App/DrawViewSymbol.cpp | 58 ++++-------
src/Mod/TechDraw/App/QDomNodeModel.cpp | 2 +
src/Mod/TechDraw/App/XMLQuery.cpp | 75 ++++++++++++++
src/Mod/TechDraw/App/XMLQuery.h | 49 +++++++++
src/Mod/TechDraw/Gui/QGISVGTemplate.cpp | 32 ++----
7 files changed, 213 insertions(+), 128 deletions(-)
create mode 100644 src/Mod/TechDraw/App/XMLQuery.cpp
create mode 100644 src/Mod/TechDraw/App/XMLQuery.h
diff --git a/src/Mod/TechDraw/App/CMakeLists.txt b/src/Mod/TechDraw/App/CMakeLists.txt
index 8eb26da5f9..52e8f1c43c 100644
--- a/src/Mod/TechDraw/App/CMakeLists.txt
+++ b/src/Mod/TechDraw/App/CMakeLists.txt
@@ -175,6 +175,8 @@ SET(TechDraw_SRCS
TechDrawExport.h
ProjectionAlgos.cpp
ProjectionAlgos.h
+ XMLQuery.cpp
+ XMLQuery.h
)
SET(Geometry_SRCS
diff --git a/src/Mod/TechDraw/App/DrawSVGTemplate.cpp b/src/Mod/TechDraw/App/DrawSVGTemplate.cpp
index f9e58f5704..f6ff7edfb7 100644
--- a/src/Mod/TechDraw/App/DrawSVGTemplate.cpp
+++ b/src/Mod/TechDraw/App/DrawSVGTemplate.cpp
@@ -26,10 +26,7 @@
#ifndef _PreComp_
# include
# include
-# include
# include
-# include
-# include
#endif
#include
@@ -44,6 +41,7 @@
#include "DrawSVGTemplate.h"
#include "DrawSVGTemplatePy.h"
#include "DrawUtil.h"
+#include "XMLQuery.h"
using namespace TechDraw;
@@ -113,72 +111,64 @@ QString DrawSVGTemplate::processTemplate()
return QString();
}
- QDomDocument templateDocument;
- if (!templateDocument.setContent(&templateFile)) {
+ QDomDocument templateDocument;
+ if (!templateDocument.setContent(&templateFile)) {
Base::Console().Error("DrawSVGTemplate::processTemplate - failed to parse file: %s\n",
PageResult.getValue());
- return QString();
- }
+ return QString();
+ }
- QXmlQuery query(QXmlQuery::XQuery10);
- QDomNodeModel model(query.namePool(), templateDocument);
- query.setFocus(QXmlItem(model.fromDomNode(templateDocument.documentElement())));
+ XMLQuery query(templateDocument);
+ std::map substitutions = EditableTexts.getValues();
- // XPath query to select all nodes whose parent
- // has "freecad:editable" attribute
- query.setQuery(QString::fromUtf8(
- "declare default element namespace \"" SVG_NS_URI "\"; "
- "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
- "//text[@freecad:editable]/tspan"));
+ // XPath query to select all nodes whose parent
+ // has "freecad:editable" attribute
+ query.processItems(QString::fromUtf8(
+ "declare default element namespace \"" SVG_NS_URI "\"; "
+ "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
+ "//text[@freecad:editable]/tspan"),
+ [&substitutions, &templateDocument](QDomElement& tspan) -> bool {
+ // Replace the editable text spans with new nodes holding actual values
+ QString editableName = tspan.parentNode().toElement().attribute(QString::fromUtf8("freecad:editable"));
+ std::map::iterator item =
+ substitutions.find(editableName.toStdString());
+ if (item != substitutions.end()) {
+ // Keep all spaces in the text node
+ tspan.setAttribute(QString::fromUtf8("xml:space"), QString::fromUtf8("preserve"));
- QXmlResultItems queryResult;
- query.evaluateTo(&queryResult);
+ // Remove all child nodes and append text node with editable replacement as the only descendant
+ while (!tspan.lastChild().isNull()) {
+ tspan.removeChild(tspan.lastChild());
+ }
+ tspan.appendChild(templateDocument.createTextNode(QString::fromUtf8(item->second.c_str())));
+ }
+ return true;
+ });
- std::map substitutions = EditableTexts.getValues();
- while (!queryResult.next().isNull())
- {
- QDomElement tspan = model.toDomNode(queryResult.current().toNodeModelIndex()).toElement();
+ // Calculate the dimensions of the page and store for retrieval
+ // Obtain the size of the SVG document by reading the document attributes
+ QDomElement docElement = templateDocument.documentElement();
+ Base::Quantity quantity;
- // Replace the editable text spans with new nodes holding actual values
- QString editableName = tspan.parentNode().toElement().attribute(QString::fromUtf8("freecad:editable"));
- std::map::iterator item =
- substitutions.find(std::string(editableName.toUtf8().constData()));
- if (item != substitutions.end()) {
- // Keep all spaces in the text node
- tspan.setAttribute(QString::fromUtf8("xml:space"), QString::fromUtf8("preserve"));
+ // Obtain the width
+ QString str = docElement.attribute(QString::fromLatin1("width"));
+ quantity = Base::Quantity::parse(str);
+ quantity.setUnit(Base::Unit::Length);
- // Remove all child nodes and append text node with editable replacement as the only descendant
- while (!tspan.lastChild().isNull()) {
- tspan.removeChild(tspan.lastChild());
- }
- tspan.appendChild(templateDocument.createTextNode(QString::fromUtf8(item->second.c_str())));
- }
- }
+ Width.setValue(quantity.getValue());
- // Calculate the dimensions of the page and store for retrieval
- // Obtain the size of the SVG document by reading the document attributes
- QDomElement docElement = templateDocument.documentElement();
- Base::Quantity quantity;
+ str = docElement.attribute(QString::fromLatin1("height"));
+ quantity = Base::Quantity::parse(str);
+ quantity.setUnit(Base::Unit::Length);
- // Obtain the width
- QString str = docElement.attribute(QString::fromLatin1("width"));
- quantity = Base::Quantity::parse(str);
- quantity.setUnit(Base::Unit::Length);
+ Height.setValue(quantity.getValue());
- Width.setValue(quantity.getValue());
+ bool isLandscape = getWidth() / getHeight() >= 1.;
- str = docElement.attribute(QString::fromLatin1("height"));
- quantity = Base::Quantity::parse(str);
- quantity.setUnit(Base::Unit::Length);
+ Orientation.setValue(isLandscape ? 1 : 0);
- Height.setValue(quantity.getValue());
-
- bool isLandscape = getWidth() / getHeight() >= 1.;
-
- Orientation.setValue(isLandscape ? 1 : 0);
-
- //all Qt holds on files should be released on exit #4085
- return templateDocument.toString();
+ //all Qt holds on files should be released on exit #4085
+ return templateDocument.toString();
}
double DrawSVGTemplate::getWidth() const
@@ -218,7 +208,7 @@ std::map DrawSVGTemplate::getEditableTextsFromTemplate
Base::FileInfo tfi(templateFilename);
if (!tfi.isReadable()) {
- // if there is a old absolute template file set use a redirect
+ // if there is an old absolute template file set use a redirect
tfi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + tfi.fileName());
// try the redirect
if (!tfi.isReadable()) {
@@ -240,29 +230,22 @@ std::map DrawSVGTemplate::getEditableTextsFromTemplate
return editables;
}
- QXmlQuery query(QXmlQuery::XQuery10);
- QDomNodeModel model(query.namePool(), templateDocument, true);
- query.setFocus(QXmlItem(model.fromDomNode(templateDocument.documentElement())));
+ XMLQuery query(templateDocument);
// XPath query to select all nodes whose parent
// has "freecad:editable" attribute
- query.setQuery(QString::fromUtf8(
+ query.processItems(QString::fromUtf8(
"declare default element namespace \"" SVG_NS_URI "\"; "
"declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
- "//text[@freecad:editable]/tspan"));
-
- QXmlResultItems queryResult;
- query.evaluateTo(&queryResult);
-
- while (!queryResult.next().isNull()) {
- QDomElement tspan = model.toDomNode(queryResult.current().toNodeModelIndex()).toElement();
-
+ "//text[@freecad:editable]/tspan"),
+ [&editables](QDomElement& tspan) -> bool {
QString editableName = tspan.parentNode().toElement().attribute(QString::fromUtf8("freecad:editable"));
QString editableValue = tspan.firstChild().nodeValue();
editables[std::string(editableName.toUtf8().constData())] =
std::string(editableValue.toUtf8().constData());
- }
+ return true;
+ });
return editables;
}
diff --git a/src/Mod/TechDraw/App/DrawViewSymbol.cpp b/src/Mod/TechDraw/App/DrawViewSymbol.cpp
index 90dc8aa606..4b83b34b77 100644
--- a/src/Mod/TechDraw/App/DrawViewSymbol.cpp
+++ b/src/Mod/TechDraw/App/DrawViewSymbol.cpp
@@ -23,11 +23,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include
-
-# include "QDomNodeModel.h"
# include
-# include
-# include
#endif
#include
@@ -36,6 +32,7 @@
#include "DrawViewSymbolPy.h" // generated from DrawViewSymbolPy.xml
#include "DrawPage.h"
#include "DrawUtil.h"
+#include "XMLQuery.h"
using namespace TechDraw;
@@ -105,30 +102,22 @@ bool DrawViewSymbol::checkFit(TechDraw::DrawPage* p) const
std::vector DrawViewSymbol::getEditableFields()
{
QDomDocument symbolDocument;
- QXmlResultItems queryResult;
std::vector editables;
bool rc = loadQDomDocument(symbolDocument);
if (rc) {
- QDomElement symbolDocElem = symbolDocument.documentElement();
- QXmlQuery query(QXmlQuery::XQuery10);
- QDomNodeModel model(query.namePool(), symbolDocument);
- query.setFocus(QXmlItem(model.fromDomNode(symbolDocument.documentElement())));
+ XMLQuery query(symbolDocument);
// XPath query to select all nodes whose parent
// has "freecad:editable" attribute
- query.setQuery(QString::fromUtf8("declare default element namespace \"" SVG_NS_URI "\"; "
- "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
- "//text[@freecad:editable]/tspan"));
-
- query.evaluateTo(&queryResult);
-
- while (!queryResult.next().isNull()) {
- QDomElement tspan =
- model.toDomNode(queryResult.current().toNodeModelIndex()).toElement();
+ query.processItems(QString::fromUtf8("declare default element namespace \"" SVG_NS_URI "\"; "
+ "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
+ "//text[@freecad:editable]/tspan"),
+ [&editables](QDomElement& tspan) -> bool {
QString editableValue = tspan.firstChild().nodeValue();
- editables.emplace_back(editableValue.toUtf8().constData());
- }
+ editables.emplace_back(editableValue.toStdString());
+ return true;
+ });
}
return editables;
}
@@ -142,27 +131,22 @@ void DrawViewSymbol::updateFieldsInSymbol()
}
QDomDocument symbolDocument;
- QXmlResultItems queryResult;
bool rc = loadQDomDocument(symbolDocument);
if (rc) {
- QDomElement symbolDocElem = symbolDocument.documentElement();
- QXmlQuery query(QXmlQuery::XQuery10);
- QDomNodeModel model(query.namePool(), symbolDocument);
- query.setFocus(QXmlItem(model.fromDomNode(symbolDocElem)));
+ XMLQuery query(symbolDocument);
+ std::size_t count = 0;
// XPath query to select all nodes whose parent
// has "freecad:editable" attribute
- query.setQuery(QString::fromUtf8("declare default element namespace \"" SVG_NS_URI "\"; "
- "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
- "//text[@freecad:editable]/tspan"));
- query.evaluateTo(&queryResult);
-
- unsigned int count = 0;
- while (!queryResult.next().isNull()) {
- QDomElement tspanElement =
- model.toDomNode(queryResult.current().toNodeModelIndex()).toElement();
+ query.processItems(QString::fromUtf8("declare default element namespace \"" SVG_NS_URI "\"; "
+ "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
+ "//text[@freecad:editable]/tspan"),
+ [&symbolDocument, &editText, &count](QDomElement& tspanElement) -> bool {
+ if (count >= editText.size()) {
+ return false;
+ }
// Keep all spaces in the text node
tspanElement.setAttribute(QString::fromUtf8("xml:space"),
QString::fromUtf8("preserve"));
@@ -174,9 +158,11 @@ void DrawViewSymbol::updateFieldsInSymbol()
// Finally append text node with editable replacement as the only descendant
tspanElement.appendChild(
- symbolDocument.createTextNode(QString::fromUtf8(editText[count].c_str())));
+ symbolDocument.createTextNode(QString::fromStdString(editText[count])));
++count;
- }
+ return true;
+ });
+
Symbol.setValue(symbolDocument.toString(1).toStdString());
}
}
diff --git a/src/Mod/TechDraw/App/QDomNodeModel.cpp b/src/Mod/TechDraw/App/QDomNodeModel.cpp
index 901aeadb40..702902ff34 100644
--- a/src/Mod/TechDraw/App/QDomNodeModel.cpp
+++ b/src/Mod/TechDraw/App/QDomNodeModel.cpp
@@ -28,6 +28,7 @@
#include
#include
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
#include "QDomNodeModel.h"
#include
#include
@@ -359,3 +360,4 @@ QXmlNodeModelIndex QDomNodeModel::nextFromSimpleAxis ( SimpleAxis axis, const QX
return QXmlNodeModelIndex();
}
+#endif
diff --git a/src/Mod/TechDraw/App/XMLQuery.cpp b/src/Mod/TechDraw/App/XMLQuery.cpp
new file mode 100644
index 0000000000..9090907c1a
--- /dev/null
+++ b/src/Mod/TechDraw/App/XMLQuery.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+ * Copyright (c) 2023 Werner Mayer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+
+#ifndef _PreComp_
+# include
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+# include "QDomNodeModel.h"
+# include
+# include
+#endif
+#endif
+
+#include "XMLQuery.h"
+
+
+using namespace TechDraw;
+
+XMLQuery::XMLQuery(QDomDocument& dom)
+ : domDocument(dom)
+{
+
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+bool XMLQuery::processItems(const QString& queryStr, const std::function& process)
+{
+ QXmlQuery query(QXmlQuery::XQuery10);
+ QDomNodeModel model(query.namePool(), domDocument);
+ QDomElement symbolDocElem = domDocument.documentElement();
+ query.setFocus(QXmlItem(model.fromDomNode(symbolDocElem)));
+
+ query.setQuery(queryStr);
+ QXmlResultItems queryResult;
+ query.evaluateTo(&queryResult);
+
+ while (!queryResult.next().isNull()) {
+ QDomElement tspanElement =
+ model.toDomNode(queryResult.current().toNodeModelIndex()).toElement();
+ if (!process(tspanElement)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#else
+bool XMLQuery::processItems(const QString& queryStr, const std::function& process)
+{
+ //TODO: Port to Qt6
+ Q_UNUSED(queryStr)
+ Q_UNUSED(process)
+ return false;
+}
+#endif
diff --git a/src/Mod/TechDraw/App/XMLQuery.h b/src/Mod/TechDraw/App/XMLQuery.h
new file mode 100644
index 0000000000..309fe4c17e
--- /dev/null
+++ b/src/Mod/TechDraw/App/XMLQuery.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (c) 2023 Werner Mayer *
+ * *
+ * 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 TECHDRAW_XMLQuery_h_
+#define TECHDRAW_XMLQuery_h_
+
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+class QDomDocument;
+class QDomElement;
+QT_END_NAMESPACE
+
+namespace TechDraw
+{
+
+class TechDrawExport XMLQuery
+{
+public:
+ XMLQuery(QDomDocument&);
+ bool processItems(const QString& queryStr, const std::function& process);
+
+private:
+ QDomDocument& domDocument;
+};
+
+} //namespace TechDraw
+
+#endif //TECHDRAW_XMLQuery_h_
diff --git a/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp b/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp
index 2cdf7f8bca..298e3ab972 100644
--- a/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp
+++ b/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp
@@ -29,8 +29,6 @@
# include
# include
# include
-# include
-# include
#endif// #ifndef _PreComp_
#include
@@ -39,7 +37,7 @@
#include
#include
-#include
+#include
#include "QGISVGTemplate.h"
#include "PreferencesGui.h"
@@ -165,20 +163,6 @@ void QGISVGTemplate::createClickHandles()
}
file.close();
- QDomElement templateDocElem = templateDocument.documentElement();
-
- QXmlQuery query(QXmlQuery::XQuery10);
- QDomNodeModel model(query.namePool(), templateDocument);
- query.setFocus(QXmlItem(model.fromDomNode(templateDocElem)));
-
- // XPath query to select all nodes with "freecad:editable" attribute
- query.setQuery(QString::fromUtf8("declare default element namespace \"" SVG_NS_URI "\"; "
- "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
- "//text[@freecad:editable]"));
-
- QXmlResultItems queryResult;
- query.evaluateTo(&queryResult);
-
//TODO: Find location of special fields (first/third angle) and make graphics items for them
Base::Reference hGrp = App::GetApplication()
@@ -194,10 +178,13 @@ void QGISVGTemplate::createClickHandles()
double width = editClickBoxSize;
double height = editClickBoxSize;
- while (!queryResult.next().isNull()) {
- QDomElement textElement =
- model.toDomNode(queryResult.current().toNodeModelIndex()).toElement();
+ TechDraw::XMLQuery query(templateDocument);
+ // XPath query to select all nodes with "freecad:editable" attribute
+ query.processItems(QString::fromUtf8("declare default element namespace \"" SVG_NS_URI "\"; "
+ "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; "
+ "//text[@freecad:editable]"),
+ [&](QDomElement& textElement) -> bool {
QString name = textElement.attribute(QString::fromUtf8("freecad:editable"));
double x = Rez::guiX(
textElement.attribute(QString::fromUtf8("x"), QString::fromUtf8("0.0")).toDouble());
@@ -207,7 +194,7 @@ void QGISVGTemplate::createClickHandles()
if (name.isEmpty()) {
Base::Console().Warning(
"QGISVGTemplate::createClickHandles - no name for editable text at %f, %f\n", x, y);
- continue;
+ return true;
}
auto item(new TemplateTextField(this, svgTemplate, name.toStdString()));
@@ -229,7 +216,8 @@ void QGISVGTemplate::createClickHandles()
addToGroup(item);
textFields.push_back(item);
- }
+ return true;
+ });
}
#include
From 86333b210dbbc90322b5a533c5cca85e3b206ad3 Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Sun, 19 Mar 2023 00:41:13 +0100
Subject: [PATCH 22/53] Remove use of = operator in object construction
---
tests/src/App/MappedName.cpp | 105 +++++++++++++++++------------------
1 file changed, 51 insertions(+), 54 deletions(-)
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index 9ebeb7d41b..aa959a4665 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -14,7 +14,7 @@
TEST(MappedName, defaultConstruction)
{
// Act
- Data::MappedName mappedName = Data::MappedName();
+ Data::MappedName mappedName;
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -27,7 +27,7 @@ TEST(MappedName, defaultConstruction)
TEST(MappedName, namedConstruction)
{
// Act
- Data::MappedName mappedName = Data::MappedName("TEST");
+ Data::MappedName mappedName("TEST");
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -40,7 +40,7 @@ TEST(MappedName, namedConstruction)
TEST(MappedName, namedConstructionWithMaxSize)
{
// Act
- Data::MappedName mappedName = Data::MappedName("TEST", 2);
+ Data::MappedName mappedName("TEST", 2);
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -56,7 +56,7 @@ TEST(MappedName, namedConstructionDiscardPrefix)
std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
// Act
- Data::MappedName mappedName = Data::MappedName(name.c_str());
+ Data::MappedName mappedName(name.c_str());
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -69,7 +69,7 @@ TEST(MappedName, namedConstructionDiscardPrefix)
TEST(MappedName, stringNamedConstruction)
{
// Act
- Data::MappedName mappedName = Data::MappedName(std::string("TEST"));
+ Data::MappedName mappedName(std::string("TEST"));
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -85,7 +85,7 @@ TEST(MappedName, stringNamedConstructionDiscardPrefix)
std::string name = Data::ComplexGeoData::elementMapPrefix() + "TEST";
// Act
- Data::MappedName mappedName = Data::MappedName(name);
+ Data::MappedName mappedName(name);
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -98,10 +98,10 @@ TEST(MappedName, stringNamedConstructionDiscardPrefix)
TEST(MappedName, copyConstructor)
{
// Arrange
- Data::MappedName temp = Data::MappedName("TEST");
+ Data::MappedName temp("TEST");
// Act
- Data::MappedName mappedName = Data::MappedName(temp);
+ Data::MappedName mappedName(temp);
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -114,10 +114,10 @@ TEST(MappedName, copyConstructor)
TEST(MappedName, copyConstructorWithPostfix)
{
// Arrange
- Data::MappedName temp = Data::MappedName("TEST");
+ Data::MappedName temp("TEST");
// Act
- Data::MappedName mappedName = Data::MappedName(temp, "POSTFIXTEST");
+ Data::MappedName mappedName(temp, "POSTFIXTEST");
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -126,27 +126,24 @@ TEST(MappedName, copyConstructorWithPostfix)
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
- // Arrange
- temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
-
// Act
- mappedName = Data::MappedName(temp, "ANOTHERPOSTFIX");
+ Data::MappedName mappedName2(mappedName, "ANOTHERPOSTFIX");
// Assert
- EXPECT_EQ(mappedName.isRaw(), false);
- EXPECT_EQ(mappedName.empty(), false);
- EXPECT_EQ(mappedName.size(), 29);
- EXPECT_EQ(mappedName.dataBytes(), QByteArray("TESTPOSTFIXTEST"));
- EXPECT_EQ(mappedName.postfixBytes(), QByteArray("ANOTHERPOSTFIX"));
+ EXPECT_EQ(mappedName2.isRaw(), false);
+ EXPECT_EQ(mappedName2.empty(), false);
+ EXPECT_EQ(mappedName2.size(), 29);
+ EXPECT_EQ(mappedName2.dataBytes(), QByteArray("TESTPOSTFIXTEST"));
+ EXPECT_EQ(mappedName2.postfixBytes(), QByteArray("ANOTHERPOSTFIX"));
}
TEST(MappedName, copyConstructorStartpos)
{
// Arrange
- Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName temp(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
- Data::MappedName mappedName = Data::MappedName(temp, 2, -1);
+ Data::MappedName mappedName(temp, 2, -1);
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -159,10 +156,10 @@ TEST(MappedName, copyConstructorStartpos)
TEST(MappedName, copyConstructorStartposAndSize)
{
// Arrange
- Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName temp(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
- Data::MappedName mappedName = Data::MappedName(temp, 2, 6);
+ Data::MappedName mappedName(temp, 2, 6);
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -175,10 +172,10 @@ TEST(MappedName, copyConstructorStartposAndSize)
TEST(MappedName, moveConstructor)
{
// Arrange
- Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName temp(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
- Data::MappedName mappedName = Data::MappedName(std::move(temp));
+ Data::MappedName mappedName(std::move(temp));
// Assert
EXPECT_EQ(mappedName.isRaw(), false);
@@ -258,7 +255,7 @@ TEST(MappedName, fromRawDataCopyStartposAndSize)
TEST(MappedName, assignmentOperator)
{
// Arrange
- Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName temp(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
Data::MappedName mappedName = temp;
@@ -306,7 +303,7 @@ TEST(MappedName, assignmentOperatorConstCharPtr)
TEST(MappedName, assignmentOperatorMove)
{
// Arrange
- Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName temp(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
Data::MappedName mappedName = std::move(temp);
@@ -328,7 +325,7 @@ TEST(MappedName, assignmentOperatorMove)
TEST(MappedName, streamInsertionOperator)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
std::stringstream ss;
@@ -341,10 +338,10 @@ TEST(MappedName, streamInsertionOperator)
TEST(MappedName, comparisonOperators)
{
// Arrange
- Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- Data::MappedName mappedName2 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- Data::MappedName mappedName3 = Data::MappedName(Data::MappedName("TESTPOST"), "FIXTEST");
- Data::MappedName mappedName4 = Data::MappedName(Data::MappedName("THIS"), "ISDIFFERENT");
+ Data::MappedName mappedName1(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName2(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName3(Data::MappedName("TESTPOST"), "FIXTEST");
+ Data::MappedName mappedName4(Data::MappedName("THIS"), "ISDIFFERENT");
// Act & Assert
EXPECT_EQ(mappedName1 == mappedName1, true);
@@ -361,7 +358,7 @@ TEST(MappedName, comparisonOperators)
TEST(MappedName, additionOperators)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
mappedName += "POST1";
@@ -396,7 +393,7 @@ TEST(MappedName, additionOperators)
TEST(MappedName, append)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName();
+ Data::MappedName mappedName;
// Act
mappedName.append("TEST");
@@ -432,8 +429,8 @@ TEST(MappedName, append)
TEST(MappedName, appendMappedNameObj)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName();
- Data::MappedName temp = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName;
+ Data::MappedName temp(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
mappedName.append(temp);
@@ -459,7 +456,7 @@ TEST(MappedName, appendMappedNameObj)
TEST(MappedName, toString)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act & Assert
EXPECT_EQ(mappedName.toString(0), "TESTPOSTFIXTEST");
@@ -471,7 +468,7 @@ TEST(MappedName, toString)
TEST(MappedName, toConstString)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
int size;
// Act
@@ -492,7 +489,7 @@ TEST(MappedName, toConstString)
TEST(MappedName, toRawBytes)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act & Assert
EXPECT_EQ(mappedName.toRawBytes(), QByteArray("TESTPOSTFIXTEST"));
@@ -504,7 +501,7 @@ TEST(MappedName, toRawBytes)
TEST(MappedName, toBytes)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act & Assert
EXPECT_EQ(mappedName.toBytes(), QByteArray("TESTPOSTFIXTEST"));
@@ -513,12 +510,12 @@ TEST(MappedName, toBytes)
TEST(MappedName, compare)
{
// Arrange
- Data::MappedName mappedName1 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- Data::MappedName mappedName2 = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- Data::MappedName mappedName3 = Data::MappedName(Data::MappedName("TESTPOST"), "FIXTEST");
- Data::MappedName mappedName4 = Data::MappedName(Data::MappedName("THIS"), "ISDIFFERENT");
- Data::MappedName mappedName5 = Data::MappedName(Data::MappedName("SH"), "ORTHER");
- Data::MappedName mappedName6 = Data::MappedName(Data::MappedName("VERYVERYVERY"), "VERYMUCHLONGER");
+ Data::MappedName mappedName1(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName2(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName3(Data::MappedName("TESTPOST"), "FIXTEST");
+ Data::MappedName mappedName4(Data::MappedName("THIS"), "ISDIFFERENT");
+ Data::MappedName mappedName5(Data::MappedName("SH"), "ORTHER");
+ Data::MappedName mappedName6(Data::MappedName("VERYVERYVERY"), "VERYMUCHLONGER");
// Act & Assert
EXPECT_EQ(mappedName1.compare(mappedName1), 0);
@@ -539,7 +536,7 @@ TEST(MappedName, compare)
TEST(MappedName, subscriptOperator)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act & Assert
EXPECT_EQ(mappedName[0], 'T');
@@ -557,7 +554,7 @@ TEST(MappedName, subscriptOperator)
TEST(MappedName, copy)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
Data::MappedName mappedName2 = mappedName.copy();
@@ -585,7 +582,7 @@ TEST(MappedName, compact)
TEST(MappedName, boolOperator)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName();
+ Data::MappedName mappedName;
// Act & Assert
EXPECT_EQ((bool)mappedName, false);
@@ -600,7 +597,7 @@ TEST(MappedName, boolOperator)
TEST(MappedName, clear)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act
mappedName.clear();
@@ -612,7 +609,7 @@ TEST(MappedName, clear)
TEST(MappedName, find)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act & Assert
EXPECT_EQ(mappedName.find(nullptr), -1);
@@ -630,7 +627,7 @@ TEST(MappedName, find)
TEST(MappedName, rfind)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
// Act & Assert
EXPECT_EQ(mappedName.rfind(nullptr), -1);
@@ -666,7 +663,7 @@ TEST(MappedName, rfind)
TEST(MappedName, endswith)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName("TEST");
+ Data::MappedName mappedName("TEST");
// Act & Assert
EXPECT_EQ(mappedName.endsWith(nullptr), false);
@@ -687,7 +684,7 @@ TEST(MappedName, endswith)
TEST(MappedName, startsWith)
{
// Arrange
- Data::MappedName mappedName = Data::MappedName("TEST");
+ Data::MappedName mappedName("TEST");
// Act & Assert
EXPECT_EQ(mappedName.startsWith(QByteArray()), true);
From 2721a83a08dcf3770b80e2abd3ff59c9663afcb9 Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Sun, 19 Mar 2023 01:32:29 +0100
Subject: [PATCH 23/53] Improved some tests
---
tests/src/App/MappedName.cpp | 56 +++++++++++++++++++++++++-----------
1 file changed, 39 insertions(+), 17 deletions(-)
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index aa959a4665..f50b7caa34 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -222,6 +222,7 @@ TEST(MappedName, fromRawDataCopy)
// Arrange
Data::MappedName temp = Data::MappedName::fromRawData(QByteArray("TESTTEST", 10));
temp.append("TESTPOSTFIX");
+ temp.compact(); //Always call compact before accessing data!
// Act
Data::MappedName mappedName = Data::MappedName::fromRawData(temp, 0);
@@ -326,9 +327,9 @@ TEST(MappedName, streamInsertionOperator)
{
// Arrange
Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ std::stringstream ss;
// Act
- std::stringstream ss;
ss << mappedName;
// Assert
@@ -614,14 +615,30 @@ TEST(MappedName, find)
// Act & Assert
EXPECT_EQ(mappedName.find(nullptr), -1);
EXPECT_EQ(mappedName.find(""), 0);
+ EXPECT_EQ(mappedName.find(std::string("")), 0);
EXPECT_EQ(mappedName.find("TEST"), 0);
EXPECT_EQ(mappedName.find("STPO"), -1); //sentence must be fully contained in data or postfix
EXPECT_EQ(mappedName.find("POST"), 4);
- EXPECT_EQ(mappedName.find("ST", 3), 6); //found in postfix
EXPECT_EQ(mappedName.find("POST", 4), 4);
EXPECT_EQ(mappedName.find("POST", 5), -1);
-
- EXPECT_EQ(mappedName.find(std::string("")), 0);
+
+ EXPECT_EQ(mappedName.rfind("ST"), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 15), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 14), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 13), 13);
+ EXPECT_EQ(mappedName.rfind("ST", 12), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 11), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 10), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 9), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 8), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 7), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 6), 6);
+ EXPECT_EQ(mappedName.rfind("ST", 5), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 4), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 3), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 2), 2);
+ EXPECT_EQ(mappedName.rfind("ST", 1), -1);
+ EXPECT_EQ(mappedName.rfind("ST", 0), -1);
}
TEST(MappedName, rfind)
@@ -632,9 +649,12 @@ TEST(MappedName, rfind)
// Act & Assert
EXPECT_EQ(mappedName.rfind(nullptr), -1);
EXPECT_EQ(mappedName.rfind(""), mappedName.size());
+ EXPECT_EQ(mappedName.rfind(std::string("")), mappedName.size());
EXPECT_EQ(mappedName.rfind("TEST"), 11);
EXPECT_EQ(mappedName.rfind("STPO"), -1); //sentence must be fully contained in data or postfix
EXPECT_EQ(mappedName.rfind("POST"), 4);
+ EXPECT_EQ(mappedName.rfind("POST", 4), 4);
+ EXPECT_EQ(mappedName.rfind("POST", 3), -1);
EXPECT_EQ(mappedName.rfind("ST"), 13);
EXPECT_EQ(mappedName.rfind("ST", 0), -1);
@@ -653,11 +673,6 @@ TEST(MappedName, rfind)
EXPECT_EQ(mappedName.rfind("ST", 13), 13);
EXPECT_EQ(mappedName.rfind("ST", 14), 13);
EXPECT_EQ(mappedName.rfind("ST", 15), 13);
-
- EXPECT_EQ(mappedName.rfind("POST", 4), 4);
- EXPECT_EQ(mappedName.rfind("POST", 3), -1);
-
- EXPECT_EQ(mappedName.rfind(std::string("")), mappedName.size());
}
TEST(MappedName, endswith)
@@ -668,9 +683,8 @@ TEST(MappedName, endswith)
// Act & Assert
EXPECT_EQ(mappedName.endsWith(nullptr), false);
EXPECT_EQ(mappedName.endsWith("TEST"), true);
- EXPECT_EQ(mappedName.endsWith("WASD"), false);
-
EXPECT_EQ(mappedName.endsWith(std::string("TEST")), true);
+ EXPECT_EQ(mappedName.endsWith("WASD"), false);
// Arrange
mappedName.append("POSTFIX");
@@ -684,16 +698,24 @@ TEST(MappedName, endswith)
TEST(MappedName, startsWith)
{
// Arrange
- Data::MappedName mappedName("TEST");
-
+ Data::MappedName mappedName;
+
// Act & Assert
+ EXPECT_EQ(mappedName.startsWith(nullptr), false);
+ EXPECT_EQ(mappedName.startsWith(QByteArray()), true);
+ EXPECT_EQ(mappedName.startsWith(""), true);
+ EXPECT_EQ(mappedName.startsWith(std::string("")), true);
+ EXPECT_EQ(mappedName.startsWith("WASD"), false);
+
+ // Arrange
+ mappedName.append("TEST");
+
+ // Act & Assert
+ EXPECT_EQ(mappedName.startsWith(nullptr), false);
EXPECT_EQ(mappedName.startsWith(QByteArray()), true);
EXPECT_EQ(mappedName.startsWith("TEST"), true);
- EXPECT_EQ(mappedName.startsWith("WASD"), false);
-
- EXPECT_EQ(mappedName.startsWith(nullptr), false);
- EXPECT_EQ(mappedName.startsWith("TEST"), true);
EXPECT_EQ(mappedName.startsWith(std::string("TEST")), true);
+ EXPECT_EQ(mappedName.startsWith("WASD"), false);
}
//TODO test hash function
From 88a06ce6d52cf500dd6176286d1932ea0c8408a5 Mon Sep 17 00:00:00 2001
From: Chris Hennes
Date: Sat, 18 Mar 2023 20:13:22 -0400
Subject: [PATCH 24/53] App/Toponaming: Add IndexedName tests for MappedName
class
---
tests/src/App/MappedName.cpp | 81 +++++++++++++++++++++++++++---------
1 file changed, 62 insertions(+), 19 deletions(-)
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index f50b7caa34..feb16c63d0 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -6,11 +6,9 @@
#include "App/ComplexGeoData.h"
#include
-#include
+// NOLINTBEGIN(readability-magic-numbers)
-
-// clang-format off
TEST(MappedName, defaultConstruction)
{
// Act
@@ -95,6 +93,31 @@ TEST(MappedName, stringNamedConstructionDiscardPrefix)
EXPECT_EQ(mappedName.postfixBytes(), QByteArray());
}
+TEST(MappedName, constructFromIndexedNameNoIndex)
+{
+ // Arrange
+ Data::IndexedName indexedName {"INDEXED_NAME"};
+
+ // Act
+ Data::MappedName mappedName {indexedName};
+
+ // Assert
+ EXPECT_EQ(mappedName.dataBytes().constData(), indexedName.getType()); // shared memory
+}
+
+TEST(MappedName, constructFromIndexedNameWithIndex)
+{
+ // Arrange
+ Data::IndexedName indexedName {"INDEXED_NAME", 1};
+
+ // Act
+ Data::MappedName mappedName {indexedName};
+
+ // Assert
+ EXPECT_NE(mappedName.dataBytes().constData(), indexedName.getType()); // NOT shared memory
+ EXPECT_EQ(mappedName.toString(), indexedName.toString());
+}
+
TEST(MappedName, copyConstructor)
{
// Arrange
@@ -183,12 +206,6 @@ TEST(MappedName, moveConstructor)
EXPECT_EQ(mappedName.size(), 15);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
-
- EXPECT_EQ(temp.isRaw(), false);
- EXPECT_EQ(temp.empty(), true);
- EXPECT_EQ(temp.size(), 0);
- EXPECT_EQ(temp.dataBytes(), QByteArray());
- EXPECT_EQ(temp.postfixBytes(), QByteArray());
}
TEST(MappedName, fromRawData)
@@ -315,12 +332,6 @@ TEST(MappedName, assignmentOperatorMove)
EXPECT_EQ(mappedName.size(), 15);
EXPECT_EQ(mappedName.dataBytes(), QByteArray("TEST"));
EXPECT_EQ(mappedName.postfixBytes(), QByteArray("POSTFIXTEST"));
-
- EXPECT_EQ(temp.isRaw(), false);
- EXPECT_EQ(temp.empty(), true);
- EXPECT_EQ(temp.size(), 0);
- EXPECT_EQ(temp.dataBytes(), QByteArray());
- EXPECT_EQ(temp.postfixBytes(), QByteArray());
}
TEST(MappedName, streamInsertionOperator)
@@ -470,7 +481,7 @@ TEST(MappedName, toConstString)
{
// Arrange
Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
- int size;
+ int size{0};
// Act
const char *temp = mappedName.toConstString(0, size);
@@ -499,6 +510,40 @@ TEST(MappedName, toRawBytes)
EXPECT_EQ(mappedName.toRawBytes(502, 5), QByteArray());
}
+TEST(MappedName, toIndexedNameASCIIOnly)
+{
+ // Arrange
+ Data::MappedName mappedName {"MAPPED_NAME"};
+
+ // Act
+ auto indexedName = mappedName.toIndexedName();
+
+ // Assert
+ EXPECT_FALSE(indexedName.isNull());
+}
+
+TEST(MappedName, toIndexedNameInvalid)
+{
+ // Arrange
+ Data::MappedName mappedName {"MAPPED-NAME"};
+
+ // Act
+ auto indexedName = mappedName.toIndexedName();
+
+ // Assert
+ EXPECT_TRUE(indexedName.isNull());
+}
+
+TEST(MappedName, toPrefixedString)
+{
+ // TODO Write this test
+}
+
+TEST(MappedName, appendToBufferWithPrefix)
+{
+ // TODO Write this test
+}
+
TEST(MappedName, toBytes)
{
// Arrange
@@ -719,7 +764,5 @@ TEST(MappedName, startsWith)
}
//TODO test hash function
-//TODO test indexedName functions
-
-// clang-format on
\ No newline at end of file
+// NOLINTEND(readability-magic-numbers)
From dce458d1e861dec4cfbe1bacc3f68d4bf5edd000 Mon Sep 17 00:00:00 2001
From: Pesc0
Date: Sun, 19 Mar 2023 02:55:24 +0100
Subject: [PATCH 25/53] Added all tests and minor fixes
---
src/App/MappedName.cpp | 7 ++--
src/App/MappedName.h | 16 +++++---
tests/src/App/MappedName.cpp | 72 ++++++++++++++++++++++++++++++++++--
3 files changed, 82 insertions(+), 13 deletions(-)
diff --git a/src/App/MappedName.cpp b/src/App/MappedName.cpp
index f7620ff7c8..ba9b90c2ac 100644
--- a/src/App/MappedName.cpp
+++ b/src/App/MappedName.cpp
@@ -33,13 +33,12 @@
using namespace Data;
-void MappedName::compact() const
+void MappedName::compact()
{
- auto self = const_cast(this);
if (this->raw) {
- self->data = QByteArray(self->data.constData(), self->data.size());
- self->raw = false;
+ this->data = QByteArray(this->data.constData(), this->data.size());
+ this->raw = false;
}
#if 0
diff --git a/src/App/MappedName.h b/src/App/MappedName.h
index 90172b9c99..84a6ca6927 100644
--- a/src/App/MappedName.h
+++ b/src/App/MappedName.h
@@ -89,11 +89,12 @@ public:
/// is appended as text to the MappedName. In that case the memory is *not* shared between the
/// original IndexedName and the MappedName.
explicit MappedName(const IndexedName& element)
- : data(element.getType()),
- raw(false)
+ : data(QByteArray::fromRawData(element.getType(), qstrlen(element.getType()))),
+ raw(true)
{
if (element.getIndex() > 0) {
- data += QByteArray::number(element.getIndex());
+ this->data += QByteArray::number(element.getIndex());
+ this->raw = false;
}
}
@@ -664,8 +665,13 @@ public:
/// continuing through postfix. No bounds checking is performed when compiled in release mode.
char operator[](int index) const
{
- // FIXME overflow underflow checks?
+ if (index < 0) {
+ index = 0;
+ }
if (index >= this->data.size()) {
+ if (index - this->data.size() > this->postfix.size() - 1) {
+ index = this->postfix.size() - 1;
+ }
return this->postfix[index - this->data.size()];
}
return this->data[index];
@@ -708,7 +714,7 @@ public:
}
/// Ensure that this data is unshared, making a copy if necessary.
- void compact() const;
+ void compact();
/// Boolean conversion is the inverse of empty(), returning true if there is data in either the
/// data or postfix, and false if there is nothing in either.
diff --git a/tests/src/App/MappedName.cpp b/tests/src/App/MappedName.cpp
index feb16c63d0..99f833782c 100644
--- a/tests/src/App/MappedName.cpp
+++ b/tests/src/App/MappedName.cpp
@@ -103,6 +103,7 @@ TEST(MappedName, constructFromIndexedNameNoIndex)
// Assert
EXPECT_EQ(mappedName.dataBytes().constData(), indexedName.getType()); // shared memory
+ EXPECT_EQ(mappedName.isRaw(), true);
}
TEST(MappedName, constructFromIndexedNameWithIndex)
@@ -115,6 +116,7 @@ TEST(MappedName, constructFromIndexedNameWithIndex)
// Assert
EXPECT_NE(mappedName.dataBytes().constData(), indexedName.getType()); // NOT shared memory
+ EXPECT_EQ(mappedName.isRaw(), false);
EXPECT_EQ(mappedName.toString(), indexedName.toString());
}
@@ -534,14 +536,69 @@ TEST(MappedName, toIndexedNameInvalid)
EXPECT_TRUE(indexedName.isNull());
}
-TEST(MappedName, toPrefixedString)
+TEST(MappedName, appendToBuffer)
{
- // TODO Write this test
+ // Arrange
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ std::string buffer("STUFF");
+
+ // Act
+ mappedName.appendToBuffer(buffer);
+
+ // Assert
+ EXPECT_EQ(buffer, std::string("STUFFTESTPOSTFIXTEST"));
+
+ // Act
+ mappedName.appendToBuffer(buffer, 2, 7);
+
+ // Assert
+ EXPECT_EQ(buffer, std::string("STUFFTESTPOSTFIXTESTSTPOSTF"));
}
TEST(MappedName, appendToBufferWithPrefix)
{
- // TODO Write this test
+ // Arrange
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ std::string buffer("STUFF");
+ std::string elemMapPrefix = Data::ComplexGeoData::elementMapPrefix();
+
+ // Act
+ mappedName.appendToBufferWithPrefix(buffer);
+
+ // Assert
+ EXPECT_EQ(buffer, std::string("STUFF") + elemMapPrefix + std::string("TESTPOSTFIXTEST"));
+
+ // Arrange
+ Data::MappedName mappedName2("TEST"); //If mappedName does not have a postfix and is a valid indexedName: prefix is not added
+
+ // Act
+ mappedName2.appendToBufferWithPrefix(buffer);
+
+ // Assert
+ EXPECT_EQ(buffer, std::string("STUFF") + elemMapPrefix + std::string("TESTPOSTFIXTEST") + /*missing prefix*/ std::string("TEST"));
+}
+
+TEST(MappedName, toPrefixedString)
+{
+ // Arrange
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+ std::string buffer("STUFF");
+ std::string elemMapPrefix = Data::ComplexGeoData::elementMapPrefix();
+
+ // Act
+ buffer += mappedName.toPrefixedString();
+
+ // Assert
+ EXPECT_EQ(buffer, std::string("STUFF") + elemMapPrefix + std::string("TESTPOSTFIXTEST"));
+
+ // Arrange
+ Data::MappedName mappedName2("TEST"); //If mappedName does not have a postfix and is a valid indexedName: prefix is not added
+
+ // Act
+ buffer += mappedName2.toPrefixedString();
+
+ // Assert
+ EXPECT_EQ(buffer, std::string("STUFF") + elemMapPrefix + std::string("TESTPOSTFIXTEST") + /*missing prefix*/ std::string("TEST"));
}
TEST(MappedName, toBytes)
@@ -763,6 +820,13 @@ TEST(MappedName, startsWith)
EXPECT_EQ(mappedName.startsWith("WASD"), false);
}
-//TODO test hash function
+TEST(MappedName, hash)
+{
+ // Arrange
+ Data::MappedName mappedName(Data::MappedName("TEST"), "POSTFIXTEST");
+
+ // Act & Assert
+ EXPECT_EQ(mappedName.hash(), qHash(QByteArray("TEST"), qHash(QByteArray("POSTFIXTEST"))));
+}
// NOLINTEND(readability-magic-numbers)
From 0e64e76514b66262af636cb533e9a01445b98880 Mon Sep 17 00:00:00 2001
From: wmayer
Date: Sat, 18 Mar 2023 18:29:18 +0100
Subject: [PATCH 26/53] Gui: fix some lint warnings
---
src/Gui/PropertyPage.cpp | 51 +++++++++++++++++-----------------------
src/Gui/PropertyPage.h | 8 +++----
src/Gui/UiLoader.cpp | 4 ++--
src/Gui/UiLoader.h | 1 +
4 files changed, 29 insertions(+), 35 deletions(-)
diff --git a/src/Gui/PropertyPage.cpp b/src/Gui/PropertyPage.cpp
index 16c09c7711..a26772c23e 100644
--- a/src/Gui/PropertyPage.cpp
+++ b/src/Gui/PropertyPage.cpp
@@ -35,13 +35,9 @@
using namespace Gui::Dialog;
/** Construction */
-PropertyPage::PropertyPage(QWidget* parent) : QWidget(parent)
-{
- bChanged = false;
-}
-
-/** Destruction */
-PropertyPage::~PropertyPage()
+PropertyPage::PropertyPage(QWidget* parent)
+ : QWidget(parent)
+ , bChanged{false}
{
}
@@ -61,40 +57,40 @@ void PropertyPage::reset()
}
/** Returns whether the page was modified or not. */
-bool PropertyPage::isModified()
+bool PropertyPage::isModified() const
{
- return bChanged;
+ return bChanged;
}
/** Sets the page to be modified. */
-void PropertyPage::setModified(bool b)
+void PropertyPage::setModified(bool value)
{
- bChanged = b;
+ bChanged = value;
}
/** Applies all changes calling @ref apply() and resets the modified state. */
void PropertyPage::onApply()
{
- if (isModified())
- apply();
+ if (isModified()) {
+ apply();
+ }
- setModified(false);
+ setModified(false);
}
/** Discards all changes calling @ref cancel() and resets the modified state. */
void PropertyPage::onCancel()
{
- if (isModified())
- {
- cancel();
- setModified(false);
- }
+ if (isModified()) {
+ cancel();
+ setModified(false);
+ }
}
/** Resets to the default values. */
void PropertyPage::onReset()
{
- reset();
+ reset();
}
// ----------------------------------------------------------------
@@ -104,26 +100,23 @@ PreferencePage::PreferencePage(QWidget* parent) : QWidget(parent)
{
}
-/** Destruction */
-PreferencePage::~PreferencePage()
+void PreferencePage::changeEvent(QEvent* event)
{
-}
-
-void PreferencePage::changeEvent(QEvent *e)
-{
- QWidget::changeEvent(e);
+ QWidget::changeEvent(event);
}
// ----------------------------------------------------------------
PreferenceUiForm::PreferenceUiForm(const QString& fn, QWidget* parent)
- : PreferencePage(parent), form(nullptr)
+ : PreferencePage(parent)
+ , form(nullptr)
{
auto loader = UiLoader::newInstance();
loader->setWorkingDirectory(QFileInfo(fn).absolutePath());
QFile file(fn);
- if (file.open(QFile::ReadOnly))
+ if (file.open(QFile::ReadOnly)) {
form = loader->load(&file, this);
+ }
file.close();
if (form) {
this->setWindowTitle(form->windowTitle());
diff --git a/src/Gui/PropertyPage.h b/src/Gui/PropertyPage.h
index 4a67b21e36..1794c6800f 100644
--- a/src/Gui/PropertyPage.h
+++ b/src/Gui/PropertyPage.h
@@ -39,9 +39,9 @@ class GuiExport PropertyPage : public QWidget
public:
explicit PropertyPage(QWidget* parent = nullptr);
- ~PropertyPage() override;
+ ~PropertyPage() override = default;
- bool isModified();
+ bool isModified() const;
void setModified(bool b);
void onApply();
void onCancel();
@@ -69,14 +69,14 @@ class GuiExport PreferencePage : public QWidget
public:
explicit PreferencePage(QWidget* parent = nullptr);
- ~PreferencePage() override;
+ ~PreferencePage() override = default;
public Q_SLOTS:
virtual void loadSettings()=0;
virtual void saveSettings()=0;
protected:
- void changeEvent(QEvent *e) override = 0;
+ void changeEvent(QEvent* event) override = 0;
};
/** Subclass that embeds a form from a UI file.
diff --git a/src/Gui/UiLoader.cpp b/src/Gui/UiLoader.cpp
index 20db81ce55..3a8821017c 100644
--- a/src/Gui/UiLoader.cpp
+++ b/src/Gui/UiLoader.cpp
@@ -495,8 +495,8 @@ UiLoader::UiLoader(QObject* parent)
std::unique_ptr UiLoader::newInstance(QObject *parent)
{
- QCoreApplication *app=QCoreApplication::instance();
- QStringList libPaths= app->libraryPaths();
+ QCoreApplication* app = QCoreApplication::instance();
+ QStringList libPaths = app->libraryPaths();
app->setLibraryPaths(QStringList{}); //< backup library paths, so QUiLoader won't load plugins by default
std::unique_ptr rv{new UiLoader{parent}};
diff --git a/src/Gui/UiLoader.h b/src/Gui/UiLoader.h
index 94a7ab16dc..461fd3165b 100644
--- a/src/Gui/UiLoader.h
+++ b/src/Gui/UiLoader.h
@@ -34,6 +34,7 @@
#endif
#include
+#include
QT_BEGIN_NAMESPACE
From 21c2eb6014ce71e81734bea8b1c675b87d33802f Mon Sep 17 00:00:00 2001
From: flachyjoe
Date: Mon, 13 Mar 2023 21:39:32 +0100
Subject: [PATCH 27/53] Sketcher: Add circle to circle distance constraint
---
src/Mod/Sketcher/App/ConstraintPyImp.cpp | 17 ++-
src/Mod/Sketcher/App/PythonConverter.cpp | 4 +
src/Mod/Sketcher/App/Sketch.cpp | 30 ++++-
src/Mod/Sketcher/App/Sketch.h | 9 ++
src/Mod/Sketcher/App/planegcs/Constraints.cpp | 104 ++++++++++++++++
src/Mod/Sketcher/App/planegcs/Constraints.h | 19 ++-
src/Mod/Sketcher/App/planegcs/GCS.cpp | 8 ++
src/Mod/Sketcher/App/planegcs/GCS.h | 2 +
src/Mod/Sketcher/Gui/CommandConstraints.cpp | 114 +++++++++++++++++-
.../Gui/EditModeConstraintCoinManager.cpp | 16 ++-
src/Mod/Sketcher/Gui/Utils.cpp | 33 +++++
src/Mod/Sketcher/Gui/Utils.h | 3 +
src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 11 +-
13 files changed, 350 insertions(+), 20 deletions(-)
diff --git a/src/Mod/Sketcher/App/ConstraintPyImp.cpp b/src/Mod/Sketcher/App/ConstraintPyImp.cpp
index 457aee001e..dd33c0a5ca 100644
--- a/src/Mod/Sketcher/App/ConstraintPyImp.cpp
+++ b/src/Mod/Sketcher/App/ConstraintPyImp.cpp
@@ -224,14 +224,6 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
if (PyNumber_Check(index_or_value)) { // can be float or int
SecondIndex = any_index;
Value = PyFloat_AsDouble(index_or_value);
- //if (strcmp("Distance",ConstraintType) == 0) {
- // this->getConstraintPtr()->Type = Distance;
- // this->getConstraintPtr()->First = FirstIndex;
- // this->getConstraintPtr()->Second = SecondIndex;
- // this->getConstraintPtr()->Value = Value;
- // return 0;
- //}
- //else
if (strcmp("Angle",ConstraintType) == 0) {
if (PyObject_TypeCheck(index_or_value, &(Base::QuantityPy::Type))) {
Base::Quantity q = *(static_cast(index_or_value)->getQuantityPtr());
@@ -244,6 +236,13 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->setValue(Value);
return 0;
}
+ else if (strcmp("Distance",ConstraintType) == 0) {
+ this->getConstraintPtr()->Type = Distance;
+ this->getConstraintPtr()->First = FirstIndex;
+ this->getConstraintPtr()->Second = SecondIndex;
+ this->getConstraintPtr()->setValue(Value);
+ return 0;
+ }
else if (strcmp("DistanceX",ConstraintType) == 0) {
FirstPos = SecondIndex;
SecondIndex = -1;
@@ -481,7 +480,7 @@ std::string ConstraintPy::representation() const
case Coincident : result << "'Coincident'>";break;
case Horizontal : result << "'Horizontal' (" << getConstraintPtr()->First << ")>";break;
case Vertical : result << "'Vertical' (" << getConstraintPtr()->First << ")>";break;
- case Block : result << "'Block' (" << getConstraintPtr()->First << ")>";break;
+ case Block : result << "'Block' (" << getConstraintPtr()->First << ")>";break;
case Radius : result << "'Radius'>";break;
case Diameter : result << "'Diameter'>";break;
case Weight : result << "'Weight'>";break;
diff --git a/src/Mod/Sketcher/App/PythonConverter.cpp b/src/Mod/Sketcher/App/PythonConverter.cpp
index 53196e3bb9..e97d3c0203 100644
--- a/src/Mod/Sketcher/App/PythonConverter.cpp
+++ b/src/Mod/Sketcher/App/PythonConverter.cpp
@@ -296,6 +296,10 @@ std::string PythonConverter::process(const Sketcher::Constraint * constraint)
return boost::str(boost::format("Sketcher.Constraint('Distance', %i, %f)") %
constr->First % constr->getValue());
}
+ else if(constr->FirstPos == Sketcher::PointPos::none){
+ return boost::str(boost::format("Sketcher.Constraint('Distance', %i, %i, %f)") %
+ constr->First % constr->Second % constr->getValue());
+ }
else if(constr->SecondPos == Sketcher::PointPos::none){
return boost::str(boost::format("Sketcher.Constraint('Distance', %i, %i, %i, %f)") %
constr->First % static_cast(constr->FirstPos) % constr->Second % constr->getValue());
diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp
index fab57754e0..3a6b9e448b 100644
--- a/src/Mod/Sketcher/App/Sketch.cpp
+++ b/src/Mod/Sketcher/App/Sketch.cpp
@@ -1797,6 +1797,20 @@ int Sketch::addConstraint(const Constraint *constraint)
constraint->Second,constraint->SecondPos,
c.value,c.driving);
}
+ else if (constraint->FirstPos == PointPos::none &&
+ constraint->SecondPos == PointPos::none &&
+ constraint->Second != GeoEnum::GeoUndef &&
+ constraint->Third == GeoEnum::GeoUndef) { // circle to circle, circle to arc, etc.
+
+ c.value = new double(constraint->getValue());
+ if(c.driving)
+ FixParameters.push_back(c.value);
+ else {
+ Parameters.push_back(c.value);
+ DrivenParameters.push_back(c.value);
+ }
+ rtn = addDistanceConstraint(constraint->First, constraint->Second,c.value,c.driving);
+ }
else if (constraint->Second != GeoEnum::GeoUndef) {
if (constraint->FirstPos != PointPos::none) { // point to line distance
c.value = new double(constraint->getValue());
@@ -1806,8 +1820,7 @@ int Sketch::addConstraint(const Constraint *constraint)
Parameters.push_back(c.value);
DrivenParameters.push_back(c.value);
}
- rtn = addDistanceConstraint(constraint->First,constraint->FirstPos,
- constraint->Second,c.value,c.driving);
+ rtn = addDistanceConstraint(constraint->First,constraint->FirstPos,constraint->Second,c.value,c.driving);
}
}
else {// line length
@@ -2740,6 +2753,19 @@ int Sketch::addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, PointPo
return -1;
}
+// circle-circle offset distance constraint
+int Sketch::addDistanceConstraint(int geoId1, int geoId2, double * value, bool driving)
+{
+ if ((Geoms[geoId1].type == Circle) && (Geoms[geoId2].type == Circle)) {
+ GCS::Circle &c1 = Circles[Geoms[geoId1].index];
+ GCS::Circle &c2 = Circles[Geoms[geoId2].index];
+ int tag = ++ConstraintsCounter;
+ GCSsys.addConstraintC2CDistance(c1, c2, value, tag, driving);
+ return ConstraintsCounter;
+ }
+ return -1;
+}
+
int Sketch::addRadiusConstraint(int geoId, double * value, bool driving)
{
geoId = checkGeoId(geoId);
diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h
index 6987e55dd2..69e6743c57 100644
--- a/src/Mod/Sketcher/App/Sketch.h
+++ b/src/Mod/Sketcher/App/Sketch.h
@@ -276,6 +276,15 @@ public:
* Parameters array, as the case may be.
*/
int addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double * value, bool driving = true);
+ /**
+ * add a length or distance constraint
+ *
+ * double * value is a pointer to double allocated in the heap, containing the
+ * constraint value and already inserted into either the FixParameters or
+ * Parameters array, as the case may be.
+ */
+ int addDistanceConstraint(int geoId1, int geoId2, double * value, bool driving = true);
+
/// add a parallel constraint between two lines
int addParallelConstraint(int geoId1, int geoId2);
/// add a perpendicular constraint between two lines
diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.cpp b/src/Mod/Sketcher/App/planegcs/Constraints.cpp
index 32c48e147f..c04e54ef01 100644
--- a/src/Mod/Sketcher/App/planegcs/Constraints.cpp
+++ b/src/Mod/Sketcher/App/planegcs/Constraints.cpp
@@ -2585,5 +2585,109 @@ double ConstraintEqualLineLength::grad(double *param)
return deriv*scale;
}
+// ConstraintC2CDistance
+ConstraintC2CDistance::ConstraintC2CDistance(Circle &c1, Circle &c2, double *d)
+{
+ this->d = d;
+ pvec.push_back(d);
+
+ this->c1 = c1;
+ this->c1.PushOwnParams(pvec);
+
+ this->c2 = c2;
+ this->c2.PushOwnParams(pvec);
+
+ origpvec = pvec;
+ pvecChangedFlag = true;
+ rescale();
+}
+
+void ConstraintC2CDistance::ReconstructGeomPointers()
+{
+ int i=0;
+ i++; // skip the first parameter as there is the inline function distance for it
+ c1.ReconstructOnNewPvec(pvec, i);
+ c2.ReconstructOnNewPvec(pvec, i);
+ pvecChangedFlag = false;
+}
+
+ConstraintType ConstraintC2CDistance::getTypeId()
+{
+ return C2CDistance;
+}
+
+void ConstraintC2CDistance::rescale(double coef)
+{
+ scale = coef * 1;
+}
+
+void ConstraintC2CDistance::errorgrad(double *err, double *grad, double *param)
+{
+ if (pvecChangedFlag) ReconstructGeomPointers();
+
+ DeriVector2 ct1 (c1.center, param);
+ DeriVector2 ct2 (c2.center, param);
+
+ DeriVector2 vector_ct12 = ct1.subtr(ct2);
+
+ double length_ct12, dlength_ct12;
+ length_ct12 = vector_ct12.length(dlength_ct12);
+
+ // outer case (defined as the centers of the circles are outside the center of the other circles)
+ // it may well be that the circles intersect.
+ if( length_ct12 >= *c1.rad &&
+ length_ct12 >= *c2.rad ) {
+ if (err) {
+ *err = length_ct12 - (*c2.rad + *c1.rad + *distance());
+ }
+ else if (grad) {
+ double drad = (param == c2.rad || param == c1.rad || param == distance())?-1.0:0.0;
+ *grad = dlength_ct12 + drad;
+ }
+ }
+ else {
+ double * bigradius = (*c1.rad >= *c2.rad)?c1.rad:c2.rad;
+ double * smallradius = (*c1.rad >= *c2.rad)?c2.rad:c1.rad;
+
+ double smallspan = *smallradius + length_ct12 + *distance();
+
+ if (err) {
+ *err = *bigradius - smallspan;
+ }
+ else if (grad) {
+ double drad = 0.0;
+
+ if(param == bigradius) {
+ drad = 1.0;
+ }
+ else if(param == smallradius) {
+ drad = -1.0;
+ }
+ else if(param == distance()) {
+ drad = (*distance()<0.)?1.0:-1.0;
+ }
+
+ *grad = -dlength_ct12 + drad;
+ }
+ }
+}
+
+double ConstraintC2CDistance::error()
+{
+ double err;
+ errorgrad(&err,nullptr,nullptr);
+ return scale * err;
+}
+
+double ConstraintC2CDistance::grad(double *param)
+{
+ if ( findParamInPvec(param) == -1 )
+ return 0.0;
+
+ double deriv;
+ errorgrad(nullptr, &deriv, param);
+
+ return deriv*scale;
+}
} //namespace GCS
diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.h b/src/Mod/Sketcher/App/planegcs/Constraints.h
index 0ff4b40349..957e021a0b 100644
--- a/src/Mod/Sketcher/App/planegcs/Constraints.h
+++ b/src/Mod/Sketcher/App/planegcs/Constraints.h
@@ -72,7 +72,8 @@ namespace GCS
CenterOfGravity = 26,
WeightedLinearCombination = 27,
SlopeAtBSplineKnot = 28,
- PointOnBSpline = 29
+ PointOnBSpline = 29,
+ C2CDistance = 30
};
enum InternalAlignmentType {
@@ -745,6 +746,22 @@ namespace GCS
double grad(double *) override;
};
+ class ConstraintC2CDistance : public Constraint
+ {
+ private:
+ Circle c1;
+ Circle c2;
+ double *d;
+ inline double* distance() { return pvec[0]; }
+ void ReconstructGeomPointers(); //writes pointers in pvec to the parameters of c1, c2
+ void errorgrad(double* err, double* grad, double *param); //error and gradient combined. Values are returned through pointers.
+ public:
+ ConstraintC2CDistance(Circle &c1, Circle &c2, double *d);
+ ConstraintType getTypeId() override;
+ void rescale(double coef=1.) override;
+ double error() override;
+ double grad(double *) override;
+ };
} //namespace GCS
diff --git a/src/Mod/Sketcher/App/planegcs/GCS.cpp b/src/Mod/Sketcher/App/planegcs/GCS.cpp
index f80d5e03bc..0ee8e39366 100644
--- a/src/Mod/Sketcher/App/planegcs/GCS.cpp
+++ b/src/Mod/Sketcher/App/planegcs/GCS.cpp
@@ -817,6 +817,14 @@ int System::addConstraintTangentAtBSplineKnot(BSpline &b, Line &l, unsigned int
return addConstraint(constr);
}
+int System::addConstraintC2CDistance(Circle &c1, Circle &c2, double *dist, int tagId, bool driving)
+{
+ Constraint *constr = new ConstraintC2CDistance(c1, c2, dist);
+ constr->setTag(tagId);
+ constr->setDriving(driving);
+ return addConstraint(constr);
+}
+
// derived constraints
int System::addConstraintP2PCoincident(Point &p1, Point &p2, int tagId, bool driving)
diff --git a/src/Mod/Sketcher/App/planegcs/GCS.h b/src/Mod/Sketcher/App/planegcs/GCS.h
index 29e9162f18..fe11547151 100644
--- a/src/Mod/Sketcher/App/planegcs/GCS.h
+++ b/src/Mod/Sketcher/App/planegcs/GCS.h
@@ -315,6 +315,8 @@ namespace GCS
bool flipn1, bool flipn2,
int tagId, bool driving = true);
+ int addConstraintC2CDistance(Circle &c1, Circle &c2, double *dist, int tagId, bool driving = true);
+
// internal alignment constraints
int addConstraintInternalAlignmentPoint2Ellipse(Ellipse &e, Point &p1, InternalAlignmentType alignmentType, int tagId=0, bool driving = true);
int addConstraintInternalAlignmentEllipseMajorDiameter(Ellipse &e, Point &p1, Point &p2, int tagId=0, bool driving = true);
diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp
index a1dd198a80..7f878661f8 100644
--- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp
+++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp
@@ -2150,7 +2150,7 @@ CmdSketcherConstrainDistance::CmdSketcherConstrainDistance()
sAppModule = "Sketcher";
sGroup = "Sketcher";
sMenuText = QT_TR_NOOP("Constrain distance");
- sToolTipText = QT_TR_NOOP("Fix a length of a line or the distance between a line and a vertex");
+ sToolTipText = QT_TR_NOOP("Fix a length of a line or the distance between a line and a vertex or between two circles");
sWhatsThis = "Sketcher_ConstrainDistance";
sStatusTip = sToolTipText;
sPixmap = "Constraint_Length";
@@ -2160,7 +2160,8 @@ CmdSketcherConstrainDistance::CmdSketcherConstrainDistance()
allowedSelSequences = {{SelVertex, SelVertexOrRoot}, {SelRoot, SelVertex},
{SelEdge}, {SelExternalEdge},
{SelVertex, SelEdgeOrAxis}, {SelRoot, SelEdge},
- {SelVertex, SelExternalEdge}, {SelRoot, SelExternalEdge}};
+ {SelVertex, SelExternalEdge}, {SelRoot, SelExternalEdge},
+ {SelEdge, SelEdge}};
}
void CmdSketcherConstrainDistance::activated(int iMsg)
@@ -2289,6 +2290,55 @@ void CmdSketcherConstrainDistance::activated(int iMsg)
return;
}
}
+ else if (isEdge(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) { // circle to circle distance
+ const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
+ const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
+ if (geom1->getTypeId() == Part::GeomCircle::getClassTypeId()
+ && geom2->getTypeId() == Part::GeomCircle::getClassTypeId() ) {
+ auto circleSeg1 = static_cast(geom1);
+ double radius1 = circleSeg1->getRadius();
+ Base::Vector3d center1 = circleSeg1->getCenter();
+
+ auto circleSeg2 = static_cast(geom2);
+ double radius2 = circleSeg2->getRadius();
+ Base::Vector3d center2 = circleSeg2->getCenter();
+
+ double ActDist = 0.;
+
+ Base::Vector3d intercenter = center1 - center2;
+ double intercenterdistance = intercenter.Length();
+
+ if( intercenterdistance >= radius1 &&
+ intercenterdistance >= radius2 ) {
+
+ ActDist = intercenterdistance - radius1 - radius2;
+ }
+ else {
+ double bigradius = std::max(radius1,radius2);
+ double smallradius = std::min(radius1,radius2);
+
+ ActDist = bigradius - smallradius - intercenterdistance;
+ }
+
+ openCommand(QT_TRANSLATE_NOOP("Command", "Add circle to circle distance constraint"));
+ Gui::cmdAppObjectArgs(selection[0].getObject(),
+ "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f)) ",
+ GeoId1,GeoId2,ActDist);
+
+ if (arebothpointsorsegmentsfixed || constraintCreationMode==Reference) { // it is a constraint on a external line, make it non-driving
+ const std::vector &ConStr = Obj->Constraints.getValues();
+
+ Gui::cmdAppObjectArgs(selection[0].getObject(),
+ "setDriving(%i,%s)",
+ ConStr.size()-1,"False");
+ finishDatumConstraint (this, Obj, false);
+ }
+ else
+ finishDatumConstraint (this, Obj, true);
+
+ return;
+ }
+ }
else if (isEdge(GeoId1,PosId1)) { // line length
if (GeoId1 < 0 && GeoId1 >= Sketcher::GeoEnum::VAxis) {
Gui::TranslatedNotification(Obj,
@@ -2327,7 +2377,7 @@ void CmdSketcherConstrainDistance::activated(int iMsg)
Gui::TranslatedNotification(Obj,
QObject::tr("Wrong selection"),
- QObject::tr("Select exactly one line or one point and one line or two points from the sketch."));
+ QObject::tr("Select exactly one line or one point and one line or two points or two circles from the sketch."));
return;
}
@@ -2416,6 +2466,9 @@ void CmdSketcherConstrainDistance::applyConstraint(std::vector &selSe
else
finishDatumConstraint (this, Obj, true);
}
+ else if (geom->getTypeId() == Part::GeomCircle::getClassTypeId()) {
+ // allow this selection but do nothing as it needs 2 circles
+ }
else {
Gui::TranslatedNotification(Obj,
QObject::tr("Wrong selection"),
@@ -2460,6 +2513,61 @@ void CmdSketcherConstrainDistance::applyConstraint(std::vector &selSe
return;
}
+ case 8: // {SelEdge, SelEdge}
+ {
+ GeoId1 = selSeq.at(0).GeoId; GeoId2 = selSeq.at(1).GeoId;
+ const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
+ const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
+ if (geom1->getTypeId() == Part::GeomCircle::getClassTypeId()
+ && geom2->getTypeId() == Part::GeomCircle::getClassTypeId() ) { // circle to circle distance
+ auto circleSeg1 = static_cast(geom1);
+ double radius1 = circleSeg1->getRadius();
+ Base::Vector3d center1 = circleSeg1->getCenter();
+
+ auto circleSeg2 = static_cast(geom2);
+ double radius2 = circleSeg2->getRadius();
+ Base::Vector3d center2 = circleSeg2->getCenter();
+
+ double ActDist = 0.;
+
+ Base::Vector3d intercenter = center1 - center2;
+ double intercenterdistance = intercenter.Length();
+
+ if( intercenterdistance >= radius1 &&
+ intercenterdistance >= radius2 ) {
+
+ ActDist = intercenterdistance - radius1 - radius2;
+ }
+ else {
+ double bigradius = std::max(radius1,radius2);
+ double smallradius = std::min(radius1,radius2);
+
+ ActDist = bigradius - smallradius - intercenterdistance;
+ }
+
+ openCommand(QT_TRANSLATE_NOOP("Command", "Add circle to circle distance constraint"));
+ Gui::cmdAppObjectArgs(Obj,
+ "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f)) ",
+ GeoId1,GeoId2,ActDist);
+
+ if (arebothpointsorsegmentsfixed || constraintCreationMode==Reference) { // it is a constraint on a external line, make it non-driving
+ const std::vector &ConStr = Obj->Constraints.getValues();
+
+ Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)",
+ ConStr.size()-1,"False");
+ finishDatumConstraint (this, Obj, false);
+ }
+ else
+ finishDatumConstraint (this, Obj, true);
+
+ return;
+ } else {
+ Gui::TranslatedNotification(Obj,
+ QObject::tr("Wrong selection"),
+ QObject::tr("Select exactly one line or one point and one line or two points or two circles from the sketch."));
+
+ }
+ }
default:
break;
}
diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp
index c365b2cede..ffeb8283ee 100644
--- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp
+++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp
@@ -62,6 +62,7 @@
#include "SoZoomTranslation.h"
#include "ViewProviderSketch.h"
#include "ViewProviderSketchCoinAttorney.h"
+#include "Utils.h"
using namespace SketcherGui;
@@ -654,24 +655,33 @@ Restart:
if (Constr->SecondPos != Sketcher::PointPos::none) { // point to point distance
pnt1 = geolistfacade.getPoint(Constr->First, Constr->FirstPos);
pnt2 = geolistfacade.getPoint(Constr->Second, Constr->SecondPos);
- } else if (Constr->Second != GeoEnum::GeoUndef) { // point to line distance
+ } else if (Constr->Second != GeoEnum::GeoUndef) {
pnt1 = geolistfacade.getPoint(Constr->First, Constr->FirstPos);
const Part::Geometry *geo = geolistfacade.getGeometryFromGeoId(Constr->Second);
- if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
+ if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { // point to line distance
const Part::GeomLineSegment *lineSeg = static_cast(geo);
Base::Vector3d l2p1 = lineSeg->getStartPoint();
Base::Vector3d l2p2 = lineSeg->getEndPoint();
// calculate the projection of p1 onto line2
pnt2.ProjectToLine(pnt1-l2p1, l2p2-l2p1);
pnt2 += pnt1;
+
+ } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { // circle to circle distance
+ const Part::Geometry *geo1 = geolistfacade.getGeometryFromGeoId(Constr->First);
+ if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) {
+ const Part::GeomCircle *circleSeg1 = static_cast(geo1);
+ auto circleSeg2 = static_cast(geo);
+ GetCirclesMinimalDistance(circleSeg1, circleSeg2, pnt1, pnt2);
+ }
+
} else
break;
} else if (Constr->FirstPos != Sketcher::PointPos::none) {
pnt2 = geolistfacade.getPoint(Constr->First, Constr->FirstPos);
} else if (Constr->First != GeoEnum::GeoUndef) {
const Part::Geometry *geo = geolistfacade.getGeometryFromGeoId(Constr->First);
- if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
+ if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { // segment distance
const Part::GeomLineSegment *lineSeg = static_cast(geo);
pnt1 = lineSeg->getStartPoint();
pnt2 = lineSeg->getEndPoint();
diff --git a/src/Mod/Sketcher/Gui/Utils.cpp b/src/Mod/Sketcher/Gui/Utils.cpp
index d4d92316da..daf6c19b3f 100644
--- a/src/Mod/Sketcher/Gui/Utils.cpp
+++ b/src/Mod/Sketcher/Gui/Utils.cpp
@@ -327,6 +327,39 @@ double SketcherGui::GetPointAngle(const Base::Vector2d& p1, const Base::Vector2d
return dY >= 0 ? atan2(dY, dX) : atan2(dY, dX) + 2 * M_PI;
}
+// Set the two points on circles at minimal distance
+// in concentric case set points on relative X axis
+void SketcherGui::GetCirclesMinimalDistance(const Part::GeomCircle *circle1, const Part::GeomCircle *circle2, Base::Vector3d &point1, Base::Vector3d &point2)
+{
+ double radius1 = circle1->getRadius();
+ double radius2 = circle2->getRadius();
+
+ point1 = circle1->getCenter();
+ point2 = circle2->getCenter();
+
+ Base::Vector3d v = point2 - point1;
+ double length = v.Length();
+
+ if (length == 0) { //concentric case
+ point1.x += radius1;
+ point2.x += radius2;
+ } else {
+ v = v.Normalize();
+ if (length <= std::max(radius1, radius2)){ //inner case
+ if (radius1 > radius2){
+ point1 += v * radius1;
+ point2 += v * radius2;
+ } else {
+ point1 += -v * radius1;
+ point2 += -v * radius2;
+ }
+ } else { //outer case
+ point1 += v * radius1;
+ point2 += -v * radius2;
+ }
+ }
+}
+
void SketcherGui::ActivateHandler(Gui::Document* doc, DrawSketchHandler* handler)
{
std::unique_ptr ptr(handler);
diff --git a/src/Mod/Sketcher/Gui/Utils.h b/src/Mod/Sketcher/Gui/Utils.h
index 547246a6a2..662d9f941f 100644
--- a/src/Mod/Sketcher/Gui/Utils.h
+++ b/src/Mod/Sketcher/Gui/Utils.h
@@ -119,6 +119,9 @@ inline bool isEdge(int GeoId, Sketcher::PointPos PosId)
// Return counter-clockwise angle from horizontal out of p1 to p2 in radians.
double GetPointAngle (const Base::Vector2d &p1, const Base::Vector2d &p2);
+// Set the two points on circles at minimal distance
+void GetCirclesMinimalDistance(const Part::GeomCircle *circle1, const Part::GeomCircle *circle2, Base::Vector3d &point1, Base::Vector3d &point2);
+
void ActivateHandler(Gui::Document *doc, DrawSketchHandler *handler);
/// Returns if a sketch is in edit mode
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
index 37fda52260..62d81b0f8c 100644
--- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
+++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
@@ -1416,16 +1416,23 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2d &toPo
if (Constr->SecondPos != Sketcher::PointPos::none) { // point to point distance
p1 = getSolvedSketch().getPoint(Constr->First, Constr->FirstPos);
p2 = getSolvedSketch().getPoint(Constr->Second, Constr->SecondPos);
- } else if (Constr->Second != GeoEnum::GeoUndef) { // point to line distance
+ } else if (Constr->Second != GeoEnum::GeoUndef) {
p1 = getSolvedSketch().getPoint(Constr->First, Constr->FirstPos);
const Part::Geometry *geo = GeoList::getGeometryFromGeoId (geomlist, Constr->Second);
- if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
+ if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { // point to line distance
const Part::GeomLineSegment *lineSeg = static_cast(geo);
Base::Vector3d l2p1 = lineSeg->getStartPoint();
Base::Vector3d l2p2 = lineSeg->getEndPoint();
// calculate the projection of p1 onto line2
p2.ProjectToLine(p1-l2p1, l2p2-l2p1);
p2 += p1;
+ } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { // circle to circle distance
+ const Part::Geometry *geo1 = GeoList::getGeometryFromGeoId (geomlist, Constr->First);
+ if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) {
+ const Part::GeomCircle *circleSeg1 = static_cast(geo1);
+ const Part::GeomCircle *circleSeg2 = static_cast(geo);
+ GetCirclesMinimalDistance(circleSeg1, circleSeg2, p1, p2);
+ }
} else
return;
} else if (Constr->FirstPos != Sketcher::PointPos::none) {
From 0f274c2e071c3545dea0ee3d312d264f5807dbce Mon Sep 17 00:00:00 2001
From: Paddle
Date: Wed, 15 Mar 2023 11:08:54 +0100
Subject: [PATCH 28/53] Sketcher: Snap: initial implementation: - creation of
SnapManager class. - Move grid snap to this new class. - Add snap to object.
- Add snap at angle.
---
src/Mod/Sketcher/Gui/CMakeLists.txt | 2 +
src/Mod/Sketcher/Gui/Command.cpp | 275 +++++++++++--
src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 2 +
.../Resources/icons/general/Sketcher_Snap.svg | 386 ++++++++++++++++++
.../general/Sketcher_Snap_Deactivated.svg | 377 +++++++++++++++++
src/Mod/Sketcher/Gui/SnapManager.cpp | 364 +++++++++++++++++
src/Mod/Sketcher/Gui/SnapManager.h | 125 ++++++
src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 43 +-
src/Mod/Sketcher/Gui/ViewProviderSketch.h | 22 +-
src/Mod/Sketcher/Gui/Workbench.cpp | 3 +-
10 files changed, 1526 insertions(+), 73 deletions(-)
create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap.svg
create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap_Deactivated.svg
create mode 100644 src/Mod/Sketcher/Gui/SnapManager.cpp
create mode 100644 src/Mod/Sketcher/Gui/SnapManager.h
diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt
index 3320d06710..5de66a2124 100644
--- a/src/Mod/Sketcher/Gui/CMakeLists.txt
+++ b/src/Mod/Sketcher/Gui/CMakeLists.txt
@@ -144,6 +144,8 @@ SET(SketcherGui_SRCS
SketchRectangularArrayDialog.cpp
SketcherRegularPolygonDialog.h
SketcherRegularPolygonDialog.cpp
+ SnapManager.cpp
+ SnapManager.h
TaskDlgEditSketch.cpp
TaskDlgEditSketch.h
ViewProviderPython.cpp
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index 1af8fcbeb4..6de8a85aa8 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -995,7 +995,7 @@ public:
updateCheckBox(checkbox, propvalue);
};
- updateCheckBox(gridSnap, sketchView->getSnapMode() == SnapMode::SnapToGrid);
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
updateCheckBoxFromProperty(gridAutoSpacing, sketchView->GridAuto);
@@ -1005,10 +1005,6 @@ public:
void languageChange()
{
- gridSnap->setText(tr("Grid Snap"));
- gridSnap->setToolTip(tr("New points will snap to the nearest grid line.\nPoints must be set closer than a fifth of the grid spacing to a grid line to snap."));
- gridSnap->setStatusTip(gridSnap->toolTip());
-
gridAutoSpacing->setText(tr("Grid Auto Spacing"));
gridAutoSpacing->setToolTip(tr("Resize grid automatically depending on zoom."));
gridAutoSpacing->setStatusTip(gridAutoSpacing->toolTip());
@@ -1020,8 +1016,6 @@ public:
protected:
QWidget* createWidget(QWidget* parent) override
{
- gridSnap = new QCheckBox();
-
gridAutoSpacing = new QCheckBox();
sizeLabel = new QLabel();
@@ -1034,27 +1028,12 @@ protected:
QWidget* gridSizeW = new QWidget(parent);
auto* layout = new QGridLayout(gridSizeW);
- layout->addWidget(gridSnap, 0, 0);
- layout->addWidget(gridAutoSpacing, 1, 0);
- layout->addWidget(sizeLabel, 2, 0);
- layout->addWidget(gridSizeBox, 2, 1);
+ layout->addWidget(gridAutoSpacing, 0, 0, 1, 2);
+ layout->addWidget(sizeLabel, 1, 0);
+ layout->addWidget(gridSizeBox, 1, 1);
languageChange();
- QObject::connect(gridSnap, &QCheckBox::stateChanged, [this](int state) {
- auto* sketchView = getView();
-
- if(sketchView) {
- if(state == Qt::Checked) {
- sketchView->setSnapMode(SnapMode::SnapToGrid);
- }
- else {
- sketchView->setSnapMode(SnapMode::None);
- }
- }
- });
-
-
QObject::connect(gridAutoSpacing, &QCheckBox::stateChanged, [this](int state) {
auto* sketchView = getView();
@@ -1086,7 +1065,6 @@ private:
}
private:
- QCheckBox * gridSnap;
QCheckBox * gridAutoSpacing;
QLabel * sizeLabel;
Gui::QuantitySpinBox * gridSizeBox;
@@ -1213,6 +1191,250 @@ bool CmdSketcherGrid::isActive()
return false;
}
+/* Snap tool */
+class SnapSpaceAction : public QWidgetAction
+{
+public:
+ SnapSpaceAction(QObject* parent) : QWidgetAction(parent) {
+ setEnabled(false);
+ }
+
+ void updateWidget() {
+
+ auto* sketchView = getView();
+
+ if (sketchView) {
+
+ auto updateCheckBox = [](QCheckBox* checkbox, bool value) {
+ auto checked = checkbox->checkState() == Qt::Checked;
+
+ if (value != checked) {
+ const QSignalBlocker blocker(checkbox);
+ checkbox->setChecked(value);
+ }
+ };
+
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+
+ updateCheckBox(snapToObjects, hGrp->GetBool("SnapToObjects", true));
+
+ updateCheckBox(snapToGrid, hGrp->GetBool("SnapToGrid", false));
+
+ snapAngle->setValue(hGrp->GetFloat("SnapAngle", 5.0));
+
+ bool snapActivated = hGrp->GetBool("Snap", true);
+ snapToObjects->setEnabled(snapActivated);
+ snapToGrid->setEnabled(snapActivated);
+ angleLabel->setEnabled(snapActivated);
+ snapAngle->setEnabled(snapActivated);
+ }
+ }
+
+ void languageChange()
+ {
+
+ snapToObjects->setText(tr("Snap to objects"));
+ snapToObjects->setToolTip(tr("New points will snap to the currently preselected object. It will also snap to the middle of lines and arcs."));
+ snapToObjects->setStatusTip(snapToObjects->toolTip());
+
+ snapToGrid->setText(tr("Snap to Grid"));
+ snapToGrid->setToolTip(tr("New points will snap to the nearest grid line.\nPoints must be set closer than a fifth of the grid spacing to a grid line to snap."));
+ snapToGrid->setStatusTip(snapToGrid->toolTip());
+
+ angleLabel->setText(tr("Snap angle"));
+ snapAngle->setToolTip(tr("Angular step for tools that use 'Snap at Angle' (line for instance). Hold CTRL to enable 'Snap at Angle'. The angle start from the East axis (horizontal right)"));
+ }
+
+protected:
+ QWidget* createWidget(QWidget* parent) override
+ {
+ snapToObjects = new QCheckBox();
+
+ snapToGrid = new QCheckBox();
+
+ angleLabel = new QLabel();
+
+ snapAngle = new Gui::QuantitySpinBox();
+ snapAngle->setProperty("unit", QVariant(QStringLiteral("deg")));
+ snapAngle->setObjectName(QStringLiteral("snapAngle"));
+ snapAngle->setMaximum(99999999.0);
+ snapAngle->setMinimum(0);
+
+ QWidget* snapW = new QWidget(parent);
+ auto* layout = new QGridLayout(snapW);
+ layout->addWidget(snapToGrid, 0, 0, 1, 2);
+ layout->addWidget(snapToObjects, 1, 0, 1, 2);
+ layout->addWidget(angleLabel, 2, 0);
+ layout->addWidget(snapAngle, 2, 1);
+
+ languageChange();
+
+ QObject::connect(snapToObjects, &QCheckBox::stateChanged, [this](int state) {
+ auto* sketchView = getView();
+
+ if (sketchView) {
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ hGrp->SetBool("SnapToObjects", state == Qt::Checked);
+ }
+ });
+
+ QObject::connect(snapToGrid, &QCheckBox::stateChanged, [this](int state) {
+ auto* sketchView = getView();
+ if (sketchView) {
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ hGrp->SetBool("SnapToGrid", state == Qt::Checked);
+ }
+ });
+
+ QObject::connect(snapAngle, qOverload(&Gui::QuantitySpinBox::valueChanged), [this](double val) {
+ auto* sketchView = getView();
+
+ if (sketchView) {
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ hGrp->SetFloat("SnapAngle", val);
+ }
+ });
+
+ return snapW;
+ }
+
+private:
+ ViewProviderSketch* getView() {
+ Gui::Document* doc = Gui::Application::Instance->activeDocument();
+
+ if (doc) {
+ return dynamic_cast(doc->getInEdit());
+ }
+
+ return nullptr;
+ }
+
+private:
+ QCheckBox* snapToObjects;
+ QCheckBox* snapToGrid;
+ QLabel* angleLabel;
+ Gui::QuantitySpinBox* snapAngle;
+};
+
+class CmdSketcherSnap : public Gui::Command
+{
+public:
+ CmdSketcherSnap();
+ virtual ~CmdSketcherSnap() {}
+ virtual const char* className() const
+ {
+ return "CmdSketcherSnap";
+ }
+ virtual void languageChange();
+protected:
+ virtual void activated(int iMsg);
+ virtual bool isActive(void);
+ virtual Gui::Action* createAction(void);
+private:
+ void updateIcon(bool value);
+
+ CmdSketcherSnap(const CmdSketcherSnap&) = delete;
+ CmdSketcherSnap(CmdSketcherSnap&&) = delete;
+ CmdSketcherSnap& operator= (const CmdSketcherSnap&) = delete;
+ CmdSketcherSnap& operator= (CmdSketcherSnap&&) = delete;
+};
+
+CmdSketcherSnap::CmdSketcherSnap()
+ : Command("Sketcher_Snap")
+{
+ sAppModule = "Sketcher";
+ sGroup = "Sketcher";
+ sMenuText = QT_TR_NOOP("Toggle Snap");
+ sToolTipText = QT_TR_NOOP("Toggle all snapping functionalities. In the menu you can toggle individually 'Snap to Grid', 'Snap to Objects' and further snap settings");
+ sWhatsThis = "Sketcher_Snap";
+ sStatusTip = sToolTipText;
+ eType = 0;
+}
+
+void CmdSketcherSnap::updateIcon(bool value)
+{
+ static QIcon active = Gui::BitmapFactory().iconFromTheme("Sketcher_Snap");
+ static QIcon inactive = Gui::BitmapFactory().iconFromTheme("Sketcher_Snap_Deactivated");
+
+ auto* pcAction = qobject_cast(getAction());
+ pcAction->setIcon(value ? active : inactive);
+}
+
+void CmdSketcherSnap::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ bool value = !hGrp->GetBool("Snap", true);
+
+ hGrp->SetBool("Snap", value);
+
+ updateIcon(value);
+
+ //Update the widget :
+ if (!_pcAction)
+ return;
+
+ Gui::ActionGroup* pcAction = qobject_cast(_pcAction);
+ QList a = pcAction->actions();
+
+ auto* ssa = static_cast(a[0]);
+ ssa->updateWidget();
+}
+
+Gui::Action* CmdSketcherSnap::createAction()
+{
+ auto* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow());
+ pcAction->setDropDownMenu(true);
+ pcAction->setExclusive(false);
+ applyCommandData(this->className(), pcAction);
+
+ SnapSpaceAction* ssa = new SnapSpaceAction(pcAction);
+ pcAction->addAction(ssa);
+
+ _pcAction = pcAction;
+
+ QObject::connect(pcAction, &Gui::ActionGroup::aboutToShow, [ssa](QMenu* menu) {
+ Q_UNUSED(menu)
+ ssa->updateWidget();
+ });
+
+ // set the right pixmap
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ updateIcon(hGrp->GetBool("Snap", true));
+
+ return pcAction;
+}
+
+void CmdSketcherSnap::languageChange()
+{
+ Command::languageChange();
+
+ if (!_pcAction)
+ return;
+
+ Gui::ActionGroup* pcAction = qobject_cast(_pcAction);
+ QList a = pcAction->actions();
+
+ auto* ssa = static_cast(a[0]);
+ ssa->languageChange();
+}
+
+bool CmdSketcherSnap::isActive()
+{
+ auto* vp = getInactiveHandlerEditModeSketchViewProvider();
+
+ if (vp) {
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ bool value = hGrp->GetBool("Snap", true);
+
+ updateIcon(value);
+
+ return true;
+ }
+
+ return false;
+}
void CreateSketcherCommands()
{
@@ -1230,4 +1452,5 @@ void CreateSketcherCommands()
rcCmdMgr.addCommand(new CmdSketcherMergeSketches());
rcCmdMgr.addCommand(new CmdSketcherViewSection());
rcCmdMgr.addCommand(new CmdSketcherGrid());
+ rcCmdMgr.addCommand(new CmdSketcherSnap());
}
diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
index 207021d7e5..8786bcdf87 100644
--- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
+++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
@@ -106,6 +106,8 @@
icons/general/Sketcher_ViewSketch.svg
icons/general/Sketcher_GridToggle.svg
icons/general/Sketcher_GridToggle_Deactivated.svg
+ icons/general/Sketcher_Snap.svg
+ icons/general/Sketcher_Snap_Deactivated.svg
icons/geometry/Sketcher_AlterFillet.svg
diff --git a/src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap.svg b/src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap.svg
new file mode 100644
index 0000000000..612a8fac4d
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap.svg
@@ -0,0 +1,386 @@
+
+
diff --git a/src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap_Deactivated.svg b/src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap_Deactivated.svg
new file mode 100644
index 0000000000..833108cf87
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap_Deactivated.svg
@@ -0,0 +1,377 @@
+
+
diff --git a/src/Mod/Sketcher/Gui/SnapManager.cpp b/src/Mod/Sketcher/Gui/SnapManager.cpp
new file mode 100644
index 0000000000..56638de4bc
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/SnapManager.cpp
@@ -0,0 +1,364 @@
+/***************************************************************************
+ * Copyright (c) 2023 Pierre-Louis Boyer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#endif // #ifndef _PreComp_
+
+#include
+
+#include "SnapManager.h"
+#include "ViewProviderSketch.h"
+
+
+using namespace SketcherGui;
+using namespace Sketcher;
+
+/************************************ Attorney *******************************************/
+
+inline int ViewProviderSketchSnapAttorney::getPreselectPoint(const ViewProviderSketch& vp)
+{
+ return vp.getPreselectPoint();
+}
+
+inline int ViewProviderSketchSnapAttorney::getPreselectCross(const ViewProviderSketch& vp)
+{
+ return vp.getPreselectCross();
+}
+
+inline int ViewProviderSketchSnapAttorney::getPreselectCurve(const ViewProviderSketch& vp)
+{
+ return vp.getPreselectCurve();
+}
+
+/**************************** ParameterObserver nested class *****************************/
+SnapManager::ParameterObserver::ParameterObserver(SnapManager& client) : client(client)
+{
+ initParameters();
+ subscribeToParameters();
+}
+
+SnapManager::ParameterObserver::~ParameterObserver()
+{
+ unsubscribeToParameters();
+}
+
+void SnapManager::ParameterObserver::initParameters()
+{
+ // static map to avoid substantial if/else branching
+ //
+ // key->first => String of parameter,
+ // key->second => Update function to be called for the parameter,
+ str2updatefunction = {
+ {"Snap",
+ [this](const std::string& param) {updateSnapParameter(param); }},
+ {"SnapToObjects",
+ [this](const std::string& param) {updateSnapToObjectParameter(param); }},
+ {"SnapToGrid",
+ [this](const std::string& param) {updateSnapToGridParameter(param); }},
+ {"SnapAngle",
+ [this](const std::string& param) {updateSnapAngleParameter(param); }},
+ };
+
+ for (auto& val : str2updatefunction) {
+ auto string = val.first;
+ auto function = val.second;
+
+ function(string);
+ }
+}
+
+void SnapManager::ParameterObserver::updateSnapParameter(const std::string& parametername)
+{
+ ParameterGrp::handle hGrp = getParameterGrpHandle();
+
+ client.snapRequested = hGrp->GetBool(parametername.c_str(), true);
+}
+
+void SnapManager::ParameterObserver::updateSnapToObjectParameter(const std::string& parametername)
+{
+ ParameterGrp::handle hGrp = getParameterGrpHandle();
+
+ client.snapToObjectsRequested = hGrp->GetBool(parametername.c_str(), true);
+}
+
+void SnapManager::ParameterObserver::updateSnapToGridParameter(const std::string& parametername)
+{
+ ParameterGrp::handle hGrp = getParameterGrpHandle();
+
+ client.snapToGridRequested = hGrp->GetBool(parametername.c_str(), false);
+}
+
+void SnapManager::ParameterObserver::updateSnapAngleParameter(const std::string& parametername)
+{
+ ParameterGrp::handle hGrp = getParameterGrpHandle();
+
+ client.snapAngle = fmod(hGrp->GetFloat(parametername.c_str(), 5.) * M_PI / 180, 2 * M_PI);
+}
+
+void SnapManager::ParameterObserver::subscribeToParameters()
+{
+ try {
+ ParameterGrp::handle hGrp = getParameterGrpHandle();
+ hGrp->Attach(this);
+ }
+ catch (const Base::ValueError& e) { // ensure that if parameter strings are not well-formed, the exception is not propagated
+ Base::Console().Error("SnapManager: Malformed parameter string: %s\n", e.what());
+ }
+}
+
+void SnapManager::ParameterObserver::unsubscribeToParameters()
+{
+ try {
+ ParameterGrp::handle hGrp = getParameterGrpHandle();
+ hGrp->Detach(this);
+ }
+ catch (const Base::ValueError& e) {// ensure that if parameter strings are not well-formed, the program is not terminated when calling the noexcept destructor.
+ Base::Console().Error("SnapManager: Malformed parameter string: %s\n", e.what());
+ }
+}
+
+void SnapManager::ParameterObserver::OnChange(Base::Subject& rCaller, const char* sReason)
+{
+ (void)rCaller;
+
+ auto key = str2updatefunction.find(sReason);
+ if (key != str2updatefunction.end()) {
+ auto string = key->first;
+ auto function = key->second;
+
+ function(string);
+ }
+}
+
+ParameterGrp::handle SnapManager::ParameterObserver::getParameterGrpHandle()
+{
+ return App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+}
+
+//**************************** SnapManager class ******************************
+
+SnapManager::SnapManager(ViewProviderSketch &vp):viewProvider(vp), angleSnapEnabled(false), referencePoint(Base::Vector2d(0.,0.)), lastMouseAngle(0.0)
+{
+ // Create parameter observer and initialise watched parameters
+ pObserver = std::make_unique(*this);
+}
+
+SnapManager::~SnapManager() {}
+
+bool SnapManager::snap(double& x, double& y)
+{
+ if (!snapRequested)
+ {
+ return false;
+ }
+
+ //In order of priority :
+
+ // 1 - Snap at an angle
+ if (angleSnapEnabled && QApplication::keyboardModifiers() == Qt::ControlModifier) {
+ return snapAtAngle(x, y);
+ }
+ else {
+ lastMouseAngle = 0.0;
+ }
+
+ // 2 - Snap to objects
+ if (snapToObjectsRequested
+ && snapToObject(x, y)) {
+ return true;
+ }
+
+ // 3 - Snap to grid
+ if (snapToGridRequested /*&& viewProvider.ShowGrid.getValue() */ ) { //Snap to grid is enabled even if the grid is not visible.
+ return snapToGrid(x, y);
+ }
+
+ return false;
+}
+
+bool SnapManager::snapAtAngle(double& x, double& y)
+{
+ Base::Vector2d pointToOverride(x, y);
+ double length = (pointToOverride - referencePoint).Length();
+
+ double angle1 = (pointToOverride - referencePoint).Angle();
+ double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI;
+ lastMouseAngle = abs(angle1 - lastMouseAngle) < abs(angle2 - lastMouseAngle) ? angle1 : angle2;
+
+ double angle = round(lastMouseAngle / snapAngle) * snapAngle;
+ pointToOverride = referencePoint + length * Base::Vector2d(cos(angle), sin(angle));
+ x = pointToOverride.x;
+ y = pointToOverride.y;
+
+ return true;
+}
+
+bool SnapManager::snapToObject(double& x, double& y)
+{
+ Sketcher::SketchObject* Obj = viewProvider.getSketchObject();
+ int geoId = GeoEnum::GeoUndef;
+ Sketcher::PointPos posId = Sketcher::PointPos::none;
+
+ int VtId = ViewProviderSketchSnapAttorney::getPreselectPoint(viewProvider);
+ int CrsId = ViewProviderSketchSnapAttorney::getPreselectCross(viewProvider);
+ int CrvId = ViewProviderSketchSnapAttorney::getPreselectCurve(viewProvider);
+
+ if (CrsId == 0 || VtId >= 0) {
+ if (CrsId == 0) {
+ geoId = Sketcher::GeoEnum::RtPnt;
+ posId = Sketcher::PointPos::start;
+ }
+ else if (VtId >= 0) {
+ Obj->getGeoVertexIndex(VtId, geoId, posId);
+ }
+
+ x = Obj->getPoint(geoId, posId).x;
+ y = Obj->getPoint(geoId, posId).y;
+ return true;
+ }
+ else if (CrsId == 1) { //H_Axis
+ y = 0;
+ return true;
+ }
+ else if (CrsId == 2) { //V_Axis
+ x = 0;
+ return true;
+ }
+ else if (CrvId >= 0 || CrvId <= Sketcher::GeoEnum::RefExt) { //Curves
+
+ const Part::Geometry* geo = Obj->getGeometry(CrvId);
+
+ Base::Vector3d pointToOverride(x, y, 0.);
+
+ double pointParam = 0.0;
+ auto curve = dynamic_cast(geo);
+ if (curve) {
+ try {
+ curve->closestParameter(pointToOverride, pointParam);
+ pointToOverride = curve->pointAtParameter(pointParam);
+ }
+ catch (Base::CADKernelError& e) {
+ e.ReportException();
+ return false;
+ }
+
+ //If it is a line, then we check if we need to snap to the middle.
+ if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
+ const Part::GeomLineSegment* line = static_cast(geo);
+ snapToLineMiddle(pointToOverride, line);
+ }
+
+ //If it is an arc, then we check if we need to snap to the middle (not the center).
+ if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
+ const Part::GeomArcOfCircle* arc = static_cast(geo);
+ snapToArcMiddle(pointToOverride, arc);
+ }
+
+ x = pointToOverride.x;
+ y = pointToOverride.y;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SnapManager::snapToGrid(double& x, double& y)
+{
+ // Snap Tolerance in pixels
+ const double snapTol = viewProvider.getGridSize() / 5;
+
+ double tmpX = x, tmpY = y;
+
+ viewProvider.getClosestGridPoint(tmpX, tmpY);
+
+ bool snapped = false;
+
+ // Check if x within snap tolerance
+ if (x < tmpX + snapTol && x > tmpX - snapTol) {
+ x = tmpX; // Snap X Mouse Position
+ snapped = true;
+ }
+
+ // Check if y within snap tolerance
+ if (y < tmpY + snapTol && y > tmpY - snapTol) {
+ y = tmpY; // Snap Y Mouse Position
+ snapped = true;
+ }
+
+ return snapped;
+}
+
+bool SnapManager::snapToLineMiddle(Base::Vector3d& pointToOverride, const Part::GeomLineSegment* line)
+{
+ Base::Vector3d startPoint = line->getStartPoint();
+ Base::Vector3d endPoint = line->getEndPoint();
+ Base::Vector3d midPoint = (startPoint + endPoint) / 2;
+
+ //Check if we are at middle of the line and if so snap to it.
+ if ((pointToOverride - midPoint).Length() < (endPoint - startPoint).Length() * 0.05) {
+ pointToOverride = midPoint;
+ return true;
+ }
+
+ return false;
+}
+
+bool SnapManager::snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::GeomArcOfCircle* arc)
+{
+ Base::Vector3d centerPoint = arc->getCenter();
+ Base::Vector3d startVec = (arc->getStartPoint() - centerPoint);
+ Base::Vector3d middleVec = startVec + (arc->getEndPoint() - centerPoint);
+
+ /* Handle the case of arc angle = 180 */
+ if (middleVec.Length() < Precision::Confusion()) {
+ middleVec.x = startVec.y;
+ middleVec.y = -startVec.x;
+ }
+ else {
+ middleVec = middleVec / middleVec.Length() * arc->getRadius();
+ }
+
+ Base::Vector2d mVec = Base::Vector2d(middleVec.x, middleVec.y);
+ Base::Vector3d pointVec = pointToOverride - centerPoint;
+ Base::Vector2d pVec = Base::Vector2d(pointVec.x, pointVec.y);
+
+ double u, v;
+ arc->getRange(u, v, true);
+ if (v < u)
+ v += 2 * M_PI;
+ double angle = v - u;
+ int revert = angle < M_PI ? 1 : -1;
+
+ /*To know if we are close to the middle of the arc, we are going to compare the angle of the
+ * (mouse cursor - center) to the angle of the middle of the arc. If it's less than 10% of the arc angle, then we snap.
+ */
+ if (fabs(pVec.Angle() - (revert * mVec).Angle()) < 0.10 * angle) {
+ pointToOverride = centerPoint + middleVec * revert;
+ return true;
+ }
+
+ return false;
+}
\ No newline at end of file
diff --git a/src/Mod/Sketcher/Gui/SnapManager.h b/src/Mod/Sketcher/Gui/SnapManager.h
new file mode 100644
index 0000000000..18f2a94ad0
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/SnapManager.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * Copyright (c) 2023 Pierre-Louis Boyer *
+ * *
+ * 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 *
+ * *
+ * SnapManager initially funded by the Open Toolchain Foundation *
+ ***************************************************************************/
+
+#ifndef SKETCHERGUI_SnapManager_H
+#define SKETCHERGUI_SnapManager_H
+
+
+#include
+
+
+namespace SketcherGui {
+
+class ViewProviderSketch;
+
+
+class ViewProviderSketchSnapAttorney {
+private:
+
+ static inline int getPreselectPoint(const ViewProviderSketch& vp);
+ static inline int getPreselectCross(const ViewProviderSketch& vp);
+ static inline int getPreselectCurve(const ViewProviderSketch& vp);
+
+ friend class SnapManager;
+};
+
+/* This class is used to manage the overriding of mouse pointer coordinates in Sketcher
+* (in Edit-Mode) depending on the situation. Those situations are in priority order :
+* 1 - Snap at angle: For tools like Slot, Arc, Line, Ellipse, this enables to constrain the angle at steps of 5° (or customized angle).
+* This is useful to make features at a certain angle (45° for example)
+* 2 - Snap to object: This snaps the mouse pointer onto objects.
+* 3 - Snap to grid: This snaps the mouse pointer on the grid.
+*/
+class SnapManager
+{
+
+ /** @brief Class for monitoring changes in parameters affecting Snapping
+ * @details
+ *
+ * This nested class is a helper responsible for attaching to the parameters relevant for
+ * SnapManager, initialising the SnapManager to the current configuration
+ * and handle in real time any change to their values.
+ */
+ class ParameterObserver : public ParameterGrp::ObserverType
+ {
+ public:
+ explicit ParameterObserver(SnapManager& client);
+ ~ParameterObserver() override;
+
+ void subscribeToParameters();
+
+ void unsubscribeToParameters();
+
+ /** Observer for parameter group. */
+ void OnChange(Base::Subject& rCaller, const char* sReason) override;
+
+ private:
+ void initParameters();
+ void updateSnapParameter(const std::string& parametername);
+ void updateSnapToObjectParameter(const std::string& parametername);
+ void updateSnapToGridParameter(const std::string& parametername);
+ void updateSnapAngleParameter(const std::string& parametername);
+
+ static ParameterGrp::handle getParameterGrpHandle();
+
+ private:
+ std::map> str2updatefunction;
+ SnapManager& client;
+ };
+
+public:
+ explicit SnapManager(ViewProviderSketch &vp);
+ ~SnapManager();
+
+ bool snap(double& x, double& y);
+ bool snapAtAngle(double& x, double& y);
+ bool snapToObject(double& x, double& y);
+ bool snapToGrid(double& x, double& y);
+
+ bool snapToLineMiddle(Base::Vector3d& pointToOverride, const Part::GeomLineSegment* line);
+ bool snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::GeomArcOfCircle* arc);
+
+ bool angleSnapEnabled;
+ Base::Vector2d referencePoint;
+
+private:
+ double snapAngle;
+ double lastMouseAngle;
+
+ bool snapRequested;
+ bool snapToObjectsRequested;
+ bool snapToGridRequested;
+
+ /// Reference to ViewProviderSketch in order to access the public and the Attorney Interface
+ ViewProviderSketch & viewProvider;
+
+ /// Observer to track all the needed parameters.
+ std::unique_ptr pObserver;
+};
+
+
+} // namespace SketcherGui
+
+
+#endif // SKETCHERGUI_SnapManager_H
+
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
index 62d81b0f8c..e74c17b76f 100644
--- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
+++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
@@ -65,6 +65,7 @@
#include "DrawSketchHandler.h"
#include "EditDatumDialog.h"
#include "EditModeCoinManager.h"
+#include "SnapManager.h"
#include "TaskDlgEditSketch.h"
#include "TaskSketcherValidation.h"
#include "Utils.h"
@@ -304,6 +305,7 @@ ViewProviderSketch::ViewProviderSketch()
Mode(STATUS_NONE),
listener(nullptr),
editCoinManager(nullptr),
+ snapManager(nullptr),
pObserver(std::make_unique(*this)),
sketchHandler(nullptr),
viewOrientationFactor(1)
@@ -551,36 +553,11 @@ bool ViewProviderSketch::keyPressed(bool pressed, int key)
return true; // handle all other key events
}
-void ViewProviderSketch::setSnapMode(SnapMode mode)
+void ViewProviderSketch::setAngleSnapping(bool enable, Base::Vector2d referencePoint)
{
- snapMode = mode; // to be redirected to SnapManager
-}
-
-SnapMode ViewProviderSketch::getSnapMode() const
-{
- return snapMode; // to be redirected to SnapManager
-}
-
-void ViewProviderSketch::snapToGrid(double &x, double &y) // Paddle, when resolving this conflict, make sure to use the function in ViewProviderGridExtension
-{
- if (snapMode == SnapMode::SnapToGrid && ShowGrid.getValue()) {
- // Snap Tolerance in pixels
- const double snapTol = getGridSize() / 5;
-
- double tmpX = x, tmpY = y;
-
- getClosestGridPoint(tmpX, tmpY);
-
- // Check if x within snap tolerance
- if (x < tmpX + snapTol && x > tmpX - snapTol) {
- x = tmpX; // Snap X Mouse Position
- }
-
- // Check if y within snap tolerance
- if (y < tmpY + snapTol && y > tmpY - snapTol) {
- y = tmpY; // Snap Y Mouse Position
- }
- }
+ assert(snapManager);
+ snapManager->angleSnapEnabled = enable;
+ snapManager->referencePoint = referencePoint;
}
void ViewProviderSketch::getProjectingLine(const SbVec2s& pnt, const Gui::View3DInventorViewer *viewer, SbLine& line) const
@@ -679,7 +656,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe
try {
getCoordsOnSketchPlane(pos,normal,x,y);
- snapToGrid(x, y);
+ snapManager->snap(x, y);
}
catch (const Base::ZeroDivisionError&) {
return false;
@@ -1148,7 +1125,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor
double x,y;
try {
getCoordsOnSketchPlane(line.getPosition(),line.getDirection(),x,y);
- snapToGrid(x, y);
+ snapManager->snap(x, y);
}
catch (const Base::ZeroDivisionError&) {
return false;
@@ -1275,7 +1252,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor
SbLine line2;
getProjectingLine(DoubleClick::prvCursorPos, viewer, line2);
getCoordsOnSketchPlane(line2.getPosition(),line2.getDirection(),drag.xInit,drag.yInit);
- snapToGrid(drag.xInit, drag.yInit);
+ snapManager->snap(drag.xInit, drag.yInit);
} else {
drag.resetVector();
}
@@ -2877,6 +2854,7 @@ bool ViewProviderSketch::setEdit(int ModNum)
preselection.reset();
selection.reset();
editCoinManager = std::make_unique(*this);
+ snapManager = std::make_unique(*this);
auto editDoc = Gui::Application::Instance->editDocument();
App::DocumentObject *editObj = getSketchObject();
@@ -3123,6 +3101,7 @@ void ViewProviderSketch::unsetEdit(int ModNum)
deactivateHandler();
editCoinManager = nullptr;
+ snapManager = nullptr;
preselection.reset();
selection.reset();
this->detachSelection();
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h
index eb1765f864..f8280420ff 100644
--- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h
+++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h
@@ -85,15 +85,9 @@ namespace Sketcher {
namespace SketcherGui {
class EditModeCoinManager;
+class SnapManager;
class DrawSketchHandler;
-enum class SnapMode { // to be moved to SnapManager
- None,
- SnapToObject,
- SnapToAngle,
- SnapToGrid,
-};
-
using GeoList = Sketcher::GeoList;
using GeoListFacade = Sketcher::GeoListFacade;
@@ -484,8 +478,10 @@ public:
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
//@}
- void setSnapMode(SnapMode mode);
- SnapMode getSnapMode() const;
+ /** @name Toggle angle snapping and set the reference point */
+ //@{
+ /// Toggle angle snapping and set the reference point
+ void setAngleSnapping(bool enable, Base::Vector2d referencePoint = Base::Vector2d(0., 0.));
/** @name Access to Sketch and Solver objects */
//@{
@@ -566,6 +562,7 @@ public:
//@{
friend class ViewProviderSketchDrawSketchHandlerAttorney;
friend class ViewProviderSketchCoinAttorney;
+ friend class ViewProviderSketchSnapAttorney;
friend class ViewProviderSketchShortcutListenerAttorney;
//@}
protected:
@@ -660,9 +657,6 @@ private:
/** @name miscelanea utilities */
//@{
- /// snap points x,y (mouse coordinates) onto grid if enabled
- void snapToGrid(double &x, double &y);
-
/// moves a selected constraint
void moveConstraint(int constNum, const Base::Vector2d &toPos);
@@ -784,6 +778,8 @@ private:
std::unique_ptr editCoinManager;
+ std::unique_ptr snapManager;
+
std::unique_ptr pObserver;
std::unique_ptr sketchHandler;
@@ -792,8 +788,6 @@ private:
SoNodeSensor cameraSensor;
int viewOrientationFactor; // stores if sketch viewed from front or back
-
- SnapMode snapMode = SnapMode::None; // temporary - to be moved to SnapManager
};
} // namespace PartGui
diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp
index 5b8bf0fef0..9babd176dc 100644
--- a/src/Mod/Sketcher/Gui/Workbench.cpp
+++ b/src/Mod/Sketcher/Gui/Workbench.cpp
@@ -188,7 +188,8 @@ inline void SketcherAddWorkbenchSketchEditModeActions(Gui::ToolBarItem& sketch)
sketch << "Sketcher_LeaveSketch"
<< "Sketcher_ViewSketch"
<< "Sketcher_ViewSection"
- << "Sketcher_Grid";
+ << "Sketcher_Grid"
+ << "Sketcher_Snap";
}
template
From 7d97a5d8da88f3e3fe42eb1accc10ff11fe3a24f Mon Sep 17 00:00:00 2001
From: Paddle
Date: Wed, 15 Mar 2023 11:09:09 +0100
Subject: [PATCH 29/53] Sketcher: Snap: Add 'Snap at angle' support to
DrawSketchHandler.
---
src/Mod/Sketcher/Gui/DrawSketchHandler.cpp | 10 ++++++++++
src/Mod/Sketcher/Gui/DrawSketchHandler.h | 4 ++++
2 files changed, 14 insertions(+)
diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp
index a3161dcec5..190f1febd2 100644
--- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp
+++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp
@@ -114,6 +114,11 @@ inline int ViewProviderSketchDrawSketchHandlerAttorney::getPreselectCross(const
return vp.getPreselectCross();
}
+inline void ViewProviderSketchDrawSketchHandlerAttorney::setAngleSnapping(ViewProviderSketch &vp, bool enable, Base::Vector2d referencePoint)
+{
+ vp.setAngleSnapping(enable, referencePoint);
+}
+
/**************************** CurveConverter **********************************************/
@@ -250,6 +255,7 @@ void DrawSketchHandler::deactivate()
drawEditMarkers(std::vector());
resetPositionText();
unsetCursor();
+ setAngleSnapping(false);
}
void DrawSketchHandler::preActivated()
@@ -992,3 +998,7 @@ Sketcher::SketchObject * DrawSketchHandler::getSketchObject()
return sketchgui->getSketchObject();
}
+void DrawSketchHandler::setAngleSnapping(bool enable, Base::Vector2d referencePoint)
+{
+ ViewProviderSketchDrawSketchHandlerAttorney::setAngleSnapping(*sketchgui, enable, referencePoint);
+}
\ No newline at end of file
diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.h b/src/Mod/Sketcher/Gui/DrawSketchHandler.h
index 2cd1cf4c5d..750db4e87e 100644
--- a/src/Mod/Sketcher/Gui/DrawSketchHandler.h
+++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.h
@@ -86,11 +86,13 @@ private:
static inline void setAxisPickStyle(ViewProviderSketch &vp, bool on);
static inline void moveCursorToSketchPoint(ViewProviderSketch &vp, Base::Vector2d point);
static inline void preselectAtPoint(ViewProviderSketch &vp, Base::Vector2d point);
+ static inline void setAngleSnapping(ViewProviderSketch &vp, bool enable, Base::Vector2d referencePoint = Base::Vector2d(0., 0.));
static inline int getPreselectPoint(const ViewProviderSketch &vp);
static inline int getPreselectCurve(const ViewProviderSketch &vp);
static inline int getPreselectCross(const ViewProviderSketch &vp);
+
friend class DrawSketchHandler;
};
@@ -203,6 +205,8 @@ protected:
Sketcher::SketchObject * getSketchObject();
+ void setAngleSnapping(bool enable, Base::Vector2d referencePoint = Base::Vector2d(0., 0.));
+
private:
void setSvgCursor(const QString &svgName, int x, int y,
const std::map& colorMapping = std::map());
From e62d6b854bdf7c27f978164b3a960d8cd363df6c Mon Sep 17 00:00:00 2001
From: Paddle
Date: Wed, 15 Mar 2023 11:09:21 +0100
Subject: [PATCH 30/53] Sketcher: Snap: Add 'Snap at angle' to Arc DSH.
---
src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h
index c0cd8ce294..6a4ca2ac2f 100644
--- a/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h
+++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h
@@ -131,6 +131,7 @@ public:
CenterPoint = onSketchPos;
EditCurve.resize(34);
EditCurve[0] = onSketchPos;
+ setAngleSnapping(true, EditCurve[0]);
Mode = STATUS_SEEK_Second;
}
else if (Mode==STATUS_SEEK_Second){
@@ -158,6 +159,7 @@ public:
drawEdit(EditCurve);
applyCursor();
+ setAngleSnapping(false);
Mode = STATUS_End;
}
From 7b7368b04b86137b25c59d865772c89e92eac16b Mon Sep 17 00:00:00 2001
From: Paddle
Date: Wed, 15 Mar 2023 11:09:31 +0100
Subject: [PATCH 31/53] Sketcher: Snap: Add 'Snap at angle' to Line DSH.
---
src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h
index b8772a3250..eb3fa27ea5 100644
--- a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h
+++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h
@@ -76,11 +76,13 @@ public:
if (Mode==STATUS_SEEK_First){
EditCurve[0] = onSketchPos;
+ setAngleSnapping(true, EditCurve[0]);
Mode = STATUS_SEEK_Second;
}
else {
EditCurve[1] = onSketchPos;
drawEdit(EditCurve);
+ setAngleSnapping(false);
Mode = STATUS_End;
}
return true;
From 4922a489978224d1a699dbb49ebba399ea02f225 Mon Sep 17 00:00:00 2001
From: Paddle
Date: Wed, 15 Mar 2023 11:09:43 +0100
Subject: [PATCH 32/53] Sketcher: Snap: Add 'Snap at angle' to Ellipse DSH.
---
src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h
index 0c2ddc335a..61fade5d12 100644
--- a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h
+++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h
@@ -216,10 +216,12 @@ public:
if (method == PERIAPSIS_APOAPSIS_B) {
if (mode == STATUS_SEEK_PERIAPSIS) {
periapsis = onSketchPos;
+ setAngleSnapping(true, periapsis);
mode = STATUS_SEEK_APOAPSIS;
}
else if (mode == STATUS_SEEK_APOAPSIS) {
apoapsis = onSketchPos;
+ setAngleSnapping(false);
mode = STATUS_SEEK_B;
}
else {
@@ -228,10 +230,12 @@ public:
} else { // method is CENTER_PERIAPSIS_B
if (mode == STATUS_SEEK_CENTROID) {
centroid = onSketchPos;
+ setAngleSnapping(true, centroid);
mode = STATUS_SEEK_PERIAPSIS;
}
else if (mode == STATUS_SEEK_PERIAPSIS) {
periapsis = onSketchPos;
+ setAngleSnapping(false);
mode = STATUS_SEEK_B;
}
else {
From de57296576eaa779b5a6ee3b654ac175274e2262 Mon Sep 17 00:00:00 2001
From: Paddle
Date: Wed, 15 Mar 2023 11:10:05 +0100
Subject: [PATCH 33/53] Sketcher: Snap: Add 'Snap at angle' to Arc of Ellipse
DSH.
---
src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h
index dfe28a105d..4a74f8b386 100644
--- a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h
+++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h
@@ -176,6 +176,7 @@ public:
if (Mode==STATUS_SEEK_First){
EditCurve[0] = onSketchPos;
centerPoint = onSketchPos;
+ setAngleSnapping(true, centerPoint);
Mode = STATUS_SEEK_Second;
}
else if(Mode==STATUS_SEEK_Second) {
@@ -192,6 +193,7 @@ public:
else { // Fourth
endPoint = onSketchPos;
+ setAngleSnapping(false);
Mode = STATUS_Close;
}
return true;
From af0f4b10f6a0c5d6d4956096adba25012a48ba09 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 07:41:57 +0100
Subject: [PATCH 34/53] Remove left-over code
---
src/Mod/Sketcher/Gui/Command.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index 6de8a85aa8..cf11fad413 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -995,8 +995,6 @@ public:
updateCheckBox(checkbox, propvalue);
};
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
-
updateCheckBoxFromProperty(gridAutoSpacing, sketchView->GridAuto);
gridSizeBox->setValue(sketchView->GridSize.getValue());
From 50b3662535ec81e182dc11346b9ef366a3ea1b04 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 07:57:10 +0100
Subject: [PATCH 35/53] Rename preference parameter
---
src/Mod/Sketcher/Gui/Command.cpp | 14 +++++++-------
src/Mod/Sketcher/Gui/SnapManager.cpp | 4 ++--
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index cf11fad413..650b67fd0b 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -1212,7 +1212,7 @@ public:
}
};
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
updateCheckBox(snapToObjects, hGrp->GetBool("SnapToObjects", true));
@@ -1271,7 +1271,7 @@ protected:
auto* sketchView = getView();
if (sketchView) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
hGrp->SetBool("SnapToObjects", state == Qt::Checked);
}
});
@@ -1279,7 +1279,7 @@ protected:
QObject::connect(snapToGrid, &QCheckBox::stateChanged, [this](int state) {
auto* sketchView = getView();
if (sketchView) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
hGrp->SetBool("SnapToGrid", state == Qt::Checked);
}
});
@@ -1288,7 +1288,7 @@ protected:
auto* sketchView = getView();
if (sketchView) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
hGrp->SetFloat("SnapAngle", val);
}
});
@@ -1362,7 +1362,7 @@ void CmdSketcherSnap::activated(int iMsg)
{
Q_UNUSED(iMsg);
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
bool value = !hGrp->GetBool("Snap", true);
hGrp->SetBool("Snap", value);
@@ -1398,7 +1398,7 @@ Gui::Action* CmdSketcherSnap::createAction()
});
// set the right pixmap
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
updateIcon(hGrp->GetBool("Snap", true));
return pcAction;
@@ -1423,7 +1423,7 @@ bool CmdSketcherSnap::isActive()
auto* vp = getInactiveHandlerEditModeSketchViewProvider();
if (vp) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
bool value = hGrp->GetBool("Snap", true);
updateIcon(value);
diff --git a/src/Mod/Sketcher/Gui/SnapManager.cpp b/src/Mod/Sketcher/Gui/SnapManager.cpp
index 56638de4bc..76927e34e2 100644
--- a/src/Mod/Sketcher/Gui/SnapManager.cpp
+++ b/src/Mod/Sketcher/Gui/SnapManager.cpp
@@ -153,7 +153,7 @@ void SnapManager::ParameterObserver::OnChange(Base::Subject& rCalle
ParameterGrp::handle SnapManager::ParameterObserver::getParameterGrpHandle()
{
- return App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
+ return App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
}
//**************************** SnapManager class ******************************
@@ -361,4 +361,4 @@ bool SnapManager::snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::G
}
return false;
-}
\ No newline at end of file
+}
From 41408b411fe420b310058e94e1c96cb5fe9072bc Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 08:04:13 +0100
Subject: [PATCH 36/53] Encapsulate interface data members
---
src/Mod/Sketcher/Gui/SnapManager.cpp | 6 ++++++
src/Mod/Sketcher/Gui/SnapManager.h | 6 ++++--
src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 3 +--
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/SnapManager.cpp b/src/Mod/Sketcher/Gui/SnapManager.cpp
index 76927e34e2..ee2a7ec48c 100644
--- a/src/Mod/Sketcher/Gui/SnapManager.cpp
+++ b/src/Mod/Sketcher/Gui/SnapManager.cpp
@@ -362,3 +362,9 @@ bool SnapManager::snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::G
return false;
}
+
+void SnapManager::setAngleSnapping(bool enable, Base::Vector2d referencepoint)
+{
+ angleSnapEnabled = enable;
+ referencePoint = referencepoint;
+}
diff --git a/src/Mod/Sketcher/Gui/SnapManager.h b/src/Mod/Sketcher/Gui/SnapManager.h
index 18f2a94ad0..232bdbdf96 100644
--- a/src/Mod/Sketcher/Gui/SnapManager.h
+++ b/src/Mod/Sketcher/Gui/SnapManager.h
@@ -99,8 +99,7 @@ public:
bool snapToLineMiddle(Base::Vector3d& pointToOverride, const Part::GeomLineSegment* line);
bool snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::GeomArcOfCircle* arc);
- bool angleSnapEnabled;
- Base::Vector2d referencePoint;
+ void setAngleSnapping(bool enable, Base::Vector2d referencepoint);
private:
double snapAngle;
@@ -110,6 +109,9 @@ private:
bool snapToObjectsRequested;
bool snapToGridRequested;
+ bool angleSnapEnabled;
+ Base::Vector2d referencePoint;
+
/// Reference to ViewProviderSketch in order to access the public and the Attorney Interface
ViewProviderSketch & viewProvider;
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
index e74c17b76f..17febf8329 100644
--- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
+++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
@@ -556,8 +556,7 @@ bool ViewProviderSketch::keyPressed(bool pressed, int key)
void ViewProviderSketch::setAngleSnapping(bool enable, Base::Vector2d referencePoint)
{
assert(snapManager);
- snapManager->angleSnapEnabled = enable;
- snapManager->referencePoint = referencePoint;
+ snapManager->setAngleSnapping(enable, referencePoint);
}
void ViewProviderSketch::getProjectingLine(const SbVec2s& pnt, const Gui::View3DInventorViewer *viewer, SbLine& line) const
From e763fd3d80fb33adcbde3c2e374b68b1f4754544 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 08:08:33 +0100
Subject: [PATCH 37/53] Remove warning - SnapManager initialisation order in
constructor different from class declaration
---
src/Mod/Sketcher/Gui/SnapManager.h | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/SnapManager.h b/src/Mod/Sketcher/Gui/SnapManager.h
index 232bdbdf96..f7c0c14f94 100644
--- a/src/Mod/Sketcher/Gui/SnapManager.h
+++ b/src/Mod/Sketcher/Gui/SnapManager.h
@@ -102,19 +102,18 @@ public:
void setAngleSnapping(bool enable, Base::Vector2d referencepoint);
private:
- double snapAngle;
+ /// Reference to ViewProviderSketch in order to access the public and the Attorney Interface
+ ViewProviderSketch & viewProvider;
+ bool angleSnapEnabled;
+ Base::Vector2d referencePoint;
double lastMouseAngle;
+ double snapAngle;
+
bool snapRequested;
bool snapToObjectsRequested;
bool snapToGridRequested;
- bool angleSnapEnabled;
- Base::Vector2d referencePoint;
-
- /// Reference to ViewProviderSketch in order to access the public and the Attorney Interface
- ViewProviderSketch & viewProvider;
-
/// Observer to track all the needed parameters.
std::unique_ptr pObserver;
};
From 75fd0dbc73acb862315dad62eb6550d9b9d90053 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 08:12:30 +0100
Subject: [PATCH 38/53] Remov warning -squash group by meaningful groups
---
src/Mod/Sketcher/Gui/SnapManager.h | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/SnapManager.h b/src/Mod/Sketcher/Gui/SnapManager.h
index f7c0c14f94..7c0255fba8 100644
--- a/src/Mod/Sketcher/Gui/SnapManager.h
+++ b/src/Mod/Sketcher/Gui/SnapManager.h
@@ -104,16 +104,17 @@ public:
private:
/// Reference to ViewProviderSketch in order to access the public and the Attorney Interface
ViewProviderSketch & viewProvider;
+
bool angleSnapEnabled;
+ bool snapRequested;
+ bool snapToObjectsRequested;
+ bool snapToGridRequested;
+
Base::Vector2d referencePoint;
double lastMouseAngle;
double snapAngle;
- bool snapRequested;
- bool snapToObjectsRequested;
- bool snapToGridRequested;
-
/// Observer to track all the needed parameters.
std::unique_ptr pObserver;
};
From 65ec96d12d0418edb522e16bab45dbcc98511cd6 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 08:17:11 +0100
Subject: [PATCH 39/53] Rename angleSnapEnabled to angleSnapRequested for
consistency with the other snap flags
---
src/Mod/Sketcher/Gui/SnapManager.cpp | 6 +++---
src/Mod/Sketcher/Gui/SnapManager.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/SnapManager.cpp b/src/Mod/Sketcher/Gui/SnapManager.cpp
index ee2a7ec48c..d6385b901d 100644
--- a/src/Mod/Sketcher/Gui/SnapManager.cpp
+++ b/src/Mod/Sketcher/Gui/SnapManager.cpp
@@ -158,7 +158,7 @@ ParameterGrp::handle SnapManager::ParameterObserver::getParameterGrpHandle()
//**************************** SnapManager class ******************************
-SnapManager::SnapManager(ViewProviderSketch &vp):viewProvider(vp), angleSnapEnabled(false), referencePoint(Base::Vector2d(0.,0.)), lastMouseAngle(0.0)
+SnapManager::SnapManager(ViewProviderSketch &vp):viewProvider(vp), angleSnapRequested(false), referencePoint(Base::Vector2d(0.,0.)), lastMouseAngle(0.0)
{
// Create parameter observer and initialise watched parameters
pObserver = std::make_unique(*this);
@@ -176,7 +176,7 @@ bool SnapManager::snap(double& x, double& y)
//In order of priority :
// 1 - Snap at an angle
- if (angleSnapEnabled && QApplication::keyboardModifiers() == Qt::ControlModifier) {
+ if (angleSnapRequested && QApplication::keyboardModifiers() == Qt::ControlModifier) {
return snapAtAngle(x, y);
}
else {
@@ -365,6 +365,6 @@ bool SnapManager::snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::G
void SnapManager::setAngleSnapping(bool enable, Base::Vector2d referencepoint)
{
- angleSnapEnabled = enable;
+ angleSnapRequested = enable;
referencePoint = referencepoint;
}
diff --git a/src/Mod/Sketcher/Gui/SnapManager.h b/src/Mod/Sketcher/Gui/SnapManager.h
index 7c0255fba8..8fc4a7134a 100644
--- a/src/Mod/Sketcher/Gui/SnapManager.h
+++ b/src/Mod/Sketcher/Gui/SnapManager.h
@@ -105,7 +105,7 @@ private:
/// Reference to ViewProviderSketch in order to access the public and the Attorney Interface
ViewProviderSketch & viewProvider;
- bool angleSnapEnabled;
+ bool angleSnapRequested;
bool snapRequested;
bool snapToObjectsRequested;
bool snapToGridRequested;
From 8d33a2409280eb62cd387a67f255fb9ea73db035 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 08:35:17 +0100
Subject: [PATCH 40/53] Remove unnecessary ViewProvider retrieving and
checking, as it is unused
---
src/Mod/Sketcher/Gui/Command.cpp | 61 ++++++++++++--------------------
1 file changed, 22 insertions(+), 39 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index 650b67fd0b..1c12786baa 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -1199,38 +1199,32 @@ public:
void updateWidget() {
- auto* sketchView = getView();
+ auto updateCheckBox = [](QCheckBox* checkbox, bool value) {
+ auto checked = checkbox->checkState() == Qt::Checked;
- if (sketchView) {
+ if (value != checked) {
+ const QSignalBlocker blocker(checkbox);
+ checkbox->setChecked(value);
+ }
+ };
- auto updateCheckBox = [](QCheckBox* checkbox, bool value) {
- auto checked = checkbox->checkState() == Qt::Checked;
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
- if (value != checked) {
- const QSignalBlocker blocker(checkbox);
- checkbox->setChecked(value);
- }
- };
+ updateCheckBox(snapToObjects, hGrp->GetBool("SnapToObjects", true));
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ updateCheckBox(snapToGrid, hGrp->GetBool("SnapToGrid", false));
- updateCheckBox(snapToObjects, hGrp->GetBool("SnapToObjects", true));
+ snapAngle->setValue(hGrp->GetFloat("SnapAngle", 5.0));
- updateCheckBox(snapToGrid, hGrp->GetBool("SnapToGrid", false));
-
- snapAngle->setValue(hGrp->GetFloat("SnapAngle", 5.0));
-
- bool snapActivated = hGrp->GetBool("Snap", true);
- snapToObjects->setEnabled(snapActivated);
- snapToGrid->setEnabled(snapActivated);
- angleLabel->setEnabled(snapActivated);
- snapAngle->setEnabled(snapActivated);
- }
+ bool snapActivated = hGrp->GetBool("Snap", true);
+ snapToObjects->setEnabled(snapActivated);
+ snapToGrid->setEnabled(snapActivated);
+ angleLabel->setEnabled(snapActivated);
+ snapAngle->setEnabled(snapActivated);
}
void languageChange()
{
-
snapToObjects->setText(tr("Snap to objects"));
snapToObjects->setToolTip(tr("New points will snap to the currently preselected object. It will also snap to the middle of lines and arcs."));
snapToObjects->setStatusTip(snapToObjects->toolTip());
@@ -1268,29 +1262,18 @@ protected:
languageChange();
QObject::connect(snapToObjects, &QCheckBox::stateChanged, [this](int state) {
- auto* sketchView = getView();
-
- if (sketchView) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
- hGrp->SetBool("SnapToObjects", state == Qt::Checked);
- }
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ hGrp->SetBool("SnapToObjects", state == Qt::Checked);
});
QObject::connect(snapToGrid, &QCheckBox::stateChanged, [this](int state) {
- auto* sketchView = getView();
- if (sketchView) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
- hGrp->SetBool("SnapToGrid", state == Qt::Checked);
- }
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ hGrp->SetBool("SnapToGrid", state == Qt::Checked);
});
QObject::connect(snapAngle, qOverload(&Gui::QuantitySpinBox::valueChanged), [this](double val) {
- auto* sketchView = getView();
-
- if (sketchView) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
- hGrp->SetFloat("SnapAngle", val);
- }
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ hGrp->SetFloat("SnapAngle", val);
});
return snapW;
From 5ae5d0db87c60f900cf8c93dfa750c377873c294 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 08:46:29 +0100
Subject: [PATCH 41/53] Prevent unnecessary update of snapAngle, block signals
when auto updating
---
src/Mod/Sketcher/Gui/Command.cpp | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index 1c12786baa..742e3fab6e 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -1208,13 +1208,22 @@ public:
}
};
+ auto updateSpinBox = [](Gui::QuantitySpinBox* spinbox, double value) {
+ auto currentvalue = spinbox->rawValue();
+
+ if (currentvalue != value) {
+ const QSignalBlocker blocker(spinbox);
+ spinbox->setValue(value);
+ }
+ };
+
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
updateCheckBox(snapToObjects, hGrp->GetBool("SnapToObjects", true));
updateCheckBox(snapToGrid, hGrp->GetBool("SnapToGrid", false));
- snapAngle->setValue(hGrp->GetFloat("SnapAngle", 5.0));
+ updateSpinBox(snapAngle, hGrp->GetFloat("SnapAngle", 5.0));
bool snapActivated = hGrp->GetBool("Snap", true);
snapToObjects->setEnabled(snapActivated);
From a07630dfb3d4c5a8d733b90498858a4704a72f15 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 08:51:43 +0100
Subject: [PATCH 42/53] Refactor parameter in a single place
---
src/Mod/Sketcher/Gui/Command.cpp | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index 742e3fab6e..8410f60dfa 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -1217,7 +1217,7 @@ public:
}
};
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ ParameterGrp::handle hGrp = getParameterPath();
updateCheckBox(snapToObjects, hGrp->GetBool("SnapToObjects", true));
@@ -1271,17 +1271,17 @@ protected:
languageChange();
QObject::connect(snapToObjects, &QCheckBox::stateChanged, [this](int state) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ ParameterGrp::handle hGrp = this->getParameterPath();
hGrp->SetBool("SnapToObjects", state == Qt::Checked);
});
QObject::connect(snapToGrid, &QCheckBox::stateChanged, [this](int state) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ ParameterGrp::handle hGrp = this->getParameterPath();
hGrp->SetBool("SnapToGrid", state == Qt::Checked);
});
QObject::connect(snapAngle, qOverload(&Gui::QuantitySpinBox::valueChanged), [this](double val) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ ParameterGrp::handle hGrp = this->getParameterPath();
hGrp->SetFloat("SnapAngle", val);
});
@@ -1289,14 +1289,8 @@ protected:
}
private:
- ViewProviderSketch* getView() {
- Gui::Document* doc = Gui::Application::Instance->activeDocument();
-
- if (doc) {
- return dynamic_cast(doc->getInEdit());
- }
-
- return nullptr;
+ ParameterGrp::handle getParameterPath() {
+ return App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
}
private:
From 6ffd22fa9bc77c72f187070d9c5a31e38b63bf0e Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 09:22:40 +0100
Subject: [PATCH 43/53] Refactor of CmdSketcherSnap and SnapSpaceAction to
reduce verbose calls to retrieve preference parameters
---
src/Mod/Sketcher/Gui/Command.cpp | 63 +++++++++++++++++++++-----------
1 file changed, 41 insertions(+), 22 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index 8410f60dfa..9ac434706c 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -1197,7 +1197,7 @@ public:
setEnabled(false);
}
- void updateWidget() {
+ void updateWidget(bool snapenabled) {
auto updateCheckBox = [](QCheckBox* checkbox, bool value) {
auto checked = checkbox->checkState() == Qt::Checked;
@@ -1225,11 +1225,10 @@ public:
updateSpinBox(snapAngle, hGrp->GetFloat("SnapAngle", 5.0));
- bool snapActivated = hGrp->GetBool("Snap", true);
- snapToObjects->setEnabled(snapActivated);
- snapToGrid->setEnabled(snapActivated);
- angleLabel->setEnabled(snapActivated);
- snapAngle->setEnabled(snapActivated);
+ snapToObjects->setEnabled(snapenabled);
+ snapToGrid->setEnabled(snapenabled);
+ angleLabel->setEnabled(snapenabled);
+ snapAngle->setEnabled(snapenabled);
}
void languageChange()
@@ -1300,16 +1299,18 @@ private:
Gui::QuantitySpinBox* snapAngle;
};
-class CmdSketcherSnap : public Gui::Command
+class CmdSketcherSnap : public Gui::Command, public ParameterGrp::ObserverType
{
public:
CmdSketcherSnap();
- virtual ~CmdSketcherSnap() {}
+ virtual ~CmdSketcherSnap();
virtual const char* className() const
{
return "CmdSketcherSnap";
}
virtual void languageChange();
+
+ void OnChange(Base::Subject &rCaller, const char * sReason) override;
protected:
virtual void activated(int iMsg);
virtual bool isActive(void);
@@ -1317,10 +1318,16 @@ protected:
private:
void updateIcon(bool value);
+ ParameterGrp::handle getParameterPath() {
+ return App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
+ }
+
CmdSketcherSnap(const CmdSketcherSnap&) = delete;
CmdSketcherSnap(CmdSketcherSnap&&) = delete;
CmdSketcherSnap& operator= (const CmdSketcherSnap&) = delete;
CmdSketcherSnap& operator= (CmdSketcherSnap&&) = delete;
+
+ bool snapEnabled;
};
CmdSketcherSnap::CmdSketcherSnap()
@@ -1333,6 +1340,24 @@ CmdSketcherSnap::CmdSketcherSnap()
sWhatsThis = "Sketcher_Snap";
sStatusTip = sToolTipText;
eType = 0;
+
+ ParameterGrp::handle hGrp = this->getParameterPath();
+ hGrp->Attach(this);
+}
+
+CmdSketcherSnap::~CmdSketcherSnap() {
+
+ ParameterGrp::handle hGrp = this->getParameterPath();
+ hGrp->Detach(this);
+}
+
+void CmdSketcherSnap::OnChange(Base::Subject &rCaller, const char * sReason)
+{
+ Q_UNUSED(rCaller)
+
+ if (strcmp(sReason, "Snap") == 0) {
+ snapEnabled = getParameterPath()->GetBool("Snap", true);
+ }
}
void CmdSketcherSnap::updateIcon(bool value)
@@ -1348,12 +1373,10 @@ void CmdSketcherSnap::activated(int iMsg)
{
Q_UNUSED(iMsg);
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
- bool value = !hGrp->GetBool("Snap", true);
-
- hGrp->SetBool("Snap", value);
+ getParameterPath()->SetBool("Snap", !snapEnabled);
- updateIcon(value);
+ // snapEnable updated via observer
+ updateIcon(snapEnabled);
//Update the widget :
if (!_pcAction)
@@ -1363,7 +1386,7 @@ void CmdSketcherSnap::activated(int iMsg)
QList a = pcAction->actions();
auto* ssa = static_cast(a[0]);
- ssa->updateWidget();
+ ssa->updateWidget(snapEnabled);
}
Gui::Action* CmdSketcherSnap::createAction()
@@ -1378,14 +1401,13 @@ Gui::Action* CmdSketcherSnap::createAction()
_pcAction = pcAction;
- QObject::connect(pcAction, &Gui::ActionGroup::aboutToShow, [ssa](QMenu* menu) {
+ QObject::connect(pcAction, &Gui::ActionGroup::aboutToShow, [ssa, this](QMenu* menu) {
Q_UNUSED(menu)
- ssa->updateWidget();
+ ssa->updateWidget(snapEnabled);
});
// set the right pixmap
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
- updateIcon(hGrp->GetBool("Snap", true));
+ updateIcon(snapEnabled);
return pcAction;
}
@@ -1409,10 +1431,7 @@ bool CmdSketcherSnap::isActive()
auto* vp = getInactiveHandlerEditModeSketchViewProvider();
if (vp) {
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Snap");
- bool value = hGrp->GetBool("Snap", true);
-
- updateIcon(value);
+ updateIcon(snapEnabled);
return true;
}
From f7f78aa44b24dd3ae0bc813c8f67eb230ff933ac Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 09:40:13 +0100
Subject: [PATCH 44/53] Missing overrides
---
src/Mod/Sketcher/Gui/Command.cpp | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp
index 9ac434706c..0cecb39bd2 100644
--- a/src/Mod/Sketcher/Gui/Command.cpp
+++ b/src/Mod/Sketcher/Gui/Command.cpp
@@ -1073,13 +1073,13 @@ class CmdSketcherGrid : public Gui::Command
public:
CmdSketcherGrid();
virtual ~CmdSketcherGrid(){}
- virtual const char* className() const
+ virtual const char* className() const override
{ return "CmdSketcherGrid"; }
- virtual void languageChange();
+ virtual void languageChange() override;
protected:
- virtual void activated(int iMsg);
- virtual bool isActive(void);
- virtual Gui::Action * createAction(void);
+ virtual void activated(int iMsg) override;
+ virtual bool isActive(void) override;
+ virtual Gui::Action * createAction(void) override;
private:
void updateIcon(bool value);
void updateInactiveHandlerIcon();
@@ -1304,17 +1304,17 @@ class CmdSketcherSnap : public Gui::Command, public ParameterGrp::ObserverType
public:
CmdSketcherSnap();
virtual ~CmdSketcherSnap();
- virtual const char* className() const
+ virtual const char* className() const override
{
return "CmdSketcherSnap";
}
- virtual void languageChange();
+ virtual void languageChange() override;
void OnChange(Base::Subject &rCaller, const char * sReason) override;
protected:
- virtual void activated(int iMsg);
- virtual bool isActive(void);
- virtual Gui::Action* createAction(void);
+ virtual void activated(int iMsg) override;
+ virtual bool isActive(void) override;
+ virtual Gui::Action* createAction(void) override;
private:
void updateIcon(bool value);
From 09fbf45925979e7197875d58151823cd2d6e1e7a Mon Sep 17 00:00:00 2001
From: Uwe
Date: Sat, 18 Mar 2023 19:31:45 +0100
Subject: [PATCH 45/53] [FEM] output less messages
- the message how to use the feature is not useful since it is triggered by the GUI selection and in the GUI has already the info in form of tooltips how to use
---
src/Mod/Fem/femguiutils/selection_widgets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Mod/Fem/femguiutils/selection_widgets.py b/src/Mod/Fem/femguiutils/selection_widgets.py
index 12986efacc..e9db4068ab 100644
--- a/src/Mod/Fem/femguiutils/selection_widgets.py
+++ b/src/Mod/Fem/femguiutils/selection_widgets.py
@@ -599,7 +599,7 @@ class FemSelectionObserver:
def __init__(self, parseSelectionFunction, print_message=""):
self.parseSelectionFunction = parseSelectionFunction
FreeCADGui.Selection.addObserver(self)
- FreeCAD.Console.PrintMessage(print_message + "!\n")
+ #FreeCAD.Console.PrintMessage(print_message + "!\n")
def addSelection(self, docName, objName, sub, pos):
selected_object = FreeCAD.getDocument(docName).getObject(objName) # get the obj objName
From a2fec5192343f862ff07702ed1cdf508a4612d0f Mon Sep 17 00:00:00 2001
From: Uwe
Date: Mon, 20 Mar 2023 00:47:56 +0100
Subject: [PATCH 46/53] [FEM] Elmer: support for variable strings
- Elmer offers the "Variable" calls do define variables via math equations. These are for example used to define as constraint a certain velocity profile
---
src/Mod/Fem/femsolver/elmer/sifio.py | 31 ++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/src/Mod/Fem/femsolver/elmer/sifio.py b/src/Mod/Fem/femsolver/elmer/sifio.py
index 3bce29ce74..789258e61b 100644
--- a/src/Mod/Fem/femsolver/elmer/sifio.py
+++ b/src/Mod/Fem/femsolver/elmer/sifio.py
@@ -77,6 +77,7 @@ _TYPE_INTEGER = "Integer"
_TYPE_LOGICAL = "Logical"
_TYPE_STRING = "String"
_TYPE_FILE = "File"
+_TYPE_VARIABLE = "Variable"
WARN = "\"Warn\""
IGNORE = "\"Ignore\""
@@ -357,9 +358,20 @@ class _Writer(object):
self._stream.write(_WHITESPACE)
self._stream.write("=")
self._stream.write(_WHITESPACE)
- self._stream.write(attrType)
+ # check if we have a variable string
+ if attrType is _TYPE_STRING:
+ if data.startswith('Variable'):
+ attrType = _TYPE_VARIABLE
+ if attrType is not _TYPE_VARIABLE:
+ self._stream.write(attrType)
self._stream.write(_WHITESPACE)
- self._stream.write(self._preprocess(data, type(data)))
+ output = self._preprocess(data, type(data))
+ # in case of a variable the output must be without the quatoation marks
+ if attrType is _TYPE_VARIABLE:
+ output = output.lstrip('\"')
+ # we cannot use rstrip because there are two subsequent " at the end
+ output = output[:-1]
+ self._stream.write(output)
def _writeArrAttr(self, key, data):
attrType = self._getAttrTypeArr(data)
@@ -369,10 +381,21 @@ class _Writer(object):
self._stream.write(_WHITESPACE)
self._stream.write("=")
self._stream.write(_WHITESPACE)
- self._stream.write(attrType)
+ # check if we have a variable string
+ if attrType is _TYPE_STRING:
+ if data.startswith('Variable'):
+ attrType = _TYPE_VARIABLE
+ if attrType is not _TYPE_VARIABLE:
+ self._stream.write(attrType)
for val in data:
self._stream.write(_WHITESPACE)
- self._stream.write(self._preprocess(val, type(val)))
+ output = self._preprocess(val, type(val))
+ # in case of a variable the output must be without the quatoation marks
+ if attrType is _TYPE_VARIABLE:
+ output = output.lstrip('\"')
+ # we cannot use rstrip because there are two subsequent " at the end
+ output = output[:-1]
+ self._stream.write(output)
def _writeFileAttr(self, key, data):
self._stream.write(_INDENT)
From 06061e37dc2b1e42f168457b99744f8fb1453ecc Mon Sep 17 00:00:00 2001
From: Uwe
Date: Sat, 18 Mar 2023 05:36:36 +0100
Subject: [PATCH 47/53] [FEM] rewrite velocity constraint
- complete revision of the constraint.
This is a breaking change, meaning existing constraints won't work.
This is possible because since 2 days ago the whole flow equation did not work at all. Also the existing constraint implementation if buggy and cannot be used to do the Elmer tutorial. Also, the constraint is only used by Elmer and only be the flow equation.
Since nobody complained about the obvious wrong results, we can assume the flow equation was not yet in practical usage (and for FC 0.20 we known that it does not work at all, first with FC 0.20.1).
It is necessary since it must be possible to either input a velocity or an equation. With an equation, a velocity profile can be specified.
- update the flow examples accordingly:
-- simplify them since an initial and and output velocity is not necessary to specify
-- use a formula as input velocity for the non-turbulent example
---
src/Mod/Fem/Gui/Resources/ui/FlowVelocity.ui | 280 +++++++++---------
.../Fem/femexamples/equation_flow_elmer_2D.py | 48 +--
.../equation_flow_turbulent_elmer_2D.py | 48 +--
.../Fem/femobjects/constraint_flowvelocity.py | 54 +++-
.../femsolver/elmer/equations/flow_writer.py | 21 +-
.../task_constraint_flowvelocity.py | 190 ++++++++++--
6 files changed, 391 insertions(+), 250 deletions(-)
diff --git a/src/Mod/Fem/Gui/Resources/ui/FlowVelocity.ui b/src/Mod/Fem/Gui/Resources/ui/FlowVelocity.ui
index 3793c63e4f..088c802cc8 100644
--- a/src/Mod/Fem/Gui/Resources/ui/FlowVelocity.ui
+++ b/src/Mod/Fem/Gui/Resources/ui/FlowVelocity.ui
@@ -6,78 +6,27 @@
0
0
- 400
- 300
+ 300
+ 197
Constraint Properties
-
-
-
-
-
- Velocity x:
-
-
-
- -
-
-
- Velocity y:
-
-
-
- -
-
-
- Velocity z:
-
-
-
- -
-
-
-
-
+
+
-
+
+
-
+
false
-
- 1.000000000000000
-
-
- m/s
-
-
-
- -
-
- unspecified
-
-
- true
+ formula
-
-
- -
-
-
-
-
-
- false
-
-
- 1.000000000000000
-
-
- m/s
-
-
-
- -
+
-
unspecified
@@ -87,24 +36,52 @@
-
-
- -
-
-
-
-
-
- false
-
-
- 1.000000000000000
-
-
- m/s
+
-
+
+
+ Velocity x:
- -
+
-
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ formula
+
+
+
+ -
+
+
+ Velocity y:
+
+
+
+ -
unspecified
@@ -114,12 +91,77 @@
+ -
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
- -
+
-
+
+
-
+
+
+ unspecified
+
+
+ true
+
+
+
+ -
+
+
+ false
+
+
+ formula
+
+
+
+ -
+
+
+ Velocity z:
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
+
+
+ -
- normal to boundary
+ Normal to boundary
@@ -127,9 +169,9 @@
- Gui::InputField
- QLineEdit
-
+ Gui::QuantitySpinBox
+ QWidget
+
@@ -137,96 +179,48 @@
velocityXBox
toggled(bool)
- velocityXTxt
- setEnabled(bool)
-
-
- 230
- 44
-
-
- 230
- 18
-
-
-
-
- velocityXBox
- toggled(bool)
- velocityXTxt
+ formulaXCB
setDisabled(bool)
- 230
- 44
+ 351
+ 19
- 230
- 18
+ 351
+ 45
velocityYBox
toggled(bool)
- velocityYTxt
- setEnabled(bool)
-
-
- 347
- 53
-
-
- 184
- 53
-
-
-
-
- velocityYBox
- toggled(bool)
- velocityYTxt
+ formulaYCB
setDisabled(bool)
- 347
- 53
+ 351
+ 73
- 184
- 53
+ 351
+ 99
velocityZBox
toggled(bool)
- velocityZTxt
- setEnabled(bool)
-
-
- 347
- 87
-
-
- 184
- 87
-
-
-
-
- velocityZBox
- toggled(bool)
- velocityZTxt
+ formulaZCB
setDisabled(bool)
- 347
- 87
+ 351
+ 127
- 184
- 87
+ 351
+ 153
diff --git a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
index 32d09e317d..60e71d5cb1 100644
--- a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
@@ -71,19 +71,19 @@ def setup(doc=None, solvertype="elmer"):
# geometric objects
# the wire defining the pipe volume in 2D
- p1 = Vector(400, 0, -50.000)
- p2 = Vector(400, 0, -150.000)
- p3 = Vector(1200, 0, -150.000)
- p4 = Vector(1200, 0, 50.000)
- p5 = Vector(0, 0, 50.000)
- p6 = Vector(0, 0, -50.000)
+ p1 = Vector(400, -50.000, 0)
+ p2 = Vector(400, -150.000, 0)
+ p3 = Vector(1200, -150.000, 0)
+ p4 = Vector(1200, 50.000, 0)
+ p5 = Vector(0, 50.000, 0)
+ p6 = Vector(0, -50.000, 0)
wire = Draft.make_wire([p1, p2, p3, p4, p5, p6], closed=True)
wire.Label = "Wire"
# the circle defining the heating rod
pCirc = Vector(160, 0, 0)
axisCirc = Vector(1, 0, 0)
- placementCircle = Placement(pCirc, Rotation(axisCirc, 90))
+ placementCircle = Placement(pCirc, Rotation(axisCirc, 0))
circle = Draft.make_circle(10, placement=placementCircle)
circle.Label = "HeatingRod"
circle.ViewObject.Visibility = False
@@ -107,7 +107,6 @@ def setup(doc=None, solvertype="elmer"):
doc.recompute()
if FreeCAD.GuiUp:
BooleanFragments.ViewObject.Transparency = 50
- BooleanFragments.ViewObject.Document.activeView().viewFront()
BooleanFragments.ViewObject.Document.activeView().fitAll()
# analysis
@@ -119,6 +118,7 @@ def setup(doc=None, solvertype="elmer"):
# solver
if solvertype == "elmer":
solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer")
+ solver_obj.CoordinateSystem = "Cartesian 2D"
equation_flow = ObjectsFem.makeEquationFlow(doc, solver_obj)
equation_heat = ObjectsFem.makeEquationHeat(doc, solver_obj)
else:
@@ -133,6 +133,7 @@ def setup(doc=None, solvertype="elmer"):
equation_flow.IdrsParameter = 3
equation_flow.LinearIterativeMethod = "Idrs"
equation_flow.LinearPreconditioning = "ILU1"
+ equation_flow.Variable = "Flow Solution[Velocity:2 Pressure:1]"
equation_heat.Convection = "Computed"
equation_heat.IdrsParameter = 3
equation_heat.LinearIterativeMethod = "Idrs"
@@ -179,20 +180,11 @@ def setup(doc=None, solvertype="elmer"):
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
FlowVelocity_Inlet.NormalDirection = Vector(-1, 0, 0)
- FlowVelocity_Inlet.VelocityX = 0.020
- FlowVelocity_Inlet.VelocityXEnabled = True
- FlowVelocity_Inlet.VelocityYEnabled = True
- FlowVelocity_Inlet.VelocityZEnabled = True
+ FlowVelocity_Inlet.VelocityXFormula = "Variable Coordinate 2; Real MATC \"-0.01*(tx-1)*(2-tx)\""
+ FlowVelocity_Inlet.VelocityXUnspecified = False
+ FlowVelocity_Inlet.VelocityXHasFormula = True
analysis.addObject(FlowVelocity_Inlet)
- # constraint outlet velocity
- FlowVelocity_Outlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Outlet")
- FlowVelocity_Outlet.References = [(BooleanFragments, "Edge6")]
- FlowVelocity_Outlet.NormalDirection = Vector(1, 0, 0)
- FlowVelocity_Outlet.VelocityYEnabled = True
- FlowVelocity_Outlet.VelocityZEnabled = True
- analysis.addObject(FlowVelocity_Outlet)
-
# constraint wall velocity
FlowVelocity_Wall = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Wall")
FlowVelocity_Wall.References = [
@@ -200,21 +192,11 @@ def setup(doc=None, solvertype="elmer"):
(BooleanFragments, "Edge3"),
(BooleanFragments, "Edge4"),
(BooleanFragments, "Edge7")]
- FlowVelocity_Wall.NormalDirection = Vector(0, 0, -1)
- FlowVelocity_Wall.VelocityXEnabled = True
- FlowVelocity_Wall.VelocityYEnabled = True
- FlowVelocity_Wall.VelocityZEnabled = True
+ FlowVelocity_Wall.NormalDirection = Vector(0, -1, 0)
+ FlowVelocity_Wall.VelocityXUnspecified = False
+ FlowVelocity_Wall.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Wall)
- # constraint initial velocity
- FlowVelocity_Initial = ObjectsFem.makeConstraintInitialFlowVelocity(doc, "FlowVelocity_Initial")
- FlowVelocity_Initial.References = [(BooleanFragments, "Face2")]
- FlowVelocity_Initial.NormalDirection = Vector(0, -1, 0)
- FlowVelocity_Initial.VelocityXEnabled = True
- FlowVelocity_Initial.VelocityYEnabled = True
- FlowVelocity_Initial.VelocityZEnabled = True
- analysis.addObject(FlowVelocity_Initial)
-
# constraint initial temperature
Temperature_Initial = ObjectsFem.makeConstraintInitialTemperature(doc, "Temperature_Initial")
Temperature_Initial.initialTemperature = 300.0
diff --git a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
index e21510bc75..3e8e2c631c 100644
--- a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
@@ -71,19 +71,19 @@ def setup(doc=None, solvertype="elmer"):
# geometric objects
# the wire defining the pipe volume in 2D
- p1 = Vector(400, 0, -50.000)
- p2 = Vector(400, 0, -150.000)
- p3 = Vector(1200, 0, -150.000)
- p4 = Vector(1200, 0, 50.000)
- p5 = Vector(0, 0, 50.000)
- p6 = Vector(0, 0, -50.000)
+ p1 = Vector(400, -50.000, 0)
+ p2 = Vector(400, -150.000, 0)
+ p3 = Vector(1200, -150.000, 0)
+ p4 = Vector(1200, 50.000, 0)
+ p5 = Vector(0, 50.000, 0)
+ p6 = Vector(0, -50.000, 0)
wire = Draft.make_wire([p1, p2, p3, p4, p5, p6], closed=True)
wire.Label = "Wire"
# the circle defining the heating rod
pCirc = Vector(160, 0, 0)
axisCirc = Vector(1, 0, 0)
- placementCircle = Placement(pCirc, Rotation(axisCirc, 90))
+ placementCircle = Placement(pCirc, Rotation(axisCirc, 0))
circle = Draft.make_circle(10, placement=placementCircle)
circle.Label = "HeatingRod"
circle.ViewObject.Visibility = False
@@ -107,7 +107,6 @@ def setup(doc=None, solvertype="elmer"):
doc.recompute()
if FreeCAD.GuiUp:
BooleanFragments.ViewObject.Transparency = 50
- BooleanFragments.ViewObject.Document.activeView().viewFront()
BooleanFragments.ViewObject.Document.activeView().fitAll()
# analysis
@@ -119,6 +118,7 @@ def setup(doc=None, solvertype="elmer"):
# solver
if solvertype == "elmer":
solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer")
+ solver_obj.CoordinateSystem = "Cartesian 2D"
equation_flow = ObjectsFem.makeEquationFlow(doc, solver_obj)
equation_heat = ObjectsFem.makeEquationHeat(doc, solver_obj)
else:
@@ -131,7 +131,6 @@ def setup(doc=None, solvertype="elmer"):
# solver settings
equation_flow.IdrsParameter = 3
- equation_flow.LinearIterations = 250
equation_flow.LinearIterativeMethod = "Idrs"
equation_flow.LinearPreconditioning = "ILU1"
equation_flow.setExpression("LinearTolerance", "1e-6")
@@ -139,9 +138,9 @@ def setup(doc=None, solvertype="elmer"):
equation_flow.NonlinearNewtonAfterIterations = 30
equation_flow.setExpression("NonlinearTolerance", "1e-4")
equation_flow.RelaxationFactor = 0.1
+ equation_flow.Variable = "Flow Solution[Velocity:2 Pressure:1]"
equation_heat.Convection = "Computed"
equation_heat.IdrsParameter = 3
- equation_heat.LinearIterations = 250
equation_heat.LinearIterativeMethod = "Idrs"
equation_heat.LinearPreconditioning = "ILU1"
equation_heat.setExpression("LinearTolerance", "1e-6")
@@ -187,20 +186,11 @@ def setup(doc=None, solvertype="elmer"):
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
FlowVelocity_Inlet.NormalDirection = Vector(-1, 0, 0)
- FlowVelocity_Inlet.VelocityX = 0.020
- FlowVelocity_Inlet.VelocityXEnabled = True
- FlowVelocity_Inlet.VelocityYEnabled = True
- FlowVelocity_Inlet.VelocityZEnabled = True
+ FlowVelocity_Inlet.VelocityX = "20.0 mm/s"
+ FlowVelocity_Inlet.VelocityXUnspecified = False
+ FlowVelocity_Inlet.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Inlet)
- # constraint outlet velocity
- FlowVelocity_Outlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Outlet")
- FlowVelocity_Outlet.References = [(BooleanFragments, "Edge6")]
- FlowVelocity_Outlet.NormalDirection = Vector(1, 0, 0)
- FlowVelocity_Outlet.VelocityYEnabled = True
- FlowVelocity_Outlet.VelocityZEnabled = True
- analysis.addObject(FlowVelocity_Outlet)
-
# constraint wall velocity
FlowVelocity_Wall = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Wall")
FlowVelocity_Wall.References = [
@@ -209,20 +199,10 @@ def setup(doc=None, solvertype="elmer"):
(BooleanFragments, "Edge4"),
(BooleanFragments, "Edge7")]
FlowVelocity_Wall.NormalDirection = Vector(0, 0, -1)
- FlowVelocity_Wall.VelocityXEnabled = True
- FlowVelocity_Wall.VelocityYEnabled = True
- FlowVelocity_Wall.VelocityZEnabled = True
+ FlowVelocity_Wall.VelocityXUnspecified = False
+ FlowVelocity_Wall.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Wall)
- # constraint initial velocity
- FlowVelocity_Initial = ObjectsFem.makeConstraintInitialFlowVelocity(doc, "FlowVelocity_Initial")
- FlowVelocity_Initial.References = [(BooleanFragments, "Face2")]
- FlowVelocity_Initial.NormalDirection = Vector(0, -1, 0)
- FlowVelocity_Initial.VelocityXEnabled = True
- FlowVelocity_Initial.VelocityYEnabled = True
- FlowVelocity_Initial.VelocityZEnabled = True
- analysis.addObject(FlowVelocity_Initial)
-
# constraint initial temperature
Temperature_Initial = ObjectsFem.makeConstraintInitialTemperature(doc, "Temperature_Initial")
Temperature_Initial.initialTemperature = 300.0
diff --git a/src/Mod/Fem/femobjects/constraint_flowvelocity.py b/src/Mod/Fem/femobjects/constraint_flowvelocity.py
index 5625439fa7..8243c3a622 100644
--- a/src/Mod/Fem/femobjects/constraint_flowvelocity.py
+++ b/src/Mod/Fem/femobjects/constraint_flowvelocity.py
@@ -40,41 +40,83 @@ class ConstraintFlowVelocity(base_fempythonobject.BaseFemPythonObject):
def __init__(self, obj):
super(ConstraintFlowVelocity, self).__init__(obj)
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyVelocity",
"VelocityX",
"Parameter",
"Velocity in x-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityXFormula",
+ "Parameter",
+ "Velocity formula in x-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityXEnabled",
+ "VelocityXUnspecified",
"Parameter",
"Use velocity in x-direction"
)
+ obj.VelocityXUnspecified = True
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyBool",
+ "VelocityXHasFormula",
+ "Parameter",
+ "Use formula for velocity in x-direction"
+ )
+
+ obj.addProperty(
+ "App::PropertyVelocity",
"VelocityY",
"Parameter",
"Velocity in y-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityYFormula",
+ "Parameter",
+ "Velocity formula in y-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityYEnabled",
+ "VelocityYUnspecified",
"Parameter",
"Use velocity in y-direction"
)
+ obj.VelocityYUnspecified = True
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyBool",
+ "VelocityYHasFormula",
+ "Parameter",
+ "Use formula for velocity in y-direction"
+ )
+
+ obj.addProperty(
+ "App::PropertyVelocity",
"VelocityZ",
"Parameter",
"Velocity in z-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityZFormula",
+ "Parameter",
+ "Velocity formula in z-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityZEnabled",
+ "VelocityZUnspecified",
"Parameter",
"Use velocity in z-direction"
)
+ obj.VelocityZUnspecified = True
+ obj.addProperty(
+ "App::PropertyBool",
+ "VelocityZHasFormula",
+ "Parameter",
+ "Use formula for velocity in z-direction"
+ )
+
obj.addProperty(
"App::PropertyBool",
"NormalToBoundary",
diff --git a/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py b/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
index 796d8adcd6..68dd68333c 100644
--- a/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
+++ b/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
@@ -227,14 +227,23 @@ class Flowwriter:
for obj in self.write.getMember("Fem::ConstraintFlowVelocity"):
if obj.References:
for name in obj.References[0][1]:
- if obj.VelocityXEnabled:
- velocity = self.write.getFromUi(obj.VelocityX, "m/s", "L/T")
+ if not obj.VelocityXUnspecified:
+ if not obj.VelocityXHasFormula:
+ velocity = float(obj.VelocityX.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityXFormula
self.write.boundary(name, "Velocity 1", velocity)
- if obj.VelocityYEnabled:
- velocity = self.write.getFromUi(obj.VelocityY, "m/s", "L/T")
+ if not obj.VelocityYUnspecified:
+ if not obj.VelocityYHasFormula:
+ velocity = float(obj.VelocityY.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityYFormula
self.write.boundary(name, "Velocity 2", velocity)
- if obj.VelocityZEnabled:
- velocity = self.write.getFromUi(obj.VelocityZ, "m/s", "L/T")
+ if not obj.VelocityZUnspecified:
+ if not obj.VelocityZHasFormula:
+ velocity = float(obj.VelocityZ.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityZFormula
self.write.boundary(name, "Velocity 3", velocity)
if obj.NormalToBoundary:
self.write.boundary(name, "Normal-Tangential Velocity", True)
diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_flowvelocity.py b/src/Mod/Fem/femtaskpanels/task_constraint_flowvelocity.py
index 7e98729b47..41f2d8d072 100644
--- a/src/Mod/Fem/femtaskpanels/task_constraint_flowvelocity.py
+++ b/src/Mod/Fem/femtaskpanels/task_constraint_flowvelocity.py
@@ -29,9 +29,10 @@ __url__ = "https://www.freecadweb.org"
# \ingroup FEM
# \brief task panel for constraint flow velocity object
+from PySide import QtCore
+
import FreeCAD
import FreeCADGui
-from FreeCAD import Units
from femguiutils import selection_widgets
from femtools import femutils
@@ -46,8 +47,7 @@ class _TaskPanel(object):
self._paramWidget = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/FlowVelocity.ui"
)
- self._initParamWidget()
-
+
# geometry selection widget
# start with Solid in list!
self._selectionWidget = selection_widgets.GeometryElementsSelection(
@@ -70,6 +70,96 @@ class _TaskPanel(object):
self._partVisible = None
self._meshVisible = None
+ # connect unspecified option
+ QtCore.QObject.connect(
+ self._paramWidget.velocityXBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityXEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.velocityYBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityYEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.velocityZBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityZEnable
+ )
+
+ # connect formula option
+ QtCore.QObject.connect(
+ self._paramWidget.formulaXCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaXEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.formulaYCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaYEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.formulaZCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaZEnable
+ )
+
+ self._initParamWidget()
+
+ def _velocityXEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaX.setDisabled(toggled)
+ self._paramWidget.velocityX.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaXCB.isChecked():
+ self._paramWidget.formulaX.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityX.setDisabled(toggled)
+
+ def _velocityYEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaY.setDisabled(toggled)
+ self._paramWidget.velocityY.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaYCB.isChecked():
+ self._paramWidget.formulaY.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityY.setDisabled(toggled)
+
+ def _velocityZEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaZ.setDisabled(toggled)
+ self._paramWidget.velocityZ.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaZCB.isChecked():
+ self._paramWidget.formulaZ.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityZ.setDisabled(toggled)
+
+ def _formulaXEnable(self, toggled):
+ FreeCAD.Console.PrintMessage("_formulaXEnable\n")
+ if self._paramWidget.velocityXBox.isChecked():
+ FreeCAD.Console.PrintMessage("velocityXBox isChecked\n")
+ return
+ else:
+ FreeCAD.Console.PrintMessage("velocityXBox not checked\n")
+ self._paramWidget.formulaX.setEnabled(toggled)
+ self._paramWidget.velocityX.setDisabled(toggled)
+
+ def _formulaYEnable(self, toggled):
+ if self._paramWidget.velocityYBox.isChecked():
+ return
+ else:
+ self._paramWidget.formulaY.setEnabled(toggled)
+ self._paramWidget.velocityY.setDisabled(toggled)
+
+ def _formulaZEnable(self, toggled):
+ if self._paramWidget.velocitZXBox.isChecked():
+ return
+ else:
+ self._paramWidget.formulaZ.setEnabled(toggled)
+ self._paramWidget.velocityZ.setDisabled(toggled)
+
def open(self):
if self._mesh is not None and self._part is not None:
self._meshVisible = self._mesh.ViewObject.isVisible()
@@ -104,36 +194,80 @@ class _TaskPanel(object):
def _initParamWidget(self):
unit = "m/s"
- self._paramWidget.velocityXTxt.setText(
- str(self._obj.VelocityX) + unit)
- self._paramWidget.velocityYTxt.setText(
- str(self._obj.VelocityY) + unit)
- self._paramWidget.velocityZTxt.setText(
- str(self._obj.VelocityZ) + unit)
+ self._paramWidget.velocityX.setProperty('unit', unit)
+ self._paramWidget.velocityY.setProperty('unit', unit)
+ self._paramWidget.velocityZ.setProperty('unit', unit)
+
+ self._paramWidget.velocityX.setProperty(
+ 'value', self._obj.VelocityX)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityX).bind(self._obj, "VelocityX")
self._paramWidget.velocityXBox.setChecked(
- not self._obj.VelocityXEnabled)
+ self._obj.VelocityXUnspecified)
+ self._paramWidget.formulaX.setText(self._obj.VelocityXFormula)
+ self._paramWidget.formulaXCB.setChecked(
+ self._obj.VelocityXHasFormula)
+
+ self._paramWidget.velocityY.setProperty(
+ 'value', self._obj.VelocityY)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityY).bind(self._obj, "VelocityY")
self._paramWidget.velocityYBox.setChecked(
- not self._obj.VelocityYEnabled)
+ self._obj.VelocityYUnspecified)
+ self._paramWidget.formulaY.setText(self._obj.VelocityYFormula)
+ self._paramWidget.formulaYCB.setChecked(
+ self._obj.VelocityYHasFormula)
+
+ self._paramWidget.velocityZ.setProperty(
+ 'value', self._obj.VelocityZ)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityZ).bind(self._obj, "VelocityZ")
self._paramWidget.velocityZBox.setChecked(
- not self._obj.VelocityZEnabled)
+ self._obj.VelocityZUnspecified)
+ self._paramWidget.formulaZ.setText(self._obj.VelocityZFormula)
+ self._paramWidget.formulaZCB.setChecked(
+ self._obj.VelocityZHasFormula)
+
self._paramWidget.normalBox.setChecked(
self._obj.NormalToBoundary)
+ def _applyVelocityChanges(self, enabledBox, velocityQSB):
+ enabled = enabledBox.isChecked()
+ velocity = None
+ try:
+ velocity = velocityQSB.property('value')
+ except ValueError:
+ FreeCAD.Console.PrintMessage(
+ "Wrong input. Not recognised input: '{}' "
+ "Velocity has not been set.\n".format(velocityQSB.text())
+ )
+ velocity = '0.0 m/s'
+ return enabled, velocity
+
def _applyWidgetChanges(self):
- unit = "m/s"
- self._obj.VelocityXEnabled = \
- not self._paramWidget.velocityXBox.isChecked()
- if self._obj.VelocityXEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityXTxt.text())
- self._obj.VelocityX = quantity.getValueAs(unit).Value
- self._obj.VelocityYEnabled = \
- not self._paramWidget.velocityYBox.isChecked()
- if self._obj.VelocityYEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityYTxt.text())
- self._obj.VelocityY = quantity.getValueAs(unit).Value
- self._obj.VelocityZEnabled = \
- not self._paramWidget.velocityZBox.isChecked()
- if self._obj.VelocityZEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
- self._obj.VelocityZ = quantity.getValueAs(unit).Value
+ # apply the velocities and their enabled state
+ self._obj.VelocityXUnspecified, self._obj.VelocityX = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityXBox,
+ self._paramWidget.velocityX
+ )
+ self._obj.VelocityXHasFormula = self._paramWidget.formulaXCB.isChecked()
+ self._obj.VelocityXFormula = self._paramWidget.formulaX.text()
+
+ self._obj.VelocityYUnspecified, self._obj.VelocityY = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityYBox,
+ self._paramWidget.velocityY
+ )
+ self._obj.VelocityYHasFormula = self._paramWidget.formulaYCB.isChecked()
+ self._obj.VelocityYFormula = self._paramWidget.formulaY.text()
+
+ self._obj.VelocityZUnspecified, self._obj.VelocityZ = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityZBox,
+ self._paramWidget.velocityZ
+ )
+ self._obj.VelocityZHasFormula = self._paramWidget.formulaZCB.isChecked()
+ self._obj.VelocityZFormula = self._paramWidget.formulaZ.text()
+
self._obj.NormalToBoundary = self._paramWidget.normalBox.isChecked()
From 90077233315743d9fb8ebff81fae1c7e3281390f Mon Sep 17 00:00:00 2001
From: Uwe
Date: Mon, 20 Mar 2023 04:28:45 +0100
Subject: [PATCH 48/53] [FEM] rewrite initial velocity constraint
- same as #8963 but for initial velocity
- add an example file that demonstrates the influence of the initial velocity
- some fine-tuning for the existing flow example
---
src/Mod/Fem/CMakeLists.txt | 1 +
.../Gui/Resources/ui/InitialFlowVelocity.ui | 247 ++++++++--------
.../Fem/femexamples/equation_flow_elmer_2D.py | 5 +-
.../equation_flow_initial_elmer_2D.py | 275 ++++++++++++++++++
.../equation_flow_turbulent_elmer_2D.py | 9 +-
src/Mod/Fem/femexamples/manager.py | 2 +
.../constraint_initialflowvelocity.py | 53 +++-
.../femsolver/elmer/equations/flow_writer.py | 21 +-
.../task_constraint_initialflowvelocity.py | 185 ++++++++++--
9 files changed, 623 insertions(+), 175 deletions(-)
create mode 100644 src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt
index e327feb1cc..6a12f99cf7 100755
--- a/src/Mod/Fem/CMakeLists.txt
+++ b/src/Mod/Fem/CMakeLists.txt
@@ -78,6 +78,7 @@ SET(FemExamples_SRCS
femexamples/equation_electrostatics_capacitance_two_balls.py
femexamples/equation_electrostatics_electricforce_elmer_nongui6.py
femexamples/equation_flow_elmer_2D.py
+ femexamples/equation_flow_initial_elmer_2D.py
femexamples/equation_flow_turbulent_elmer_2D.py
femexamples/equation_flux_elmer.py
femexamples/equation_magnetodynamics_elmer.py
diff --git a/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui b/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui
index e034b3f3f7..de26fc3c75 100644
--- a/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui
+++ b/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui
@@ -6,40 +6,27 @@
0
0
- 400
- 300
+ 300
+ 174
Constraint Properties
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
- -
-
-
- Velocity x:
-
-
-
- -
-
-
-
-
+
+
-
+
+
-
+
false
-
- 1.000000000000000
-
-
- m/s
+
+ formula
- -
+
-
unspecified
@@ -49,31 +36,52 @@
-
-
- -
-
-
- Velocity y:
-
-
-
- -
-
-
-
-
-
- false
-
-
- 1.000000000000000
-
-
- m/s
+
-
+
+
+ Velocity x:
- -
+
-
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ formula
+
+
+
+ -
+
+
+ Velocity y:
+
+
+
+ -
unspecified
@@ -83,31 +91,28 @@
-
-
- -
-
-
- Velocity z:
-
-
-
- -
-
-
-
-
+
-
+
false
-
- 1.000000000000000
+
+
+ -
+
+
+ false
- m/s
+
- -
+
+
+ -
+
+
-
unspecified
@@ -117,15 +122,49 @@
+ -
+
+
+ false
+
+
+ formula
+
+
+
+ -
+
+
+ Velocity z:
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
- Gui::InputField
- QLineEdit
-
+ Gui::QuantitySpinBox
+ QWidget
+
@@ -133,96 +172,48 @@
velocityXBox
toggled(bool)
- velocityXTxt
- setEnabled(bool)
-
-
- 230
- 44
-
-
- 230
- 18
-
-
-
-
- velocityXBox
- toggled(bool)
- velocityXTxt
+ formulaXCB
setDisabled(bool)
- 230
- 44
+ 351
+ 19
- 230
- 18
+ 351
+ 45
velocityYBox
toggled(bool)
- velocityYTxt
- setEnabled(bool)
-
-
- 347
- 53
-
-
- 184
- 53
-
-
-
-
- velocityYBox
- toggled(bool)
- velocityYTxt
+ formulaYCB
setDisabled(bool)
- 347
- 53
+ 351
+ 73
- 184
- 53
+ 351
+ 99
velocityZBox
toggled(bool)
- velocityZTxt
- setEnabled(bool)
-
-
- 347
- 87
-
-
- 184
- 87
-
-
-
-
- velocityZBox
- toggled(bool)
- velocityZTxt
+ formulaZCB
setDisabled(bool)
- 347
- 87
+ 351
+ 127
- 184
- 87
+ 351
+ 153
diff --git a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
index 60e71d5cb1..28b022b8e6 100644
--- a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
@@ -40,7 +40,7 @@ def get_information():
"name": "Flow - Elmer 2D",
"meshtype": "solid",
"meshelement": "Tet10",
- "constraints": ["initial pressure", "initial temperature", "initial velocity",
+ "constraints": ["initial pressure", "initial temperature",
"temperature", "velocity"],
"solvers": ["elmer"],
"material": "fluid",
@@ -179,10 +179,10 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet velocity
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
- FlowVelocity_Inlet.NormalDirection = Vector(-1, 0, 0)
FlowVelocity_Inlet.VelocityXFormula = "Variable Coordinate 2; Real MATC \"-0.01*(tx-1)*(2-tx)\""
FlowVelocity_Inlet.VelocityXUnspecified = False
FlowVelocity_Inlet.VelocityXHasFormula = True
+ FlowVelocity_Inlet.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Inlet)
# constraint wall velocity
@@ -192,7 +192,6 @@ def setup(doc=None, solvertype="elmer"):
(BooleanFragments, "Edge3"),
(BooleanFragments, "Edge4"),
(BooleanFragments, "Edge7")]
- FlowVelocity_Wall.NormalDirection = Vector(0, -1, 0)
FlowVelocity_Wall.VelocityXUnspecified = False
FlowVelocity_Wall.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Wall)
diff --git a/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
new file mode 100644
index 0000000000..384575558a
--- /dev/null
+++ b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
@@ -0,0 +1,275 @@
+# ***************************************************************************
+# * Copyright (c) 2023 Uwe Stöhr *
+# * *
+# * This file is part of the FreeCAD CAx development system. *
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU Lesser General Public License (LGPL) *
+# * as published by the Free Software Foundation; either version 2 of *
+# * the License, or (at your option) any later version. *
+# * for detail see the LICENCE text file. *
+# * *
+# * This program 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 program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
+
+import sys
+import FreeCAD
+from FreeCAD import Placement
+from FreeCAD import Rotation
+from FreeCAD import Vector
+
+import Draft
+import ObjectsFem
+
+from BOPTools import SplitFeatures
+from . import manager
+from .manager import get_meshname
+from .manager import init_doc
+
+def get_information():
+ return {
+ "name": "Initial Flow - Elmer 2D",
+ "meshtype": "solid",
+ "meshelement": "Tet10",
+ "constraints": ["initial pressure", "initial temperature", "initial velocity",
+ "temperature", "velocity"],
+ "solvers": ["elmer"],
+ "material": "fluid",
+ "equations": ["flow", "heat"]
+ }
+
+def get_explanation(header=""):
+ return header + """
+
+To run the example from Python console use:
+from femexamples.equation_flow_initial_elmer_2D import setup
+setup()
+
+Flow and Heat equation with initial velocity - Elmer solver
+
+"""
+
+def setup(doc=None, solvertype="elmer"):
+
+ # init FreeCAD document
+ if doc is None:
+ doc = init_doc()
+
+ # explanation object
+ # just keep the following line and change text string in get_explanation method
+ manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
+
+ # geometric objects
+
+ # the wire defining the pipe volume in 2D
+ p1 = Vector(400, -50.000, 0)
+ p2 = Vector(400, -150.000, 0)
+ p3 = Vector(1200, -150.000, 0)
+ p4 = Vector(1200, 50.000, 0)
+ p5 = Vector(0, 50.000, 0)
+ p6 = Vector(0, -50.000, 0)
+ wire = Draft.make_wire([p1, p2, p3, p4, p5, p6], closed=True)
+ wire.Label = "Wire"
+
+ # the circle defining the heating rod
+ pCirc = Vector(160, 0, 0)
+ axisCirc = Vector(1, 0, 0)
+ placementCircle = Placement(pCirc, Rotation(axisCirc, 0))
+ circle = Draft.make_circle(10, placement=placementCircle)
+ circle.Label = "HeatingRod"
+ circle.ViewObject.Visibility = False
+
+ # a link of the circle
+ circleLink = doc.addObject("App::Link", "Link-HeatingRod")
+ circleLink.LinkTransform = True
+ circleLink.LinkedObject = circle
+
+ # cut rod from wire to get volume of fluid
+ cut = doc.addObject("Part::Cut", "Cut")
+ cut.Base = wire
+ cut.Tool = circleLink
+ cut.ViewObject.Visibility = False
+
+ # BooleanFregments object to combine cut with rod
+ BooleanFragments = SplitFeatures.makeBooleanFragments(name="BooleanFragments")
+ BooleanFragments.Objects = [cut, circle]
+
+ # set view
+ doc.recompute()
+ if FreeCAD.GuiUp:
+ BooleanFragments.ViewObject.Transparency = 50
+ BooleanFragments.ViewObject.Document.activeView().fitAll()
+
+ # analysis
+ analysis = ObjectsFem.makeAnalysis(doc, "Analysis")
+ if FreeCAD.GuiUp:
+ import FemGui
+ FemGui.setActiveAnalysis(analysis)
+
+ # solver
+ if solvertype == "elmer":
+ solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer")
+ solver_obj.CoordinateSystem = "Cartesian 2D"
+ equation_flow = ObjectsFem.makeEquationFlow(doc, solver_obj)
+ equation_heat = ObjectsFem.makeEquationHeat(doc, solver_obj)
+ else:
+ FreeCAD.Console.PrintWarning(
+ "Unknown or unsupported solver type: {}. "
+ "No solver object was created.\n".format(solvertype)
+ )
+ return doc
+ analysis.addObject(solver_obj)
+
+ # solver settings
+ equation_flow.IdrsParameter = 3
+ equation_flow.LinearIterativeMethod = "Idrs"
+ equation_flow.LinearPreconditioning = "ILU1"
+ equation_flow.NonlinearIterations = 20
+ equation_flow.NonlinearNewtonAfterIterations = 20
+ equation_flow.RelaxationFactor = 0.15
+ equation_flow.Variable = "Flow Solution[Velocity:2 Pressure:1]"
+ equation_heat.Convection = "Computed"
+ equation_heat.IdrsParameter = 3
+ equation_heat.LinearIterativeMethod = "Idrs"
+ equation_heat.LinearPreconditioning = "ILU1"
+ equation_heat.NonlinearIterations = 20
+ equation_heat.NonlinearNewtonAfterIterations = 20
+ equation_heat.Priority = 5
+ equation_heat.RelaxationFactor = 0.15
+ equation_heat.Stabilize = True
+
+ # material
+
+ # fluid
+ material_obj = ObjectsFem.makeMaterialFluid(doc, "Material_Fluid")
+ mat = material_obj.Material
+ mat["Name"] = "Carbon dioxide"
+ mat["Density"] = "1.8393 kg/m^3"
+ mat["DynamicViscosity"] = "14.7e-6 kg/m/s"
+ mat["ThermalConductivity"] = "0.016242 W/m/K"
+ mat["ThermalExpansionCoefficient"] = "0.00343 m/m/K"
+ mat["SpecificHeat"] = "0.846 kJ/kg/K"
+ material_obj.Material = mat
+ material_obj.References = [(BooleanFragments, "Face2")]
+ analysis.addObject(material_obj)
+
+ # tube wall
+ material_obj = ObjectsFem.makeMaterialSolid(doc, "Material_Wall")
+ mat = material_obj.Material
+ mat["Name"] = "Aluminum Generic"
+ mat["Density"] = "2700 kg/m^3"
+ mat["PoissonRatio"] = "0.35"
+ mat["ShearModulus"] = "25.0 GPa"
+ mat["UltimateTensileStrength"] = "310 MPa"
+ mat["YoungsModulus"] = "70000 MPa"
+ mat["ThermalConductivity"] = "237.0 W/m/K"
+ mat["ThermalExpansionCoefficient"] = "23.1 µm/m/K"
+ mat["SpecificHeat"] = "897.0 J/kg/K"
+ material_obj.Material = mat
+ material_obj.References = [(BooleanFragments, "Face1")]
+ analysis.addObject(material_obj)
+
+ # constraint inlet velocity
+ FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
+ FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
+ FlowVelocity_Inlet.VelocityX = "20.0 mm/s"
+ FlowVelocity_Inlet.VelocityXUnspecified = False
+ analysis.addObject(FlowVelocity_Inlet)
+
+ # constraint wall velocity
+ FlowVelocity_Wall = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Wall")
+ FlowVelocity_Wall.References = [
+ (BooleanFragments, "Edge2"),
+ (BooleanFragments, "Edge3"),
+ (BooleanFragments, "Edge4"),
+ (BooleanFragments, "Edge7")]
+ FlowVelocity_Wall.VelocityXUnspecified = False
+ FlowVelocity_Wall.VelocityYUnspecified = False
+ analysis.addObject(FlowVelocity_Wall)
+
+ # constraint initial velocity
+ FlowVelocity_Initial = ObjectsFem.makeConstraintInitialFlowVelocity(doc, "FlowVelocity_Initial")
+ FlowVelocity_Initial.References = [(BooleanFragments, "Face2")]
+ FlowVelocity_Initial.VelocityX = "20.0 mm/s"
+ FlowVelocity_Initial.VelocityY = "-20.0 mm/s"
+ FlowVelocity_Initial.VelocityXUnspecified = False
+ FlowVelocity_Initial.VelocityYUnspecified = False
+ analysis.addObject(FlowVelocity_Initial)
+
+ # constraint initial temperature
+ Temperature_Initial = ObjectsFem.makeConstraintInitialTemperature(doc, "Temperature_Initial")
+ Temperature_Initial.initialTemperature = 300.0
+ analysis.addObject(Temperature_Initial)
+
+ # constraint wall temperature
+ Temperature_Wall = ObjectsFem.makeConstraintTemperature(doc, "Temperature_Wall")
+ Temperature_Wall.Temperature = 300.0
+ Temperature_Wall.NormalDirection = Vector(0, 0, -1)
+ Temperature_Wall.References = [
+ (BooleanFragments, "Edge2"),
+ (BooleanFragments, "Edge3"),
+ (BooleanFragments, "Edge4"),
+ (BooleanFragments, "Edge7")]
+ analysis.addObject(Temperature_Wall)
+
+ # constraint inlet temperature
+ Temperature_Inlet = ObjectsFem.makeConstraintTemperature(doc, "Temperature_Inlet")
+ Temperature_Inlet.Temperature = 350.0
+ Temperature_Inlet.NormalDirection = Vector(-1, 0, 0)
+ Temperature_Inlet.References = [(BooleanFragments, "Edge5")]
+ analysis.addObject(Temperature_Inlet)
+
+ # constraint heating rod temperature
+ Temperature_HeatingRod = ObjectsFem.makeConstraintTemperature(doc, "Temperature_HeatingRod")
+ Temperature_HeatingRod.Temperature = 373.0
+ Temperature_HeatingRod.NormalDirection = Vector(0, -1, 0)
+ Temperature_HeatingRod.References = [(BooleanFragments, "Edge1")]
+ analysis.addObject(Temperature_HeatingRod)
+
+ # constraint initial pressure
+ Pressure_Initial = ObjectsFem.makeConstraintInitialPressure(doc, "Pressure_Initial")
+ Pressure_Initial.Pressure = "100.0 kPa"
+ Pressure_Initial.NormalDirection = Vector(0, -1, 0)
+ Pressure_Initial.References = [(BooleanFragments, "Face2")]
+ analysis.addObject(Pressure_Initial)
+
+ # mesh
+ femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
+ femmesh_obj.Part = BooleanFragments
+ femmesh_obj.ElementOrder = "1st"
+ femmesh_obj.CharacteristicLengthMax = "4 mm"
+ femmesh_obj.ViewObject.Visibility = False
+
+ # mesh_region
+ mesh_region = ObjectsFem.makeMeshRegion(doc, femmesh_obj, name="MeshRegion")
+ mesh_region.CharacteristicLength = "2 mm"
+ mesh_region.References = [
+ (BooleanFragments, "Edge1"),
+ (BooleanFragments, "Vertex2"),
+ (BooleanFragments, "Vertex4"),
+ (BooleanFragments, "Vertex6")]
+ mesh_region.ViewObject.Visibility = False
+
+ # generate the mesh
+ from femmesh import gmshtools
+ gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis)
+ try:
+ error = gmsh_mesh.create_mesh()
+ except Exception:
+ error = sys.exc_info()[1]
+ FreeCAD.Console.PrintError(
+ "Unexpected error when creating mesh: {}\n"
+ .format(error)
+ )
+
+ doc.recompute()
+ return doc
diff --git a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
index 3e8e2c631c..a203da2160 100644
--- a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
@@ -40,7 +40,7 @@ def get_information():
"name": "Turbulent Flow - Elmer 2D",
"meshtype": "solid",
"meshelement": "Tet10",
- "constraints": ["initial pressure", "initial temperature", "initial velocity",
+ "constraints": ["initial pressure", "initial temperature",
"temperature", "velocity"],
"solvers": ["elmer"],
"material": "fluid",
@@ -54,7 +54,7 @@ To run the example from Python console use:
from femexamples.equation_flow_turbulent_elmer_2D import setup
setup()
-Flow and Heat equation - Elmer solver
+Flow and Heat equation in turbulent flow - Elmer solver
"""
@@ -136,8 +136,8 @@ def setup(doc=None, solvertype="elmer"):
equation_flow.setExpression("LinearTolerance", "1e-6")
equation_flow.NonlinearIterations = 30
equation_flow.NonlinearNewtonAfterIterations = 30
- equation_flow.setExpression("NonlinearTolerance", "1e-4")
equation_flow.RelaxationFactor = 0.1
+ equation_flow.setExpression("NonlinearTolerance", "1e-4")
equation_flow.Variable = "Flow Solution[Velocity:2 Pressure:1]"
equation_heat.Convection = "Computed"
equation_heat.IdrsParameter = 3
@@ -185,10 +185,8 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet velocity
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
- FlowVelocity_Inlet.NormalDirection = Vector(-1, 0, 0)
FlowVelocity_Inlet.VelocityX = "20.0 mm/s"
FlowVelocity_Inlet.VelocityXUnspecified = False
- FlowVelocity_Inlet.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Inlet)
# constraint wall velocity
@@ -198,7 +196,6 @@ def setup(doc=None, solvertype="elmer"):
(BooleanFragments, "Edge3"),
(BooleanFragments, "Edge4"),
(BooleanFragments, "Edge7")]
- FlowVelocity_Wall.NormalDirection = Vector(0, 0, -1)
FlowVelocity_Wall.VelocityXUnspecified = False
FlowVelocity_Wall.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Wall)
diff --git a/src/Mod/Fem/femexamples/manager.py b/src/Mod/Fem/femexamples/manager.py
index a0eda86964..a23316e7e8 100644
--- a/src/Mod/Fem/femexamples/manager.py
+++ b/src/Mod/Fem/femexamples/manager.py
@@ -71,6 +71,7 @@ def run_all():
run_example("equation_electrostatics_capacitance_two_balls", run_solver=True)
run_example("equation_electrostatics_electricforce_elmer_nongui6", run_solver=True)
run_example("equation_flow_elmer_2D", run_solver=True)
+ run_example("equation_flow_initial_elmer_2D", run_solver=True)
run_example("equation_flow_turbulent_elmer_2D", run_solver=True)
run_example("equation_flux_elmer", run_solver=True)
run_example("equation_magnetodynamics_elmer", run_solver=True)
@@ -109,6 +110,7 @@ def setup_all():
run_example("equation_electrostatics_capacitance_two_balls")
run_example("equation_electrostatics_electricforce_elmer_nongui6")
run_example("equation_flow_elmer_2D")
+ run_example("equation_flow_initial_elmer_2D")
run_example("equation_flow_turbulent_elmer_2D")
run_example("equation_flux_elmer")
run_example("equation_magnetodynamics_elmer")
diff --git a/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py b/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py
index 0598767641..097e390679 100644
--- a/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py
+++ b/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py
@@ -40,38 +40,79 @@ class ConstraintInitialFlowVelocity(base_fempythonobject.BaseFemPythonObject):
def __init__(self, obj):
super(ConstraintInitialFlowVelocity, self).__init__(obj)
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyVelocity",
"VelocityX",
"Parameter",
"Velocity in x-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityXFormula",
+ "Parameter",
+ "Velocity formula in x-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityXEnabled",
+ "VelocityXUnspecified",
"Parameter",
"Use velocity in x-direction"
)
+ obj.VelocityXUnspecified = True
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyBool",
+ "VelocityXHasFormula",
+ "Parameter",
+ "Use formula for velocity in x-direction"
+ )
+
+ obj.addProperty(
+ "App::PropertyVelocity",
"VelocityY",
"Parameter",
"Velocity in y-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityYFormula",
+ "Parameter",
+ "Velocity formula in y-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityYEnabled",
+ "VelocityYUnspecified",
"Parameter",
"Use velocity in y-direction"
)
+ obj.VelocityYUnspecified = True
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyBool",
+ "VelocityYHasFormula",
+ "Parameter",
+ "Use formula for velocity in y-direction"
+ )
+
+ obj.addProperty(
+ "App::PropertyVelocity",
"VelocityZ",
"Parameter",
"Velocity in z-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityZFormula",
+ "Parameter",
+ "Velocity formula in z-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityZEnabled",
+ "VelocityZUnspecified",
"Parameter",
"Use velocity in z-direction"
)
+ obj.VelocityZUnspecified = True
+ obj.addProperty(
+ "App::PropertyBool",
+ "VelocityZHasFormula",
+ "Parameter",
+ "Use formula for velocity in z-direction"
+ )
diff --git a/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py b/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
index 68dd68333c..176706a56d 100644
--- a/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
+++ b/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
@@ -193,14 +193,23 @@ class Flowwriter:
def _outputInitialVelocity(self, obj, name):
# flow only makes sense for fluid material
if self.write.isBodyMaterialFluid(name):
- if obj.VelocityXEnabled:
- velocity = self.write.getFromUi(obj.VelocityX, "m/s", "L/T")
+ if not obj.VelocityXUnspecified:
+ if not obj.VelocityXHasFormula:
+ velocity = float(obj.VelocityX.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityXFormula
self.write.initial(name, "Velocity 1", velocity)
- if obj.VelocityYEnabled:
- velocity = self.write.getFromUi(obj.VelocityY, "m/s", "L/T")
+ if not obj.VelocityYUnspecified:
+ if not obj.VelocityYHasFormula:
+ velocity = float(obj.VelocityY.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityYFormula
self.write.initial(name, "Velocity 2", velocity)
- if obj.VelocityZEnabled:
- velocity = self.write.getFromUi(obj.VelocityZ, "m/s", "L/T")
+ if not obj.VelocityZUnspecified:
+ if not obj.VelocityZHasFormula:
+ velocity = float(obj.VelocityZ.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityZFormula
self.write.initial(name, "Velocity 3", velocity)
def handleFlowInitialVelocity(self, bodies):
diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py b/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py
index 91fafc536a..dcae4622f8 100644
--- a/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py
+++ b/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py
@@ -30,6 +30,8 @@ __url__ = "https://www.freecadweb.org"
# \ingroup FEM
# \brief task panel for constraint initial flow velocity object
+from PySide import QtCore
+
import FreeCAD
import FreeCADGui
from FreeCAD import Units
@@ -46,7 +48,6 @@ class _TaskPanel(object):
self._paramWidget = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/InitialFlowVelocity.ui")
- self._initParamWidget()
# geometry selection widget
# start with Solid in list!
@@ -70,6 +71,96 @@ class _TaskPanel(object):
self._partVisible = None
self._meshVisible = None
+ # connect unspecified option
+ QtCore.QObject.connect(
+ self._paramWidget.velocityXBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityXEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.velocityYBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityYEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.velocityZBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityZEnable
+ )
+
+ # connect formula option
+ QtCore.QObject.connect(
+ self._paramWidget.formulaXCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaXEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.formulaYCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaYEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.formulaZCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaZEnable
+ )
+
+ self._initParamWidget()
+
+ def _velocityXEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaX.setDisabled(toggled)
+ self._paramWidget.velocityX.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaXCB.isChecked():
+ self._paramWidget.formulaX.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityX.setDisabled(toggled)
+
+ def _velocityYEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaY.setDisabled(toggled)
+ self._paramWidget.velocityY.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaYCB.isChecked():
+ self._paramWidget.formulaY.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityY.setDisabled(toggled)
+
+ def _velocityZEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaZ.setDisabled(toggled)
+ self._paramWidget.velocityZ.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaZCB.isChecked():
+ self._paramWidget.formulaZ.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityZ.setDisabled(toggled)
+
+ def _formulaXEnable(self, toggled):
+ FreeCAD.Console.PrintMessage("_formulaXEnable\n")
+ if self._paramWidget.velocityXBox.isChecked():
+ FreeCAD.Console.PrintMessage("velocityXBox isChecked\n")
+ return
+ else:
+ FreeCAD.Console.PrintMessage("velocityXBox not checked\n")
+ self._paramWidget.formulaX.setEnabled(toggled)
+ self._paramWidget.velocityX.setDisabled(toggled)
+
+ def _formulaYEnable(self, toggled):
+ if self._paramWidget.velocityYBox.isChecked():
+ return
+ else:
+ self._paramWidget.formulaY.setEnabled(toggled)
+ self._paramWidget.velocityY.setDisabled(toggled)
+
+ def _formulaZEnable(self, toggled):
+ if self._paramWidget.velocitZXBox.isChecked():
+ return
+ else:
+ self._paramWidget.formulaZ.setEnabled(toggled)
+ self._paramWidget.velocityZ.setDisabled(toggled)
+
def open(self):
if self._mesh is not None and self._part is not None:
self._meshVisible = self._mesh.ViewObject.isVisible()
@@ -104,33 +195,75 @@ class _TaskPanel(object):
def _initParamWidget(self):
unit = "m/s"
- self._paramWidget.velocityXTxt.setText(
- str(self._obj.VelocityX) + unit)
- self._paramWidget.velocityYTxt.setText(
- str(self._obj.VelocityY) + unit)
- self._paramWidget.velocityZTxt.setText(
- str(self._obj.VelocityZ) + unit)
+ self._paramWidget.velocityX.setProperty('unit', unit)
+ self._paramWidget.velocityY.setProperty('unit', unit)
+ self._paramWidget.velocityZ.setProperty('unit', unit)
+
+ self._paramWidget.velocityX.setProperty(
+ 'value', self._obj.VelocityX)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityX).bind(self._obj, "VelocityX")
self._paramWidget.velocityXBox.setChecked(
- not self._obj.VelocityXEnabled)
+ self._obj.VelocityXUnspecified)
+ self._paramWidget.formulaX.setText(self._obj.VelocityXFormula)
+ self._paramWidget.formulaXCB.setChecked(
+ self._obj.VelocityXHasFormula)
+
+ self._paramWidget.velocityY.setProperty(
+ 'value', self._obj.VelocityY)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityY).bind(self._obj, "VelocityY")
self._paramWidget.velocityYBox.setChecked(
- not self._obj.VelocityYEnabled)
+ self._obj.VelocityYUnspecified)
+ self._paramWidget.formulaY.setText(self._obj.VelocityYFormula)
+ self._paramWidget.formulaYCB.setChecked(
+ self._obj.VelocityYHasFormula)
+
+ self._paramWidget.velocityZ.setProperty(
+ 'value', self._obj.VelocityZ)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityZ).bind(self._obj, "VelocityZ")
self._paramWidget.velocityZBox.setChecked(
- not self._obj.VelocityZEnabled)
+ self._obj.VelocityZUnspecified)
+ self._paramWidget.formulaZ.setText(self._obj.VelocityZFormula)
+ self._paramWidget.formulaZCB.setChecked(
+ self._obj.VelocityZHasFormula)
+
+ def _applyVelocityChanges(self, enabledBox, velocityQSB):
+ enabled = enabledBox.isChecked()
+ velocity = None
+ try:
+ velocity = velocityQSB.property('value')
+ except ValueError:
+ FreeCAD.Console.PrintMessage(
+ "Wrong input. Not recognised input: '{}' "
+ "Velocity has not been set.\n".format(velocityQSB.text())
+ )
+ velocity = '0.0 m/s'
+ return enabled, velocity
def _applyWidgetChanges(self):
- unit = "m/s"
- self._obj.VelocityXEnabled = \
- not self._paramWidget.velocityXBox.isChecked()
- if self._obj.VelocityXEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityXTxt.text())
- self._obj.VelocityX = quantity.getValueAs(unit).Value
- self._obj.VelocityYEnabled = \
- not self._paramWidget.velocityYBox.isChecked()
- if self._obj.VelocityYEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityYTxt.text())
- self._obj.VelocityY = quantity.getValueAs(unit).Value
- self._obj.VelocityZEnabled = \
- not self._paramWidget.velocityZBox.isChecked()
- if self._obj.VelocityZEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
- self._obj.VelocityZ = quantity.getValueAs(unit).Value
+ # apply the velocities and their enabled state
+ self._obj.VelocityXUnspecified, self._obj.VelocityX = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityXBox,
+ self._paramWidget.velocityX
+ )
+ self._obj.VelocityXHasFormula = self._paramWidget.formulaXCB.isChecked()
+ self._obj.VelocityXFormula = self._paramWidget.formulaX.text()
+
+ self._obj.VelocityYUnspecified, self._obj.VelocityY = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityYBox,
+ self._paramWidget.velocityY
+ )
+ self._obj.VelocityYHasFormula = self._paramWidget.formulaYCB.isChecked()
+ self._obj.VelocityYFormula = self._paramWidget.formulaY.text()
+
+ self._obj.VelocityZUnspecified, self._obj.VelocityZ = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityZBox,
+ self._paramWidget.velocityZ
+ )
+ self._obj.VelocityZHasFormula = self._paramWidget.formulaZCB.isChecked()
+ self._obj.VelocityZFormula = self._paramWidget.formulaZ.text()
From 431fafc5337976c43bf50aae7bc75b46ee8037c7 Mon Sep 17 00:00:00 2001
From: Uwe
Date: Mon, 20 Mar 2023 07:03:56 +0100
Subject: [PATCH 49/53] [FEM] fine-tune flow examples
- use a more sensible velocity distribution
- change inlet temperature for 2 examples
- also change step size for nonlinear iterations for more convenience for practical usage
---
src/Mod/Fem/femexamples/equation_flow_elmer_2D.py | 4 ++--
.../femexamples/equation_flow_initial_elmer_2D.py | 2 +-
.../femexamples/equation_flow_turbulent_elmer_2D.py | 12 +++++++-----
src/Mod/Fem/femsolver/elmer/equations/nonlinear.py | 2 +-
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
index 28b022b8e6..5bf55721eb 100644
--- a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
@@ -179,7 +179,7 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet velocity
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
- FlowVelocity_Inlet.VelocityXFormula = "Variable Coordinate 2; Real MATC \"-0.01*(tx-1)*(2-tx)\""
+ FlowVelocity_Inlet.VelocityXFormula = "Variable Coordinate 2; Real MATC \"10*(tx+50e-3)*(50e-3-tx)\""
FlowVelocity_Inlet.VelocityXUnspecified = False
FlowVelocity_Inlet.VelocityXHasFormula = True
FlowVelocity_Inlet.VelocityYUnspecified = False
@@ -214,7 +214,7 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet temperature
Temperature_Inlet = ObjectsFem.makeConstraintTemperature(doc, "Temperature_Inlet")
- Temperature_Inlet.Temperature = 350.0
+ Temperature_Inlet.Temperature = 300.0
Temperature_Inlet.NormalDirection = Vector(-1, 0, 0)
Temperature_Inlet.References = [(BooleanFragments, "Edge5")]
analysis.addObject(Temperature_Inlet)
diff --git a/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
index 384575558a..7edb3331ca 100644
--- a/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
@@ -223,7 +223,7 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet temperature
Temperature_Inlet = ObjectsFem.makeConstraintTemperature(doc, "Temperature_Inlet")
- Temperature_Inlet.Temperature = 350.0
+ Temperature_Inlet.Temperature = 300.0
Temperature_Inlet.NormalDirection = Vector(-1, 0, 0)
Temperature_Inlet.References = [(BooleanFragments, "Edge5")]
analysis.addObject(Temperature_Inlet)
diff --git a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
index a203da2160..454509b974 100644
--- a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
@@ -134,8 +134,8 @@ def setup(doc=None, solvertype="elmer"):
equation_flow.LinearIterativeMethod = "Idrs"
equation_flow.LinearPreconditioning = "ILU1"
equation_flow.setExpression("LinearTolerance", "1e-6")
- equation_flow.NonlinearIterations = 30
- equation_flow.NonlinearNewtonAfterIterations = 30
+ equation_flow.NonlinearIterations = 40
+ equation_flow.NonlinearNewtonAfterIterations = 40
equation_flow.RelaxationFactor = 0.1
equation_flow.setExpression("NonlinearTolerance", "1e-4")
equation_flow.Variable = "Flow Solution[Velocity:2 Pressure:1]"
@@ -144,8 +144,8 @@ def setup(doc=None, solvertype="elmer"):
equation_heat.LinearIterativeMethod = "Idrs"
equation_heat.LinearPreconditioning = "ILU1"
equation_heat.setExpression("LinearTolerance", "1e-6")
- equation_heat.NonlinearIterations = 30
- equation_heat.NonlinearNewtonAfterIterations = 30
+ equation_heat.NonlinearIterations = 40
+ equation_heat.NonlinearNewtonAfterIterations = 40
equation_heat.setExpression("NonlinearTolerance", "1e-4")
equation_heat.Priority = 5
equation_heat.RelaxationFactor = 0.1
@@ -185,8 +185,10 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet velocity
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
- FlowVelocity_Inlet.VelocityX = "20.0 mm/s"
+ FlowVelocity_Inlet.VelocityXFormula = "Variable Coordinate 2; Real MATC \"10*(tx+50e-3)*(50e-3-tx)\""
FlowVelocity_Inlet.VelocityXUnspecified = False
+ FlowVelocity_Inlet.VelocityXHasFormula = True
+ FlowVelocity_Inlet.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Inlet)
# constraint wall velocity
diff --git a/src/Mod/Fem/femsolver/elmer/equations/nonlinear.py b/src/Mod/Fem/femsolver/elmer/equations/nonlinear.py
index a0229a076f..2498ade7b2 100644
--- a/src/Mod/Fem/femsolver/elmer/equations/nonlinear.py
+++ b/src/Mod/Fem/femsolver/elmer/equations/nonlinear.py
@@ -76,7 +76,7 @@ class Proxy(linear.Proxy):
)
)
- obj.NonlinearIterations = (500, 1, int(1e6), 50)
+ obj.NonlinearIterations = (500, 1, int(1e6), 10)
obj.NonlinearNewtonAfterIterations = (3, 1, 100, 1)
# for small numbers we must set an expression because we don't have a UI,
# the user has to view and edit the tolerance via the property editor and
From 37eeccf705befce1df214a6f925c63e978c63acb Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri
Date: Sun, 19 Mar 2023 18:48:18 +0100
Subject: [PATCH 50/53] NotificationBox/NotificationArea: Restrict rendering
area to main frame
========================================================================
The NotificationBox is extended to take the QRect in global coordinates. Then
it will try to dimension the label within this area. If a fixed width is provided, that
is enforced (take precedence).
The NotificationArea passes the QRect of the main window to the NotificationBox.
This is intended to fix:
https://github.com/FreeCAD/FreeCAD/issues/8940
---
src/Gui/NotificationArea.cpp | 13 +++++++---
src/Gui/NotificationBox.cpp | 48 +++++++++++++++++++++++++-----------
src/Gui/NotificationBox.h | 11 ++++++---
3 files changed, 52 insertions(+), 20 deletions(-)
diff --git a/src/Gui/NotificationArea.cpp b/src/Gui/NotificationArea.cpp
index 53e27c644f..8e81a502cc 100644
--- a/src/Gui/NotificationArea.cpp
+++ b/src/Gui/NotificationArea.cpp
@@ -234,7 +234,7 @@ void NotificationAreaObserver::SendLog(const std::string& notifiername, const st
.trimmed();// remove any leading and trailing whitespace character ('\n')
// avoid processing empty strings
- if(simplifiedstring.isEmpty())
+ if (simplifiedstring.isEmpty())
return;
if (level == Base::LogStyle::TranslatedNotification) {
@@ -827,7 +827,7 @@ void NotificationArea::pushNotification(const QString& notifiername, const QStri
auto timer_thread = pImp->inhibitTimer.thread();
auto current_thread = QThread::currentThread();
- if(timer_thread == current_thread)
+ if (timer_thread == current_thread)
pImp->inhibitTimer.start(pImp->inhibitNotificationTime);
}
@@ -939,7 +939,8 @@ void NotificationArea::showInNotificationArea()
iconstr = QStringLiteral(":/icons/info.svg");
}
- QString tmpmessage = convertFromPlainText(item->msg, Qt::WhiteSpaceMode::WhiteSpaceNormal);
+ QString tmpmessage =
+ convertFromPlainText(item->msg, Qt::WhiteSpaceMode::WhiteSpaceNormal);
msgw +=
QString::fromLatin1(
@@ -990,11 +991,17 @@ void NotificationArea::showInNotificationArea()
msgw += QString::fromLatin1("
");
+ // Calculate the main window QRect in global screen coordinates.
+ auto mainwindow = getMainWindow();
+ auto mainwindowrect = mainwindow->rect();
+ auto globalmainwindowrect =
+ QRect(mainwindow->mapToGlobal(mainwindowrect.topLeft()), mainwindowrect.size());
NotificationBox::showText(this->mapToGlobal(QPoint()),
msgw,
pImp->notificationExpirationTime,
pImp->minimumOnScreenTime,
+ globalmainwindowrect,
pImp->notificationWidth);
}
}
diff --git a/src/Gui/NotificationBox.cpp b/src/Gui/NotificationBox.cpp
index 41bfe05d16..79e528d069 100644
--- a/src/Gui/NotificationBox.cpp
+++ b/src/Gui/NotificationBox.cpp
@@ -73,6 +73,8 @@ public:
bool notificationLabelChanged(const QString& text);
/// Place the notification at the given position
void placeNotificationLabel(const QPoint& pos);
+ /// Set the windowrect defining an area to which the label should be constrained
+ void setTipRect(const QRect &restrictionarea);
/// The instance
static qobject_delete_later_unique_ptr instance;
@@ -91,6 +93,8 @@ private:
int minShowTime;
QTimer hideTimer;
QTimer expireTimer;
+
+ QRect restrictionArea;
};
qobject_delete_later_unique_ptr NotificationLabel::instance = nullptr;
@@ -263,25 +267,36 @@ void NotificationLabel::placeNotificationLabel(const QPoint& pos)
p += offset;
- QRect screenRect = screen->geometry();
+ QRect actinglimit = screen->geometry();
- if (p.x() + this->width() > screenRect.x() + screenRect.width())
- p.rx() -= 4 + this->width();
- if (p.y() + this->height() > screenRect.y() + screenRect.height())
- p.ry() -= 24 + this->height();
- if (p.y() < screenRect.y())
- p.setY(screenRect.y());
- if (p.x() + this->width() > screenRect.x() + screenRect.width())
- p.setX(screenRect.x() + screenRect.width() - this->width());
- if (p.x() < screenRect.x())
- p.setX(screenRect.x());
- if (p.y() + this->height() > screenRect.y() + screenRect.height())
- p.setY(screenRect.y() + screenRect.height() - this->height());
+ if(!restrictionArea.isNull())
+ actinglimit = restrictionArea;
+
+ const int standard_x_padding = 4;
+ const int standard_y_padding = 24;
+
+ if (p.x() + this->width() > actinglimit.x() + actinglimit.width())
+ p.rx() -= standard_x_padding + this->width();
+ if (p.y() + standard_y_padding + this->height() > actinglimit.y() + actinglimit.height())
+ p.ry() -= standard_y_padding + this->height();
+ if (p.y() < actinglimit.y())
+ p.setY(actinglimit.y());
+ if (p.x() + this->width() > actinglimit.x() + actinglimit.width())
+ p.setX(actinglimit.x() + actinglimit.width() - this->width());
+ if (p.x() < actinglimit.x())
+ p.setX(actinglimit.x());
+ if (p.y() + this->height() > actinglimit.y() + actinglimit.height())
+ p.setY(actinglimit.y() + actinglimit.height() - this->height());
}
this->move(p);
}
+void NotificationLabel::setTipRect(const QRect &restrictionarea)
+{
+ restrictionArea = restrictionarea;
+}
+
bool NotificationLabel::notificationLabelChanged(const QString& text)
{
return NotificationLabel::instance->text() != text;
@@ -290,7 +305,7 @@ bool NotificationLabel::notificationLabelChanged(const QString& text)
/***************************** NotificationBox **********************************/
void NotificationBox::showText(const QPoint& pos, const QString& text, int displayTime,
- unsigned int minShowTime, int width)
+ unsigned int minShowTime, const QRect &restrictionarea, int width)
{
// a label does already exist
if (NotificationLabel::instance && NotificationLabel::instance->isVisible()) {
@@ -301,6 +316,7 @@ void NotificationBox::showText(const QPoint& pos, const QString& text, int displ
else {
// If the label has changed, reuse the one that is showing (removes flickering)
if (NotificationLabel::instance->notificationLabelChanged(text)) {
+ NotificationLabel::instance->setTipRect(restrictionarea);
NotificationLabel::instance->reuseNotification(text, displayTime, pos, width);
NotificationLabel::instance->placeNotificationLabel(pos);
}
@@ -310,12 +326,16 @@ void NotificationBox::showText(const QPoint& pos, const QString& text, int displ
// no label can be reused, create new label:
if (!text.isEmpty()) {
+ // Note: The Label takes no parent, as on windows, we can't use the widget as parent
+ // otherwise the window will be raised when the tooltip will be shown. We do not use
+ // it on Linux either for consistency.
new NotificationLabel(text,
pos,
displayTime,
minShowTime,
width);// sets NotificationLabel::instance to itself
+ NotificationLabel::instance->setTipRect(restrictionarea);
NotificationLabel::instance->placeNotificationLabel(pos);
NotificationLabel::instance->setObjectName(QLatin1String("NotificationBox_label"));
diff --git a/src/Gui/NotificationBox.h b/src/Gui/NotificationBox.h
index 0008d5ad7e..4ddcd93083 100644
--- a/src/Gui/NotificationBox.h
+++ b/src/Gui/NotificationBox.h
@@ -54,11 +54,16 @@ public:
* an event, see class documentation above)
* @param minShowTime Time during which the notification can only be made disappear by popping
* it out (clicking inside it).
- * @param width Fixes the width of the notification. Default value makes the width to be system determined (dependent on
- * the text).
+ * @param restrictionarea Try to keep the NotificationBox within this area. If this area is not
+ * provided, the whole screen is used as restriction area. This are must be provided in global
+ * screen coordinates.
+ * @param width Fixes the width of the notification. Default value makes the width to be system
+ * determined (dependent on the text). If a fixed width is provided it is enforced over the
+ * restrictionarea.
*/
static void showText(const QPoint& pos, const QString& text, int displayTime = -1,
- unsigned int minShowTime = 0, int width = 0);
+ unsigned int minShowTime = 0, const QRect& restrictionarea = {},
+ int width = 0);
/// Hides a notification.
static inline void hideText()
{
From 27ed6d6349127b9dd8a7fa8d47e310a1fb2601b3 Mon Sep 17 00:00:00 2001
From: Florian Foinant-Willig
Date: Mon, 20 Mar 2023 08:30:12 +0100
Subject: [PATCH 51/53] Fix circles distance constraint for concentrics
---
src/Mod/Sketcher/App/planegcs/Constraints.cpp | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.cpp b/src/Mod/Sketcher/App/planegcs/Constraints.cpp
index c04e54ef01..3a628de3a6 100644
--- a/src/Mod/Sketcher/App/planegcs/Constraints.cpp
+++ b/src/Mod/Sketcher/App/planegcs/Constraints.cpp
@@ -2666,8 +2666,11 @@ void ConstraintC2CDistance::errorgrad(double *err, double *grad, double *param)
else if(param == distance()) {
drad = (*distance()<0.)?1.0:-1.0;
}
-
- *grad = -dlength_ct12 + drad;
+ if (length_ct12>1e-13) {
+ *grad = -dlength_ct12 + drad;
+ } else { // concentric case
+ *grad = drad;
+ }
}
}
}
From d5a313146fcf8087700a2aaae5b06feb1998d44d Mon Sep 17 00:00:00 2001
From: luzpaz
Date: Sun, 19 Mar 2023 12:09:59 +0000
Subject: [PATCH 52/53] Fix various whitespace issues
---
.../Fem/femtaskpanels/task_solver_ccxtools.py | 2 +-
src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py | 6 +++---
src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py | 2 +-
src/Tools/ThumbnailProvider/Main.cpp | 16 ++++++++--------
.../ThumbnailProvider/ThumbnailProvider.cpp | 16 ++++++++--------
5 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py b/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py
index 6a25f7b2d0..417cee429a 100644
--- a/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py
+++ b/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py
@@ -295,7 +295,7 @@ class _TaskPanel:
CCX_mesh = self.fea.analysis.Document.getObject("ResultMesh")
if CCX_mesh is not None:
CCX_mesh.ViewObject.Visibility = self.CCX_mesh_visibility
-
+
def choose_working_dir(self):
wd = QtGui.QFileDialog.getExistingDirectory(None, "Choose CalculiX working directory",
self.fea.working_dir)
diff --git a/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py b/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py
index 4dab44f35b..8657a42fb8 100644
--- a/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py
+++ b/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py
@@ -32,9 +32,9 @@ class DrawViewDimensionTest(unittest.TestCase):
self.view1.Source = [self.document.Sphere]
self.view1.X = 220
self.view1.Y = 150
-
+
self.document.recompute()
-
+
#wait for threads to complete before checking result
loop = QtCore.QEventLoop()
@@ -53,7 +53,7 @@ class DrawViewDimensionTest(unittest.TestCase):
"""Tests if a length dimension can be added to view"""
# make length dimension
print("making length dimension")
-
+
dimension = self.document.addObject("TechDraw::DrawViewDimension", "Dimension")
self.page.addView(dimension)
dimension.Type = "Distance"
diff --git a/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py b/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py
index b65a634645..532354ce37 100644
--- a/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py
+++ b/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py
@@ -6,7 +6,7 @@ def createPageWithSVGTemplate(doc=None):
"""Returns a page with an SVGTemplate added on the ActiveDocument"""
path = os.path.dirname(os.path.abspath(__file__))
templateFileSpec = path + "/TestTemplate.svg"
-
+
if not doc:
doc = FreeCAD.ActiveDocument
diff --git a/src/Tools/ThumbnailProvider/Main.cpp b/src/Tools/ThumbnailProvider/Main.cpp
index 38cc6a7374..5612f404c2 100644
--- a/src/Tools/ThumbnailProvider/Main.cpp
+++ b/src/Tools/ThumbnailProvider/Main.cpp
@@ -49,8 +49,8 @@ STDAPI CreateRegistryKeys(REGKEY_SUBKEY_AND_VALUE* aKeys, ULONG cKeys);
STDAPI DeleteRegistryKeys(REGKEY_DELETEKEY* aKeys, ULONG cKeys);
-BOOL APIENTRY DllMain(HINSTANCE hinstDll,
- DWORD dwReason,
+BOOL APIENTRY DllMain(HINSTANCE hinstDll,
+ DWORD dwReason,
LPVOID pvReserved)
{
switch (dwReason)
@@ -88,8 +88,8 @@ STDAPI_(ULONG) DllRelease()
STDAPI DllRegisterServer()
{
- // This tells the shell to invalidate the thumbnail cache. This is important because any .recipe files
- // viewed before registering this handler would otherwise show cached blank thumbnails.
+ // This tells the shell to invalidate the thumbnail cache. This is important because any .recipe files
+ // viewed before registering this handler would otherwise show cached blank thumbnails.
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
WCHAR szModule[MAX_PATH];
@@ -101,12 +101,12 @@ STDAPI DllRegisterServer()
REGKEY_SUBKEY_AND_VALUE keys[] = {
{HKEY_CLASSES_ROOT, L"CLSID\\" szCLSID_SampleThumbnailProvider, NULL, REG_SZ, (DWORD_PTR)L"FCStd Thumbnail Provider"},
#if 1
- //{HKEY_CLASSES_ROOT, L"CLSID\\DisableProcessIsolation", NULL, REG_DWORD, (DWORD) 1},
- {HKEY_CLASSES_ROOT, L"CLSID\\" szCLSID_SampleThumbnailProvider, L"DisableProcessIsolation", REG_DWORD, (DWORD) 1},
+ //{HKEY_CLASSES_ROOT, L"CLSID\\DisableProcessIsolation", NULL, REG_DWORD, (DWORD) 1},
+ {HKEY_CLASSES_ROOT, L"CLSID\\" szCLSID_SampleThumbnailProvider, L"DisableProcessIsolation", REG_DWORD, (DWORD) 1},
#endif
{HKEY_CLASSES_ROOT, L"CLSID\\" szCLSID_SampleThumbnailProvider L"\\InprocServer32", NULL, REG_SZ, (DWORD_PTR)szModule},
{HKEY_CLASSES_ROOT, L"CLSID\\" szCLSID_SampleThumbnailProvider L"\\InprocServer32", L"ThreadingModel", REG_SZ, (DWORD_PTR)L"Apartment"},
- //{HKEY_CLASSES_ROOT, L".FCStd\\shellex", L"Trick only here to create shellex when not existing",REG_DWORD, 1},
+ //{HKEY_CLASSES_ROOT, L".FCStd\\shellex", L"Trick only here to create shellex when not existing",REG_DWORD, 1},
{HKEY_CLASSES_ROOT, L".FCStd\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}", NULL, REG_SZ, (DWORD_PTR)szCLSID_SampleThumbnailProvider},
{HKEY_CLASSES_ROOT, L".FCBak\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}", NULL, REG_SZ, (DWORD_PTR)szCLSID_SampleThumbnailProvider}
};
@@ -143,7 +143,7 @@ STDAPI CreateRegistryKey(REGKEY_SUBKEY_AND_VALUE* pKey)
cbData += sizeof(WCHAR);
}
break;
-
+
default:
hr = E_INVALIDARG;
}
diff --git a/src/Tools/ThumbnailProvider/ThumbnailProvider.cpp b/src/Tools/ThumbnailProvider/ThumbnailProvider.cpp
index acf1d60b68..b980c7c55e 100644
--- a/src/Tools/ThumbnailProvider/ThumbnailProvider.cpp
+++ b/src/Tools/ThumbnailProvider/ThumbnailProvider.cpp
@@ -178,7 +178,7 @@ CThumbnailProvider::~CThumbnailProvider()
STDMETHODIMP CThumbnailProvider::QueryInterface(REFIID riid,
void** ppvObject)
{
- static const QITAB qit[] =
+ static const QITAB qit[] =
{
//QITABENT(CThumbnailProvider, IInitializeWithStream),
QITABENT(CThumbnailProvider, IInitializeWithFile),
@@ -206,16 +206,16 @@ STDMETHODIMP_(ULONG) CThumbnailProvider::Release()
}
-STDMETHODIMP CThumbnailProvider::Initialize(IStream *pstm,
+STDMETHODIMP CThumbnailProvider::Initialize(IStream *pstm,
DWORD grfMode)
{
return S_OK;
}
-STDMETHODIMP CThumbnailProvider::Initialize(LPCWSTR pszFilePath,
+STDMETHODIMP CThumbnailProvider::Initialize(LPCWSTR pszFilePath,
DWORD grfMode)
{
- wcscpy_s(m_szFile, pszFilePath);
+ wcscpy_s(m_szFile, pszFilePath);
return S_OK;
}
@@ -235,8 +235,8 @@ bool CThumbnailProvider::CheckZip() const
return true;
}
-STDMETHODIMP CThumbnailProvider::GetThumbnail(UINT cx,
- HBITMAP *phbmp,
+STDMETHODIMP CThumbnailProvider::GetThumbnail(UINT cx,
+ HBITMAP *phbmp,
WTS_ALPHATYPE *pdwAlpha)
{
try {
@@ -277,11 +277,11 @@ STDMETHODIMP CThumbnailProvider::GetThumbnail(UINT cx,
// or whatever could go wrong
}
- return NOERROR;
+ return NOERROR;
}
-STDMETHODIMP CThumbnailProvider::GetSite(REFIID riid,
+STDMETHODIMP CThumbnailProvider::GetSite(REFIID riid,
void** ppvSite)
{
if (m_pSite)
From 2cb2063249c22e4c74e284d55b96f0b2c871d8fa Mon Sep 17 00:00:00 2001
From: Uwe
Date: Mon, 20 Mar 2023 16:32:27 +0100
Subject: [PATCH 53/53] [Sketch] Constraints.cpp: formatting fixes
- fix too long lines
- also let clang reformat the file to uniform the formatting
---
src/Mod/Sketcher/App/planegcs/Constraints.cpp | 1272 +++++++++--------
1 file changed, 712 insertions(+), 560 deletions(-)
diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.cpp b/src/Mod/Sketcher/App/planegcs/Constraints.cpp
index 3a628de3a6..e7674f639a 100644
--- a/src/Mod/Sketcher/App/planegcs/Constraints.cpp
+++ b/src/Mod/Sketcher/App/planegcs/Constraints.cpp
@@ -20,15 +20,16 @@
* *
***************************************************************************/
-#include
-#include "Constraints.h"
#include
-
+#include
#define DEBUG_DERIVS 0
#if DEBUG_DERIVS
-#include
+# include
#endif
+#include "Constraints.h"
+
+
namespace GCS
{
@@ -37,20 +38,24 @@ namespace GCS
///////////////////////////////////////
Constraint::Constraint()
-: origpvec(0), pvec(0), scale(1.), tag(0), pvecChangedFlag(true), driving(true), internalAlignment(Alignment::NoInternalAlignment)
-{
-}
+ : origpvec(0),
+ pvec(0),
+ scale(1.),
+ tag(0),
+ pvecChangedFlag(true),
+ driving(true),
+ internalAlignment(Alignment::NoInternalAlignment)
+{}
-void Constraint::redirectParams(const MAP_pD_pD & redirectionmap)
+void Constraint::redirectParams(const MAP_pD_pD& redirectionmap)
{
- int i=0;
- for (VEC_pD::iterator param=origpvec.begin();
- param != origpvec.end(); ++param, i++) {
+ int i = 0;
+ for (VEC_pD::iterator param = origpvec.begin(); param != origpvec.end(); ++param, i++) {
MAP_pD_pD::const_iterator it = redirectionmap.find(*param);
if (it != redirectionmap.end())
pvec[i] = it->second;
}
- pvecChangedFlag=true;
+ pvecChangedFlag = true;
}
void Constraint::revertParams()
@@ -66,17 +71,17 @@ ConstraintType Constraint::getTypeId()
void Constraint::rescale(double coef)
{
- scale = coef * 1.;
+ scale = coef * 1.0;
}
double Constraint::error()
{
- return 0.;
+ return 0.0;
}
double Constraint::grad(double * /*param*/)
{
- return 0.;
+ return 0.0;
}
double Constraint::maxStep(MAP_pD_D & /*dir*/, double lim)
@@ -84,11 +89,11 @@ double Constraint::maxStep(MAP_pD_D & /*dir*/, double lim)
return lim;
}
-int Constraint::findParamInPvec(double *param)
+int Constraint::findParamInPvec(double* param)
{
int ret = -1;
- for( std::size_t i=0 ; i(i);
break;
}
@@ -96,6 +101,8 @@ int Constraint::findParamInPvec(double *param)
return ret;
}
+
+// --------------------------------------------------------
// Equal
ConstraintEqual::ConstraintEqual(double *p1, double *p2, double p1p2ratio)
{
@@ -129,14 +136,17 @@ double ConstraintEqual::grad(double *param)
return scale * deriv;
}
-// Weighted Linear Combination
-ConstraintWeightedLinearCombination::ConstraintWeightedLinearCombination(size_t givennumpoles, const std::vector& givenpvec, const std::vector& givenfactors)
- : factors(givenfactors)
- , numpoles(givennumpoles)
+// --------------------------------------------------------
+// Weighted Linear Combination
+ConstraintWeightedLinearCombination::ConstraintWeightedLinearCombination(
+ size_t givennumpoles, const std::vector& givenpvec,
+ const std::vector& givenfactors)
+ : factors(givenfactors),
+ numpoles(givennumpoles)
{
pvec = givenpvec;
- assert(pvec.size() == 2*numpoles + 1);
+ assert(pvec.size() == 2 * numpoles + 1);
assert(factors.size() == numpoles);
origpvec = pvec;
rescale();
@@ -169,12 +179,12 @@ double ConstraintWeightedLinearCombination::error()
return scale * ((*thepoint()) * wsum - sum);
}
-double ConstraintWeightedLinearCombination::grad(double *param)
+double ConstraintWeightedLinearCombination::grad(double* param)
{
// Equations are from here:
// https://forum.freecadweb.org/viewtopic.php?f=9&t=71130&start=120#p635538
- double deriv=0.;
+ double deriv = 0.;
if (param == thepoint()) {
// Eq. (11)
@@ -202,9 +212,11 @@ double ConstraintWeightedLinearCombination::grad(double *param)
return scale * deriv;
}
-// Center of Gravity
-ConstraintCenterOfGravity::ConstraintCenterOfGravity(const std::vector& givenpvec, const std::vector& givenweights)
+// --------------------------------------------------------
+// Center of Gravity
+ConstraintCenterOfGravity::ConstraintCenterOfGravity(const std::vector& givenpvec,
+ const std::vector& givenweights)
: weights(givenweights)
{
pvec = givenpvec;
@@ -247,8 +259,9 @@ double ConstraintCenterOfGravity::grad(double *param)
return scale * deriv;
}
-// Slope at B-spline knot
+// --------------------------------------------------------
+// Slope at B-spline knot
ConstraintSlopeAtBSplineKnot::ConstraintSlopeAtBSplineKnot(BSpline& b, Line& l, size_t knotindex)
{
// set up pvec: pole x-coords, pole y-coords, pole weights,
@@ -258,7 +271,7 @@ ConstraintSlopeAtBSplineKnot::ConstraintSlopeAtBSplineKnot(BSpline& b, Line& l,
// slope at knot doesn't make sense if there's only C0 continuity
assert(numpoles >= 2);
- pvec.reserve(3*numpoles + 4);
+ pvec.reserve(3 * numpoles + 4);
// `startpole` is the first pole affecting the knot with `knotindex`
size_t startpole = 0;
@@ -285,13 +298,13 @@ ConstraintSlopeAtBSplineKnot::ConstraintSlopeAtBSplineKnot(BSpline& b, Line& l,
slopefactors.resize(numpoles);
for (size_t i = 0; i < numpoles + 1; ++i) {
tempfactors[i] =
- b.getLinCombFactor(*(b.knots[knotindex]), startpole + b.degree, startpole + i, b.degree - 1) /
- (b.flattenedknots[startpole + b.degree + i] - b.flattenedknots[startpole + i]);
+ b.getLinCombFactor(
+ *(b.knots[knotindex]), startpole + b.degree, startpole + i, b.degree - 1)
+ / (b.flattenedknots[startpole + b.degree + i] - b.flattenedknots[startpole + i]);
}
for (size_t i = 0; i < numpoles; ++i) {
- factors[i] =
- b.getLinCombFactor(*(b.knots[knotindex]), startpole + b.degree, startpole + i);
- slopefactors[i] = b.degree * (tempfactors[i] - tempfactors[i+1]);
+ factors[i] = b.getLinCombFactor(*(b.knots[knotindex]), startpole + b.degree, startpole + i);
+ slopefactors[i] = b.degree * (tempfactors[i] - tempfactors[i + 1]);
}
origpvec = pvec;
@@ -312,7 +325,7 @@ void ConstraintSlopeAtBSplineKnot::rescale(double coef)
slopey += *poleyat(i) * slopefactors[i];
}
- scale = coef / sqrt((slopex*slopex + slopey*slopey));
+ scale = coef / sqrt((slopex * slopex + slopey * slopey));
}
double ConstraintSlopeAtBSplineKnot::error()
@@ -335,29 +348,29 @@ double ConstraintSlopeAtBSplineKnot::error()
// This is actually wsum^2 * the respective slopes
// See Eq (19) from:
// https://forum.freecadweb.org/viewtopic.php?f=9&t=71130&start=120#p635538
- double slopex = wsum*xslopesum - wslopesum*xsum;
- double slopey = wsum*yslopesum - wslopesum*ysum;
+ double slopex = wsum * xslopesum - wslopesum * xsum;
+ double slopey = wsum * yslopesum - wslopesum * ysum;
// Normalizing it ensures that the cross product is not zero just because
// one vector is zero.
double linex = *linep2x() - *linep1x();
double liney = *linep2y() - *linep1y();
- double dirx = linex / sqrt(linex*linex + liney*liney);
- double diry = liney / sqrt(linex*linex + liney*liney);
+ double dirx = linex / sqrt(linex * linex + liney * liney);
+ double diry = liney / sqrt(linex * linex + liney * liney);
// error is the cross product
- return scale * (slopex*diry - slopey*dirx);
+ return scale * (slopex * diry - slopey * dirx);
}
-double ConstraintSlopeAtBSplineKnot::grad(double *param)
+double ConstraintSlopeAtBSplineKnot::grad(double* param)
{
// Equations are from here:
// https://forum.freecadweb.org/viewtopic.php?f=9&t=71130&start=120#p635538
double result = 0.0;
double linex = *linep2x() - *linep1x();
double liney = *linep2y() - *linep1y();
- double dirx = linex / sqrt(linex*linex + liney*liney);
- double diry = liney / sqrt(linex*linex + liney*liney);
+ double dirx = linex / sqrt(linex * linex + liney * liney);
+ double diry = liney / sqrt(linex * linex + liney * liney);
for (size_t i = 0; i < numpoles; ++i) {
if (param == polexat(i)) {
@@ -369,7 +382,7 @@ double ConstraintSlopeAtBSplineKnot::grad(double *param)
wsum += wcontrib;
wslopesum += wslopecontrib;
}
- result = (wsum*slopefactors[i] - wslopesum*factors[i]) * diry;
+ result = (wsum * slopefactors[i] - wslopesum * factors[i]) * diry;
return scale * result;
}
if (param == poleyat(i)) {
@@ -381,7 +394,7 @@ double ConstraintSlopeAtBSplineKnot::grad(double *param)
wsum += wcontrib;
wslopesum += wslopecontrib;
}
- result = - (wsum*slopefactors[i] - wslopesum*factors[i]) * dirx;
+ result = -(wsum * slopefactors[i] - wslopesum * factors[i]) * dirx;
return scale * result;
}
if (param == weightat(i)) {
@@ -396,9 +409,8 @@ double ConstraintSlopeAtBSplineKnot::grad(double *param)
ysum += wcontrib * (*poleyat(j) - *poleyat(i));
yslopesum += wslopecontrib * (*poleyat(j) - *poleyat(i));
}
- result =
- (factors[i]*xslopesum - slopefactors[i]*xsum) * diry -
- (factors[i]*yslopesum - slopefactors[i]*ysum) * dirx;
+ result = (factors[i] * xslopesum - slopefactors[i] * xsum) * diry
+ - (factors[i] * yslopesum - slopefactors[i] * ysum) * dirx;
return scale * result;
}
}
@@ -422,55 +434,57 @@ double ConstraintSlopeAtBSplineKnot::grad(double *param)
}
// This is actually wsum^2 * the respective slopes
- slopex = wsum*xslopesum - wslopesum*xsum;
- slopey = wsum*yslopesum - wslopesum*ysum;
+ slopex = wsum * xslopesum - wslopesum * xsum;
+ slopey = wsum * yslopesum - wslopesum * ysum;
};
if (param == linep1x()) {
getSlopes();
- double dDirxDLinex = (liney*liney) / pow(linex*linex + liney*liney, 1.5);
- double dDiryDLinex = -(linex*liney) / pow(linex*linex + liney*liney, 1.5);
+ double dDirxDLinex = (liney * liney) / pow(linex * linex + liney * liney, 1.5);
+ double dDiryDLinex = -(linex * liney) / pow(linex * linex + liney * liney, 1.5);
// NOTE: d(linex)/d(x1) = -1
- result = slopex*(-dDiryDLinex) - slopey*(-dDirxDLinex);
+ result = slopex * (-dDiryDLinex) - slopey * (-dDirxDLinex);
return scale * result;
}
if (param == linep2x()) {
getSlopes();
- double dDirxDLinex = (liney*liney) / pow(linex*linex + liney*liney, 1.5);
- double dDiryDLinex = -(linex*liney) / pow(linex*linex + liney*liney, 1.5);
+ double dDirxDLinex = (liney * liney) / pow(linex * linex + liney * liney, 1.5);
+ double dDiryDLinex = -(linex * liney) / pow(linex * linex + liney * liney, 1.5);
// NOTE: d(linex)/d(x2) = 1
- result = slopex*dDiryDLinex - slopey*dDirxDLinex;
+ result = slopex * dDiryDLinex - slopey * dDirxDLinex;
return scale * result;
}
if (param == linep1y()) {
getSlopes();
- double dDirxDLiney = -(linex*liney) / pow(linex*linex + liney*liney, 1.5);
- double dDiryDLiney = (linex*linex) / pow(linex*linex + liney*liney, 1.5);
+ double dDirxDLiney = -(linex * liney) / pow(linex * linex + liney * liney, 1.5);
+ double dDiryDLiney = (linex * linex) / pow(linex * linex + liney * liney, 1.5);
// NOTE: d(liney)/d(y1) = -1
- result = slopex*(-dDiryDLiney) - slopey*(-dDirxDLiney);
+ result = slopex * (-dDiryDLiney) - slopey * (-dDirxDLiney);
return scale * result;
}
if (param == linep2y()) {
getSlopes();
- double dDirxDLiney = -(linex*liney) / pow(linex*linex + liney*liney, 1.5);
- double dDiryDLiney = (linex*linex) / pow(linex*linex + liney*liney, 1.5);
+ double dDirxDLiney = -(linex * liney) / pow(linex * linex + liney * liney, 1.5);
+ double dDiryDLiney = (linex * linex) / pow(linex * linex + liney * liney, 1.5);
// NOTE: d(liney)/d(y2) = 1
- result = slopex*dDiryDLiney - slopey*dDirxDLiney;
+ result = slopex * dDiryDLiney - slopey * dDirxDLiney;
return scale * result;
}
return scale * result;
}
-// Point On BSpline
-ConstraintPointOnBSpline::ConstraintPointOnBSpline(double* point, double* initparam, int coordidx, BSpline& b)
+// --------------------------------------------------------
+// Point On BSpline
+ConstraintPointOnBSpline::ConstraintPointOnBSpline(double* point, double* initparam, int coordidx,
+ BSpline& b)
: bsp(b)
{
// This is always going to be true
numpoints = bsp.degree + 1;
- pvec.reserve(2 + 2*b.poles.size());
+ pvec.reserve(2 + 2 * b.poles.size());
pvec.push_back(point);
pvec.push_back(initparam);
@@ -516,8 +530,8 @@ void ConstraintPointOnBSpline::rescale(double coef)
double ConstraintPointOnBSpline::error()
{
- if (*theparam() < bsp.flattenedknots[startpole + bsp.degree] ||
- *theparam() > bsp.flattenedknots[startpole + bsp.degree + 1])
+ if (*theparam() < bsp.flattenedknots[startpole + bsp.degree]
+ || *theparam() > bsp.flattenedknots[startpole + bsp.degree + 1])
setStartPole(*theparam());
double sum = 0;
@@ -527,51 +541,58 @@ double ConstraintPointOnBSpline::error()
VEC_D d(numpoints);
for (size_t i = 0; i < numpoints; ++i)
d[i] = *poleat(i) * *weightat(i);
- sum = BSpline::splineValue(*theparam(), startpole + bsp.degree, bsp.degree, d, bsp.flattenedknots);
+ sum = BSpline::splineValue(
+ *theparam(), startpole + bsp.degree, bsp.degree, d, bsp.flattenedknots);
for (size_t i = 0; i < numpoints; ++i)
d[i] = *weightat(i);
- wsum = BSpline::splineValue(*theparam(), startpole + bsp.degree, bsp.degree, d, bsp.flattenedknots);
+ wsum = BSpline::splineValue(
+ *theparam(), startpole + bsp.degree, bsp.degree, d, bsp.flattenedknots);
// TODO: Change the poles as the point moves between pieces
return scale * (*thepoint() * wsum - sum);
}
-double ConstraintPointOnBSpline::grad(double *gcsparam)
+double ConstraintPointOnBSpline::grad(double* gcsparam)
{
- double deriv=0.;
+ double deriv = 0.;
if (gcsparam == thepoint()) {
VEC_D d(numpoints);
for (size_t i = 0; i < numpoints; ++i)
d[i] = *weightat(i);
- double wsum = BSpline::splineValue(*theparam(), startpole + bsp.degree, bsp.degree, d, bsp.flattenedknots);
+ double wsum = BSpline::splineValue(
+ *theparam(), startpole + bsp.degree, bsp.degree, d, bsp.flattenedknots);
deriv += wsum;
}
if (gcsparam == theparam()) {
VEC_D d(numpoints - 1);
for (size_t i = 1; i < numpoints; ++i) {
- d[i-1] =
- (*poleat(i) * *weightat(i) - *poleat(i-1) * *weightat(i-1)) /
- (bsp.flattenedknots[startpole+i+bsp.degree] - bsp.flattenedknots[startpole+i]);
+ d[i - 1] = (*poleat(i) * *weightat(i) - *poleat(i - 1) * *weightat(i - 1))
+ / (bsp.flattenedknots[startpole + i + bsp.degree]
+ - bsp.flattenedknots[startpole + i]);
}
- double slopevalue = BSpline::splineValue(*theparam(), startpole + bsp.degree, bsp.degree-1, d, bsp.flattenedknots);
+ double slopevalue = BSpline::splineValue(
+ *theparam(), startpole + bsp.degree, bsp.degree - 1, d, bsp.flattenedknots);
for (size_t i = 1; i < numpoints; ++i) {
- d[i-1] =
- (*weightat(i) - *weightat(i-1)) /
- (bsp.flattenedknots[startpole+i+bsp.degree] - bsp.flattenedknots[startpole+i]);
+ d[i - 1] = (*weightat(i) - *weightat(i - 1))
+ / (bsp.flattenedknots[startpole + i + bsp.degree]
+ - bsp.flattenedknots[startpole + i]);
}
- double wslopevalue = BSpline::splineValue(*theparam(), startpole + bsp.degree, bsp.degree-1, d, bsp.flattenedknots);
+ double wslopevalue = BSpline::splineValue(
+ *theparam(), startpole + bsp.degree, bsp.degree - 1, d, bsp.flattenedknots);
deriv += (*thepoint() * wslopevalue - slopevalue) * bsp.degree;
}
for (size_t i = 0; i < numpoints; ++i) {
if (gcsparam == poleat(i)) {
- auto factorsI = bsp.getLinCombFactor(*theparam(), startpole + bsp.degree, startpole + i);
+ auto factorsI =
+ bsp.getLinCombFactor(*theparam(), startpole + bsp.degree, startpole + i);
deriv += -(*weightat(i) * factorsI);
}
if (gcsparam == weightat(i)) {
- auto factorsI = bsp.getLinCombFactor(*theparam(), startpole + bsp.degree, startpole + i);
+ auto factorsI =
+ bsp.getLinCombFactor(*theparam(), startpole + bsp.degree, startpole + i);
deriv += (*thepoint() - *poleat(i)) * factorsI;
}
}
@@ -604,15 +625,20 @@ double ConstraintDifference::error()
return scale * (*param2() - *param1() - *difference());
}
-double ConstraintDifference::grad(double *param)
+double ConstraintDifference::grad(double* param)
{
- double deriv=0.;
- if (param == param1()) deriv += -1;
- if (param == param2()) deriv += 1;
- if (param == difference()) deriv += -1;
+ double deriv = 0.;
+ if (param == param1())
+ deriv += -1;
+ if (param == param2())
+ deriv += 1;
+ if (param == difference())
+ deriv += -1;
return scale * deriv;
}
+
+// --------------------------------------------------------
// P2PDistance
ConstraintP2PDistance::ConstraintP2PDistance(Point &p1, Point &p2, double *d)
{
@@ -639,30 +665,34 @@ double ConstraintP2PDistance::error()
{
double dx = (*p1x() - *p2x());
double dy = (*p1y() - *p2y());
- double d = sqrt(dx*dx + dy*dy);
- double dist = *distance();
+ double d = sqrt(dx * dx + dy * dy);
+ double dist = *distance();
return scale * (d - dist);
}
-double ConstraintP2PDistance::grad(double *param)
+double ConstraintP2PDistance::grad(double* param)
{
- double deriv=0.;
- if (param == p1x() || param == p1y() ||
- param == p2x() || param == p2y()) {
+ double deriv = 0.;
+ if (param == p1x() || param == p1y() || param == p2x() || param == p2y()) {
double dx = (*p1x() - *p2x());
double dy = (*p1y() - *p2y());
- double d = sqrt(dx*dx + dy*dy);
- if (param == p1x()) deriv += dx/d;
- if (param == p1y()) deriv += dy/d;
- if (param == p2x()) deriv += -dx/d;
- if (param == p2y()) deriv += -dy/d;
+ double d = sqrt(dx * dx + dy * dy);
+ if (param == p1x())
+ deriv += dx / d;
+ if (param == p1y())
+ deriv += dy / d;
+ if (param == p2x())
+ deriv += -dx / d;
+ if (param == p2y())
+ deriv += -dy / d;
}
- if (param == distance()) deriv += -1.;
+ if (param == distance())
+ deriv += -1.;
return scale * deriv;
}
-double ConstraintP2PDistance::maxStep(MAP_pD_D &dir, double lim)
+double ConstraintP2PDistance::maxStep(MAP_pD_D& dir, double lim)
{
MAP_pD_D::iterator it;
// distance() >= 0
@@ -672,27 +702,33 @@ double ConstraintP2PDistance::maxStep(MAP_pD_D &dir, double lim)
lim = std::min(lim, -(*distance()) / it->second);
}
// restrict actual distance change
- double ddx=0.,ddy=0.;
+ double ddx = 0., ddy = 0.;
it = dir.find(p1x());
- if (it != dir.end()) ddx += it->second;
+ if (it != dir.end())
+ ddx += it->second;
it = dir.find(p1y());
- if (it != dir.end()) ddy += it->second;
+ if (it != dir.end())
+ ddy += it->second;
it = dir.find(p2x());
- if (it != dir.end()) ddx -= it->second;
+ if (it != dir.end())
+ ddx -= it->second;
it = dir.find(p2y());
- if (it != dir.end()) ddy -= it->second;
- double dd = sqrt(ddx*ddx+ddy*ddy);
- double dist = *distance();
+ if (it != dir.end())
+ ddy -= it->second;
+ double dd = sqrt(ddx * ddx + ddy * ddy);
+ double dist = *distance();
if (dd > dist) {
double dx = (*p1x() - *p2x());
double dy = (*p1y() - *p2y());
- double d = sqrt(dx*dx + dy*dy);
+ double d = sqrt(dx * dx + dy * dy);
if (dd > d)
- lim = std::min(lim, std::max(d,dist)/dd);
+ lim = std::min(lim, std::max(d, dist) / dd);
}
return lim;
}
+
+// --------------------------------------------------------
// P2PAngle
ConstraintP2PAngle::ConstraintP2PAngle(Point &p1, Point &p2, double *a, double da_)
: da(da_)
@@ -723,48 +759,54 @@ double ConstraintP2PAngle::error()
double a = *angle() + da;
double ca = cos(a);
double sa = sin(a);
- double x = dx*ca + dy*sa;
- double y = -dx*sa + dy*ca;
- return scale * atan2(y,x);
+ double x = dx * ca + dy * sa;
+ double y = -dx * sa + dy * ca;
+ return scale * atan2(y, x);
}
-double ConstraintP2PAngle::grad(double *param)
+double ConstraintP2PAngle::grad(double* param)
{
- double deriv=0.;
- if (param == p1x() || param == p1y() ||
- param == p2x() || param == p2y()) {
+ double deriv = 0.;
+ if (param == p1x() || param == p1y() || param == p2x() || param == p2y()) {
double dx = (*p2x() - *p1x());
double dy = (*p2y() - *p1y());
double a = *angle() + da;
double ca = cos(a);
double sa = sin(a);
- double x = dx*ca + dy*sa;
- double y = -dx*sa + dy*ca;
- double r2 = dx*dx+dy*dy;
- dx = -y/r2;
- dy = x/r2;
- if (param == p1x()) deriv += (-ca*dx + sa*dy);
- if (param == p1y()) deriv += (-sa*dx - ca*dy);
- if (param == p2x()) deriv += ( ca*dx - sa*dy);
- if (param == p2y()) deriv += ( sa*dx + ca*dy);
+ double x = dx * ca + dy * sa;
+ double y = -dx * sa + dy * ca;
+ double r2 = dx * dx + dy * dy;
+ dx = -y / r2;
+ dy = x / r2;
+ if (param == p1x())
+ deriv += (-ca * dx + sa * dy);
+ if (param == p1y())
+ deriv += (-sa * dx - ca * dy);
+ if (param == p2x())
+ deriv += (ca * dx - sa * dy);
+ if (param == p2y())
+ deriv += (sa * dx + ca * dy);
}
- if (param == angle()) deriv += -1;
+ if (param == angle())
+ deriv += -1;
return scale * deriv;
}
-double ConstraintP2PAngle::maxStep(MAP_pD_D &dir, double lim)
+double ConstraintP2PAngle::maxStep(MAP_pD_D& dir, double lim)
{
// step(angle()) <= pi/18 = 10°
MAP_pD_D::iterator it = dir.find(angle());
if (it != dir.end()) {
double step = std::abs(it->second);
- if (step > M_PI/18.)
- lim = std::min(lim, (M_PI/18.) / step);
+ if (step > M_PI / 18.0)
+ lim = std::min(lim, (M_PI / 18.0) / step);
}
return lim;
}
+
+// --------------------------------------------------------
// P2LDistance
ConstraintP2LDistance::ConstraintP2LDistance(Point &p, Line &l, double *d)
{
@@ -791,47 +833,55 @@ void ConstraintP2LDistance::rescale(double coef)
double ConstraintP2LDistance::error()
{
- double x0=*p0x(), x1=*p1x(), x2=*p2x();
- double y0=*p0y(), y1=*p1y(), y2=*p2y();
+ double x0 = *p0x(), x1 = *p1x(), x2 = *p2x();
+ double y0 = *p0y(), y1 = *p1y(), y2 = *p2y();
double dist = *distance();
- double dx = x2-x1;
- double dy = y2-y1;
- double d = sqrt(dx*dx+dy*dy);
- double area = std::abs(-x0*dy+y0*dx+x1*y2-x2*y1); // = x1y2 - x2y1 - x0y2 + x2y0 + x0y1 - x1y0 = 2*(triangle area)
- return scale * (area/d - dist);
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double d = sqrt(dx * dx + dy * dy);
+ double area =
+ std::abs(-x0 * dy + y0 * dx + x1 * y2
+ - x2 * y1);// = x1y2 - x2y1 - x0y2 + x2y0 + x0y1 - x1y0 = 2*(triangle area)
+ return scale * (area / d - dist);
}
-double ConstraintP2LDistance::grad(double *param)
+double ConstraintP2LDistance::grad(double* param)
{
- double deriv=0.;
+ double deriv = 0.;
// darea/dx0 = (y1-y2) darea/dy0 = (x2-x1)
// darea/dx1 = (y2-y0) darea/dy1 = (x0-x2)
// darea/dx2 = (y0-y1) darea/dy2 = (x1-x0)
- if (param == p0x() || param == p0y() ||
- param == p1x() || param == p1y() ||
- param == p2x() || param == p2y()) {
- double x0=*p0x(), x1=*p1x(), x2=*p2x();
- double y0=*p0y(), y1=*p1y(), y2=*p2y();
- double dx = x2-x1;
- double dy = y2-y1;
- double d2 = dx*dx+dy*dy;
+ if (param == p0x() || param == p0y() || param == p1x() || param == p1y() || param == p2x()
+ || param == p2y()) {
+ double x0 = *p0x(), x1 = *p1x(), x2 = *p2x();
+ double y0 = *p0y(), y1 = *p1y(), y2 = *p2y();
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double d2 = dx * dx + dy * dy;
double d = sqrt(d2);
- double area = -x0*dy+y0*dx+x1*y2-x2*y1;
- if (param == p0x()) deriv += (y1-y2) / d;
- if (param == p0y()) deriv += (x2-x1) / d ;
- if (param == p1x()) deriv += ((y2-y0)*d + (dx/d)*area) / d2;
- if (param == p1y()) deriv += ((x0-x2)*d + (dy/d)*area) / d2;
- if (param == p2x()) deriv += ((y0-y1)*d - (dx/d)*area) / d2;
- if (param == p2y()) deriv += ((x1-x0)*d - (dy/d)*area) / d2;
+ double area = -x0 * dy + y0 * dx + x1 * y2 - x2 * y1;
+ if (param == p0x())
+ deriv += (y1 - y2) / d;
+ if (param == p0y())
+ deriv += (x2 - x1) / d;
+ if (param == p1x())
+ deriv += ((y2 - y0) * d + (dx / d) * area) / d2;
+ if (param == p1y())
+ deriv += ((x0 - x2) * d + (dy / d) * area) / d2;
+ if (param == p2x())
+ deriv += ((y0 - y1) * d - (dx / d) * area) / d2;
+ if (param == p2y())
+ deriv += ((x1 - x0) * d - (dy / d) * area) / d2;
if (area < 0)
deriv *= -1;
}
- if (param == distance()) deriv += -1;
+ if (param == distance())
+ deriv += -1;
return scale * deriv;
}
-double ConstraintP2LDistance::maxStep(MAP_pD_D &dir, double lim)
+double ConstraintP2LDistance::maxStep(MAP_pD_D& dir, double lim)
{
MAP_pD_D::iterator it;
// distance() >= 0
@@ -841,36 +891,44 @@ double ConstraintP2LDistance::maxStep(MAP_pD_D &dir, double lim)
lim = std::min(lim, -(*distance()) / it->second);
}
// restrict actual area change
- double darea=0.;
- double x0=*p0x(), x1=*p1x(), x2=*p2x();
- double y0=*p0y(), y1=*p1y(), y2=*p2y();
+ double darea = 0.;
+ double x0 = *p0x(), x1 = *p1x(), x2 = *p2x();
+ double y0 = *p0y(), y1 = *p1y(), y2 = *p2y();
it = dir.find(p0x());
- if (it != dir.end()) darea += (y1-y2) * it->second;
+ if (it != dir.end())
+ darea += (y1 - y2) * it->second;
it = dir.find(p0y());
- if (it != dir.end()) darea += (x2-x1) * it->second;
+ if (it != dir.end())
+ darea += (x2 - x1) * it->second;
it = dir.find(p1x());
- if (it != dir.end()) darea += (y2-y0) * it->second;
+ if (it != dir.end())
+ darea += (y2 - y0) * it->second;
it = dir.find(p1y());
- if (it != dir.end()) darea += (x0-x2) * it->second;
+ if (it != dir.end())
+ darea += (x0 - x2) * it->second;
it = dir.find(p2x());
- if (it != dir.end()) darea += (y0-y1) * it->second;
+ if (it != dir.end())
+ darea += (y0 - y1) * it->second;
it = dir.find(p2y());
- if (it != dir.end()) darea += (x1-x0) * it->second;
+ if (it != dir.end())
+ darea += (x1 - x0) * it->second;
darea = std::abs(darea);
if (darea > 0.) {
- double dx = x2-x1;
- double dy = y2-y1;
- double area = 0.3*(*distance())*sqrt(dx*dx+dy*dy);
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double area = 0.3 * (*distance()) * sqrt(dx * dx + dy * dy);
if (darea > area) {
- area = std::max(area, 0.3*std::abs(-x0*dy+y0*dx+x1*y2-x2*y1));
+ area = std::max(area, 0.3 * std::abs(-x0 * dy + y0 * dx + x1 * y2 - x2 * y1));
if (darea > area)
- lim = std::min(lim, area/darea);
+ lim = std::min(lim, area / darea);
}
}
return lim;
}
+
+// --------------------------------------------------------
// PointOnLine
ConstraintPointOnLine::ConstraintPointOnLine(Point &p, Line &l)
{
@@ -908,41 +966,49 @@ void ConstraintPointOnLine::rescale(double coef)
double ConstraintPointOnLine::error()
{
- double x0=*p0x(), x1=*p1x(), x2=*p2x();
- double y0=*p0y(), y1=*p1y(), y2=*p2y();
- double dx = x2-x1;
- double dy = y2-y1;
- double d = sqrt(dx*dx+dy*dy);
- double area = -x0*dy+y0*dx+x1*y2-x2*y1; // = x1y2 - x2y1 - x0y2 + x2y0 + x0y1 - x1y0 = 2*(triangle area)
- return scale * area/d;
+ double x0 = *p0x(), x1 = *p1x(), x2 = *p2x();
+ double y0 = *p0y(), y1 = *p1y(), y2 = *p2y();
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double d = sqrt(dx * dx + dy * dy);
+ double area = -x0 * dy + y0 * dx + x1 * y2
+ - x2 * y1;// = x1y2 - x2y1 - x0y2 + x2y0 + x0y1 - x1y0 = 2*(triangle area)
+ return scale * area / d;
}
-double ConstraintPointOnLine::grad(double *param)
+double ConstraintPointOnLine::grad(double* param)
{
- double deriv=0.;
+ double deriv = 0.;
// darea/dx0 = (y1-y2) darea/dy0 = (x2-x1)
// darea/dx1 = (y2-y0) darea/dy1 = (x0-x2)
// darea/dx2 = (y0-y1) darea/dy2 = (x1-x0)
- if (param == p0x() || param == p0y() ||
- param == p1x() || param == p1y() ||
- param == p2x() || param == p2y()) {
- double x0=*p0x(), x1=*p1x(), x2=*p2x();
- double y0=*p0y(), y1=*p1y(), y2=*p2y();
- double dx = x2-x1;
- double dy = y2-y1;
- double d2 = dx*dx+dy*dy;
+ if (param == p0x() || param == p0y() || param == p1x() || param == p1y() || param == p2x()
+ || param == p2y()) {
+ double x0 = *p0x(), x1 = *p1x(), x2 = *p2x();
+ double y0 = *p0y(), y1 = *p1y(), y2 = *p2y();
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double d2 = dx * dx + dy * dy;
double d = sqrt(d2);
- double area = -x0*dy+y0*dx+x1*y2-x2*y1;
- if (param == p0x()) deriv += (y1-y2) / d;
- if (param == p0y()) deriv += (x2-x1) / d ;
- if (param == p1x()) deriv += ((y2-y0)*d + (dx/d)*area) / d2;
- if (param == p1y()) deriv += ((x0-x2)*d + (dy/d)*area) / d2;
- if (param == p2x()) deriv += ((y0-y1)*d - (dx/d)*area) / d2;
- if (param == p2y()) deriv += ((x1-x0)*d - (dy/d)*area) / d2;
+ double area = -x0 * dy + y0 * dx + x1 * y2 - x2 * y1;
+ if (param == p0x())
+ deriv += (y1 - y2) / d;
+ if (param == p0y())
+ deriv += (x2 - x1) / d;
+ if (param == p1x())
+ deriv += ((y2 - y0) * d + (dx / d) * area) / d2;
+ if (param == p1y())
+ deriv += ((x0 - x2) * d + (dy / d) * area) / d2;
+ if (param == p2x())
+ deriv += ((y0 - y1) * d - (dx / d) * area) / d2;
+ if (param == p2y())
+ deriv += ((x1 - x0) * d - (dy / d) * area) / d2;
}
return scale * deriv;
}
+
+// --------------------------------------------------------
// PointOnPerpBisector
ConstraintPointOnPerpBisector::ConstraintPointOnPerpBisector(Point &p, Line &l)
{
@@ -978,11 +1044,11 @@ void ConstraintPointOnPerpBisector::rescale(double coef)
scale = coef;
}
-void ConstraintPointOnPerpBisector::errorgrad(double *err, double *grad, double *param)
+void ConstraintPointOnPerpBisector::errorgrad(double* err, double* grad, double* param)
{
- DeriVector2 p0(Point(p0x(),p0y()), param);
- DeriVector2 p1(Point(p1x(),p1y()), param);
- DeriVector2 p2(Point(p2x(),p2y()), param);
+ DeriVector2 p0(Point(p0x(), p0y()), param);
+ DeriVector2 p1(Point(p1x(), p1y()), param);
+ DeriVector2 p2(Point(p2x(), p2y()), param);
DeriVector2 d1 = p0.subtr(p1);
DeriVector2 d2 = p0.subtr(p2);
@@ -995,15 +1061,15 @@ void ConstraintPointOnPerpBisector::errorgrad(double *err, double *grad, double
projd2 = d2.scalarProd(D, &dprojd2);
if (err)
- *err = projd1+projd2;
+ *err = projd1 + projd2;
if (grad)
- *grad = dprojd1+dprojd2;
+ *grad = dprojd1 + dprojd2;
}
double ConstraintPointOnPerpBisector::error()
{
double err;
- errorgrad(&err,nullptr,nullptr);
+ errorgrad(&err, nullptr, nullptr);
return scale * err;
}
@@ -1019,6 +1085,8 @@ double ConstraintPointOnPerpBisector::grad(double *param)
return deriv*scale;
}
+
+// --------------------------------------------------------
// Parallel
ConstraintParallel::ConstraintParallel(Line &l1, Line &l2)
{
@@ -1045,7 +1113,7 @@ void ConstraintParallel::rescale(double coef)
double dy1 = (*l1p1y() - *l1p2y());
double dx2 = (*l2p1x() - *l2p2x());
double dy2 = (*l2p1y() - *l2p2y());
- scale = coef / sqrt((dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2));
+ scale = coef / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2));
}
double ConstraintParallel::error()
@@ -1054,25 +1122,35 @@ double ConstraintParallel::error()
double dy1 = (*l1p1y() - *l1p2y());
double dx2 = (*l2p1x() - *l2p2x());
double dy2 = (*l2p1y() - *l2p2y());
- return scale * (dx1*dy2 - dy1*dx2);
+ return scale * (dx1 * dy2 - dy1 * dx2);
}
-double ConstraintParallel::grad(double *param)
+double ConstraintParallel::grad(double* param)
{
- double deriv=0.;
- if (param == l1p1x()) deriv += (*l2p1y() - *l2p2y()); // = dy2
- if (param == l1p2x()) deriv += -(*l2p1y() - *l2p2y()); // = -dy2
- if (param == l1p1y()) deriv += -(*l2p1x() - *l2p2x()); // = -dx2
- if (param == l1p2y()) deriv += (*l2p1x() - *l2p2x()); // = dx2
+ double deriv = 0.;
+ if (param == l1p1x())
+ deriv += (*l2p1y() - *l2p2y());// = dy2
+ if (param == l1p2x())
+ deriv += -(*l2p1y() - *l2p2y());// = -dy2
+ if (param == l1p1y())
+ deriv += -(*l2p1x() - *l2p2x());// = -dx2
+ if (param == l1p2y())
+ deriv += (*l2p1x() - *l2p2x());// = dx2
- if (param == l2p1x()) deriv += -(*l1p1y() - *l1p2y()); // = -dy1
- if (param == l2p2x()) deriv += (*l1p1y() - *l1p2y()); // = dy1
- if (param == l2p1y()) deriv += (*l1p1x() - *l1p2x()); // = dx1
- if (param == l2p2y()) deriv += -(*l1p1x() - *l1p2x()); // = -dx1
+ if (param == l2p1x())
+ deriv += -(*l1p1y() - *l1p2y());// = -dy1
+ if (param == l2p2x())
+ deriv += (*l1p1y() - *l1p2y());// = dy1
+ if (param == l2p1y())
+ deriv += (*l1p1x() - *l1p2x());// = dx1
+ if (param == l2p2y())
+ deriv += -(*l1p1x() - *l1p2x());// = -dx1
return scale * deriv;
}
+
+// --------------------------------------------------------
// Perpendicular
ConstraintPerpendicular::ConstraintPerpendicular(Line &l1, Line &l2)
{
@@ -1114,7 +1192,7 @@ void ConstraintPerpendicular::rescale(double coef)
double dy1 = (*l1p1y() - *l1p2y());
double dx2 = (*l2p1x() - *l2p2x());
double dy2 = (*l2p1y() - *l2p2y());
- scale = coef / sqrt((dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2));
+ scale = coef / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2));
}
double ConstraintPerpendicular::error()
@@ -1123,25 +1201,35 @@ double ConstraintPerpendicular::error()
double dy1 = (*l1p1y() - *l1p2y());
double dx2 = (*l2p1x() - *l2p2x());
double dy2 = (*l2p1y() - *l2p2y());
- return scale * (dx1*dx2 + dy1*dy2);
+ return scale * (dx1 * dx2 + dy1 * dy2);
}
-double ConstraintPerpendicular::grad(double *param)
+double ConstraintPerpendicular::grad(double* param)
{
- double deriv=0.;
- if (param == l1p1x()) deriv += (*l2p1x() - *l2p2x()); // = dx2
- if (param == l1p2x()) deriv += -(*l2p1x() - *l2p2x()); // = -dx2
- if (param == l1p1y()) deriv += (*l2p1y() - *l2p2y()); // = dy2
- if (param == l1p2y()) deriv += -(*l2p1y() - *l2p2y()); // = -dy2
+ double deriv = 0.;
+ if (param == l1p1x())
+ deriv += (*l2p1x() - *l2p2x());// = dx2
+ if (param == l1p2x())
+ deriv += -(*l2p1x() - *l2p2x());// = -dx2
+ if (param == l1p1y())
+ deriv += (*l2p1y() - *l2p2y());// = dy2
+ if (param == l1p2y())
+ deriv += -(*l2p1y() - *l2p2y());// = -dy2
- if (param == l2p1x()) deriv += (*l1p1x() - *l1p2x()); // = dx1
- if (param == l2p2x()) deriv += -(*l1p1x() - *l1p2x()); // = -dx1
- if (param == l2p1y()) deriv += (*l1p1y() - *l1p2y()); // = dy1
- if (param == l2p2y()) deriv += -(*l1p1y() - *l1p2y()); // = -dy1
+ if (param == l2p1x())
+ deriv += (*l1p1x() - *l1p2x());// = dx1
+ if (param == l2p2x())
+ deriv += -(*l1p1x() - *l1p2x());// = -dx1
+ if (param == l2p1y())
+ deriv += (*l1p1y() - *l1p2y());// = dy1
+ if (param == l2p2y())
+ deriv += -(*l1p1y() - *l1p2y());// = -dy1
return scale * deriv;
}
+
+// --------------------------------------------------------
// L2LAngle
ConstraintL2LAngle::ConstraintL2LAngle(Line &l1, Line &l2, double *a)
{
@@ -1190,63 +1278,72 @@ double ConstraintL2LAngle::error()
double dy1 = (*l1p2y() - *l1p1y());
double dx2 = (*l2p2x() - *l2p1x());
double dy2 = (*l2p2y() - *l2p1y());
- double a = atan2(dy1,dx1) + *angle();
+ double a = atan2(dy1, dx1) + *angle();
double ca = cos(a);
double sa = sin(a);
- double x2 = dx2*ca + dy2*sa;
- double y2 = -dx2*sa + dy2*ca;
- return scale * atan2(y2,x2);
+ double x2 = dx2 * ca + dy2 * sa;
+ double y2 = -dx2 * sa + dy2 * ca;
+ return scale * atan2(y2, x2);
}
-double ConstraintL2LAngle::grad(double *param)
+double ConstraintL2LAngle::grad(double* param)
{
- double deriv=0.;
- if (param == l1p1x() || param == l1p1y() ||
- param == l1p2x() || param == l1p2y()) {
+ double deriv = 0.;
+ if (param == l1p1x() || param == l1p1y() || param == l1p2x() || param == l1p2y()) {
double dx1 = (*l1p2x() - *l1p1x());
double dy1 = (*l1p2y() - *l1p1y());
- double r2 = dx1*dx1+dy1*dy1;
- if (param == l1p1x()) deriv += -dy1/r2;
- if (param == l1p1y()) deriv += dx1/r2;
- if (param == l1p2x()) deriv += dy1/r2;
- if (param == l1p2y()) deriv += -dx1/r2;
+ double r2 = dx1 * dx1 + dy1 * dy1;
+ if (param == l1p1x())
+ deriv += -dy1 / r2;
+ if (param == l1p1y())
+ deriv += dx1 / r2;
+ if (param == l1p2x())
+ deriv += dy1 / r2;
+ if (param == l1p2y())
+ deriv += -dx1 / r2;
}
- if (param == l2p1x() || param == l2p1y() ||
- param == l2p2x() || param == l2p2y()) {
+ if (param == l2p1x() || param == l2p1y() || param == l2p2x() || param == l2p2y()) {
double dx1 = (*l1p2x() - *l1p1x());
double dy1 = (*l1p2y() - *l1p1y());
double dx2 = (*l2p2x() - *l2p1x());
double dy2 = (*l2p2y() - *l2p1y());
- double a = atan2(dy1,dx1) + *angle();
+ double a = atan2(dy1, dx1) + *angle();
double ca = cos(a);
double sa = sin(a);
- double x2 = dx2*ca + dy2*sa;
- double y2 = -dx2*sa + dy2*ca;
- double r2 = dx2*dx2+dy2*dy2;
- dx2 = -y2/r2;
- dy2 = x2/r2;
- if (param == l2p1x()) deriv += (-ca*dx2 + sa*dy2);
- if (param == l2p1y()) deriv += (-sa*dx2 - ca*dy2);
- if (param == l2p2x()) deriv += ( ca*dx2 - sa*dy2);
- if (param == l2p2y()) deriv += ( sa*dx2 + ca*dy2);
+ double x2 = dx2 * ca + dy2 * sa;
+ double y2 = -dx2 * sa + dy2 * ca;
+ double r2 = dx2 * dx2 + dy2 * dy2;
+ dx2 = -y2 / r2;
+ dy2 = x2 / r2;
+ if (param == l2p1x())
+ deriv += (-ca * dx2 + sa * dy2);
+ if (param == l2p1y())
+ deriv += (-sa * dx2 - ca * dy2);
+ if (param == l2p2x())
+ deriv += (ca * dx2 - sa * dy2);
+ if (param == l2p2y())
+ deriv += (sa * dx2 + ca * dy2);
}
- if (param == angle()) deriv += -1;
+ if (param == angle())
+ deriv += -1;
return scale * deriv;
}
-double ConstraintL2LAngle::maxStep(MAP_pD_D &dir, double lim)
+double ConstraintL2LAngle::maxStep(MAP_pD_D& dir, double lim)
{
// step(angle()) <= pi/18 = 10°
MAP_pD_D::iterator it = dir.find(angle());
if (it != dir.end()) {
double step = std::abs(it->second);
- if (step > M_PI/18.)
- lim = std::min(lim, (M_PI/18.) / step);
+ if (step > M_PI / 18.0)
+ lim = std::min(lim, (M_PI / 18.0) / step);
}
return lim;
}
+
+// --------------------------------------------------------
// MidpointOnLine
ConstraintMidpointOnLine::ConstraintMidpointOnLine(Line &l1, Line &l2)
{
@@ -1262,7 +1359,8 @@ ConstraintMidpointOnLine::ConstraintMidpointOnLine(Line &l1, Line &l2)
rescale();
}
-ConstraintMidpointOnLine::ConstraintMidpointOnLine(Point &l1p1, Point &l1p2, Point &l2p1, Point &l2p2)
+ConstraintMidpointOnLine::ConstraintMidpointOnLine(Point& l1p1, Point& l1p2, Point& l2p1,
+ Point& l2p2)
{
pvec.push_back(l1p1.x);
pvec.push_back(l1p1.y);
@@ -1288,51 +1386,60 @@ void ConstraintMidpointOnLine::rescale(double coef)
double ConstraintMidpointOnLine::error()
{
- double x0=((*l1p1x())+(*l1p2x()))/2;
- double y0=((*l1p1y())+(*l1p2y()))/2;
- double x1=*l2p1x(), x2=*l2p2x();
- double y1=*l2p1y(), y2=*l2p2y();
- double dx = x2-x1;
- double dy = y2-y1;
- double d = sqrt(dx*dx+dy*dy);
- double area = -x0*dy+y0*dx+x1*y2-x2*y1; // = x1y2 - x2y1 - x0y2 + x2y0 + x0y1 - x1y0 = 2*(triangle area)
- return scale * area/d;
+ double x0 = ((*l1p1x()) + (*l1p2x())) / 2;
+ double y0 = ((*l1p1y()) + (*l1p2y())) / 2;
+ double x1 = *l2p1x(), x2 = *l2p2x();
+ double y1 = *l2p1y(), y2 = *l2p2y();
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double d = sqrt(dx * dx + dy * dy);
+ double area = -x0 * dy + y0 * dx + x1 * y2
+ - x2 * y1;// = x1y2 - x2y1 - x0y2 + x2y0 + x0y1 - x1y0 = 2*(triangle area)
+ return scale * area / d;
}
-double ConstraintMidpointOnLine::grad(double *param)
+double ConstraintMidpointOnLine::grad(double* param)
{
- double deriv=0.;
+ double deriv = 0.;
// darea/dx0 = (y1-y2) darea/dy0 = (x2-x1)
// darea/dx1 = (y2-y0) darea/dy1 = (x0-x2)
// darea/dx2 = (y0-y1) darea/dy2 = (x1-x0)
- if (param == l1p1x() || param == l1p1y() ||
- param == l1p2x() || param == l1p2y()||
- param == l2p1x() || param == l2p1y() ||
- param == l2p2x() || param == l2p2y()) {
- double x0=((*l1p1x())+(*l1p2x()))/2;
- double y0=((*l1p1y())+(*l1p2y()))/2;
- double x1=*l2p1x(), x2=*l2p2x();
- double y1=*l2p1y(), y2=*l2p2y();
- double dx = x2-x1;
- double dy = y2-y1;
- double d2 = dx*dx+dy*dy;
+ if (param == l1p1x() || param == l1p1y() || param == l1p2x() || param == l1p2y()
+ || param == l2p1x() || param == l2p1y() || param == l2p2x() || param == l2p2y()) {
+ double x0 = ((*l1p1x()) + (*l1p2x())) / 2;
+ double y0 = ((*l1p1y()) + (*l1p2y())) / 2;
+ double x1 = *l2p1x(), x2 = *l2p2x();
+ double y1 = *l2p1y(), y2 = *l2p2y();
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double d2 = dx * dx + dy * dy;
double d = sqrt(d2);
- double area = -x0*dy+y0*dx+x1*y2-x2*y1;
- if (param == l1p1x()) deriv += (y1-y2) / (2*d);
- if (param == l1p1y()) deriv += (x2-x1) / (2*d);
- if (param == l1p2x()) deriv += (y1-y2) / (2*d);
- if (param == l1p2y()) deriv += (x2-x1) / (2*d);
- if (param == l2p1x()) deriv += ((y2-y0)*d + (dx/d)*area) / d2;
- if (param == l2p1y()) deriv += ((x0-x2)*d + (dy/d)*area) / d2;
- if (param == l2p2x()) deriv += ((y0-y1)*d - (dx/d)*area) / d2;
- if (param == l2p2y()) deriv += ((x1-x0)*d - (dy/d)*area) / d2;
+ double area = -x0 * dy + y0 * dx + x1 * y2 - x2 * y1;
+ if (param == l1p1x())
+ deriv += (y1 - y2) / (2 * d);
+ if (param == l1p1y())
+ deriv += (x2 - x1) / (2 * d);
+ if (param == l1p2x())
+ deriv += (y1 - y2) / (2 * d);
+ if (param == l1p2y())
+ deriv += (x2 - x1) / (2 * d);
+ if (param == l2p1x())
+ deriv += ((y2 - y0) * d + (dx / d) * area) / d2;
+ if (param == l2p1y())
+ deriv += ((x0 - x2) * d + (dy / d) * area) / d2;
+ if (param == l2p2x())
+ deriv += ((y0 - y1) * d - (dx / d) * area) / d2;
+ if (param == l2p2y())
+ deriv += ((x1 - x0) * d - (dy / d) * area) / d2;
}
return scale * deriv;
}
+
+// --------------------------------------------------------
// TangentCircumf
-ConstraintTangentCircumf::ConstraintTangentCircumf(Point &p1, Point &p2,
- double *rad1, double *rad2, bool internal_)
+ConstraintTangentCircumf::ConstraintTangentCircumf(Point& p1, Point& p2, double* rad1, double* rad2,
+ bool internal_)
{
internal = internal_;
pvec.push_back(p1.x);
@@ -1360,36 +1467,45 @@ double ConstraintTangentCircumf::error()
double dx = (*c1x() - *c2x());
double dy = (*c1y() - *c2y());
if (internal)
- return scale * (sqrt(dx*dx + dy*dy) - std::abs(*r1() - *r2()));
+ return scale * (sqrt(dx * dx + dy * dy) - std::abs(*r1() - *r2()));
else
- return scale * (sqrt(dx*dx + dy*dy) - (*r1() + *r2()));
+ return scale * (sqrt(dx * dx + dy * dy) - (*r1() + *r2()));
}
-double ConstraintTangentCircumf::grad(double *param)
+double ConstraintTangentCircumf::grad(double* param)
{
- double deriv=0.;
- if (param == c1x() || param == c1y() ||
- param == c2x() || param == c2y()||
- param == r1() || param == r2()) {
+ double deriv = 0.;
+ if (param == c1x() || param == c1y() || param == c2x() || param == c2y() || param == r1()
+ || param == r2()) {
double dx = (*c1x() - *c2x());
double dy = (*c1y() - *c2y());
- double d = sqrt(dx*dx + dy*dy);
- if (param == c1x()) deriv += dx/d;
- if (param == c1y()) deriv += dy/d;
- if (param == c2x()) deriv += -dx/d;
- if (param == c2y()) deriv += -dy/d;
+ double d = sqrt(dx * dx + dy * dy);
+ if (param == c1x())
+ deriv += dx / d;
+ if (param == c1y())
+ deriv += dy / d;
+ if (param == c2x())
+ deriv += -dx / d;
+ if (param == c2y())
+ deriv += -dy / d;
if (internal) {
- if (param == r1()) deriv += (*r1() > *r2()) ? -1 : 1;
- if (param == r2()) deriv += (*r1() > *r2()) ? 1 : -1;
+ if (param == r1())
+ deriv += (*r1() > *r2()) ? -1 : 1;
+ if (param == r2())
+ deriv += (*r1() > *r2()) ? 1 : -1;
}
else {
- if (param == r1()) deriv += -1;
- if (param == r2()) deriv += -1;
+ if (param == r1())
+ deriv += -1;
+ if (param == r2())
+ deriv += -1;
}
}
return scale * deriv;
}
+
+// --------------------------------------------------------
// ConstraintPointOnEllipse
ConstraintPointOnEllipse::ConstraintPointOnEllipse(Point &p, Ellipse &e)
{
@@ -1424,19 +1540,17 @@ double ConstraintPointOnEllipse::error()
double Y_F1 = *f1y();
double b = *rmin();
- double err=sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) + sqrt(pow(X_0 +
- X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 - 2*Y_c, 2)) - 2*sqrt(pow(b, 2) +
- pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2));
+ double err = sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ + sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2))
+ - 2 * sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2));
return scale * err;
}
-double ConstraintPointOnEllipse::grad(double *param)
+double ConstraintPointOnEllipse::grad(double* param)
{
- double deriv=0.;
- if (param == p1x() || param == p1y() ||
- param == f1x() || param == f1y() ||
- param == cx() || param == cy() ||
- param == rmin()) {
+ double deriv = 0.;
+ if (param == p1x() || param == p1y() || param == f1x() || param == f1y() || param == cx()
+ || param == cy() || param == rmin()) {
double X_0 = *p1x();
double Y_0 = *p1y();
@@ -1447,38 +1561,39 @@ double ConstraintPointOnEllipse::grad(double *param)
double b = *rmin();
if (param == p1x())
- deriv += (X_0 - X_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) +
- (X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 -
- 2*Y_c, 2));
+ deriv += (X_0 - X_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ + (X_0 + X_F1 - 2 * X_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == p1y())
- deriv += (Y_0 - Y_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) +
- (Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 -
- 2*Y_c, 2));
+ deriv += (Y_0 - Y_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ + (Y_0 + Y_F1 - 2 * Y_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == f1x())
- deriv += -(X_0 - X_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) -
- 2*(X_F1 - X_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
- + (X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1
- - 2*Y_c, 2));
+ deriv += -(X_0 - X_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ - 2 * (X_F1 - X_c) / sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ + (X_0 + X_F1 - 2 * X_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == f1y())
- deriv +=-(Y_0 - Y_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) -
- 2*(Y_F1 - Y_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
- + (Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1
- - 2*Y_c, 2));
+ deriv += -(Y_0 - Y_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ - 2 * (Y_F1 - Y_c) / sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ + (Y_0 + Y_F1 - 2 * Y_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == cx())
- deriv += 2*(X_F1 - X_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1
- - Y_c, 2)) - 2*(X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) +
- pow(Y_0 + Y_F1 - 2*Y_c, 2));
+ deriv += 2 * (X_F1 - X_c) / sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ - 2 * (X_0 + X_F1 - 2 * X_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == cy())
- deriv +=2*(Y_F1 - Y_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1
- - Y_c, 2)) - 2*(Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) +
- pow(Y_0 + Y_F1 - 2*Y_c, 2));
+ deriv += 2 * (Y_F1 - Y_c) / sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ - 2 * (Y_0 + Y_F1 - 2 * Y_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == rmin())
- deriv += -2*b/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c,
- 2));
+ deriv += -2 * b / sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2));
}
return scale * deriv;
}
+
+// --------------------------------------------------------
// ConstraintEllipseTangentLine
ConstraintEllipseTangentLine::ConstraintEllipseTangentLine(Line &l, Ellipse &e)
{
@@ -1510,57 +1625,58 @@ void ConstraintEllipseTangentLine::rescale(double coef)
scale = coef * 1;
}
-void ConstraintEllipseTangentLine::errorgrad(double *err, double *grad, double *param)
+void ConstraintEllipseTangentLine::errorgrad(double* err, double* grad, double* param)
{
// DeepSOIC equation
// http://forum.freecadweb.org/viewtopic.php?f=10&t=7520&start=140
- if (pvecChangedFlag) ReconstructGeomPointers();
- DeriVector2 p1 (l.p1, param);
- DeriVector2 p2 (l.p2, param);
- DeriVector2 f1 (e.focus1, param);
- DeriVector2 c (e.center, param);
- DeriVector2 f2 = c.linCombi(2.0, f1, -1.0); // 2*cv - f1v
+ if (pvecChangedFlag)
+ ReconstructGeomPointers();
+ DeriVector2 p1(l.p1, param);
+ DeriVector2 p2(l.p2, param);
+ DeriVector2 f1(e.focus1, param);
+ DeriVector2 c(e.center, param);
+ DeriVector2 f2 = c.linCombi(2.0, f1, -1.0);// 2*cv - f1v
- //mirror F1 against the line
+ // mirror F1 against the line
DeriVector2 nl = l.CalculateNormal(l.p1, param).getNormalized();
- double distF1L = 0, ddistF1L = 0; //distance F1 to line
- distF1L = f1.subtr(p1).scalarProd(nl,&ddistF1L);
- DeriVector2 f1m = f1.sum(nl.multD(-2*distF1L,-2*ddistF1L));//f1m = f1 mirrored
+ double distF1L = 0, ddistF1L = 0;// distance F1 to line
+ distF1L = f1.subtr(p1).scalarProd(nl, &ddistF1L);
+ DeriVector2 f1m = f1.sum(nl.multD(-2 * distF1L, -2 * ddistF1L));// f1m = f1 mirrored
- //calculate distance form f1m to f2
+ // calculate distance form f1m to f2
double distF1mF2, ddistF1mF2;
distF1mF2 = f2.subtr(f1m).length(ddistF1mF2);
- //calculate major radius (to compare the distance to)
+ // calculate major radius (to compare the distance to)
double dradmin = (param == e.radmin) ? 1.0 : 0.0;
double radmaj, dradmaj;
- radmaj = e.getRadMaj(c,f1,*e.radmin, dradmin, dradmaj);
+ radmaj = e.getRadMaj(c, f1, *e.radmin, dradmin, dradmaj);
if (err)
- *err = distF1mF2 - 2*radmaj;
+ *err = distF1mF2 - 2 * radmaj;
if (grad)
- *grad = ddistF1mF2 - 2*dradmaj;
+ *grad = ddistF1mF2 - 2 * dradmaj;
}
double ConstraintEllipseTangentLine::error()
{
double err;
- errorgrad(&err,nullptr,nullptr);
+ errorgrad(&err, nullptr, nullptr);
return scale * err;
}
-double ConstraintEllipseTangentLine::grad(double *param)
+double ConstraintEllipseTangentLine::grad(double* param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
- //use numeric for testing
- #if 0
+// use numeric for testing
+#if 0
double const eps = 0.00001;
double oldparam = *param;
double v0 = this->error();
@@ -1570,18 +1686,20 @@ double ConstraintEllipseTangentLine::grad(double *param)
double vl = this->error();
*param = oldparam;
//If not nasty, real derivative should be between left one and right one
- double numretl = (v0-vl)/eps;
- double numretr = (vr-v0)/eps;
- assert(deriv <= std::max(numretl,numretr) );
- assert(deriv >= std::min(numretl,numretr) );
- #endif
+ double numretl = (v0 - vl) / eps;
+ double numretr = (vr - v0) / eps;
+ assert(deriv <= std::max(numretl, numretr));
+ assert(deriv >= std::min(numretl, numretr));
+#endif
-
- return deriv*scale;
+ return deriv * scale;
}
+
+// --------------------------------------------------------
// ConstraintInternalAlignmentPoint2Ellipse
-ConstraintInternalAlignmentPoint2Ellipse::ConstraintInternalAlignmentPoint2Ellipse(Ellipse &e, Point &p1, InternalAlignmentType alignmentType)
+ConstraintInternalAlignmentPoint2Ellipse::ConstraintInternalAlignmentPoint2Ellipse(
+ Ellipse& e, Point& p1, InternalAlignmentType alignmentType)
{
this->p = p1;
pvec.push_back(p.x);
@@ -1596,8 +1714,10 @@ ConstraintInternalAlignmentPoint2Ellipse::ConstraintInternalAlignmentPoint2Ellip
void ConstraintInternalAlignmentPoint2Ellipse::ReconstructGeomPointers()
{
int i = 0;
- p.x = pvec[i]; i++;
- p.y = pvec[i]; i++;
+ p.x = pvec[i];
+ i++;
+ p.y = pvec[i];
+ i++;
e.ReconstructOnNewPvec(pvec, i);
pvecChangedFlag = false;
}
@@ -1612,82 +1732,84 @@ void ConstraintInternalAlignmentPoint2Ellipse::rescale(double coef)
scale = coef * 1;
}
-void ConstraintInternalAlignmentPoint2Ellipse::errorgrad(double *err, double *grad, double *param)
+void ConstraintInternalAlignmentPoint2Ellipse::errorgrad(double* err, double* grad, double* param)
{
- if (pvecChangedFlag) ReconstructGeomPointers();
+ if (pvecChangedFlag)
+ ReconstructGeomPointers();
- //todo: prefill only what's needed, not everything
+ // todo: prefill only what's needed, not everything
DeriVector2 c(e.center, param);
DeriVector2 f1(e.focus1, param);
DeriVector2 emaj = f1.subtr(c).getNormalized();
DeriVector2 emin = emaj.rotate90ccw();
- DeriVector2 pv (p, param);
- double b, db;//minor radius
- b = *e.radmin; db = (e.radmin == param) ? 1.0 : 0.0;
+ DeriVector2 pv(p, param);
+ double b, db;// minor radius
+ b = *e.radmin;
+ db = (e.radmin == param) ? 1.0 : 0.0;
- //major radius
+ // major radius
double a, da;
- a = e.getRadMaj(c,f1,b,db,da);
+ a = e.getRadMaj(c, f1, b, db, da);
- DeriVector2 poa;//point to align to
- bool by_y_not_by_x = false;//a flag to indicate if the alignment error function is for y (false - x, true - y).
+ DeriVector2 poa;// point to align to
+ bool by_y_not_by_x =
+ false;// a flag to indicate if the alignment error function is for y (false - x, true - y)
- switch(AlignmentType){
+ switch (AlignmentType) {
case EllipsePositiveMajorX:
case EllipsePositiveMajorY:
poa = c.sum(emaj.multD(a, da));
by_y_not_by_x = AlignmentType == EllipsePositiveMajorY;
- break;
+ break;
case EllipseNegativeMajorX:
case EllipseNegativeMajorY:
poa = c.sum(emaj.multD(-a, -da));
by_y_not_by_x = AlignmentType == EllipseNegativeMajorY;
- break;
+ break;
case EllipsePositiveMinorX:
case EllipsePositiveMinorY:
poa = c.sum(emin.multD(b, db));
by_y_not_by_x = AlignmentType == EllipsePositiveMinorY;
- break;
+ break;
case EllipseNegativeMinorX:
case EllipseNegativeMinorY:
poa = c.sum(emin.multD(-b, -db));
by_y_not_by_x = AlignmentType == EllipseNegativeMinorY;
- break;
+ break;
case EllipseFocus2X:
case EllipseFocus2Y:
poa = c.linCombi(2.0, f1, -1.0);
by_y_not_by_x = AlignmentType == EllipseFocus2Y;
- break;
+ break;
default:
- //shouldn't happen
- poa = pv;//align to the point itself, doing nothing essentially
+ // shouldn't happen
+ poa = pv;// align to the point itself, doing nothing essentially
}
- if(err)
+ if (err)
*err = by_y_not_by_x ? pv.y - poa.y : pv.x - poa.x;
- if(grad)
+ if (grad)
*grad = by_y_not_by_x ? pv.dy - poa.dy : pv.dx - poa.dx;
}
double ConstraintInternalAlignmentPoint2Ellipse::error()
{
double err;
- errorgrad(&err,nullptr,nullptr);
+ errorgrad(&err, nullptr, nullptr);
return scale * err;
-
}
-double ConstraintInternalAlignmentPoint2Ellipse::grad(double *param)
+double ConstraintInternalAlignmentPoint2Ellipse::grad(double* param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
- //use numeric for testing
- #if 0
+// use numeric for testing
+#if 0
double const eps = 0.00001;
double oldparam = *param;
double v0 = this->error();
@@ -1697,18 +1819,20 @@ double ConstraintInternalAlignmentPoint2Ellipse::grad(double *param)
double vl = this->error();
*param = oldparam;
//If not nasty, real derivative should be between left one and right one
- double numretl = (v0-vl)/eps;
- double numretr = (vr-v0)/eps;
- assert(deriv <= std::max(numretl,numretr) );
- assert(deriv >= std::min(numretl,numretr) );
- #endif
-
- return deriv*scale;
+ double numretl = (v0 - vl) / eps;
+ double numretr = (vr - v0) / eps;
+ assert(deriv <= std::max(numretl, numretr));
+ assert(deriv >= std::min(numretl, numretr));
+#endif
+ return deriv * scale;
}
+
+// --------------------------------------------------------
// ConstraintInternalAlignmentPoint2Hyperbola
-ConstraintInternalAlignmentPoint2Hyperbola::ConstraintInternalAlignmentPoint2Hyperbola(Hyperbola &e, Point &p1, InternalAlignmentType alignmentType)
+ConstraintInternalAlignmentPoint2Hyperbola::ConstraintInternalAlignmentPoint2Hyperbola(
+ Hyperbola& e, Point& p1, InternalAlignmentType alignmentType)
{
this->p = p1;
pvec.push_back(p.x);
@@ -1739,29 +1863,32 @@ void ConstraintInternalAlignmentPoint2Hyperbola::rescale(double coef)
scale = coef * 1;
}
-void ConstraintInternalAlignmentPoint2Hyperbola::errorgrad(double *err, double *grad, double *param)
+void ConstraintInternalAlignmentPoint2Hyperbola::errorgrad(double* err, double* grad, double* param)
{
- if (pvecChangedFlag) ReconstructGeomPointers();
+ if (pvecChangedFlag)
+ ReconstructGeomPointers();
- //todo: prefill only what's needed, not everything
+ // todo: prefill only what's needed, not everything
DeriVector2 c(e.center, param);
DeriVector2 f1(e.focus1, param);
DeriVector2 emaj = f1.subtr(c).getNormalized();
DeriVector2 emin = emaj.rotate90ccw();
- DeriVector2 pv (p, param);
+ DeriVector2 pv(p, param);
- double b, db;//minor radius
- b = *e.radmin; db = (e.radmin == param) ? 1.0 : 0.0;
+ double b, db;// minor radius
+ b = *e.radmin;
+ db = (e.radmin == param) ? 1.0 : 0.0;
- //major radius
+ // major radius
double a, da;
- a = e.getRadMaj(c,f1,b,db,da);
+ a = e.getRadMaj(c, f1, b, db, da);
- DeriVector2 poa;//point to align to
- bool by_y_not_by_x = false;//a flag to indicate if the alignment error function is for y (false - x, true - y).
+ DeriVector2 poa;// point to align to
+ bool by_y_not_by_x =
+ false;// a flag to indicate if the alignment error function is for y (false - x, true - y)
- switch(AlignmentType){
+ switch (AlignmentType) {
case HyperbolaPositiveMajorX:
case HyperbolaPositiveMajorY:
poa = c.sum(emaj.multD(a, da));
@@ -1773,59 +1900,58 @@ void ConstraintInternalAlignmentPoint2Hyperbola::errorgrad(double *err, double *
by_y_not_by_x = AlignmentType == HyperbolaNegativeMajorY;
break;
case HyperbolaPositiveMinorX:
- case HyperbolaPositiveMinorY:
- {
+ case HyperbolaPositiveMinorY: {
DeriVector2 pa = c.sum(emaj.multD(a, da));
- //DeriVector2 A(pa.x,pa.y);
- //poa = A.sum(emin.multD(b, db));
+ // DeriVector2 A(pa.x,pa.y);
+ // poa = A.sum(emin.multD(b, db));
poa = pa.sum(emin.multD(b, db));
by_y_not_by_x = AlignmentType == HyperbolaPositiveMinorY;
break;
}
case HyperbolaNegativeMinorX:
- case HyperbolaNegativeMinorY:
- {
+ case HyperbolaNegativeMinorY: {
DeriVector2 pa = c.sum(emaj.multD(a, da));
- //DeriVector2 A(pa.x,pa.y);
- //poa = A.sum(emin.multD(-b, -db));
+ // DeriVector2 A(pa.x,pa.y);
+ // poa = A.sum(emin.multD(-b, -db));
poa = pa.sum(emin.multD(-b, -db));
by_y_not_by_x = AlignmentType == HyperbolaNegativeMinorY;
break;
}
default:
- //shouldn't happen
- poa = pv;//align to the point itself, doing nothing essentially
+ // shouldn't happen
+ poa = pv;// align to the point itself, doing nothing essentially
}
- if(err)
+ if (err)
*err = by_y_not_by_x ? pv.y - poa.y : pv.x - poa.x;
- if(grad)
+ if (grad)
*grad = by_y_not_by_x ? pv.dy - poa.dy : pv.dx - poa.dx;
}
double ConstraintInternalAlignmentPoint2Hyperbola::error()
{
double err;
- errorgrad(&err,nullptr,nullptr);
+ errorgrad(&err, nullptr, nullptr);
return scale * err;
-
}
-double ConstraintInternalAlignmentPoint2Hyperbola::grad(double *param)
+double ConstraintInternalAlignmentPoint2Hyperbola::grad(double* param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
- return deriv*scale;
-
+ return deriv * scale;
}
+
+// --------------------------------------------------------
// ConstraintEqualMajorAxesEllipse
-ConstraintEqualMajorAxesConic:: ConstraintEqualMajorAxesConic(MajorRadiusConic * a1, MajorRadiusConic * a2)
+ConstraintEqualMajorAxesConic::ConstraintEqualMajorAxesConic(MajorRadiusConic* a1,
+ MajorRadiusConic* a2)
{
this->e1 = a1;
this->e1->PushOwnParams(pvec);
@@ -1838,7 +1964,7 @@ ConstraintEqualMajorAxesConic:: ConstraintEqualMajorAxesConic(MajorRadiusConic *
void ConstraintEqualMajorAxesConic::ReconstructGeomPointers()
{
- int i =0;
+ int i = 0;
e1->ReconstructOnNewPvec(pvec, i);
e2->ReconstructOnNewPvec(pvec, i);
pvecChangedFlag = false;
@@ -1870,14 +1996,14 @@ void ConstraintEqualMajorAxesConic::errorgrad(double *err, double *grad, double
double ConstraintEqualMajorAxesConic::error()
{
double err;
- errorgrad(&err,nullptr,nullptr);
+ errorgrad(&err, nullptr, nullptr);
return scale * err;
}
-double ConstraintEqualMajorAxesConic::grad(double *param)
+double ConstraintEqualMajorAxesConic::grad(double* param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
@@ -1887,7 +2013,7 @@ double ConstraintEqualMajorAxesConic::grad(double *param)
}
// ConstraintEqualFocalDistance
-ConstraintEqualFocalDistance:: ConstraintEqualFocalDistance(ArcOfParabola * a1, ArcOfParabola * a2)
+ConstraintEqualFocalDistance::ConstraintEqualFocalDistance(ArcOfParabola* a1, ArcOfParabola* a2)
{
this->e1 = a1;
this->e1->PushOwnParams(pvec);
@@ -1951,10 +2077,10 @@ double ConstraintEqualFocalDistance::error()
return scale * err;
}
-double ConstraintEqualFocalDistance::grad(double *param)
+double ConstraintEqualFocalDistance::grad(double* param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
@@ -1963,6 +2089,8 @@ double ConstraintEqualFocalDistance::grad(double *param)
return deriv * scale;
}
+
+// --------------------------------------------------------
// ConstraintCurveValue
ConstraintCurveValue::ConstraintCurveValue(Point &p, double* pcoord, Curve& crv, double *u)
{
@@ -1984,11 +2112,13 @@ ConstraintCurveValue::~ConstraintCurveValue()
void ConstraintCurveValue::ReconstructGeomPointers()
{
- int i=0;
- p.x=pvec[i]; i++;
- p.y=pvec[i]; i++;
- i++;//we have an inline function for point coordinate
- i++;//we have an inline function for the parameterU
+ int i = 0;
+ p.x = pvec[i];
+ i++;
+ p.y = pvec[i];
+ i++;
+ i++;// we have an inline function for point coordinate
+ i++;// we have an inline function for the parameterU
this->crv->ReconstructOnNewPvec(pvec, i);
pvecChangedFlag = false;
}
@@ -2008,7 +2138,7 @@ void ConstraintCurveValue::errorgrad(double *err, double *grad, double *param)
if (pvecChangedFlag) ReconstructGeomPointers();
double u, du;
- u = *(this->u()); du = ( param == this->u() ) ? 1.0 : 0.0;
+ u = *(this->u()); du = ( param == this->u() ) ? 1.0 : 0.0;
DeriVector2 P_to; //point of curve at parameter value of u, in global coordinates
P_to = this->crv->Value(u,du,param);
@@ -2040,16 +2170,16 @@ double ConstraintCurveValue::error()
return scale * err;
}
-double ConstraintCurveValue::grad(double *param)
+double ConstraintCurveValue::grad(double* param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
- return deriv*scale;
+ return deriv * scale;
}
double ConstraintCurveValue::maxStep(MAP_pD_D &/*dir*/, double lim)
@@ -2066,6 +2196,8 @@ double ConstraintCurveValue::maxStep(MAP_pD_D &/*dir*/, double lim)
return lim;
}
+
+// --------------------------------------------------------
// ConstraintPointOnHyperbola
ConstraintPointOnHyperbola::ConstraintPointOnHyperbola(Point &p, Hyperbola &e)
{
@@ -2126,19 +2258,17 @@ double ConstraintPointOnHyperbola::error()
// show(a)
// DM=sqrt((P-F2)*(P-F2))-sqrt((P-F1)*(P-F1))-2*a
// show(DM.simplify_radical())
- double err=-sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) + sqrt(pow(X_0
- + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 - 2*Y_c, 2)) - 2*sqrt(-pow(b, 2) +
- pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2));
+ double err = -sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ + sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2))
+ - 2 * sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2));
return scale * err;
}
-double ConstraintPointOnHyperbola::grad(double *param)
+double ConstraintPointOnHyperbola::grad(double* param)
{
- double deriv=0.;
- if (param == p1x() || param == p1y() ||
- param == f1x() || param == f1y() ||
- param == cx() || param == cy() ||
- param == rmin()) {
+ double deriv = 0.;
+ if (param == p1x() || param == p1y() || param == f1x() || param == f1y() || param == cx()
+ || param == cy() || param == rmin()) {
double X_0 = *p1x();
double Y_0 = *p1y();
@@ -2149,37 +2279,39 @@ double ConstraintPointOnHyperbola::grad(double *param)
double b = *rmin();
if (param == p1x())
- deriv += -(X_0 - X_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) +
- (X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 -
- 2*Y_c, 2));
+ deriv += -(X_0 - X_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ + (X_0 + X_F1 - 2 * X_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == p1y())
- deriv += -(Y_0 - Y_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) +
- (Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 -
- 2*Y_c, 2));
+ deriv += -(Y_0 - Y_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ + (Y_0 + Y_F1 - 2 * Y_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == f1x())
- deriv += (X_0 - X_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) -
- 2*(X_F1 - X_c)/sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c,
- 2)) + (X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 +
- Y_F1 - 2*Y_c, 2));
+ deriv += (X_0 - X_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ - 2 * (X_F1 - X_c) / sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ + (X_0 + X_F1 - 2 * X_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == f1y())
- deriv +=(Y_0 - Y_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) -
- 2*(Y_F1 - Y_c)/sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c,
- 2)) + (Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 +
- Y_F1 - 2*Y_c, 2));
+ deriv += (Y_0 - Y_F1) / sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2))
+ - 2 * (Y_F1 - Y_c) / sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ + (Y_0 + Y_F1 - 2 * Y_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == cx())
- deriv += 2*(X_F1 - X_c)/sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1
- - Y_c, 2)) - 2*(X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) +
- pow(Y_0 + Y_F1 - 2*Y_c, 2));
+ deriv += 2 * (X_F1 - X_c) / sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ - 2 * (X_0 + X_F1 - 2 * X_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == cy())
- deriv +=2*(Y_F1 - Y_c)/sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1
- - Y_c, 2)) - 2*(Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) +
- pow(Y_0 + Y_F1 - 2*Y_c, 2));
+ deriv += 2 * (Y_F1 - Y_c) / sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))
+ - 2 * (Y_0 + Y_F1 - 2 * Y_c)
+ / sqrt(pow(X_0 + X_F1 - 2 * X_c, 2) + pow(Y_0 + Y_F1 - 2 * Y_c, 2));
if (param == rmin())
- deriv += 2*b/sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c,2));
- }
- return scale * deriv;
+ deriv += 2 * b / sqrt(-pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2));
+ }
+ return scale * deriv;
}
+
+// --------------------------------------------------------
// ConstraintPointOnParabola
ConstraintPointOnParabola::ConstraintPointOnParabola(Point &p, Parabola &e)
{
@@ -2267,20 +2399,22 @@ double ConstraintPointOnParabola::error()
return scale * err;
}
-double ConstraintPointOnParabola::grad(double *param)
+double ConstraintPointOnParabola::grad(double* param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
- return 0.0;
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
+ return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
- return deriv*scale;
+ return deriv * scale;
}
+
+// --------------------------------------------------------
// ConstraintAngleViaPoint
-ConstraintAngleViaPoint::ConstraintAngleViaPoint(Curve &acrv1, Curve &acrv2, Point p, double* angle)
+ConstraintAngleViaPoint::ConstraintAngleViaPoint(Curve& acrv1, Curve& acrv2, Point p, double* angle)
{
pvec.push_back(angle);
pvec.push_back(p.x);
@@ -2290,9 +2424,10 @@ ConstraintAngleViaPoint::ConstraintAngleViaPoint(Curve &acrv1, Curve &acrv2, Poi
crv1 = acrv1.Copy();
crv2 = acrv2.Copy();
origpvec = pvec;
- pvecChangedFlag=true;
+ pvecChangedFlag = true;
rescale();
}
+
ConstraintAngleViaPoint::~ConstraintAngleViaPoint()
{
delete crv1; crv1 = nullptr;
@@ -2322,26 +2457,28 @@ void ConstraintAngleViaPoint::rescale(double coef)
double ConstraintAngleViaPoint::error()
{
- if (pvecChangedFlag) ReconstructGeomPointers();
- double ang=*angle();
+ if (pvecChangedFlag)
+ ReconstructGeomPointers();
+ double ang = *angle();
DeriVector2 n1 = crv1->CalculateNormal(poa);
DeriVector2 n2 = crv2->CalculateNormal(poa);
- //rotate n1 by angle
- DeriVector2 n1r (n1.x*cos(ang) - n1.y*sin(ang), n1.x*sin(ang) + n1.y*cos(ang) );
+ // rotate n1 by angle
+ DeriVector2 n1r(n1.x * cos(ang) - n1.y * sin(ang), n1.x * sin(ang) + n1.y * cos(ang));
- //calculate angle between n1r and n2. Since we have rotated the n1, the angle is the error function.
- //for our atan2, y is a dot product (n2) * (n1r rotated ccw by 90 degrees).
- // x is a dot product (n2) * (n1r)
- double err = atan2(-n2.x*n1r.y+n2.y*n1r.x, n2.x*n1r.x + n2.y*n1r.y);
- //essentially, the function is equivalent to atan2(n2)-(atan2(n1)+angle). The only difference is behavior when normals are zero (the intended result is also zero in this case).
+ // calculate angle between n1r and n2. Since we have rotated the n1, the angle is the error
+ // function. for our atan2, y is a dot product (n2) * (n1r rotated ccw by 90 degrees).
+ // x is a dot product (n2) * (n1r)
+ double err = atan2(-n2.x * n1r.y + n2.y * n1r.x, n2.x * n1r.x + n2.y * n1r.y);
+ // essentially, the function is equivalent to atan2(n2)-(atan2(n1)+angle). The only difference
+ // is behavior when normals are zero (the intended result is also zero in this case).
return scale * err;
}
double ConstraintAngleViaPoint::grad(double *param)
{
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv=0.;
@@ -2351,11 +2488,11 @@ double ConstraintAngleViaPoint::grad(double *param)
if (param == angle()) deriv += -1.0;
DeriVector2 n1 = crv1->CalculateNormal(poa, param);
DeriVector2 n2 = crv2->CalculateNormal(poa, param);
- deriv -= ( (-n1.dx)*n1.y / pow(n1.length(),2) + n1.dy*n1.x / pow(n1.length(),2) );
- deriv += ( (-n2.dx)*n2.y / pow(n2.length(),2) + n2.dy*n2.x / pow(n2.length(),2) );
+ deriv -= ( (-n1.dx) * n1.y / pow(n1.length(), 2) + n1.dy * n1.x / pow(n1.length(), 2) );
+ deriv += ( (-n2.dx) * n2.y / pow(n2.length(), 2) + n2.dy * n2.x / pow(n2.length(), 2) );
-//use numeric for testing
+// use numeric for testing
#if 0
double const eps = 0.00001;
double oldparam = *param;
@@ -2375,9 +2512,11 @@ double ConstraintAngleViaPoint::grad(double *param)
return scale * deriv;
}
-//ConstraintSnell
-ConstraintSnell::ConstraintSnell(Curve &ray1, Curve &ray2, Curve &boundary, Point p, double* n1, double* n2, bool flipn1, bool flipn2)
+// --------------------------------------------------------
+// ConstraintSnell
+ConstraintSnell::ConstraintSnell(Curve& ray1, Curve& ray2, Curve& boundary, Point p, double* n1,
+ double* n2, bool flipn1, bool flipn2)
{
pvec.push_back(n1);
pvec.push_back(n2);
@@ -2390,13 +2529,14 @@ ConstraintSnell::ConstraintSnell(Curve &ray1, Curve &ray2, Curve &boundary, Poin
this->ray2 = ray2.Copy();
this->boundary = boundary.Copy();
origpvec = pvec;
- pvecChangedFlag=true;
+ pvecChangedFlag = true;
this->flipn1 = flipn1;
this->flipn2 = flipn2;
rescale();
}
+
ConstraintSnell::~ConstraintSnell()
{
delete ray1; ray1 = nullptr;
@@ -2406,14 +2546,17 @@ ConstraintSnell::~ConstraintSnell()
void ConstraintSnell::ReconstructGeomPointers()
{
- int cnt=0;
- cnt++; cnt++;//skip n1, n2 - we have an inline function for that
- poa.x = pvec[cnt]; cnt++;
- poa.y = pvec[cnt]; cnt++;
- ray1->ReconstructOnNewPvec(pvec,cnt);
- ray2->ReconstructOnNewPvec(pvec,cnt);
- boundary->ReconstructOnNewPvec(pvec,cnt);
- pvecChangedFlag=false;
+ int cnt = 0;
+ cnt++;
+ cnt++;// skip n1, n2 - we have an inline function for that
+ poa.x = pvec[cnt];
+ cnt++;
+ poa.y = pvec[cnt];
+ cnt++;
+ ray1->ReconstructOnNewPvec(pvec, cnt);
+ ray2->ReconstructOnNewPvec(pvec, cnt);
+ boundary->ReconstructOnNewPvec(pvec, cnt);
+ pvecChangedFlag = false;
}
ConstraintType ConstraintSnell::getTypeId()
@@ -2426,25 +2569,32 @@ void ConstraintSnell::rescale(double coef)
scale = coef * 1.;
}
-//error and gradient combined. Values are returned through pointers.
-void ConstraintSnell::errorgrad(double *err, double *grad, double* param)
+// error and gradient combined. Values are returned through pointers.
+void ConstraintSnell::errorgrad(double* err, double* grad, double* param)
{
- if (pvecChangedFlag) ReconstructGeomPointers();
+ if (pvecChangedFlag)
+ ReconstructGeomPointers();
DeriVector2 tang1 = ray1->CalculateNormal(poa, param).rotate90cw().getNormalized();
DeriVector2 tang2 = ray2->CalculateNormal(poa, param).rotate90cw().getNormalized();
DeriVector2 tangB = boundary->CalculateNormal(poa, param).rotate90cw().getNormalized();
double sin1, dsin1, sin2, dsin2;
- sin1 = tang1.scalarProd(tangB, &dsin1);//sinus of angle of incidence
+ sin1 = tang1.scalarProd(tangB, &dsin1);// sinus of angle of incidence
sin2 = tang2.scalarProd(tangB, &dsin2);
- if (flipn1) {sin1 = -sin1; dsin1 = -dsin1;}
- if (flipn2) {sin2 = -sin2; dsin2 = -dsin2;}
+ if (flipn1) {
+ sin1 = -sin1;
+ dsin1 = -dsin1;
+ }
+ if (flipn2) {
+ sin2 = -sin2;
+ dsin2 = -dsin2;
+ }
double dn1 = (param == n1()) ? 1.0 : 0.0;
double dn2 = (param == n2()) ? 1.0 : 0.0;
if (err)
- *err = *n1()*sin1 - *n2()*sin2;
+ *err = *n1() * sin1 - *n2() * sin2;
if (grad)
- *grad = dn1*sin1 + *n1()*dsin1 - dn2*sin2 - *n2()*dsin2;
+ *grad = dn1 * sin1 + *n1() * dsin1 - dn2 * sin2 - *n2() * dsin2;
}
double ConstraintSnell::error()
@@ -2456,16 +2606,14 @@ double ConstraintSnell::error()
double ConstraintSnell::grad(double *param)
{
-
- //first of all, check that we need to compute anything.
- if ( findParamInPvec(param) == -1 )
+ // first of all, check that we need to compute anything.
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
-
-//use numeric for testing
+// use numeric for testing
#if 0
double const eps = 0.00001;
double oldparam = *param;
@@ -2476,17 +2624,19 @@ double ConstraintSnell::grad(double *param)
double vl = this->error();
*param = oldparam;
//If not nasty, real derivative should be between left one and right one
- double numretl = (v0-vl)/eps;
- double numretr = (vr-v0)/eps;
- assert(deriv <= std::max(numretl,numretr) );
- assert(deriv >= std::min(numretl,numretr) );
+ double numretl = (v0 - vl) / eps;
+ double numretr = (vr - v0) / eps;
+ assert(deriv <= std::max(numretl, numretr));
+ assert(deriv >= std::min(numretl, numretr));
#endif
return scale * deriv;
}
+
+// --------------------------------------------------------
// ConstraintEqualLineLength
-ConstraintEqualLineLength::ConstraintEqualLineLength(Line &l1, Line &l2)
+ConstraintEqualLineLength::ConstraintEqualLineLength(Line& l1, Line& l2)
{
this->l1 = l1;
this->l1.PushOwnParams(pvec);
@@ -2545,23 +2695,23 @@ void ConstraintEqualLineLength::errorgrad(double *err, double *grad, double *par
// So here we maintain the very small derivative of 1e-10 when the gradient is under such value, such
// that the diagnose function with pivot threshold of 1e-13 treats the value as non-zero and correctly
// detects and can tell apart when a parameter is fully constrained or just locked into a maximum/minimum
- if(fabs(*grad) < 1e-10) {
+ if (fabs(*grad) < 1e-10) {
double surrogate = 1e-10;
- if( param == l1.p1.x )
+ if (param == l1.p1.x)
*grad = v1.x > 0 ? surrogate : -surrogate;
- if( param == l1.p1.y )
+ if (param == l1.p1.y)
*grad = v1.y > 0 ? surrogate : -surrogate;
- if( param == l1.p2.x )
+ if (param == l1.p2.x)
*grad = v1.x > 0 ? -surrogate : surrogate;
- if( param == l1.p2.y )
+ if (param == l1.p2.y)
*grad = v1.y > 0 ? -surrogate : surrogate;
- if( param == l2.p1.x )
+ if (param == l2.p1.x)
*grad = v2.x > 0 ? surrogate : -surrogate;
- if( param == l2.p1.y )
+ if (param == l2.p1.y)
*grad = v2.y > 0 ? surrogate : -surrogate;
- if( param == l2.p2.x )
+ if (param == l2.p2.x)
*grad = v2.x > 0 ? -surrogate : surrogate;
- if( param == l2.p2.y )
+ if (param == l2.p2.y)
*grad = v2.y > 0 ? -surrogate : surrogate;
}
}
@@ -2570,23 +2720,25 @@ void ConstraintEqualLineLength::errorgrad(double *err, double *grad, double *par
double ConstraintEqualLineLength::error()
{
double err;
- errorgrad(&err,nullptr,nullptr);
+ errorgrad(&err, nullptr, nullptr);
return scale * err;
}
-double ConstraintEqualLineLength::grad(double *param)
+double ConstraintEqualLineLength::grad(double* param)
{
- if ( findParamInPvec(param) == -1 )
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
- return deriv*scale;
+ return deriv * scale;
}
+
+// --------------------------------------------------------
// ConstraintC2CDistance
-ConstraintC2CDistance::ConstraintC2CDistance(Circle &c1, Circle &c2, double *d)
+ConstraintC2CDistance::ConstraintC2CDistance(Circle& c1, Circle& c2, double* d)
{
this->d = d;
pvec.push_back(d);
@@ -2604,8 +2756,8 @@ ConstraintC2CDistance::ConstraintC2CDistance(Circle &c1, Circle &c2, double *d)
void ConstraintC2CDistance::ReconstructGeomPointers()
{
- int i=0;
- i++; // skip the first parameter as there is the inline function distance for it
+ int i = 0;
+ i++;// skip the first parameter as there is the inline function distance for it
c1.ReconstructOnNewPvec(pvec, i);
c2.ReconstructOnNewPvec(pvec, i);
pvecChangedFlag = false;
@@ -2635,13 +2787,12 @@ void ConstraintC2CDistance::errorgrad(double *err, double *grad, double *param)
// outer case (defined as the centers of the circles are outside the center of the other circles)
// it may well be that the circles intersect.
- if( length_ct12 >= *c1.rad &&
- length_ct12 >= *c2.rad ) {
+ if (length_ct12 >= *c1.rad && length_ct12 >= *c2.rad) {
if (err) {
*err = length_ct12 - (*c2.rad + *c1.rad + *distance());
}
else if (grad) {
- double drad = (param == c2.rad || param == c1.rad || param == distance())?-1.0:0.0;
+ double drad = (param == c2.rad || param == c1.rad || param == distance()) ? -1.0 : 0.0;
*grad = dlength_ct12 + drad;
}
}
@@ -2657,18 +2808,19 @@ void ConstraintC2CDistance::errorgrad(double *err, double *grad, double *param)
else if (grad) {
double drad = 0.0;
- if(param == bigradius) {
+ if (param == bigradius) {
drad = 1.0;
}
- else if(param == smallradius) {
+ else if (param == smallradius) {
drad = -1.0;
}
- else if(param == distance()) {
- drad = (*distance()<0.)?1.0:-1.0;
+ else if (param == distance()) {
+ drad = (*distance() < 0.) ? 1.0 : -1.0;
}
- if (length_ct12>1e-13) {
+ if (length_ct12 > 1e-13) {
*grad = -dlength_ct12 + drad;
- } else { // concentric case
+ }
+ else {// concentric case
*grad = drad;
}
}
@@ -2684,13 +2836,13 @@ double ConstraintC2CDistance::error()
double ConstraintC2CDistance::grad(double *param)
{
- if ( findParamInPvec(param) == -1 )
+ if (findParamInPvec(param) == -1)
return 0.0;
double deriv;
errorgrad(nullptr, &deriv, param);
- return deriv*scale;
+ return deriv * scale;
}
} //namespace GCS