Commit Graph

29 Commits (771086fa5050def63eddce79f0bb94684a36d6a5)

Author SHA1 Message Date
Koen Schmeets dcdfdec564 Add an option to edit dimension immediately after adding. 2019-11-26 22:34:53 +00:00
EvilSpirit 9d1c295495 Add a setting to format constraint labels using SI prefixes.
Supported metric units: km, m, cm, mm, µm, nm.
Supported USCS units: in, mil, µin.

Also, use the newly introduced unit formatting machinery in tools for
measuring perimeter, area and volume, so that e.g. volume is not
displayed in millions of cubic millimeters.
2019-05-24 12:31:41 +00:00
whitequark ac7b82d7c1 Allow configuring the amount of digits displayed after decimal point.
This is useful in niche cases, like making angular measurement tools.

Also, use simpler and more principled code for numeric precision
while editing constraints: don't special-case angles, but use up to
10 digits after the decimal point for everything.
2019-05-23 17:53:53 +00:00
Dynamo Dan e67f967933 Implement turntable (SketchUp-like) mouse navigation. 2019-05-23 15:45:15 +00:00
Sergiusz Bazanski 9e512882d1 Add checkbox to control automatic line constraints
Signed-off-by: Sergiusz Bazanski <q3k@q3k.org>
2019-02-11 13:17:38 +00:00
whitequark 8426992f27 Eliminate blocking in Error() and Message() calls.
This serves two purposes.

First, we want to (some day) convert these messages into a less
obtrustive form, something like toaster notifications, such that they
don't interrupt workflow as harshly. That would, of course, be
nonblocking.

Second, some platforms, like Emscripten, do not support nested event
loops, and it's not possible to display a modal dialog on them
synchronously.

When making this commit, I've reviewed all Error() and Message()
calls to ensure that only some of the following is true for all
of them:
  * The call is followed a break or return statement that exits
    an UI entry point (e.g. an MenuX function);
  * The call is followed by cleanup (in fact, in this case the new
    behavior is better, since even with a synchronous modal dialog
    we have to be reentrant);
  * The message is an informational message only and nothing
    unexpected will happen if the operation proceeds in background.

In general, all Error() calls already satisfied the above conditions,
although in some cases I changed control flow aroudn them to more
clearly show that. The Message() calls that didn't satisfy these
conditions were reworked into an asynchronous form.

There are three explicit RunModal() calls left that need to be
reworked into an async form.
2018-07-20 04:40:19 +00:00
whitequark f324477dd0 Implement a platform abstraction for windows.
This commit removes a large amount of code partially duplicated
between the text and the graphics windows, and opens the path to
having more than one model window on screen at any given time,
as well as simplifies platform work.

This commit also adds complete support for High-DPI device pixel
ratio. It adds support for font scale factor (a fractional factor
on top of integral device pixel ratio) on the platform side, but not
on the application side.

This commit also adds error checking to all Windows API calls
(within the abstracted code) and fixes a significant number of
misuses and non-future-proof uses of Windows API.

This commit also makes uses of Windows API idiomatic, e.g. using
the built-in vertical scroll bar, native tooltips, control
subclassing instead of hooks in the global dispatch loop, and so on.

It reinstates tooltip support and removes menu-related hacks.
2018-07-17 13:31:17 +00:00
whitequark 7ab87caa88 Implement a platform abstraction for timers.
This commit temporarily disables tooltip functionality; it will
be handled natively in a platform abstraction for windows using
much simpler code.
2018-07-16 11:21:30 +00:00
EvilSpirit 99f6ea34f1 Add an option to display areas of closed contours.
This is useful e.g. for architectural work.
2017-04-08 16:43:06 +00:00
whitequark 984f74d271 Internationalize all messages without substitutions. 2017-01-07 06:47:40 +00:00
EvilSpirit 52557ee979 Add an interface for view-independent rendering.
To actually achieve improved performance with the OpenGL 2 renderer,
we have to cache geometry that doesn't change when the viewport does
(note that the rendered pixels can change quite dramatically because
we can reconfigure shaders; e.g. stippling can be drawn in screen
coordinates).

This commit adds a BatchCanvas interface that can be implemented
by renderers, and uses it for drawing entities such as lines and
points.
2016-11-18 04:04:32 +00:00
EvilSpirit 7b9d730a23 Hide OpenGL implementation details.
Abstract the exact details of the OpenGL renderer in the render.h
header; this allows us to use GL-specific types in the renderer
class and functions without including OpenGL (and Windows, where
applicable) headers in every source file.
2016-11-14 20:30:46 +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 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 a4e487d298 Don't crash when changing the autosave interval. 2016-06-23 11:56:13 +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
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
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 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 76d582720a Don't calculate halfRow for ShowEditControl manually.
Instead, grab it from hoveredRow, since almost always (with only one
exception) this is where the edit control has to be shown.

This makes it much easier to adjust views, e.g. add a new editable
field in the middle of configuration view, because it's not necessary
to manually change and test all the indexes below the row being
changed.

Additionally, it removes a lot of awkward and opaque row calculations.
2016-01-27 09:09:18 +00:00
EvilSpirit fd0b7fbc29 Update remaining sprintf calls with a stack buffer to use ssprintf.
The commit 11f29b123 has replaced most of the uses of sprintf,
but there were still many remaining in Screen* functions, and it
was annoyingly inconsistent. Moreover, while most usage of sprintf
there was fine, it is bad hygiene to leave stack overflow prone
code around.
2016-01-27 09:09:18 +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 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 71b7ad7f99 Add an autosave timer.
Original patch by Marc Britten <marc.britten@gmail.com>.
2015-07-10 15:59:12 +03:00
whitequark c5364fe7a8 Trim trailing whitespace. 2015-07-10 15:59:11 +03:00
Daniel Richard G 0a24cf40f0 Moved most of the source into a src/ subdirectory
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.
2013-11-19 18:17:32 -05:00