Commit Graph

162 Commits

Author SHA1 Message Date
whitequark
c12672be66 Internationalize platform-specific code. 2017-01-11 03:02:04 +00:00
whitequark
529e1bfd63 Internationalize the main menu. 2017-01-05 12:17:09 +00:00
whitequark
6bb73a162c GTK: remove GlWidget, use standard Gtk::GLArea.
This removes a large number of hacks from the codebase, speeds up
the rendering, and removes tearing when dragging entities.
2017-01-02 16:21:05 +00:00
Evil-Spirit
d99a133982 Do ScheduleGenerateAll in MarkGroupDirty.
This generally simplifies code, and also fixes a bug where adding
a datum point would not regenerate the sketch.
2016-12-26 07:58:00 +00:00
EvilSpirit
9148d0cb91 Force DOF check every time a constraint is added.
Before this commit, it was possible to add some redundant constraints
(e.g. vertical, horizontal or midpoint) without failing the sketch,
because SolveBySubstitution() removed the redundant equations.
However, this could result in the solve failing later because
the system didn't converge, without any pointers as to the true
cause of the failure.
2016-12-21 19:40:33 +00:00
whitequark
4a0b4fd8d3 Win32: unbreak solvespace-cli.
It was broken because of three bugs:
  * Uninitialized variables in RunCommand;
  * Trying to use (OEM-encoded) main() argc/argv arguments instead
    of GetCommandLineW();
  * Trying to pass relative paths directly into ssfopen.
2016-12-05 01:24:17 +00:00
whitequark
47244c5e89 Implement a command-line interface.
This commit adds a basic command-line interface. This interface
allows rendering thumbnails and exporting data in batch mode.
2016-11-29 04:01:07 +00:00
EvilSpirit
dbc567ed89 Reload linked files before upgrading legacy data.
Before this commit, if constraints with newly introduced params were
loaded from a file that linked other files, the upgrade code would
attempt to look up a non-existent entity.
2016-11-28 16:58:31 +00:00
whitequark
9301dec98d Use the same code for loading resources in all executables.
All of our executables need resources; e.g. the vector font is
a resource and it is necessary for generation. Before this commit,
the GUI executable loaded the resources in a nice way, and everything
else did it in a very ad-hoc, fragile way.

After this commit, all executables are placed in <build>/bin and
follow the same algorithm:
  * On Windows, resources are compiled and linked into every
    executable.
  * On Linux, resources are copied into <build>/res (which is
    tried first) and <prefix>/share/solvespace (which is tried
    second).
  * On macOS, resources are copied into <build>/res (which is
    tried first) and <build>/bin/solvespace.app/Contents/Resources
    (which is tried second).

In practice this means that we can add as many executables as we want
without duplicating lots of code. In addition, on macOS, we can
place supplementary executables into the bundle, and they can use
resources from the bundle transparently.
2016-11-28 06:18:42 +00:00
EvilSpirit
6d2c2aecff Implement an OpenGL 2 renderer.
There are two main reasons to desire an OpenGL 2 renderer:
 1. Compatibility. The compatibility profile, ironically, does not
    offer a lot of compatibility, and our OpenGL 1 renderer will not
    run on Android, iOS, or WebGL.
 2. Performance. The immediate mode does not scale, and in fact
    becomes very slow with only a moderate amount of lines on screen,
    and only a somewhat large amount of triangles.

This commit implements a basic OpenGL 2 renderer that uses only
features from the (OpenGL 3.2) core profile. It is not yet faster
than the OpenGL 1 renderer, primarily because it uses a lot of small
draw calls.

