This is done because a meaningful union extrusion is almost never
a meaningful difference extrusion, and saves a bunch of common
manual work.
To avoid creating invalid sketches this isn't done when there are any
constraints.
The immediate reason for refactoring this was that the GTK port broke
after 52af7256 since config.h is not included anymore, but it was
a fragile piece of code I will shed no tears for.
While we're at it, get rid of the mutable std::string &file to be
consistent with our conventions.
A new button is added, "Show/hide outline of solid model".
When the outline is hidden, it is rendered using the "solid edge"
style. When the outline is shown, it is rendered using the "outline"
style.
In SolveSpace's true WYSIWYG tradition, the 2d view export follows
the rendered view exactly.
Moreover, shell edges are not rendered anymore, since there is not
much need in them anymore and not drawing them lessens the overlap
between various kinds of lines, which already includes entities,
solid edges and outlines.
In my (whitequark's) experience this warning tends to expose
copy-paste errors with a high SNR, so making a few fragments
slightly less symmetric is worth it.
Also mollify -Wlogical-op-parentheses while we're at it.
This setting is generally useful, but it especially shines when
assembling, since the "same orientation" and "parallel" constraints
remove three and two rotational degrees of freedom, which makes them
impossible to use with 3d "point on line" constraint that removes
two spatial and two rotational degrees of freedom.
The setting is not enabled for all imported groups by default
because it exhibits some edge case failures. For example:
* draw two line segments sharing a point,
* constrain lengths of line segments,
* constrain line segments perpendicular,
* constrain line segments to a 90° angle.
This is a truly degenerate case and so it is not considered very
important. However, we can fix this later by using Eigen::SparseQR.
This removes the arbitrary 64 byte restriction (which effectively
limits us to as little as 16 Unicode characters with CJK encodings),
makes classes smaller, and is easier to use.
As a consequence of making the length of all ex-NameStr fields
unbounded, all functions that returned a buffer derived from those
were changed to return std::string. Then, functions that are
contextually similar to the ones described above were changed
to return std::string. Then, functions that now happened to mostly
take an std::string argument converted to a C string were changed
to accept std::string.
This has produced a bit of churn, but is probably for the better.
Now it is possible to give non-ASCII names to groups
as well as see non-ASCII filenames of imported files.
In the future this makes localization possible.
This works for LTR languages, such as European and CJK,
but not RTL such as Arabic. Does Arabic even exist in
monospaced form? I have no idea.
After this commit, SolveSpace deals with paths as follows:
* Paths are generally treated as opaque platform-specific strings.
This helps on Linux, because paths on Linux don't have any
specific encoding and it helps to avoid any operations on them.
* The UI in some places wants to get a basename. In this case,
the newly introduced PATH_SEP is used. This allows to treat
backslash as a regular character, which it is on Linux and OS X.
* The only place where any nontrivial operations on paths are
performed is the g->impFile/impFileRel logic.
Specifically, when saved, g->impFile always contains an absolute
path with separators of the current platform, and g->impFileRel
always contains a relative path with UNIX separators. This allows
to treat backslash as a regular character.
Old files will contain g->impFileRel with Windows separators;
these are detected by looking for a drive letter in g->impFile
and in that case mapping Windows separators to UNIX ones.
There is no need to treat UNIX separators (forward slashes) in
any special way on Windows because there is no way on Windows,
not even via UNC paths, to create or address a directory entry
with a forward slash in its name.
What do we gain from this? Several things.
* First, usage of PATH_MAX (the POSIX constant) is eliminated.
PATH_MAX is actually a lie; Linux and OS X (and probably other BSDs
too) do not have an actual path length limit. Linux claims 4096,
OS X claims 1024, but it is trivial to construct paths that are
longer.
* Second, while Windows does enforce a limit of MAX_PATH (the Win32
constant) for its ASCII functions, the Unicode variants, when
used with UNC paths, do not have this restriction.
The capability to use UNC paths is useful by itself, as it allows
to access files on network shares directly.
* Third, representing paths as std::string will make it easier to
interoperate with *W WinAPI functions later.
This will allow us to use non-POD classes inside these objects
in future and is otherwise functionally equivalent, as well
as more concise.
Note that there are some subtleties with handling of
brace-initialization. Specifically:
On aggregates (e.g. simple C-style structures) using an empty
brace-initializer zero-initializes the aggregate, i.e. it makes
all members zero.
On non-aggregates an empty brace-initializer calls the default
constructor. And if the constructor doesn't explicitly initialize
the members (which the auto-generated constructor doesn't) then
the members will be constructed but otherwise uninitialized.
So, what is an aggregate class? To quote the C++ standard
(C++03 8.5.1 §1):
An aggregate is an array or a class (clause 9) with no
user-declared constructors (12.1), no private or protected
non-static data members (clause 11), no base classes (clause 10),
and no virtual functions (10.3).
In SolveSpace, we only have to handle the case of base classes;
Constraint and Entity have those. Thus, they had to gain a default
constructor that does nothing but initializes the members to zero.
The main benefit is that std::swap will ensure that the type
of arguments is copy-constructible and move-constructible.
It is more concise as well.
When min and max are defined as macros, they will conflict
with STL header files included by other C++ libraries;
in this case STL will #undef any other definition.
In principle, GTK3 is the way forward, and GTK2 is officially
deprecated, though still maintained. In practice however, GTK3
is often unbearably buggy; e.g. on my system, combo boxes
don't ever roll up in GTK3 windows. So I have added support
for both.
This required a few minor changes to the core, namely:
* GTK wants to know beforehand whether a menu item is a check
menu item or a regular one.
* GTK doesn't give us an easy way to execute something after
any event is processed, so an explicit idle timer is added.
This is a no-op on Win32.
* A few function signatures were const'ed, since GTK expects
immutable strings when converting to Glib::ustring.
Microsoft defines an RGB() macro that at one point was compatible with our
version (returning a packed integer containing 8-bit red, green and blue
channels), but is no longer, and the incompatibility led to an awkward
situation in w32main.cpp where we had to restore Microsoft's form of the
macro in order for the commctrl.h header to compile. By renaming the macro
to RGBi()---analogous to the RGBf() macro we already define---we avoid the
hassle entirely.
The SolveSpace top-level directory was getting a bit cluttered, so
following the example of numerous other free-software projects, we move the
main application source into a subdirectory and adjust the build systems
accordingly.
Also, got rid of the obj/ directory in favor of creating it on the fly in
Makefile.msvc.