This includes explanation and context for non-obvious cases and
shortens debug cycles when just-in-time debugging is not available
(like on Linux) by immediately printing description of the assert
as well as symbolized backtrace.
This helps to ensure that a base class that changes underneath us
would not leave any overridden functions hanging.
This already highlighted some questionable use of GTKMM's API,
which were also fixed in this commit.
This commit integrates the bitmap font in the resource system, so
that cross-compilation would be easier.
The font handling code was carefully written to do glyph parsing
lazily; in practice this means that after this commit, startup
is less than 25ms slower, most of it spent in inflate().
This should also result in faster rendering, since there is no
rampant plane switching anymore; instead, all characters that are
actually used are stashed into same one texture.
This commit integrates icons in the resource system so that they
can be loaded (or reloaded, without restarting) in @2x mode, which
will be added in a future commit. png2c is no longer necessary.
png2c used to perform the following transformation:
if(r + g + b < 11) r = g = b = 11;
This is now achieved by switching the icons to RGBA mode and adding
alpha channel with the following imagemagick invocation, which is
equivalent to the transformation above:
for i in *.png; do
convert -fuzz 4% -channel rgba -matte \
-fill "rgba(255,255,255,0)" -opaque black \
$i $i
done
The Debian package solvespace now includes /usr/share/solvespace;
this should be split out into solvespace-data later.
Currently, icons, fonts, etc are converted to C structures at compile
time and are hardcoded to the binary. This presents several problems:
* Cross-compilation is complicated. Right now, it is necessary
to be able to run executables for the target platform; this
happens to work with wine-binfmt installed, but is rather ugly.
* Icons can only have one resolution. On OS X, modern software is
expected to take advantage of high-DPI ("Retina") screens and
use so-called @2x assets when ran in high-DPI mode.
* Localization is complicated. Win32 and OS X provide built-in
support for loading the resource appropriate for the user's
locale.
* Embedding strings can only be done as raw strings, using C++'s
R"(...)" literals. This precludes embedding sizable strings,
e.g. JavaScript libraries as used in Three.js export, and makes
git history less useful. Not embedding the libraries means we
have to rely on external CDNs, which requires an Internet
connection and adds a glaring point of failure.
* Linux distribution guidelines are violated. All architecture-
independent data, especially large data such as fonts, is
expected to be in /usr/share, not in the binary.
* Customization is impossible without recompilation. Minor
modifications like adding a few missing vector font characters
or adjusting localization require a complete development
environment, which is unreasonable to expect from users of
a mechanical CAD.
As such, this commit adds a resource system that bundles (and
sometimes builds) resources with the executable. Where they go is
platform-dependent:
* on Win32: into resources of the executable, which allows us to
keep distributing one file;
* on OS X: into the app bundle;
* on other *nix: into /usr/share/solvespace/ or ../res/ (relative
to the executable path), the latter allowing us to run freshly
built executables without installation.
It also subsides the platform-specific resources that are in src/.
The resource system is not yet used for anything; this will be added
in later commits.
This is good practice and helps to catch bugs. Several changes
were made to accomodate the newly enabled warnings:
* -Wunused-function:
* in exposed/, static functions that were supposed to be inlined
were explicitly marked as inline;
* some actually unused functions were removed;
* -Wsign-compare: explicit conversions were added, and in
the future we should find a nicer way than aux* fields;
* -Wmissing-field-initializers: added initializers;
* -Wreorder: reordered properly;
* -Wunused-but-set-variable: remove variable.
-Wunused-parameter was turned off as enabling it would result in
massive amount of churn in UI code. Despite that, we should enable
it at some point as it has a fairly high SNR otherwise.
Before this commit, when exporting a vector file without the shaded
model shown, or similarly when using formats that we do not export
the mesh to, we still generate (and then discard) the mesh in paint
order. This is a waste of time.
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.
config.h now includes the git hash and so, as long as it's included
in solvespace.h, any change of git HEAD will trigger a complete
recompilation, which makes bisecting especially annoying.
While we're at it, remove HAVE_STDINT_H from it, since we require
C++11 and all MSVC versions that include C++11 also include stdint.h.
Before this commit, the graphics window edit control always had
a width of 30 average character widths.
After this commit, the edit control has a width of 5 average
character widths (for numeric constraints) or 30 average character
widths (for comment constraints), or just enough to display
the entire value being edited, whichever is greater.
This makes the edit control overlap the sketch less in case of
editing numeric constraints (since in most cases, the numbers being
edited are short), and removes annoying scrolling in case of editing
long comments.
Before this commit, the position of the edit box was adjusted
by trial and error, as far as I can tell. This commit changes
the positioning machinery for edit controls as follows:
The coordinates passed to ShowTextEditControl/ShowGraphicsEditControl
now denote: X the left bound, and Y the baseline.
The font height passed to ShowGraphicsEditControl denotes
the absolute font height in pixels, i.e. ascent plus descent.
Platform-dependent code uses these coordinates, the font metrics
for the font appropriate for the platform, and the knowledge of
the decorations drawn around the text by the native edit control
to position the edit control in a way that overlays the text inside
the edit control with the rendered text.
On OS X, GNU Unifont (of height 16) has metrics identical to
Monaco (of height 15) and so as an exception, the edit control
is nudged slightly for a pixel-perfect fit.
Also, since the built-in vector font is proportional, this commit
also switches the edit control font to proportional when editing
constraints.
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.
Before this change, the two buttons "Show/hide shaded model" (S) and
"Show/hide hidden lines" (H) resulted in drawing the following
elements in the following styles:
Button | Non-occluded | Non-occluded | Occluded | Occluded
state | solid edges | entities | solid edges | entities
--------+--------------+--------------+-------------+--------------
!S !H | | | solid-edge | entity style
--------+ | +-------------+--------------
S !H | | | invisible
--------+ solid-edge | entity style +-------------+--------------
!S H | | | |
--------+ | | solid-edge | entity style
S H | | | |
--------+--------------+--------------+-------------+--------------
After this change, they are drawn as follows:
Button | Non-occluded | Non-occluded | Occluded | Occluded
state | solid edges | entities | solid edges | entities
--------+--------------+--------------+-------------+--------------
!S !H | | | solid-edge | entity style
--------+ | +-------------+--------------
S !H | | | invisible
--------+ solid-edge | entity style +-------------+--------------
!S H | | | |
--------+ | | hidden-edge | stippled¹
S H | | | |
--------+--------------+--------------+-------------+--------------
¹ entity style, but the stipple parameters taken from hidden-edge
In SolveSpace's true WYSIWYG tradition, the 2d view export follows
the rendered view exactly.
Also, it is now possible to edit the stipple parameters of built-in
styles, so that by changing the hidden-edge style to non-stippled
it is possible to regain the old behavior.
Before this commit, trying to export image on *nix platforms yielded
a black rectangle, since since there is nowhere to render to
when we're not in a GUI toolkit draw callback.
On Windows, nothing changes: we do a repaint without the toolbar,
glReadPixels, export. On *nix, we create another offscreen rendering
context, render into it, then destroy it. As a bonus this avoids
some minor flickering that would happen if we reused the regular
rendering path.
Most of these were just converting char* into std::string back and
forth; some more used ReadUTF8, which was converted to use nicer
STL-style iterators over UTF-8 text.
The remaining ones are:
* arguments to Expr::From, which we'll change when refactoring
the expression lexer;
* arguments to varargs functions, which we'll change when adding
localization (that requires custom printf-style functions to
allow for changing argument order);
* arguments where only string literals are ever passed, which
are OK;
* in platform-specific code, which is OK.
After commit 2f734d9, inactive groups are no longer regenerated
for trivial changes, e.g. changing parameters, so it's possible to
switch to an earlier group and work on it without incurring
the computational (slowdown) and cognitive (annoyance by red
background) overhead of later groups failing to solve.
However, if a group--any group anywhere--was not solved OK,
the interface reacted accordingly, which diminished usefulness of
the change, especially given that, if we have groups A and B with
B depending on A, if B is broken by a change in A and we activate A
and fix it, B will not be regenerated.
After this commit, only active groups are considered when deciding
if generating the entire sketch would fail.
This font is less complete than our bitmap font, Unifont: Unifont
has essentially complete Unicode coverage and LibreCAD's font only
has Latin, Cyrillic and Japanese, but it can be extended rather
easily, so this should be fine for now.
These embedded fonts fatten glhelper.o quite a bit:
bitmapfont.table.h is about 8M in gzip-compressed bitmaps and
vectorfont.table.h is about 2M in raw vector data.
In spite of that it takes just around five seconds to build
glhelper.c on my laptop, so it should be fine.
The final executable grows from about 2M to about 8M, but this
is a small price to pay for fairly extensive i18n support.
The new font has somewhat different metrics, so the rendering
code has been fudged to make it look good.
Benefits:
* Much simpler code.
* Handles the entire TTF spec, not just a small subset that
only really worked well on Windows fonts.
* Handles all character sets as well as accented characters.
* Much faster parsing, since Freetype lazily loads and
caches glyphs.
* Support for basically every kind of font that was invented,
not just TTF.
Note that OpenType features, e.g. ligatures, are not yet supported.
This means that Arabic and Devanagari scripts, among others, will
not be rendered in their proper form.
RTL scripts are not supported either, neither in TTF nor in
the text window. Adding RTL support is comparatively easy, but
given that Arabic would not be legibly rendered anyway, this is not
done so far.
Commit 89eb208 has improved the overall situation with chord
tolerance, but it changed the display chord tolerance to use
an absolute value in millimeters as a stopgap measure.
This commit changes the display chord tolerance to be specified
in percents of entity bounding box instead of millimeters.
As a result, the linearized curves are both zoom level and sketch
scale independent.
In order to compute the bounding box, all entities are generated
twice. However, this shouldn't result in a noticeable slowdown,
since the bounding box calculation does not need the expensive
triangle mesh generation and the solver will converge immediately
on the second run.
Since the meaning of the preference has changed, a new name is
used (ChordTolerancePct instead of ChordTolerance), so that it
would be reset to the default value after updating SolveSpace.
The default value, 0.5%, was selected using trial and error by
judging whether cylinders of moderate dimensions were looking
aesthetically pleasing enough.
After this change, the only real function of the spacebar
shortcut is to reload imported groups, since manual regeneration
should not change anything anymore unless there is a bug.
Before this commit, a single chord tolerance was used for both
displaying and exporting geometry. Moreover, this chord tolerance
was specified in screen pixels, and as such depended on zoom level.
This was inconvenient: exporting geometry with a required level of
precision required awkward manipulations of viewport. Moreover,
since some operations, e.g. mesh watertightness checking, were done
on triangle meshes which are generated differently depending on
the zoom level, these operations could report wildly different
and quite confusing results depending on zoom level.
The chord tolerance for display and export pursue completely distinct
goals: display chord tolerance should be set high enough to achieve
both fast regeneration and legible rendering, whereas export chord
tolerance should be set to match the dimension tolerance of
the fabrication process.
This commit introduces two distinct chord tolerances: a display
and an export one. Both chord tolerances are absolute and expressed
in millimeters; this is inappropriate for display purposes but
will be fixed in the next commits.
After exporting, the geometry is redrawn with the chord tolerance
configured for the export and an overlay message is displayed;
pressing Esc clears the message and returns the display back to
normal.
When a solver error arises after a change to the sketch, it should
be easy to understand exactly why it happened. Before this change,
two functionally distinct modes of failure were lumped into one:
the same "redundant constraints" message was displayed when all
degrees of freedom were exhausted and the had a solution, but also
when it had not.
To understand why this is problematic, let's examine several ways
in which we can end up with linearly dependent equations in our
system:
0) create a triangle, then constrain two different pairs of edges
to be perpendicular
1) add two distinct distance constraints on the same segment
2) add two identical distance constraints on the same segment
3) create a triangle, then constrain edges to lengths a, b, and c
so that a+b=c
The case (0) is our baseline case: the constraints in it make
the system unsolvable yet they do not remove more degrees of freedom
than the amount we started with. So the displayed error is
"unsolvable constraints".
The constraints in case (1) remove one too many degrees of freedom,
but otherwise are quite like the case (0): the cause of failure that
is useful to the user is that the constraints are mutually
incompatible.
The constraints in cases (2) and (3) however are not like the others:
there is a set of parameters that satisfies all of the constraints,
but the constraints still remove one degree of freedom too many.
It makes sense to display a different error message for cases (2)
and (3) because in practice, cases like this are likely to arise from
adjustment of constraint values on sketches corresponding to systems
that have a small amount of degenerate solutions, and this is very
different from systems arising in cases like (0) where no adjustment
of constraint values will ever result in a successful solution.
So the error message displayed is "redundant constraints".
At last, this commit makes cases (0) and (1) display a message
with only a minor difference in wording. This is deliberate.
The reason is that the facts "the system is unsolvable" and
"the system is unsolvable and also has linearly dependent equations"
present no meaningful, actionable difference to the user, and placing
emphasis on it would only cause confusion.
However, they are still distinguished, because in case (0) we
list all relevant constraints (and thus we say they are "mutually
incompatible") but in case (1) we only list the ones that constrain
the sketch further than some valid solution (and we say they are
"unsatisfied").
The current messages accurately reflect what happens to the system
of equations that represents the sketch, but can be quite confusing
to users that only think in terms of the constraints.
We use "unsolvable" and not "impossible" because while most of
the cases that result in this error message will indeed stem from
mutually exclusive sets of constraints, it is still possible that
there is some solution that our solver is unable to find using
numeric methods.
Most people just want a single self-contained .html file, but more
advanced usage will involve embedding in a webpage, where the default
viewer would be copied and customized, and fed with bare mesh export.