This commit uses OpenGL 2 on Linux and Mac OS X directly (i.e. links
to the GL symbols from version 2+); on Windows this is impossible
with the default drivers, so for now OpenGL 1 is still used there.
2016-11-18 04:04:29 +00:00
whitequark
802d092b13 When exporting files, initially fill in the basename of the sketch.
This is a common and convenient behavior; the basename is
pre-selected, so exporting multiple views requires just one keystroke
to put the cursor after the basename.
2016-11-17 12:54:02 +00:00
Evil-Spirit
fdd08cbead Warn if exporting a non-watertight mesh.
If a generated mesh is non-watertight, and this is not noticed for
some reason (e.g. the markers are dismissed), and the mesh is
exported for further processing, it could cause problems down
the line.
2016-11-17 00:53:28 +00:00
whitequark
74cb1f589c Add two more points to the TTF text request.
These points can be used for constraining the width of the text
(or to the width of the text).

The main parts of the commit are:
  * TtfFont is restructured to be able to return the aspect ratio
    for a given string.
  * This aspect ratio is written to the savefile, such that even if
    the font is missing, the sketch would still be solved correctly.
  * The two additional points are constrained via perpendicularly
    to the two main points (which form a v vector).

The compatibility features are as follows:
  * When the font is missing in old files, 1:1 aspect ratio is used,
    which works for the replacement symbol anyhow.
  * When the two additional points are missing in old files, their
    would-be positions are calculated and they are moved there,
    avoiding 'jumping' of underconstrained sketches.
2016-11-02 09:22:18 +00:00
EvilSpirit
3a585ea7c2 Try to re-solve groups that fail rank test.
Sometimes, after a large change in a sketch, constraints that are
geometrically fine may still cause the rank test to fail. One way
this can happen is VectorsParallel() pivoting wrong due to the big
move, converging anyways but ending up singular. It would then
re-pivot correctly on the new solution when you re-solve, making
this a transient error. This is visible when dragging the arm in
the jansen-asm.slvs example.

After this commit, if the rank test fails, equations are regenerated
the Jacobian is rewritten, and the rank test is retried, which
prevents these transient errors from interfering with dragging.

The problem described above was invisible before c011444, as rank
test was only performed before solving.
2016-10-14 00:27:38 +00:00
EvilSpirit
f4e85127d6 Wavefront OBJ: export mesh color as well. 2016-10-11 14:54:19 +00:00
whitequark
d12bf047b4 Update 58db06d8 to not even try to use std::fstream with Unicode paths.
Unfortunately there is no portable way to open an Unicode path with
std::fstream. On *nix, it is enough to call the const char*
constructor. On MSVC, it is enough to call a nonstandard
const wchar_t* constructor. However, on MinGW, there is no way at all
to construct an std::fstream with a wide path, not even using
undocumented APIs. (There used to be a const wchar_t* overload added
back in libstdc++ 4.7, but it got removed for a reason that I was not
able to find out.)
2016-10-09 20:00:02 +00:00
whitequark
58db06d845 DXF: update to use Unicode-aware file open routines on Windows. 2016-10-09 15:19:36 +00:00
whitequark
8e7d2eaa84 Implement "view → set to full scale" text window command. 2016-08-01 14:03:16 +00:00
whitequark
2fdbabc13c Add statement/condition coverage measurement for the test suite.
We're using gcov+lcov, since these tools appear to be the only
usable ones that use the SC/CC metric; and measuring just the line
coverage would be practically criminal negligence.

gcov only works with GCC and Clang, and MSVC's own coverage
measurement tools are not up to the task; so MSVC is out of luck.
2016-08-01 02:19:06 +00:00
whitequark
5e63d8301e Add a simple harness for automated, headless testing.
This commit alters the build system substantially; it adds another
platform, `headless`, that provides stubs in place of all GUI
functions, and provides a library `solvespace_headless` alongside
the main executable. To cut down build times, only the few files
that have #if defined(HEADLESS) are built twice for the executable
and the library; the rest is grouped into a new `solvespace_cad`
library. It is not usable on its own and just serves for grouping.

This commit also gates the tests behind a -DENABLE_TESTS=ON CMake
option, ON by default (but suggested as OFF in the README so that
people don't ever have to install cairo to build the executable.)

The tests introduced in this commit are (so far) rudimentary,
although functional, and they serve as a stepping point towards
introducing coverage analysis.
2016-08-01 00:48:37 +00:00
whitequark
977a0b8e6d Replace the last use of exceptions (in Expr) with setjmp/longjmp.
Without -fno-exceptions, the branch coverage information is
practically useless, as every call becomes a branch.

The functionality of Expr is retained as-is, although SjLj error
handling is a maintenance nightmare. However, the entire parser
probably should be eventually replaced, so for now it is not
a great concern.
2016-08-01 00:48:37 +00:00
whitequark
65e2cccde0 Add a Cairo rendering backend.
This backend will be used for reproducible offscreen rendering
in integration tests.
2016-08-01 00:48:37 +00:00
whitequark
8960ee365a Add a new renderer that prepares geometry for 2d backends.
SurfaceRenderer is a new renderer implementing the Canvas interface
running entirely on the CPU; it projects strokes and triangles
in the exact same way as OpenGL would, and it can be used for
rendering into raster or vector 2d surfaces.
2016-08-01 00:48:37 +00:00
EvilSpirit
7f411d1593 Unify displayEdges and displayOutlines.
This has the following benefits:
  * Less geometry to generate; we can do both in one pass;
  * Less geometry to draw;
  * Eliminate overdraw of outlines on top of emphasized edges;
  * In future, being able to seamlessly stitch stippled lines.

The contour edges are now also drawn before emphasized edges;
this makes intersections of contour and emphasized edges look better
as the thinner emphasized edge doesn't clobber the depth buffer.
2016-07-23 22:41:16 +00:00
whitequark
e7c8c1c8f2 Abstract all (ex-OpenGL) drawing operations into a Canvas interface.
This has several desirable consequences:
  * It is now possible to port SolveSpace to a later version of
    OpenGL, such as OpenGLES 2, so that it runs on platforms that
    only have that OpenGL version;
  * The majority of geometry is now rendered without references to
    the camera in C++ code, so a renderer can now submit it to
    the video card once and re-rasterize with a different projection
    matrix every time the projection is changed, avoiding expensive
    reuploads;
  * The DOGD (draw or get distance) interface is now
    a straightforward Canvas implementation;
  * There are no more direct references to SS.GW.(projection)
    in sketch rendering code, which allows rendering to multiple
    viewports;
  * There are no more unnecessary framebuffer flips on CPU on Cocoa
    and GTK;
  * The platform-dependent GL code is now confined to rendergl1.cpp.
  * The Microsoft and Apple headers required by it that are prone to
    identifier conflicts are no longer included globally;
  * The rendergl1.cpp implementation can now be omitted from
    compilation to run SolveSpace headless or with a different
    OpenGL version.

Note these implementation details of Canvas:
  * GetCamera currently always returns a reference to the field
    `Camera camera;`. This is so that a future renderer that caches
    geometry in the video memory can define it as asserting, which
    would provide assurance against code that could accidentally
    put something projection-dependent in the cache;
  * Line and triangle rendering is specified through a level of
    indirection, hStroke and hFill. This is so that a future renderer
    that batches geometry could cheaply group identical styles.
  * DrawPixmap and DrawVectorText accept a (o,u,v) and not a matrix.
    This is so that a future renderer into an output format that
    uses 2d transforms (e.g. SVG) could easily derive those.

Some additional internal changes were required to enable this:
  * Pixmap is now always passed as std::shared_ptr<{const ,}Pixmap>.
    This is so that the renderer could cache uploaded textures
    between API calls, which requires it to capture a (weak)
    reference.
  * The PlatformPathEqual function was properly extracted into
    platform-specific code. This is so that the <windows.h> header
    could be included only where needed (in platform/w32* as well
    as rendergl1.cpp).
  * The SBsp{2,3}::DebugDraw functions were removed. They can be
    rewritten using the Canvas API if they are ever needed.

While no visual changes were originally intended, some minor fixes
happened anyway:
  * The "emphasis" yellow line from top-left corner is now correctly
    rendered much wider.
  * The marquee rectangle is now pixel grid aligned.
  * The hidden entities now do not clobber the depth buffer, removing
    some minor artifacts.
  * The workplane "tab" now scales with the font used to render
    the workplane name.
  * The workplane name font is now taken from the normals style.
  * Workplane and constraint line stipple is insignificantly
    different. This is so that it can reuse the existing stipple
    codepaths; rendering of workplanes and constraints predates
    those.

Some debug functionality was added:
  * In graphics window, an fps counter that becomes red when
    rendering under 60fps is drawn.
2016-07-23 22:31:18 +00:00
whitequark
b0d37c1e78 Replace platform-specific GetMilliseconds using std::chrono. 2016-07-21 06:07:46 +00:00
EvilSpirit
5791310bb1 Annotate constants passed as boolean function arguments.
This is to ensure that:
  * it is clear, when looking at the point of usage, what is
    the purpose of "true" or "false";
  * when refactoring, a simple search will bring up any places that
    need to be changed.

Also, argument names were synchronized between declaration and
implementation.

As an exception, these are not annotated:
  * Printf(/*halfLine=*/), to avoid pointless churn.
2016-05-26 12:43:52 +00:00
EvilSpirit
f33ddc94fb Convert all enumerations to use enum class.
Specifically, take the old code that looks like this:

  class Foo {
    enum { X = 1, Y = 2 };
    int kind;
  }
  ... foo.kind = Foo::X; ...

and convert it to this:

  class Foo {
    enum class Kind : uint32_t { X = 1, Y = 2 };
    Kind kind;
  }
  ... foo.kind = Foo::Kind::X;

(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)

The benefits are as follows:
  * The type of the field gives a clear indication of intent, both
    to humans and tools (such as binding generators).
  * The compiler is able to automatically warn when a switch is not
    exhaustive; but this is currently suppressed by the
      default: ssassert(false, ...)
    idiom.
  * Integers and plain enums are weakly type checked: they implicitly
    convert into each other. This can hide bugs where type conversion
    is performed but not intended. Enum classes are strongly type
    checked.
  * Plain enums pollute parent namespaces; enum classes do not.
    Almost every defined enum we have already has a kind of ad-hoc
    namespacing via `NAMESPACE_`, which is now explicit.
  * Plain enums do not have a well-defined ABI size, which is
    important for bindings. Enum classes can have it, if specified.
    We specify the base type for all enums as uint32_t, which is
    a safe choice and allows us to not change the numeric values
    of any variants.

This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-25 07:17:14 +00:00
whitequark
7bda30aca4 Refactor SS.bgImage to use Pixmap. 2016-05-25 03:22:54 +00:00
whitequark
20d87d93c5 Add const qualifiers to functions where trivially possible.
This will allow us in future to accept `const T &` anywhere it's
necessary to reduce the amount of copying.

This commit is quite conservative: it does not attempt very hard to
refactor code that performs incidental mutation. In particular
dogd and caches are not marked with the `mutable` keyword.
dogd will be eliminated later, opening up more opportunities to
add const qualifiers.

This commit also doesn't introduce any uses of the newly added const
qualifers. This will be done later.
2016-05-25 03:22:54 +00:00
EvilSpirit
bbca4cc224 Rewrite declarations of form f(void) as f().
In C++ there is no difference and newly added functions are all
declared as f(), so this brings back consistency.
2016-05-20 12:43:20 +00:00
whitequark
ad4a204edf Replace all oops() checks with ssassert()s.
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.
2016-05-20 12:38:30 +00:00
whitequark
4415f5bb91 Implement ssassert(), a replacement for oops(). 2016-05-20 12:38:29 +00:00
whitequark
1b52c46b81 Remove some dead code. 2016-05-18 23:00:34 +00:00
whitequark
ab418b827e Use the override C++ keyword everywhere.
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.
2016-05-18 18:42:33 +00:00
whitequark
645c2d90ac Move bitmap font to res/fonts/; remove unifont2c.
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.
2016-05-18 11:24:24 +00:00
whitequark
a525f03371 Move icons to res/icons/; remove png2c.
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.
2016-05-18 11:24:24 +00:00
whitequark
f4c01f670c Implement a resource system.
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.
2016-05-18 11:24:23 +00:00
whitequark
e969bc94ad Enable -Wall -Wextra -Wno-unused-parameter on GCC/Clang.
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.
2016-05-08 00:01:35 +00:00
whitequark
febe0f5282 Rename the old "Import / Assemble" feature to "Link / Assemble".
This better reflects what it does and avoids clashes with the new
DXF import feature.
2016-05-07 05:27:54 +00:00
whitequark
d05e9a938b DWG: implement import.
Before this commit, the file filter suggested that DWG was readable,
but it wasn't.

Also, report any failures while reading DWG and DXF files.
2016-05-07 05:17:23 +00:00
EvilSpirit
70d84b30e8 DXF: implement import. 2016-05-07 04:02:34 +00:00
EvilSpirit
e1f614101f Only generate split triangles when exporting if needed.
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.
2016-05-04 04:48:24 +00:00
whitequark
e61bac2797 Refactor file filters to not use preprocessor magic.
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.
2016-05-04 03:21:12 +00:00
whitequark
52af725606 Only #include "config.h" when we need something from it.
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.
2016-04-23 23:06:31 +00:00
EvilSpirit
1c51205a11 DXF: reassemble piecewise linear fragments into polylines. 2016-04-23 19:39:39 +00:00
EvilSpirit
dabd57847e MSVC: work around binary size explosion. 2016-04-23 19:39:39 +00:00
whitequark
a61544ea9c Fix empty space at the end of the tooltips.
Also, bring MakeAcceleratorLabel to modernity.
2016-04-23 04:38:32 +00:00
whitequark
23dc36da9b Make graphics window edit control width fit the content.
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.
2016-04-16 03:10:56 +00:00
whitequark
d17771064a Ensure edit control font size matches font size of text being edited.
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.
2016-04-15 21:53:08 +00:00
whitequark
0f304b4c64 Rigorously treat font scale factors.
The old values were chosen without a good understanding of font
metrics.
2016-04-15 21:53:08 +00:00
EvilSpirit
24fc65a71c Allow rendering solid outlines using a distinct style.
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.
2016-04-15 21:53:08 +00:00
EvilSpirit
d1a2eb6d18 Allow rendering hidden solid edges using a distinct style.
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.
2016-04-15 21:53:08 +00:00
whitequark
2d25bdb51f When choosing color for a new group, consider active, not last, group. 2016-04-15 06:11:03 +00:00
whitequark
11565e081d Refactor export code to pass around hStyle, not uint32_t. 2016-04-14 18:54:09 +00:00
EvilSpirit
27b403faf5 DXF: refactor. 2016-04-14 18:54:09 +00:00
EvilSpirit
94cba11f2a PDF, EPS: export stippled lines. 2016-04-08 11:32:16 +00:00
EvilSpirit
55e3162a05 When creating a new group, use the color of last requested solid. 2016-04-08 11:21:40 +00:00
EvilSpirit
e19a2f4f35 Accept maybeFat in ssglStippledLine. 2016-04-08 10:55:11 +00:00
EvilSpirit
e17a24814b DXF: only export visible constraints. 2016-04-08 10:15:29 +00:00
EvilSpirit
96344c85a6 Eliminate DEFAULT_TEXT_HEIGHT from drawing code.
Instead, query the text height for constraint style.
2016-03-05 12:02:13 +00:00
EvilSpirit
1170a91875 Implement stippled line styles from ISO 128.
Now it's possible to use a styled line to indicate e.g.
a centerline.
2016-03-05 12:02:13 +00:00
whitequark
c9a2092b9c Fix image export on *nix.
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.
2016-03-04 15:11:14 +00:00
EvilSpirit
df0a1d64e4 DXF: include compatible AutoCAD version in format selector. 2016-02-19 23:16:36 +00:00
EvilSpirit
f87152e8c0 DXF: export constraints with labels as DXF constraints, not pwl.
Specifically, the following constraint types:
  * pt-pt-distance
  * pt-line-distance
  * diameter
  * angle
  * comment
2016-02-19 23:16:36 +00:00
EvilSpirit
e377eb8851 DXF: export color and line width. 2016-02-19 23:16:36 +00:00
EvilSpirit
c469af6600 DXF: rewrite DxfFileWriter using libdxfrw. 2016-02-19 23:16:36 +00:00
whitequark
c9648805ea Allow generating groups in arbitrary order. 2016-02-19 10:23:24 +00:00
whitequark
5c15cbf5f6 Remove extraneous instances of .c_str().
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.
2016-02-19 10:22:53 +00:00
whitequark
d43bd93060 Only consider groups until active when checking for solver failure.
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.
2016-02-14 14:09:36 +00:00
EvilSpirit
57fb3bf3dc Replace internal vector font with LibreCAD's GPLv2+ vector font.
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.
2016-02-14 14:09:36 +00:00
Peter Barfuss
784f3e5548 Rewrite TTF to Bezier conversion using Freetype.
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.
2016-02-13 21:08:18 +00:00
EvilSpirit
34a5d87011 Use relative chord tolerance instead of absolute.
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.
2016-02-13 16:16:56 +00:00
EvilSpirit
fc68804f65 Add BBox class for calculating entity bounding boxes. 2016-02-13 16:16:47 +00:00
EvilSpirit
89eb208660 Use a separate value of chord tolerance for exporting.
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.
2016-02-13 16:16:47 +00:00
EvilSpirit
b28fa34e4a Use an enum to select the mode of operation for GenerateAll. 2016-01-27 09:19:37 +00:00
EvilSpirit
804761da88 Distinguish overconstrained and redundantly constrained sketches.
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").
2016-01-21 14:15:05 +00:00
whitequark
55cde18c5a Reword error messages that are displayed when a group fails to solve.
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.
2016-01-21 12:39:18 +00:00
whitequark
28a6e04f33 Ask the user to locate imported files if they cannot be loaded. 2016-01-13 06:45:17 +00:00
whitequark
86315b2b1f Allow exporting Three.js either as bare mesh or mesh with viewer.
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.
2016-01-13 06:45:17 +00:00
whitequark
750842610c Simplify file saving code.
There is no need to record default file format choice, as
the first one is selected when an empty string is passed.
2016-01-13 06:45:17 +00:00
whitequark
259d8e0d38 Remember last used file type for all export dialogs. 2016-01-13 06:45:17 +00:00
EvilSpirit
6dced8052b Generate primitives for lathe groups.
The primitives that are generated are circles from points and
faces from axis-perpendicular line segments.
2016-01-13 06:45:17 +00:00
whitequark
818436c57d Copy any constraints that only refer to entities in the clipboard. 2016-01-13 06:45:17 +00:00
whitequark
b8e8da0c0b Add Unicode support to TTF renderer.
It works. Mostly. Sort of. Only on Windows fonts. Sometimes it
randomly refuses to render glyphs (try `х`, that's not a latin ex).
I'm not really sure why, the logic seems right.

Why do we have a homegrown TTF parser anyway? It's kind of awful.
It breaks on any slightly unusual input. It plows through UTF-16BE
font names like a nuclear-powered steamroller. It outright ignores
composite glyphs (is that why it's broken this time?). The kerning
is seizure-inducing. It ignores any characters outside BMP by design.

Maybe we should just replace it with freetype.
2016-01-13 06:45:17 +00:00
whitequark
11f29b1231 Replace NameStr with std::string.
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.
2016-01-13 06:45:17 +00:00
whitequark
9d2a035a71 Rasterize non-ASCII glyphs in the UI.
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.
2016-01-13 06:45:16 +00:00
whitequark
ba10a75a7d Use Unicode-aware fopen and remove on Windows.
After this commit, SolveSpace can robustly handle non-ASCII filenames
on every OS. Additionally, on Windows, filenames longer than 260
characeters can be used, and files on network shares can be opened
directly, without mounting them as a network drive.
2016-01-13 06:45:16 +00:00
whitequark
97a9b4743e Make sure only *W functions from Win32 API are called.
After this commit, SolveSpace always uses UTF-8 strings internally
(represented as char* and std::string) on every OS, for everything:
UI labels, paths and user input. OS X always uses UTF-8; on Windows,
strings are converted at boundary; and on Linux/BSD/etc SolveSpace
refuses to start unless the current locale is UTF-8. This will
negatively affect literally no one.

This commit does not bring forth any user-visible improvement yet;
in order to correctly handle Unicode in filenames, it is still
necessary to change the fopen calls to _wfopen on Windows.
2016-01-13 06:45:16 +00:00
whitequark
5c9c32cfc7 Rigorously treat paths on every platform.
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.
2016-01-13 06:45:16 +00:00
whitequark
32383d22bf Rewrite all path handling with std::string.
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.
2016-01-13 06:45:16 +00:00
whitequark
3ffbac38c6 Refactor Cnf* functions.
On Windows, freeze.{cpp,h} was factored into w32main.cpp.
The old implementation was too redundant and leaked registry
key handles.

On all platforms, Cnf* functions now use std::string.
This simplifies code everywhere, but will be particularly useful
when the Windows port switches to the *W WinAPI functions.
2016-01-13 06:45:16 +00:00
whitequark
c84a3b6de3 Call constructors and destructors in List and IdList.
This is necessary to store non-POD classes in these containers.

Note that List and IdList do not use MemRealloc anymore;
this is necessarily (slightly) less efficient, but is the right
semantics, as you cannot just move non-POD types, e.g. std::string,
around in memory. All STL containers provide the same guarantees
and share the performance hit.

The slowdown is mostly mitigated by moving the contained objects,
so that no additional heap allocations or copies occur beyond
that of the object itself.
2016-01-13 06:45:16 +00:00
whitequark
45f056c852 Replace all ZERO and memset with C++11 brace-initialization.
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.
2016-01-13 06:45:16 +00:00
William D. Jones
4b02bf1e81 Implement Three.js export. 2015-12-28 21:37:07 +08:00
whitequark
28166e6200 Use C++ std::{min,max,swap} instead of custom ones.
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.
2015-12-28 21:37:06 +08:00
whitequark
5e7c7fce7e Rename RgbColor to RgbaColor. 2015-07-10 15:59:12 +03:00
whitequark
75a3936b64 Add support for transparent solids.
Some extra code is necessary to determine that the back faces
should not be drawn in red for transparent solids. It is expected
that the user will first ensure that the shell is watertight
and then set the opacity; back faces are still drawn if
the opacity is exactly 1.

The savefile format is changed backwards-compatibly by stashing
the alpha value in uppermost byte of 4-byte hex color value
in Surface and Triangle clauses. The existing files have 00
in the high byte, so RgbColor::FromPackedInt treats that
as "opaque".
2015-07-10 15:59:12 +03:00
whitequark
71b7ad7f99 Add an autosave timer.
Original patch by Marc Britten <marc.britten@gmail.com>.
2015-07-10 15:59:12 +03:00
whitequark
d0c0a7ae5a Remove FLTK port.
It provides no value over the native GTK and Cocoa ports.
2015-07-10 15:59:12 +03:00