Compare commits

...

71 Commits
master ... v2.3

Author SHA1 Message Date
whitequark
7c1ca46076 Bump version to 2.3. 2016-12-24 02:09:48 +00:00
whitequark
9c30f7858f README: update Linux dependencies. 2016-12-13 09:58:10 +00:00
Elvira Khabirova
6802a12a52 Fix crash when trying to import not .dxf or .dwg files 2016-11-27 15:17:46 +00:00
whitequark
99d6f1f5b5 DXF: Fix export of wireframe as 3D DXF.
Before this commit, polylines got flattened but all other entities
got exported with the proper Z coordinate. After this commit, all
entities are exported with proper Z coordinate.

Also, instead of exporting LWPOLYLINE (2d only), POLYLINE (2d/3d)
is exported; as a bonus it is more compatible with 3rd party
software, since it is older.
2016-11-26 08:29:21 +00:00
whitequark
ece7630624 Fix detection of transparent meshes.
SSurface::TriangulateInto first populates the mesh with triangles
that have no color, and then paints them, which confused the code
that detects if a mesh is transparent into thinking that all of them
are; and that broke the "draw back faces in red" feature, since it
is disabled for transparent meshes.
2016-11-18 11:02:19 +00:00
whitequark
82746b6171 Fix a crash when adding a symmetric constraint on a line.
This is the same problem as in a2c97fc.
2016-11-16 02:19:09 +00:00
whitequark
74d8621f53 OS X: fix another out-of-bounds TW.META access.
See also e1d6dac.
2016-11-05 17:06:56 +00:00
whitequark
0b2fc34de1 Update CHANGELOG. 2016-11-02 10:22:17 +00:00
whitequark
25febd82ed TTF: use metrics of 'A' to determine cap height.
SolveSpace 2.0 used the height of 'A' (i.e. cap height) to determine
the reference height.
SolveSpace 2.1 completely broke that during transition to Freetype,
and used something more or less random, by using FT_Set_Char_Size
with units_per_EM.
SolveSpace 2.2 attempted to fix that, but also used something more
or less random, by using FT_Request_Size with "unit" values.

Turns out that Freetype actually doesn't have a concept of cap height
at all. It is possible to extract it from the TT_OS2 table that is
present in some TrueType fonts, but it is not present in Microsoft
fonts (the msttcorefonts ones), and for those Linux fonts in which
it is present it doesn't appear very reliable.

So instead, use the height of 'A' instead, like version 2.0 did.
This has the advantage that it is quite bulletproof, and also matches
exactly what the old files are measured against.

One downside is that fonts without an 'A' glyph would not render.
We can deal with that when it becomes a problem.
2016-11-02 09:00:44 +00:00
whitequark
d809d4122f TTF: actually use CID as GID when CID-to-GID mapping is absent. 2016-11-02 09:00:27 +00:00
whitequark
2e1c7a6701 TTF: only call FT_Request_Size once after loading. 2016-11-02 09:00:16 +00:00
whitequark
4fad67d721 OS X: don't crash in GetSaveFile() if default extension is invalid. 2016-10-25 09:59:52 +00:00
whitequark
a2c97fcd46 Fix a crash when adding a symmetric constraint on two points.
The crash was introduced in e2e91672; I have not noticed that some
of the code relies on past-the-size entities in GW.GS being empty.
2016-10-25 09:58:24 +00:00
whitequark
c4ad073d1b Bump version to 2.2. 2016-10-17 02:07:14 +00:00
whitequark
0f3879e37c Debian: remove in-tree packaging.
The package is now maintained by the Debian Science team at:
https://anonscm.debian.org/git/debian-science/packages/solvespace.git
2016-10-17 02:07:14 +00:00
EvilSpirit
05d9c0fab9 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:40:06 +00:00
Evil-Spirit
bc43365eff Write params if system is solved as REDUNDANT_OKAY.
A system solved as REDUNDANT_OKAY is still solved correctly,
even if the UI would consider this an error, in case that
g->allowRedundant==false. So there's no reason to discard this
solution; we might find it useful if a system loses a degree of
freedom while dragging, or to avoid regeneration after redundant
constraints are allowed.

This commit also reverts commit 3ff236c, as that is not necessary
anymore.
2016-10-14 00:34:35 +00:00
whitequark
8a96ca894c OS X: map the backspace key to the "Delete" function.
Apple hardware does not have a discrete Delete key, so Backspace
is used for deleting stuff instead.
2016-10-12 19:43:09 +00:00
whitequark
dde6030533 OS X: set scroller knob style to light.
On newer OS X versions the scrollbar is overlaid on the window
contents, so a black know is invisible.
2016-10-12 19:25:07 +00:00
whitequark
b8abf698c9 OS X: don't remap OK in message boxes to Escape.
The platform convention is to use Return.
2016-10-12 19:08:25 +00:00
whitequark
f6eb079d41 OS X: revert "sort out window visibility and focus."
This reverts commit 1dba594949.

Turns out the old behavior was more appropriate for OS X.
2016-10-12 19:08:16 +00:00
whitequark
adca3cd253 GTK: use 3DConnexion button 0 instead of SI_APP_FIT_BUTTON.
The libspnav library doesn't even define SI_APP_FIT_BUTTON, which
appears to be Windows-specific functionality, perhaps a physical
button remapped with some logic. Just use 0 instead, since that
seems always safe.
2016-10-11 13:57:09 +00:00
whitequark
33c3fd5fce Update CHANGELOG. 2016-10-10 23:43:35 +00:00
EvilSpirit
f2007326b4 Don't draw edges and outlines while dragging an entity.
This is far too slow for realtime dragging, and results in assemblies
falling apart (e.g. jansen-asm from the examples).
2016-10-10 21:32:25 +00:00
whitequark
02b7e24812 Fix a handle leak in TtfFontList::PlotString. 2016-10-10 21:18:03 +00:00
whitequark
1a5047550d Normalize the string returned by Extension() to lowercase.
This would otherwise break code that branches on the extension,
such as that after 06a188cc.
2016-10-10 20:53:16 +00:00
whitequark
5e28b35f2b OS X: correctly parse output of otool -D.
In the past this relied on otool -XD not printing the name of
the library itself, only the install name, but that doesn't work
anymore as of 10.12.
2016-10-10 19:57:11 +00:00
whitequark
19e77e7866 Mark group dirty when clicking "allow redundant constraints" link.
Otherwise, the now-valid constraint will not become satisfied.
2016-10-10 17:45:56 +00:00
whitequark
e1d6dac87a OS X: fix out-of-bounds TW.META access.
For some reason OS X can post pointer events far outside the window
rect, so be defensive here.
2016-10-10 12:26:13 +00:00
whitequark
4c022f8d79 Win32: add proper Unicode support to message boxes.
Before this commit, for every non-ASCII character, a replacement
character was also printed.
2016-10-09 21:55:10 +00:00
whitequark
bbd106044b DXF: update to use Unicode-aware file open routines on Windows. 2016-10-09 20:56:02 +00:00
whitequark
359b13bd62 GTK: show files with uppercase extensions in file open dialog.
The Windows dialog does that automatically, but the GTK one doesn't.
So this is useful for Windows interop.
2016-10-09 16:19:33 +00:00
whitequark
513f55f7d4 Travis: update brew installation instructions.
The `brew upgrade` is no longer needed as Travis updated the
versions in their image.
2016-10-09 13:37:58 +00:00
whitequark
bbf8610c57 Make translate/rotate groups inherit the "suppress solid model" option. 2016-10-09 13:29:04 +00:00
whitequark
dc0eed8322 Get rid of the MAX_SELECTED restriction in GroupSelection(). 2016-08-13 05:22:09 +00:00
whitequark
ca150aeda1 Update CHANGELOG. 2016-08-13 05:21:34 +00:00
EvilSpirit
4d2c773ee6 DXF export: always declare layers before using them.
Before this commit, the #s001-active-grp layer was not declared,
and this broke some external software, such as Inkscape.
See https://bugs.launchpad.net/inkscape/+bug/1472429 for details.
2016-08-13 04:28:14 +00:00
EvilSpirit
0b997e4c17 Forcibly show the current group once we start a drawing operation 2016-08-13 03:43:44 +00:00
EvilSpirit
bfef091ac9 Do not clear selection during operations that don't need it.
Specifically, during "Align View onto Workplane" when we are locked
in workplane (in which case it always aligns onto that workplane).
2016-08-13 03:32:02 +00:00
whitequark
bcd43c7c24 Update libdxfrw. 2016-08-13 02:24:14 +00:00
whitequark
4fae03d105 Unbreak TTF metrics.
In 2.0, the distance between the points in the TTF request specified
cap height. In 2.1, that was accidentally changed to some arbitrary
value near cap height instead, due to a 72pt factor mess-up.
This commit restores the old behavior.
2016-08-01 12:31:34 +00:00
whitequark
c0f5a31401 When snapping constraints to grid, snap the reference point. 2016-07-19 15:14:51 +00:00
whitequark
5af252eaf1 Multiply constraint values by scale when pasting with transformation. 2016-07-19 12:14:28 +00:00
whitequark
61904280a3 GTK: make Space Navigator actually work.
Before this commit, no events would actually be received.
2016-07-19 08:27:11 +00:00
EvilSpirit
51f3d7e438 Fix the "Show degrees of freedom" command.
Before this commit, it never highlighted anything at all.
It was broken when chord tolerance calculation was overhauled.
2016-06-29 17:01:59 +00:00
whitequark
561b2797e8 Don't crash when changing the autosave interval. 2016-06-23 11:59:04 +00:00
whitequark
5525303946 Do not remove autosave after successfully opening file.
If SolveSpace crashes after the open, or hangs and is forcibly
killed, data would be lost. (I lost my data.) Instead, remove
autosave only in two cases: right after a successful save, or right
after a save is declined. This should be completely safe.
2016-06-23 11:59:01 +00:00
whitequark
7f6c774bf5 Update changelog for 2.2. 2016-06-23 11:58:54 +00:00
whitequark
fd255364b3 Show "Paste" context menu item even when only constraints are copied. 2016-06-23 11:58:29 +00:00
whitequark
478973eb3c OS X: fix typo in build system. 2016-06-20 13:42:40 +00:00
Thomas Buck
8fd572d449 OS X: add 3Dconnexion device support. 2016-06-20 13:42:40 +00:00
whitequark
7b82ff68e1 Unix: also install the SolveSpace desktop icon in the xpm format.
This is required by e.g. Debian guidelines.
2016-06-16 02:51:10 +00:00
whitequark
7fc2033c9b Update debian/copyright. 2016-06-16 02:45:20 +00:00
whitequark
ff9a8284b4 OS X: find frameworks last.
Before this commit, any available libpng or libfreetype would be
picked, e.g. from Mono.framework. After, homebrew and MacPorts
are prioritized.
2016-06-13 04:15:55 +00:00
whitequark
c25e4c8973 OS X: sort out window visibility and focus. 2016-06-13 02:08:28 +04:00
whitequark
dce906465d Add CHANGELOG.md. 2016-06-11 22:30:26 +00:00
whitequark
53e5e0eb90 Fix copyright. 2016-06-11 22:29:58 +00:00
whitequark
ce656ef7c6 Fix disabling of autoconstrainter via Ctrl. 2016-06-11 22:28:02 +00:00
whitequark
fb2f32eb72 Three.js: correctly handle browser zoom.
Before this commit, controls went wild on zoom ratios other than 1:1,
and the rendering wasn't too good either.
2016-06-11 20:45:57 +00:00
EvilSpirit
917a7b93ce Load actual factory default, not saved style, when requested. 2016-06-11 20:45:57 +00:00
EvilSpirit
c838158e04 DXF, DWG: allow undoing an import. 2016-06-11 20:28:02 +00:00
whitequark
17f7a7b467 Unbreak importing files in the same directory as current file.
This commit fixes a bug introduced in commit 0d7aa0a1.
2016-06-11 20:27:00 +00:00
whitequark
e78edd9b94 Cocoa: allow dismissing Message/Error NSAlerts using Escape key. 2016-06-11 20:26:51 +00:00
whitequark
d13e29cdaf GTK: clip any editors instead of resizing GraphicsWindow.
Such resizing may well get us past OpenGL's maximum texture size
and break rendering.
2016-06-11 20:26:12 +00:00
whitequark
daee939714 Reimplement e129755d properly.
Before this commit, quitting through menu would bring up the dialog
twice when declining to save the file.
2016-06-11 20:26:01 +00:00
whitequark
44c152ccd0 Fix glyph for U+0454 є in vector font. 2016-06-11 20:24:51 +00:00
whitequark
dfc218c452 Allow copying and pasting constraints. 2016-06-11 20:23:44 +00:00
whitequark
9fc60a0c00 Cocoa: fix massive memory leak. 2016-06-11 20:23:16 +00:00
whitequark
f3e36f593b GTK: intercept the Tab key and run MNU_SHOW_TEXT_WND. 2016-06-11 20:23:09 +00:00
whitequark
b62375b554 Rename "Browser" to "Property Browser".
Also, rename confusing "Show Text Window" menu item.
2016-06-11 20:22:41 +00:00
whitequark
056d3bfa30 Properly fix workplane name overlapping workplane border.
A previous attempt to fix this was done in 0128b8679. However, it was
not rigorous. The added offset was dependent on font size and it
introduced an error into edit control positioning. Further, it is
irrelevant to non-workplanes.

After this commit, the workplane drawing code adds a fixed offset
instead. Also, the "tab" is enlarged to not overlap with #XY etc.
2016-06-11 20:22:24 +00:00
56 changed files with 947 additions and 443 deletions

View File

@ -11,18 +11,6 @@ script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/build-debian.sh; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/build-debian.sh; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/build-macos.sh; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/build-macos.sh; fi
deploy: deploy:
# Releases to solvespace/solvespace
- provider: releases
api_key:
secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM=
skip_cleanup: true
file_glob: true
file:
- ../*.deb
on:
repo: solvespace/solvespace
tags: true
condition: "$TRAVIS_OS_NAME == linux"
- provider: releases - provider: releases
api_key: api_key:
secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM= secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM=
@ -32,25 +20,3 @@ deploy:
repo: solvespace/solvespace repo: solvespace/solvespace
tags: true tags: true
condition: "$TRAVIS_OS_NAME == osx" condition: "$TRAVIS_OS_NAME == osx"
# Releases to whitequark/solvespace (to be removed)
- provider: releases
api_key:
secure: DA3tW0My37vbi2t3dZ061281Xm8KSIkeLdFZsQISrut0g1kkbWuBTPxAfvE3B6OE8p47wAclE/wxA1+obMTVkY0oYpd5u+JelYNHxU/oL8Ww0xdUANwKNJ1JD2EZP8nSz7JSvxuGILC6AFPoTjawsG97SXwiTyp7z0PA6nvzraE=
skip_cleanup: true
file_glob: true
file:
- ../*.deb
on:
repo: whitequark/solvespace
tags: true
condition: "$TRAVIS_OS_NAME == linux"
- provider: releases
api_key:
secure: DA3tW0My37vbi2t3dZ061281Xm8KSIkeLdFZsQISrut0g1kkbWuBTPxAfvE3B6OE8p47wAclE/wxA1+obMTVkY0oYpd5u+JelYNHxU/oL8Ww0xdUANwKNJ1JD2EZP8nSz7JSvxuGILC6AFPoTjawsG97SXwiTyp7z0PA6nvzraE=
skip_cleanup: true
file: build/solvespace.dmg
on:
repo: whitequark/solvespace
tags: true
condition: "$TRAVIS_OS_NAME == osx"

View File

@ -2,5 +2,7 @@
if echo $TRAVIS_TAG | grep ^v; then BUILD_TYPE=RelWithDebInfo; else BUILD_TYPE=Debug; fi if echo $TRAVIS_TAG | grep ^v; then BUILD_TYPE=RelWithDebInfo; else BUILD_TYPE=Debug; fi
export BUILD_TYPE mkdir build
dpkg-buildpackage -b -us -uc cd build
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE
make VERBOSE=1

View File

@ -1,4 +1,3 @@
#!/bin/sh -xe #!/bin/sh -xe
brew update brew update
brew upgrade cmake libpng

127
CHANGELOG.md Normal file
View File

@ -0,0 +1,127 @@
Changelog
=========
2.3
---
Bug fixes:
* Do not crash when applying a symmetry constraint to two points.
* Fix TTF font metrics again (properly this time).
* Fix the "draw back faces in red" option.
* Fix export of wireframe as 3D DXF.
* Various minor crashes.
2.2
---
Other new features:
* OS X: support 3Dconnexion devices (SpaceMouse, SpaceNavigator, etc).
* GTK: files with uppercase extensions can be opened.
Bug fixes:
* Do not remove autosaves after successfully opening a file, preventing
data loss in case of two abnormal terminations in a row.
* Do not crash when changing autosave interval.
* Unbreak the "Show degrees of freedom" command.
* Three.js: correctly respond to controls when browser zoom is used.
* OS X: do not completely hide main window when defocused.
* GTK: unbreak 3Dconnexion support.
* When pasting transformed entities, multiply constraint values by scale.
* Fix TTF font metrics (restore the behavior from version 2.0).
* Forcibly show the current group once we start a drawing operation.
* DXF export: always declare layers before using them.
* Do not truncate operations on selections to first 32 selected entities.
* Translate and rotate groups inherit the "suppress solid model" setting.
* DXF: files with paths containing non-ASCII or spaces can be exported
or imported.
* Significantly improved performance when dragging an entity.
* Various crashes and minor glitches.
2.1
---
New sketch features:
* Lathe groups create circle and face entities.
* New toolbar button for creating lathe groups.
* Chord tolerance is separated into two: display chord tolerance (specified
in percents, relative to model bounding box), and export chord tolerance
(specified in millimeters as absolute value).
* Bezier spline points can be added and removed after the spline is created.
* When an unconstrained extrusion is switched between "union" and
"difference", its normal is flipped.
* Groups can be added in the middle of the stack. Note that this results
in files incompatible with version 2.0.
* Active group can be removed.
* Removing an imported group does not cause all subsequent groups to also
be removed.
* When a new group with a solid is created, the color is taken from
a previous group with a solid, if any.
* Entities in a newly active group do not become visible.
* When entities are selected, "Zoom to fit" zooms to fit only these
entities and not the entire sketch.
* Zero-length edges are reported with a "zero-length error", not
"points not all coplanar".
New constraint features:
* Height of the font used for drawing constraint labels can be changed.
* New constraint, length difference, placed with J.
(Patch by Peter Ruevski)
* Horizontal/vertical constraints are automatically added if a line segment
is close enough to being horizontal/vertical. This can be disabled by
holding Ctrl.
* Reference dimensions and angles can be placed with Shift+D and Shift+N.
* Copying and pasting entities duplicates any constraints that only involve
entities in the clipboard, as well as selected comments.
* Diameter constraints can be shown as radius.
* The "pi" identifier can be used in expressions.
* Constraint labels can be snapped to grid.
* Integer angles are displayed without trailing zeroes.
* Angle constraints have proper reference lines and arrowheads.
* Extension lines are drawn for point-line distance constraints.
New solver features:
* Sketches with redundant and unsolvable constraints are distinguished.
* New group setting, "allow redundant constraints". Note that it makes
the solver less stable.
New rendering and styling features:
* New line style parameter: stippling, based on ISO 128.
* Outlines of solids can be drawn in a particular style (by default, thick
lines) controlled by the "Show outline of solid model" button.
* Occluded edges can be drawn in a particular style (by default, stippled
with short dashes) controlled by the "Show hidden lines" button.
* Solids can be made transparent.
New export/import features:
* The old "import" command (for .slvs files) is renamed to "link".
* If a linked .slvs file is not found, first the relative path recorded
in the .slvs file is checked and then the absolute path; this is
an inversion of the previously used order. If it is still not found,
a dialog appears offering to locate it.
* DXF and DWG files can be imported, with point-coincident, horizontal and
vertical constraints automatically inferred from geometry, and distance
and angle constraints created when a dimension placed against geometry
exists.
* Triangle mesh can be exported for viewing in the browser through WebGL.
* Export dialogs remember the last file format used, and preselect it.
* Exported DXF files have exact circles, arcs and splines instead of
a piecewise linear approximation (unless hidden line removal was needed).
* Exported DXF files preserve color and line thickness.
* In exported DXF files, constraints are represented as DXF dimensions,
instead of piecewise linear geometry.
* When exporting 2d views, overlapping lines are removed.
Other new features:
* Native Linux (GTK 2 and GTK 3) and Mac OS X ports.
* Automatically save and then restore sketches if SolveSpace crashes.
(Patch by Marc Britten)
* Unicode is supported everywhere (filenames, group names, TTF text,
comments), although RTL scripts and scripts making heavy use of ligatures
are not rendered correctly.
* The vector font is grid-fitted when rendered on screen to make it easier
to read regardless of its size.
2.0
---
Initial public release.

View File

@ -17,11 +17,16 @@ set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
# project # project
# NOTE TO PACKAGERS: The embedded git commit hash is critical for rapid bug triage when the builds
# can come from a variety of sources. If you are mirroring the sources or otherwise build when
# the .git directory is not present, please comment the following line:
include(GetGitCommitHash) include(GetGitCommitHash)
# and instead uncomment the following, adding the complete git hash of the checkout you are using:
# set(GIT_COMMIT_HASH 0000000000000000000000000000000000000000)
project(solvespace) project(solvespace)
set(solvespace_VERSION_MAJOR 2) set(solvespace_VERSION_MAJOR 2)
set(solvespace_VERSION_MINOR 1) set(solvespace_VERSION_MINOR 3)
string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH) string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH)
if(NOT WIN32 AND NOT APPLE) if(NOT WIN32 AND NOT APPLE)
@ -154,6 +159,8 @@ if(WIN32)
"${CMAKE_SOURCE_DIR}/extlib/si/siapp.lib") "${CMAKE_SOURCE_DIR}/extlib/si/siapp.lib")
endif() endif()
elseif(APPLE) elseif(APPLE)
set(CMAKE_FIND_FRAMEWORK LAST)
find_package(PNG REQUIRED) find_package(PNG REQUIRED)
find_package(Freetype REQUIRED) find_package(Freetype REQUIRED)
find_library(APPKIT_LIBRARY AppKit REQUIRED) find_library(APPKIT_LIBRARY AppKit REQUIRED)

View File

@ -26,12 +26,13 @@ Building on Linux
### Building for Linux ### Building for Linux
You will need CMake, libpng, zlib, json-c, fontconfig, freetype, gtkmm 2.4, You will need CMake, libpng, zlib, json-c, fontconfig, freetype, gtkmm 2.4,
pangomm 1.4, OpenGL and OpenGL GLU. pangomm 1.4, OpenGL, OpenGL GLU and OpenGL GLEW, and optionally, the Space Navigator
client library.
On a Debian derivative (e.g. Ubuntu) these can be installed with: On a Debian derivative (e.g. Ubuntu) these can be installed with:
apt-get install libpng12-dev libjson-c-dev libfreetype6-dev \ apt-get install libpng12-dev libjson-c-dev libfreetype6-dev \
libfontconfig1-dev libgtkmm-2.4-dev libpangomm-1.4-dev \ libfontconfig1-dev libgtkmm-2.4-dev libpangomm-1.4-dev \
libgl-dev libglu-dev libglew-dev cmake libgl-dev libglu-dev libglew-dev libspnav-dev cmake
Before building, check out the necessary submodules: Before building, check out the necessary submodules:

View File

@ -1,4 +1,4 @@
version: 2.1.{build} version: 2.2.{build}
clone_depth: 1 clone_depth: 1
before_build: before_build:
- git submodule update --init - git submodule update --init
@ -19,7 +19,6 @@ artifacts:
- path: build\src\RelWithDebInfo\solvespace.pdb - path: build\src\RelWithDebInfo\solvespace.pdb
name: solvespace.pdb name: solvespace.pdb
deploy: deploy:
# Releases to solvespace/solvespace
- provider: GitHub - provider: GitHub
auth_token: auth_token:
secure: P9/pf2nM+jlWKe7pCjMp41HycBNP/+5AsmE/TETrDUoBOa/9WFHelqdVFrbRn9IC secure: P9/pf2nM+jlWKe7pCjMp41HycBNP/+5AsmE/TETrDUoBOa/9WFHelqdVFrbRn9IC
@ -27,11 +26,3 @@ deploy:
artifact: solvespace.exe artifact: solvespace.exe
on: on:
appveyor_repo_tag: true appveyor_repo_tag: true
# Releases to whitequark/solvespace (to be removed)
- provider: GitHub
auth_token:
secure: Flqxu1cz6PyxVT1wzTP4bSrQOY8wFrO7pJxYxvjEkLqIUU4dsDQrs2rac/A9deet
description: ""
artifact: solvespace.exe
on:
appveyor_repo_tag: true

5
debian/changelog vendored
View File

@ -1,5 +0,0 @@
solvespace (2.1) unstable; urgency=low
* Initial Release.
-- whitequark <whitequark@whitequark.org> Fri, 20 Mar 2015 12:39:28 +0300

1
debian/compat vendored
View File

@ -1 +0,0 @@
9

73
debian/control vendored
View File

@ -1,73 +0,0 @@
Source: solvespace
Section: graphics
Priority: optional
Maintainer: whitequark <whitequark@whitequark.org>
Build-Depends: debhelper (>= 9), cmake, libpng12-dev, zlib1g-dev, libjson-c-dev,
libfontconfig1-dev, libgtkmm-2.4-dev, libpangomm-1.4-dev,
libgl-dev, libglu-dev, libglew-dev
Standards-Version: 3.9.5
Homepage: http://solvespace.com
Vcs-Git: git://github.com/whitequark/solvespace
Vcs-Browser: https://github.com/whitequark/solvespace
Package: solvespace
Architecture: any
Multi-Arch: foreign
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: SolveSpace parametric 2d/3d CAD
SolveSpace is a parametric 2d/3d CAD program. Applications include:
.
* modeling 3d parts — draw with extrudes, revolves, and Boolean
(union / difference) operations;
* modeling 2d parts — draw the part as a single section, and export DXF,
PDF, SVG; use 3d assembly to verify fit;
* 3d-printed parts — export the STL or other triangle mesh expected by
most 3d printers;
* preparing CAM data — export 2d vector art for a waterjet machine or
laser cutter; or generate STEP or STL, for import into third-party
CAM software for machining;
* mechanism design — use the constraint solver to simulate planar or
spatial linkages, with pin, ball, or slide joints;
* plane and solid geometry — replace hand-solved trigonometry and
spreadsheets with a live dimensioned drawing.
Package: solvespace-dbg
Architecture: any
Section: debug
Priority: extra
Depends: solvespace (= ${binary:Version}), ${misc:Depends}
Description: SolveSpace parametric 2d/3d CAD (debugging files)
SolveSpace is a parametric 2d/3d CAD.
.
This package contains the debugging symbols for solvespace.
Package: libslvs1
Section: libs
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: SolveSpace geometric kernel
SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric
kernel of SolveSpace, built as a library.
Package: libslvs1-dev
Section: libs
Architecture: any
Multi-Arch: same
Depends: libslvs1, ${misc:Depends}
Description: SolveSpace geometric kernel (development files)
SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric
kernel of SolveSpace, built as a library.
.
This package includes development files for libslvs.
Package: libslvs1-dbg
Architecture: any
Section: debug
Priority: extra
Depends: libslvs1 (= ${binary:Version}), ${misc:Depends}
Description: SolveSpace geometric kernel (debugging files)
SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric
kernel of SolveSpace, built as a library.
.
This package contains the debugging symbols for libslvs1.

33
debian/copyright vendored
View File

@ -1,33 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: solvespace
Source: https://github.com/whitequark/solvespace
Files: *
Copyright: 2008-2013 Jonathan Westhues.
License: GPL-3.0+
Files: debian/*
Copyright: 2015 Peter Zotov <whitequark@whitequark.org>
License: GPL-3.0+
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.
# Please avoid to pick license terms that are more restrictive than the
# packaged work, as it may make Debian's contributions unacceptable upstream.

2
debian/docs vendored
View File

@ -1,2 +0,0 @@
COPYING.txt
README.md

View File

@ -1 +0,0 @@
usr/include/slvs.h

View File

@ -1 +0,0 @@
usr/lib/**/libslvs.so*

7
debian/menu vendored
View File

@ -1,7 +0,0 @@
?package(solvespace):needs="X11" section="Applications/Graphics" \
title="SolveSpace" command="/usr/bin/solvespace" \
hints="CAD" \
icon16x16="/usr/share/pixmaps/solvespace-16x16.xpm" \
icon24x24="/usr/share/pixmaps/solvespace-24x24.xpm" \
icon32x32="/usr/share/pixmaps/solvespace-32x32.xpm" \
icon48x48="/usr/share/pixmaps/solvespace-48x48.xpm"

24
debian/rules vendored
View File

@ -1,24 +0,0 @@
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable)
# output every command that modifies files on the build system.
#DH_VERBOSE = 1
# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/default.mk
# main packaging script based on dh7 syntax
%:
dh $@
# debmake generated override targets
# This is example for Cmake (See http://bugs.debian.org/641051 )
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \
-DCMAKE_BUILD_TYPE=$(BUILD_TYPE)
# create a -dbg package
override_dh_strip:
dh_strip -psolvespace --dbg-package=solvespace-dbg
dh_strip -plibslvs1 --dbg-package=libslvs1-dbg

View File

@ -1,3 +0,0 @@
usr/bin/solvespace
usr/share/icons
usr/share/applications

View File

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="application/x-solvespace">
<comment>SolveSpace sketch</comment>
<glob pattern="*.slvs"/>
<generic-icon name="x-office-document"/>
</mime-type>
</mime-info>

View File

@ -1 +0,0 @@
3.0 (native)

View File

@ -1,3 +0,0 @@
tar-ignore = "*.sublime-*"
tar-ignore = "build*"
tar-ignore = ".git"

@ -1 +1 @@
Subproject commit 8d24e656fbd293cb953828389d01d362f2a1a8e0 Subproject commit 8f958955f54668c142ded760dc951ffd16d9c71b

View File

@ -342,8 +342,9 @@ if(APPLE)
set(fixups) set(fixups)
foreach(lib ${platform_BUNDLED_LIBS}) foreach(lib ${platform_BUNDLED_LIBS})
get_filename_component(name ${lib} NAME) get_filename_component(name ${lib} NAME)
execute_process(COMMAND otool -XD ${lib} execute_process(COMMAND otool -D ${lib}
OUTPUT_VARIABLE canonical_lib OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_VARIABLE canonical_lib OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REGEX REPLACE "^.+:\n" "" canonical_lib ${canonical_lib})
add_custom_command(TARGET solvespace POST_BUILD add_custom_command(TARGET solvespace POST_BUILD
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name} COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
$<TARGET_FILE:solvespace> $<TARGET_FILE:solvespace>
@ -380,6 +381,10 @@ foreach(SIZE 16x16 24x24 32x32 48x48)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}/mimetypes DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}/mimetypes
RENAME application.x-solvespace.png) RENAME application.x-solvespace.png)
endforeach() endforeach()
foreach(SIZE 16x16 24x24 32x32 48x48)
install(FILES unix/solvespace-${SIZE}.xpm
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps/)
endforeach()
# valgrind # valgrind

View File

@ -117,6 +117,15 @@ void GraphicsWindow::CopySelection(void) {
SS.clipboard.r.Add(&cr); SS.clipboard.r.Add(&cr);
} }
for(Selection *s = ls->First(); s; s = ls->NextAfter(s)) {
if(!s->constraint.v) continue;
Constraint *c = SK.GetConstraint(s->constraint);
if(c->type == Constraint::COMMENT) {
SS.clipboard.c.Add(c);
}
}
Constraint *c; Constraint *c;
for(c = SK.constraint.First(); c; c = SK.constraint.NextAfter(c)) { for(c = SK.constraint.First(); c; c = SK.constraint.NextAfter(c)) {
if(!SS.clipboard.ContainsEntity(c->ptA) || if(!SS.clipboard.ContainsEntity(c->ptA) ||
@ -124,7 +133,8 @@ void GraphicsWindow::CopySelection(void) {
!SS.clipboard.ContainsEntity(c->entityA) || !SS.clipboard.ContainsEntity(c->entityA) ||
!SS.clipboard.ContainsEntity(c->entityB) || !SS.clipboard.ContainsEntity(c->entityB) ||
!SS.clipboard.ContainsEntity(c->entityC) || !SS.clipboard.ContainsEntity(c->entityC) ||
!SS.clipboard.ContainsEntity(c->entityD)) { !SS.clipboard.ContainsEntity(c->entityD) ||
c->type == Constraint::COMMENT) {
continue; continue;
} }
SS.clipboard.c.Add(c); SS.clipboard.c.Add(c);
@ -201,7 +211,27 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) {
c.other2 = cc->other2; c.other2 = cc->other2;
c.reference = cc->reference; c.reference = cc->reference;
c.disp = cc->disp; c.disp = cc->disp;
Constraint::AddConstraint(&c, /*rememberForUndo=*/false); c.comment = cc->comment;
switch(c.type) {
case Constraint::COMMENT:
c.disp.offset = c.disp.offset.Plus(trans);
break;
case Constraint::PT_PT_DISTANCE:
case Constraint::PT_LINE_DISTANCE:
case Constraint::PROJ_PT_DISTANCE:
case Constraint::DIAMETER:
c.valA *= fabs(scale);
break;
default:
break;
}
hConstraint hc = Constraint::AddConstraint(&c, /*rememberForUndo=*/false);
if(c.type == Constraint::COMMENT) {
MakeSelected(hc);
}
} }
SS.ScheduleGenerateAll(); SS.ScheduleGenerateAll();

View File

@ -221,6 +221,9 @@ CONVERT(Rect)
CGContextDrawImage((CGContextRef) [[NSGraphicsContext currentContext] graphicsPort], CGContextDrawImage((CGContextRef) [[NSGraphicsContext currentContext] graphicsPort],
[self bounds], image); [self bounds], image);
CGImageRelease(image);
CGDataProviderRelease(provider);
} }
- (void)drawGL { - (void)drawGL {
@ -371,8 +374,6 @@ CONVERT(Rect)
if(NSString *nsChr = [event charactersIgnoringModifiers]) if(NSString *nsChr = [event charactersIgnoringModifiers])
chr = [nsChr characterAtIndex:0]; chr = [nsChr characterAtIndex:0];
if(chr == NSDeleteCharacter) /* map delete back to backspace */
chr = '\b';
if(chr >= NSF1FunctionKey && chr <= NSF12FunctionKey) if(chr >= NSF1FunctionKey && chr <= NSF12FunctionKey)
chr = SolveSpace::GraphicsWindow::FUNCTION_KEY_BASE + (chr - NSF1FunctionKey); chr = SolveSpace::GraphicsWindow::FUNCTION_KEY_BASE + (chr - NSF1FunctionKey);
@ -397,7 +398,7 @@ CONVERT(Rect)
.x = xy.x + size.width / 2, .x = xy.x + size.width / 2,
.y = xy.y - size.height / 2 .y = xy.y - size.height / 2
}; };
[[self window] becomeKeyWindow]; [[self window] makeKeyWindow];
[super startEditing:text at:[self convertPointFromBacking:point] [super startEditing:text at:[self convertPointFromBacking:point]
withHeight:fontHeight usingMonospace:FALSE]; withHeight:fontHeight usingMonospace:FALSE];
[self prepareEditorWithMinWidthInChars:minWidthChars]; [self prepareEditorWithMinWidthInChars:minWidthChars];
@ -647,12 +648,15 @@ void InitMainMenu(NSMenu *mainMenu) {
label = [[NSString stringWithUTF8String:entry->label] label = [[NSString stringWithUTF8String:entry->label]
stringByReplacingOccurrencesOfString:@"&" withString:@""]; stringByReplacingOccurrencesOfString:@"&" withString:@""];
unichar accel_char = entry->accel & unichar accelChar = entry->accel &
~(GraphicsWindow::SHIFT_MASK | GraphicsWindow::CTRL_MASK); ~(GraphicsWindow::SHIFT_MASK | GraphicsWindow::CTRL_MASK);
if(accel_char > GraphicsWindow::FUNCTION_KEY_BASE && if(accelChar > GraphicsWindow::FUNCTION_KEY_BASE &&
accel_char <= GraphicsWindow::FUNCTION_KEY_BASE + 12) accelChar <= GraphicsWindow::FUNCTION_KEY_BASE + 12) {
accel_char = NSF1FunctionKey + (accel_char - GraphicsWindow::FUNCTION_KEY_BASE - 1); accelChar = NSF1FunctionKey + (accelChar - GraphicsWindow::FUNCTION_KEY_BASE - 1);
NSString *accel = [NSString stringWithCharacters:&accel_char length:1]; } else if(accelChar == GraphicsWindow::DELETE_KEY) {
accelChar = NSBackspaceCharacter;
}
NSString *accel = [NSString stringWithCharacters:&accelChar length:1];
menuItem = [levels[entry->level] addItemWithTitle:label menuItem = [levels[entry->level] addItemWithTitle:label
action:NULL keyEquivalent:[accel lowercaseString]]; action:NULL keyEquivalent:[accel lowercaseString]];
@ -806,6 +810,9 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension,
if(defExtension != "") { if(defExtension != "") {
extensionIndex = [extensions indexOfObject: extensionIndex = [extensions indexOfObject:
[NSString stringWithUTF8String:defExtension.c_str()]]; [NSString stringWithUTF8String:defExtension.c_str()]];
if(extensionIndex == -1) {
extensionIndex = 0;
}
} }
[button selectItemAtIndex:extensionIndex]; [button selectItemAtIndex:extensionIndex];
@ -1021,16 +1028,16 @@ void InitTextWindow() {
NSUtilityWindowMask)]; NSUtilityWindowMask)];
[[TW standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; [[TW standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[TW standardWindowButton:NSWindowZoomButton] setHidden:YES]; [[TW standardWindowButton:NSWindowZoomButton] setHidden:YES];
[TW setTitle:@"Browser"]; [TW setTitle:@"Property Browser"];
[TW setFrameAutosaveName:@"TextWindow"]; [TW setFrameAutosaveName:@"TextWindow"];
[TW setFloatingPanel:YES]; [TW setFloatingPanel:YES];
[TW setBecomesKeyOnlyIfNeeded:YES]; [TW setBecomesKeyOnlyIfNeeded:YES];
[GW addChildWindow:TW ordered:NSWindowAbove];
NSScrollView *scrollView = [[NSScrollView alloc] init]; NSScrollView *scrollView = [[NSScrollView alloc] init];
[TW setContentView:scrollView]; [TW setContentView:scrollView];
[scrollView setBackgroundColor:[NSColor blackColor]]; [scrollView setBackgroundColor:[NSColor blackColor]];
[scrollView setHasVerticalScroller:YES]; [scrollView setHasVerticalScroller:YES];
[scrollView setScrollerKnobStyle:NSScrollerKnobStyleLight];
[[scrollView contentView] setCopiesOnScroll:YES]; [[scrollView contentView] setCopiesOnScroll:YES];
TWView = [[TextWindowView alloc] init]; TWView = [[TextWindowView alloc] init];
@ -1089,6 +1096,7 @@ bool TextEditControlIsVisible(void) {
void SolveSpace::DoMessageBox(const char *str, int rows, int cols, bool error) { void SolveSpace::DoMessageBox(const char *str, int rows, int cols, bool error) {
NSAlert *alert = [[NSAlert alloc] init]; NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:(error ? NSWarningAlertStyle : NSInformationalAlertStyle)]; [alert setAlertStyle:(error ? NSWarningAlertStyle : NSInformationalAlertStyle)];
[alert addButtonWithTitle:@"OK"];
/* do some additional formatting of the message these are /* do some additional formatting of the message these are
heuristics, but they are made failsafe and lead to nice results. */ heuristics, but they are made failsafe and lead to nice results. */
@ -1153,8 +1161,6 @@ std::vector<std::string> SolveSpace::GetFontFiles() {
} }
- (void)applicationWillTerminate:(NSNotification *)aNotification { - (void)applicationWillTerminate:(NSNotification *)aNotification {
SolveSpace::SK.Clear();
SolveSpace::SS.Clear();
SolveSpace::SS.Exit(); SolveSpace::SS.Exit();
} }
@ -1172,6 +1178,155 @@ void SolveSpace::ExitNow(void) {
[NSApp stop:nil]; [NSApp stop:nil];
} }
/*
* Normally we would just link to the 3DconnexionClient framework.
* We don't want to (are not allowed to) distribute the official
* framework, so we're trying to use the one installed on the users
* computer. There are some different versions of the framework,
* the official one and re-implementations using an open source driver
* for older devices (spacenav-plus). So weak-linking isn't an option,
* either. The only remaining way is using CFBundle to dynamically
* load the library at runtime, and also detect its availability.
*
* We're also defining everything needed from the 3DconnexionClientAPI,
* so we're not depending on the API headers.
*/
#pragma pack(push,2)
enum {
kConnexionClientModeTakeOver = 1,
kConnexionClientModePlugin = 2
};
#define kConnexionMsgDeviceState '3dSR'
#define kConnexionMaskButtons 0x00FF
#define kConnexionMaskAxis 0x3F00
typedef struct {
uint16_t version;
uint16_t client;
uint16_t command;
int16_t param;
int32_t value;
UInt64 time;
uint8_t report[8];
uint16_t buttons8;
int16_t axis[6];
uint16_t address;
uint32_t buttons;
} ConnexionDeviceState, *ConnexionDeviceStatePtr;
#pragma pack(pop)
typedef void (*ConnexionAddedHandlerProc)(io_connect_t);
typedef void (*ConnexionRemovedHandlerProc)(io_connect_t);
typedef void (*ConnexionMessageHandlerProc)(io_connect_t, natural_t, void *);
typedef OSErr (*InstallConnexionHandlersProc)(ConnexionMessageHandlerProc, ConnexionAddedHandlerProc, ConnexionRemovedHandlerProc);
typedef void (*CleanupConnexionHandlersProc)(void);
typedef UInt16 (*RegisterConnexionClientProc)(UInt32, UInt8 *, UInt16, UInt32);
typedef void (*UnregisterConnexionClientProc)(UInt16);
static BOOL connexionShiftIsDown = NO;
static UInt16 connexionClient = 0;
static UInt32 connexionSignature = 'SoSp';
static UInt8 *connexionName = (UInt8 *)"SolveSpace";
static CFBundleRef spaceBundle = NULL;
static InstallConnexionHandlersProc installConnexionHandlers = NULL;
static CleanupConnexionHandlersProc cleanupConnexionHandlers = NULL;
static RegisterConnexionClientProc registerConnexionClient = NULL;
static UnregisterConnexionClientProc unregisterConnexionClient = NULL;
static void connexionAdded(io_connect_t con) {}
static void connexionRemoved(io_connect_t con) {}
static void connexionMessage(io_connect_t con, natural_t type, void *arg) {
if (type != kConnexionMsgDeviceState) {
return;
}
ConnexionDeviceState *device = (ConnexionDeviceState *)arg;
dispatch_async(dispatch_get_main_queue(), ^(void){
SolveSpace::SS.GW.SpaceNavigatorMoved(
(double)device->axis[0] * -0.25,
(double)device->axis[1] * -0.25,
(double)device->axis[2] * 0.25,
(double)device->axis[3] * -0.0005,
(double)device->axis[4] * -0.0005,
(double)device->axis[5] * -0.0005,
(connexionShiftIsDown == YES) ? 1 : 0
);
});
}
static void connexionInit() {
NSString *bundlePath = @"/Library/Frameworks/3DconnexionClient.framework";
NSURL *bundleURL = [NSURL fileURLWithPath:bundlePath];
spaceBundle = CFBundleCreate(kCFAllocatorDefault, (__bridge CFURLRef)bundleURL);
// Don't continue if no Spacemouse driver is installed on this machine
if (spaceBundle == NULL) {
return;
}
installConnexionHandlers = (InstallConnexionHandlersProc)
CFBundleGetFunctionPointerForName(spaceBundle,
CFSTR("InstallConnexionHandlers"));
cleanupConnexionHandlers = (CleanupConnexionHandlersProc)
CFBundleGetFunctionPointerForName(spaceBundle,
CFSTR("CleanupConnexionHandlers"));
registerConnexionClient = (RegisterConnexionClientProc)
CFBundleGetFunctionPointerForName(spaceBundle,
CFSTR("RegisterConnexionClient"));
unregisterConnexionClient = (UnregisterConnexionClientProc)
CFBundleGetFunctionPointerForName(spaceBundle,
CFSTR("UnregisterConnexionClient"));
// Only continue if all required symbols have been loaded
if ((installConnexionHandlers == NULL) || (cleanupConnexionHandlers == NULL)
|| (registerConnexionClient == NULL) || (unregisterConnexionClient == NULL)) {
CFRelease(spaceBundle);
spaceBundle = NULL;
return;
}
installConnexionHandlers(&connexionMessage, &connexionAdded, &connexionRemoved);
connexionClient = registerConnexionClient(connexionSignature, connexionName,
kConnexionClientModeTakeOver, kConnexionMaskButtons | kConnexionMaskAxis);
// Monitor modifier flags to detect Shift button state changes
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyDownMask | NSFlagsChangedMask)
handler:^(NSEvent *event) {
if (event.modifierFlags & NSShiftKeyMask) {
connexionShiftIsDown = YES;
}
return event;
}];
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyUpMask | NSFlagsChangedMask)
handler:^(NSEvent *event) {
if (!(event.modifierFlags & NSShiftKeyMask)) {
connexionShiftIsDown = NO;
}
return event;
}];
}
static void connexionClose() {
if (spaceBundle == NULL) {
return;
}
unregisterConnexionClient(connexionClient);
cleanupConnexionHandlers();
CFRelease(spaceBundle);
}
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
[NSApplication sharedApplication]; [NSApplication sharedApplication];
ApplicationDelegate *delegate = [[ApplicationDelegate alloc] init]; ApplicationDelegate *delegate = [[ApplicationDelegate alloc] init];
@ -1182,11 +1337,15 @@ int main(int argc, const char *argv[]) {
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:nil topLevelObjects:nil]; [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:nil topLevelObjects:nil];
SolveSpace::InitMainMenu([NSApp mainMenu]); SolveSpace::InitMainMenu([NSApp mainMenu]);
connexionInit();
SolveSpace::SS.Init(); SolveSpace::SS.Init();
[GW makeKeyAndOrderFront:nil]; [GW makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
[NSApp run]; [NSApp run];
connexionClose();
SolveSpace::SK.Clear();
SolveSpace::SS.Clear();
return 0; return 0;
} }

View File

@ -453,6 +453,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
} else { } else {
Error("Bad format: specify interval in integral minutes"); Error("Bad format: specify interval in integral minutes");
} }
break;
} }
default: return false; default: return false;

View File

@ -370,6 +370,7 @@ void Constraint::MenuConstrain(int id) {
((gs.workplanes == 1 && gs.n == 3) || ((gs.workplanes == 1 && gs.n == 3) ||
(gs.n == 2))) (gs.n == 2)))
{ {
if(gs.entities > 0)
c.entityA = gs.entity[0]; c.entityA = gs.entity[0];
c.ptA = gs.point[0]; c.ptA = gs.point[0];
c.ptB = gs.point[1]; c.ptB = gs.point[1];
@ -377,9 +378,13 @@ void Constraint::MenuConstrain(int id) {
((gs.workplanes == 1 && gs.n == 2) || ((gs.workplanes == 1 && gs.n == 2) ||
(gs.n == 1))) (gs.n == 1)))
{ {
int i = SK.GetEntity(gs.entity[0])->IsWorkplane() ? 1 : 0; Entity *line;
Entity *line = SK.GetEntity(gs.entity[i]); if(SK.GetEntity(gs.entity[0])->IsWorkplane()) {
c.entityA = gs.entity[1-i]; line = SK.GetEntity(gs.entity[1]);
c.entityA = gs.entity[0];
} else {
line = SK.GetEntity(gs.entity[0]);
}
c.ptA = line->point[0]; c.ptA = line->point[0];
c.ptB = line->point[1]; c.ptB = line->point[1];
} else if(SS.GW.LockedInWorkplane() } else if(SS.GW.LockedInWorkplane()

View File

@ -156,6 +156,13 @@ void GraphicsWindow::MakeSelected(hEntity he) {
stog.entity = he; stog.entity = he;
MakeSelected(&stog); MakeSelected(&stog);
} }
void GraphicsWindow::MakeSelected(hConstraint hc) {
Selection stog = {};
stog.constraint = hc;
MakeSelected(&stog);
}
void GraphicsWindow::MakeSelected(Selection *stog) { void GraphicsWindow::MakeSelected(Selection *stog) {
if(stog->IsEmpty()) return; if(stog->IsEmpty()) return;
if(IsSelected(stog)) return; if(IsSelected(stog)) return;
@ -242,7 +249,7 @@ void GraphicsWindow::SelectByMarquee(void) {
void GraphicsWindow::GroupSelection(void) { void GraphicsWindow::GroupSelection(void) {
gs = {}; gs = {};
int i; int i;
for(i = 0; i < selection.n && i < MAX_SELECTED; i++) { for(i = 0; i < selection.n; i++) {
Selection *s = &(selection.elem[i]); Selection *s = &(selection.elem[i]);
if(s->entity.v) { if(s->entity.v) {
(gs.n)++; (gs.n)++;
@ -253,27 +260,33 @@ void GraphicsWindow::GroupSelection(void) {
// A list of points, and a list of all entities that aren't points. // A list of points, and a list of all entities that aren't points.
if(e->IsPoint()) { if(e->IsPoint()) {
gs.point[(gs.points)++] = s->entity; gs.points++;
gs.point.push_back(s->entity);
} else { } else {
gs.entity[(gs.entities)++] = s->entity; gs.entities++;
gs.entity.push_back(s->entity);
} }
// And an auxiliary list of normals, including normals from // And an auxiliary list of normals, including normals from
// workplanes. // workplanes.
if(e->IsNormal()) { if(e->IsNormal()) {
gs.anyNormal[(gs.anyNormals)++] = s->entity; gs.anyNormals++;
gs.anyNormal.push_back(s->entity);
} else if(e->IsWorkplane()) { } else if(e->IsWorkplane()) {
gs.anyNormal[(gs.anyNormals)++] = e->Normal()->h; gs.anyNormals++;
gs.anyNormal.push_back(e->Normal()->h);
} }
// And of vectors (i.e., stuff with a direction to constrain) // And of vectors (i.e., stuff with a direction to constrain)
if(e->HasVector()) { if(e->HasVector()) {
gs.vector[(gs.vectors)++] = s->entity; gs.vectors++;
gs.vector.push_back(s->entity);
} }
// Faces (which are special, associated/drawn with triangles) // Faces (which are special, associated/drawn with triangles)
if(e->IsFace()) { if(e->IsFace()) {
gs.face[(gs.faces)++] = s->entity; gs.faces++;
gs.face.push_back(s->entity);
} }
if(e->HasEndpoints()) { if(e->HasEndpoints()) {
@ -296,7 +309,8 @@ void GraphicsWindow::GroupSelection(void) {
} }
} }
if(s->constraint.v) { if(s->constraint.v) {
gs.constraint[(gs.constraints)++] = s->constraint; gs.constraints++;
gs.constraint.push_back(s->constraint);
Constraint *c = SK.GetConstraint(s->constraint); Constraint *c = SK.GetConstraint(s->constraint);
if(c->IsStylable()) gs.stylables++; if(c->IsStylable()) gs.stylables++;
if(c->HasLabel()) gs.constraintLabels++; if(c->HasLabel()) gs.constraintLabels++;

View File

@ -661,8 +661,8 @@ void Entity::DrawOrGetDistance(void) {
} }
if(!h.isFromRequest()) { if(!h.isFromRequest()) {
mm = mm.Plus(v.ScaledBy(60/SS.GW.scale)); mm = mm.Plus(v.ScaledBy(70/SS.GW.scale));
mm2 = mm2.Plus(u.ScaledBy(60/SS.GW.scale)); mm2 = mm2.Plus(u.ScaledBy(70/SS.GW.scale));
LineDrawOrGetDistance(mm2, mm); LineDrawOrGetDistance(mm2, mm);
} }
LineDrawOrGetDistance(pp, pm); LineDrawOrGetDistance(pp, pm);
@ -676,7 +676,9 @@ void Entity::DrawOrGetDistance(void) {
std::string str = DescriptionString().substr(5); std::string str = DescriptionString().substr(5);
double th = Style::DefaultTextHeight(); double th = Style::DefaultTextHeight();
if(dogd.drawing) { if(dogd.drawing) {
ssglWriteText(str, th, mm2, u, v, NULL, NULL); Vector o = mm2.Plus(u.ScaledBy(3/SS.GW.scale)).Plus(
v.ScaledBy(3/SS.GW.scale));
ssglWriteText(str, th, o, u, v, NULL, NULL);
} else { } else {
Vector pos = mm2.Plus(u.ScaledBy(ssglStrWidth(str, th)/2)).Plus( Vector pos = mm2.Plus(u.ScaledBy(ssglStrWidth(str, th)/2)).Plus(
v.ScaledBy(ssglStrCapHeight(th)/2)); v.ScaledBy(ssglStrCapHeight(th)/2));

View File

@ -859,6 +859,8 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const std::string &filename,
<script> <script>
</script> </script>
<script> <script>
window.devicePixelRatio = window.devicePixelRatio || 1;
SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset) { SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset) {
THREE.Camera.call(this); THREE.Camera.call(this);
@ -1014,13 +1016,13 @@ SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset)
switch (event.button) { switch (event.button) {
case 0: case 0:
_rotateCur.set(event.screenX, event.screenY); _rotateCur.set(event.screenX/window.devicePixelRatio, event.screenY/window.devicePixelRatio);
_rotatePrev.copy(_rotateCur); _rotatePrev.copy(_rotateCur);
document.addEventListener('mousemove', mousemove, false); document.addEventListener('mousemove', mousemove, false);
document.addEventListener('mouseup', mouseup, false); document.addEventListener('mouseup', mouseup, false);
break; break;
case 2: case 2:
_offsetCur.set(event.screenX, event.screenY); _offsetCur.set(event.screenX/window.devicePixelRatio, event.screenY/window.devicePixelRatio);
_offsetPrev.copy(_offsetCur); _offsetPrev.copy(_offsetCur);
document.addEventListener('mousemove', mousemove, false); document.addEventListener('mousemove', mousemove, false);
document.addEventListener('mouseup', mouseup, false); document.addEventListener('mouseup', mouseup, false);
@ -1043,7 +1045,7 @@ SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset)
function mousemove(event) { function mousemove(event) {
switch (event.button) { switch (event.button) {
case 0: case 0:
_rotateCur.set(event.screenX, event.screenY); _rotateCur.set(event.screenX/window.devicePixelRatio, event.screenY/window.devicePixelRatio);
var diff = new THREE.Vector2().subVectors(_rotateCur, _rotatePrev) var diff = new THREE.Vector2().subVectors(_rotateCur, _rotatePrev)
.multiplyScalar(1 / object.zoomScale); .multiplyScalar(1 / object.zoomScale);
object.rotate(-0.3 * Math.PI / 180 * diff.x * object.zoomScale, object.rotate(-0.3 * Math.PI / 180 * diff.x * object.zoomScale,
@ -1053,7 +1055,7 @@ SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset)
break; break;
case 2: case 2:
_mouseMoved = true; _mouseMoved = true;
_offsetCur.set(event.screenX, event.screenY); _offsetCur.set(event.screenX/window.devicePixelRatio, event.screenY/window.devicePixelRatio);
var diff = new THREE.Vector2().subVectors(_offsetCur, _offsetPrev) var diff = new THREE.Vector2().subVectors(_offsetCur, _offsetPrev)
.multiplyScalar(1 / object.zoomScale); .multiplyScalar(1 / object.zoomScale);
object.offsetProj(diff.x, -diff.y); object.offsetProj(diff.x, -diff.y);
@ -1197,6 +1199,9 @@ SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset)
height = params.height; height = params.height;
} }
width *= window.devicePixelRatio;
height *= window.devicePixelRatio;
domElement = init(); domElement = init();
render(); render();
return domElement; return domElement;
@ -1206,8 +1211,8 @@ SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset)
scene = new THREE.Scene(); scene = new THREE.Scene();
edgeScene = new THREE.Scene(); edgeScene = new THREE.Scene();
camera = new SolvespaceCamera(width, camera = new SolvespaceCamera(width/window.devicePixelRatio,
height, 5, new THREE.Vector3(0, 1, 0), height/window.devicePixelRatio, 5, new THREE.Vector3(0, 1, 0),
new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 0)); new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 0));
mesh = createMesh(obj); mesh = createMesh(obj);
@ -1232,6 +1237,7 @@ SolvespaceCamera = function(renderWidth, renderHeight, scale, up, right, offset)
renderer = new THREE.WebGLRenderer({ antialias: true}); renderer = new THREE.WebGLRenderer({ antialias: true});
renderer.setSize(width, height); renderer.setSize(width, height);
renderer.autoClear = false; renderer.autoClear = false;
renderer.domElement.style = "width:"+width/window.devicePixelRatio+"px;height:"+height/window.devicePixelRatio+"px;";
controls = new SolvespaceControls(camera, renderer.domElement); controls = new SolvespaceControls(camera, renderer.domElement);
controls.addEventListener("change", render); controls.addEventListener("change", render);

View File

@ -175,21 +175,16 @@ public:
layer.name = "text"; layer.name = "text";
dxf->writeLayer(&layer); dxf->writeLayer(&layer);
for(int i = 0; i < SK.style.n; i++) { std::set<uint32_t> usedStyles;
Style *s = &SK.style.elem[i];
// check for using
bool used = false;
for(DxfFileWriter::BezierPath &path : writer->paths) { for(DxfFileWriter::BezierPath &path : writer->paths) {
for(SBezier *sb : path.beziers) { for(SBezier *sb : path.beziers) {
if((uint32_t)sb->auxA != s->h.v) continue; usedStyles.insert((uint32_t)sb->auxA);
used = true;
break;
} }
if(used) break;
} }
if(!used) continue;
for(uint32_t v : usedStyles) {
Style *s = Style::Get(hStyle{v});
layer.name = s->DescriptionString(); layer.name = s->DescriptionString();
dxf->writeLayer(&layer); dxf->writeLayer(&layer);
} }
@ -264,14 +259,17 @@ public:
found = true; found = true;
e->tag = 1; e->tag = 1;
DRW_LWPolyline polyline; DRW_Polyline polyline;
assignEntityDefaults(&polyline, e->style); assignEntityDefaults(&polyline, e->style);
polyline.vertlist.push_back(new DRW_Vertex2D(start->pos.x, start->pos.y, 0.0)); polyline.vertlist.push_back(
polyline.vertlist.push_back(new DRW_Vertex2D(next->pos.x, next->pos.y, 0.0)); new DRW_Vertex(start->pos.x, start->pos.y, start->pos.z, 0.0));
polyline.vertlist.push_back(
new DRW_Vertex(next->pos.x, next->pos.y, next->pos.z, 0.0));
while(next->getNext(e->style, &next)) { while(next->getNext(e->style, &next)) {
polyline.vertlist.push_back(new DRW_Vertex2D(next->pos.x, next->pos.y, 0.0)); polyline.vertlist.push_back(
new DRW_Vertex(next->pos.x, next->pos.y, next->pos.z, 0.0));
} }
dxf->writeLWPolyline(&polyline); dxf->writePolyline(&polyline);
} }
if(!found && !loop) { if(!found && !loop) {
@ -484,16 +482,14 @@ public:
List<Vector> lv = {}; List<Vector> lv = {};
sb->MakePwlInto(&lv, SS.ExportChordTolMm()); sb->MakePwlInto(&lv, SS.ExportChordTolMm());
hStyle hs = { (uint32_t)sb->auxA }; hStyle hs = { (uint32_t)sb->auxA };
DRW_LWPolyline polyline; DRW_Polyline polyline;
assignEntityDefaults(&polyline, hs); assignEntityDefaults(&polyline, hs);
for(int i = 0; i < lv.n; i++) { for(int i = 0; i < lv.n; i++) {
Vector *v = &lv.elem[i]; Vector *v = &lv.elem[i];
DRW_Vertex2D *vertex = new DRW_Vertex2D(); DRW_Vertex *vertex = new DRW_Vertex(v->x, v->y, v->z, 0.0);
vertex->x = v->x;
vertex->y = v->y;
polyline.vertlist.push_back(vertex); polyline.vertlist.push_back(vertex);
} }
dxf->writeLWPolyline(&polyline); dxf->writePolyline(&polyline);
lv.Clear(); lv.Clear();
} }
@ -532,7 +528,8 @@ public:
spline.ncontrol = sb->deg + 1; spline.ncontrol = sb->deg + 1;
makeKnotsFor(&spline); makeKnotsFor(&spline);
for(int i = 0; i <= sb->deg; i++) { for(int i = 0; i <= sb->deg; i++) {
spline.controllist.push_back(new DRW_Coord(sb->ctrl[i].x, sb->ctrl[i].y, 0.0)); spline.controllist.push_back(
new DRW_Coord(sb->ctrl[i].x, sb->ctrl[i].y, sb->ctrl[i].z));
if(isRational) spline.weightlist.push_back(sb->weight[i]); if(isRational) spline.weightlist.push_back(sb->weight[i]);
} }
dxf->writeSpline(&spline); dxf->writeSpline(&spline);
@ -689,12 +686,19 @@ void DxfFileWriter::Bezier(SBezier *sb) {
paths.back().beziers.push_back(sb); paths.back().beziers.push_back(sb);
} }
void DxfFileWriter::FinishAndCloseFile(void) { void DxfFileWriter::FinishAndCloseFile() {
dxfRW dxf(filename.c_str()); dxfRW dxf;
DxfWriteInterface interface(this, &dxf); DxfWriteInterface interface(this, &dxf);
dxf.write(&interface, DRW::AC1021, false); std::stringstream stream;
dxf.write(stream, &interface, DRW::AC1021, /*bin=*/false);
paths.clear(); paths.clear();
constraint = NULL; constraint = NULL;
if(!WriteFile(filename, stream.str())) {
Error("Couldn't write to '%s'", filename.c_str());
return;
}
} }
bool DxfFileWriter::NeedToOutput(Constraint *c) { bool DxfFileWriter::NeedToOutput(Constraint *c) {

View File

@ -806,6 +806,8 @@ bool SolveSpaceUI::ReloadAllImported(bool canCancel)
g->linkFile = newPath; g->linkFile = newPath;
} }
// In a newly created group we only have an absolute path.
if(!g->linkFileRel.empty()) {
std::string rel = PathSepUNIXToPlatform(g->linkFileRel); std::string rel = PathSepUNIXToPlatform(g->linkFileRel);
std::string fromRel = MakePathAbsolute(SS.saveFile, rel); std::string fromRel = MakePathAbsolute(SS.saveFile, rel);
FILE *test = ssfopen(fromRel, "rb"); FILE *test = ssfopen(fromRel, "rb");
@ -818,6 +820,7 @@ bool SolveSpaceUI::ReloadAllImported(bool canCancel)
// can use the absolute filename to get us back. The relative path will be // can use the absolute filename to get us back. The relative path will be
// updated below. // updated below.
} }
}
try_load_file: try_load_file:
if(LoadEntitiesFromFile(g->linkFile, &(g->impEntity), &(g->impMesh), &(g->impShell))) if(LoadEntitiesFromFile(g->linkFile, &(g->impEntity), &(g->impMesh), &(g->impShell)))

Binary file not shown.

View File

@ -205,7 +205,7 @@ void SolveSpaceUI::GenerateAll(GenerateType type, bool andFindFree, bool genForB
// If we're generating entities for display, first we need to find // If we're generating entities for display, first we need to find
// the bounding box to turn relative chord tolerance to absolute. // the bounding box to turn relative chord tolerance to absolute.
if(!SS.exportMode && !genForBBox) { if(!SS.exportMode && !genForBBox) {
GenerateAll(type, /*andFindFree=*/false, /*genForBBox=*/true); GenerateAll(type, andFindFree, /*genForBBox=*/true);
BBox box = SK.CalculateEntityBBox(/*includeInvisibles=*/true); BBox box = SK.CalculateEntityBBox(/*includeInvisibles=*/true);
Vector size = box.maxp.Minus(box.minp); Vector size = box.maxp.Minus(box.minp);
double maxSize = std::max({ size.x, size.y, size.z }); double maxSize = std::max({ size.x, size.y, size.z });
@ -293,7 +293,10 @@ void SolveSpaceUI::GenerateAll(GenerateType type, bool andFindFree, bool genForB
if(newp->known) continue; if(newp->known) continue;
Param *prevp = prev.FindByIdNoOops(newp->h); Param *prevp = prev.FindByIdNoOops(newp->h);
if(prevp) newp->val = prevp->val; if(prevp) {
newp->val = prevp->val;
newp->free = prevp->free;
}
} }
if(g->h.v == Group::HGROUP_REFERENCES.v) { if(g->h.v == Group::HGROUP_REFERENCES.v) {
@ -305,7 +308,7 @@ void SolveSpaceUI::GenerateAll(GenerateType type, bool andFindFree, bool genForB
// The group falls inside the range, so really solve it, // The group falls inside the range, so really solve it,
// and then regenerate the mesh based on the solved stuff. // and then regenerate the mesh based on the solved stuff.
if(genForBBox) { if(genForBBox) {
SolveGroup(g->h, andFindFree); SolveGroupAndReport(g->h, andFindFree);
} else { } else {
g->GenerateLoops(); g->GenerateLoops();
g->GenerateShellAndMesh(); g->GenerateShellAndMesh();
@ -488,6 +491,23 @@ void SolveSpaceUI::MarkDraggedParams(void) {
} }
} }
void SolveSpaceUI::SolveGroupAndReport(hGroup hg, bool andFindFree) {
SolveGroup(hg, andFindFree);
Group *g = SK.GetGroup(hg);
if(g->solved.how == System::REDUNDANT_OKAY) {
// Solve again, in case we lost a degree of freedom because of a numeric error.
SolveGroup(hg, andFindFree);
}
bool isOkay = g->solved.how == System::SOLVED_OKAY ||
(g->allowRedundant && g->solved.how == System::REDUNDANT_OKAY);
if(!isOkay || (isOkay && !g->IsSolvedOkay())) {
TextWindow::ReportHowGroupSolved(g->h);
}
}
void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) { void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
int i; int i;
// Clear out the system to be solved. // Clear out the system to be solved.
@ -515,12 +535,6 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
g->solved.remove.Clear(); g->solved.remove.Clear();
int how = sys.Solve(g, &(g->solved.dof), int how = sys.Solve(g, &(g->solved.dof),
&(g->solved.remove), true, andFindFree); &(g->solved.remove), true, andFindFree);
bool isOkay = how == System::SOLVED_OKAY ||
(g->allowRedundant && how == System::REDUNDANT_OKAY);
if(!isOkay || (isOkay && !g->IsSolvedOkay()))
{
TextWindow::ReportHowGroupSolved(g->h);
}
g->solved.how = how; g->solved.how = how;
FreeAllTemporary(); FreeAllTemporary();
} }

View File

@ -81,7 +81,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Show Menu &Bar", MNU_SHOW_MENU_BAR, C|F(12), TC, mView }, { 1, "Show Menu &Bar", MNU_SHOW_MENU_BAR, C|F(12), TC, mView },
#endif #endif
{ 1, "Show &Toolbar", MNU_SHOW_TOOLBAR, 0, TC, mView }, { 1, "Show &Toolbar", MNU_SHOW_TOOLBAR, 0, TC, mView },
{ 1, "Show Text &Window", MNU_SHOW_TEXT_WND, '\t', TC, mView }, { 1, "Show Property Bro&wser", MNU_SHOW_TEXT_WND, '\t', TC, mView },
{ 1, NULL, 0, 0, TN, NULL }, { 1, NULL, 0, 0, TN, NULL },
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, TR, mView }, { 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, TR, mView },
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, TR, mView }, { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, TR, mView },
@ -488,7 +488,6 @@ void GraphicsWindow::MenuView(int id) {
case MNU_ONTO_WORKPLANE: case MNU_ONTO_WORKPLANE:
if(SS.GW.LockedInWorkplane()) { if(SS.GW.LockedInWorkplane()) {
SS.GW.AnimateOntoWorkplane(); SS.GW.AnimateOntoWorkplane();
SS.GW.ClearSuper();
SS.ScheduleShowTW(); SS.ScheduleShowTW();
break; break;
} // if not in 2d mode fall through and use ORTHO logic } // if not in 2d mode fall through and use ORTHO logic
@ -911,7 +910,8 @@ void GraphicsWindow::MenuEdit(int id) {
SS.MarkGroupDirty(ep->group); SS.MarkGroupDirty(ep->group);
} else if(s->constraint.v) { } else if(s->constraint.v) {
Constraint *c = SK.GetConstraint(s->constraint); Constraint *c = SK.GetConstraint(s->constraint);
c->disp.offset = SS.GW.SnapToGrid(c->disp.offset); Vector refp = c->GetReferencePos();
c->disp.offset = c->disp.offset.Plus(SS.GW.SnapToGrid(refp).Minus(refp));
} }
} }
// Regenerate, with these points marked as dragged so that they // Regenerate, with these points marked as dragged so that they

View File

@ -203,8 +203,10 @@ void Group::GenerateShellAndMesh(void) {
// not our own previous group. // not our own previous group.
srcg = SK.GetGroup(opA); srcg = SK.GetGroup(opA);
if(!srcg->suppress) {
GenerateForStepAndRepeat<SShell>(&(srcg->thisShell), &thisShell); GenerateForStepAndRepeat<SShell>(&(srcg->thisShell), &thisShell);
GenerateForStepAndRepeat<SMesh> (&(srcg->thisMesh), &thisMesh); GenerateForStepAndRepeat<SMesh> (&(srcg->thisMesh), &thisMesh);
}
} else if(type == EXTRUDE && haveSrc) { } else if(type == EXTRUDE && haveSrc) {
Group *src = SK.GetGroup(opA); Group *src = SK.GetGroup(opA);
Vector translate = Vector::From(h.param(0), h.param(1), h.param(2)); Vector translate = Vector::From(h.param(0), h.param(1), h.param(2));

View File

@ -55,10 +55,7 @@
#include "../unix/gloffscreen.h" #include "../unix/gloffscreen.h"
#ifdef HAVE_SPACEWARE #ifdef HAVE_SPACEWARE
# include <spnav.h> #include <spnav.h>
# ifndef SI_APP_FIT_BUTTON
# define SI_APP_FIT_BUTTON 31
# endif
#endif #endif
namespace SolveSpace { namespace SolveSpace {
@ -368,6 +365,8 @@ private:
class EditorOverlay : public Gtk::Fixed { class EditorOverlay : public Gtk::Fixed {
public: public:
EditorOverlay(Gtk::Widget &underlay) : _underlay(underlay) { EditorOverlay(Gtk::Widget &underlay) : _underlay(underlay) {
set_size_request(0, 0);
add(_underlay); add(_underlay);
_entry.set_no_show_all(true); _entry.set_no_show_all(true);
@ -513,10 +512,6 @@ public:
set_double_buffered(true); set_double_buffered(true);
} }
void emulate_key_press(GdkEventKey *event) {
on_key_press_event(event);
}
protected: protected:
virtual bool on_configure_event(GdkEventConfigure *event) { virtual bool on_configure_event(GdkEventConfigure *event) {
_w = event->width; _w = event->width;
@ -596,45 +591,6 @@ protected:
return true; return true;
} }
virtual bool on_key_press_event(GdkEventKey *event) {
int chr;
switch(event->keyval) {
case GDK_KEY_Escape:
chr = GraphicsWindow::ESCAPE_KEY;
break;
case GDK_KEY_Delete:
chr = GraphicsWindow::DELETE_KEY;
break;
case GDK_KEY_Tab:
chr = '\t';
break;
case GDK_KEY_BackSpace:
case GDK_KEY_Back:
chr = '\b';
break;
default:
if(event->keyval >= GDK_KEY_F1 && event->keyval <= GDK_KEY_F12)
chr = GraphicsWindow::FUNCTION_KEY_BASE + (event->keyval - GDK_KEY_F1);
else
chr = gdk_keyval_to_unicode(event->keyval);
}
if(event->state & GDK_SHIFT_MASK)
chr |= GraphicsWindow::SHIFT_MASK;
if(event->state & GDK_CONTROL_MASK)
chr |= GraphicsWindow::CTRL_MASK;
if(chr && SS.GW.KeyDown(chr))
return true;
return false;
}
private: private:
int _w, _h; int _w, _h;
void ij_to_xy(int i, int j, int &x, int &y) { void ij_to_xy(int i, int j, int &x, int &y) {
@ -675,6 +631,10 @@ public:
return _is_fullscreen; return _is_fullscreen;
} }
bool emulate_key_press(GdkEventKey *event) {
return on_key_press_event(event);
}
protected: protected:
virtual void on_show() { virtual void on_show() {
Gtk::Window::on_show(); Gtk::Window::on_show();
@ -689,6 +649,7 @@ protected:
} }
virtual bool on_delete_event(GdkEventAny *) { virtual bool on_delete_event(GdkEventAny *) {
if(!SS.OkayToStartNewFile()) return true;
SS.Exit(); SS.Exit();
return true; return true;
@ -705,6 +666,55 @@ protected:
return Gtk::Window::on_window_state_event(event); return Gtk::Window::on_window_state_event(event);
} }
virtual bool on_key_press_event(GdkEventKey *event) {
int chr;
switch(event->keyval) {
case GDK_KEY_Escape:
chr = GraphicsWindow::ESCAPE_KEY;
break;
case GDK_KEY_Delete:
chr = GraphicsWindow::DELETE_KEY;
break;
case GDK_KEY_Tab:
chr = '\t';
break;
case GDK_KEY_BackSpace:
case GDK_KEY_Back:
chr = '\b';
break;
default:
if(event->keyval >= GDK_KEY_F1 && event->keyval <= GDK_KEY_F12) {
chr = GraphicsWindow::FUNCTION_KEY_BASE + (event->keyval - GDK_KEY_F1);
} else {
chr = gdk_keyval_to_unicode(event->keyval);
}
}
if(event->state & GDK_SHIFT_MASK){
chr |= GraphicsWindow::SHIFT_MASK;
}
if(event->state & GDK_CONTROL_MASK) {
chr |= GraphicsWindow::CTRL_MASK;
}
if(chr && SS.GW.KeyDown(chr)) {
return true;
}
if(chr == '\t') {
// Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=123994.
GraphicsWindow::MenuView(GraphicsWindow::MNU_SHOW_TEXT_WND);
return true;
}
return Gtk::Window::on_key_press_event(event);
}
virtual void on_editing_done(Glib::ustring value) { virtual void on_editing_done(Glib::ustring value) {
SS.GW.EditControlDone(value.c_str()); SS.GW.EditControlDone(value.c_str());
} }
@ -900,6 +910,10 @@ public:
accel_key = GDK_KEY_Escape; accel_key = GDK_KEY_Escape;
break; break;
case '\t':
accel_key = GDK_KEY_Tab;
break;
default: default:
accel_key = _entry.accel & ~(GraphicsWindow::SHIFT_MASK | GraphicsWindow::CTRL_MASK); accel_key = _entry.accel & ~(GraphicsWindow::SHIFT_MASK | GraphicsWindow::CTRL_MASK);
if(accel_key > GraphicsWindow::FUNCTION_KEY_BASE && if(accel_key > GraphicsWindow::FUNCTION_KEY_BASE &&
@ -1069,6 +1083,7 @@ static std::string ConvertFilters(std::string active, const FileFilter ssFilters
for(const char *const *ssPattern = ssFilter->patterns; *ssPattern; ssPattern++) { for(const char *const *ssPattern = ssFilter->patterns; *ssPattern; ssPattern++) {
std::string pattern = "*." + std::string(*ssPattern); std::string pattern = "*." + std::string(*ssPattern);
filter->add_pattern(pattern); filter->add_pattern(pattern);
filter->add_pattern(Glib::ustring(pattern).uppercase());
if(active == "") if(active == "")
active = pattern.substr(2); active = pattern.substr(2);
if("*." + active == pattern) if("*." + active == pattern)
@ -1324,7 +1339,7 @@ public:
set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY); set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY);
set_skip_taskbar_hint(true); set_skip_taskbar_hint(true);
set_skip_pager_hint(true); set_skip_pager_hint(true);
set_title("SolveSpace - Browser"); set_title("SolveSpace - Property Browser");
set_default_size(420, 300); set_default_size(420, 300);
_box.pack_start(_overlay, true, true); _box.pack_start(_overlay, true, true);
@ -1391,6 +1406,14 @@ protected:
return _widget.event((GdkEvent*) event); return _widget.event((GdkEvent*) event);
} }
virtual bool on_key_press_event(GdkEventKey *event) {
if(GW->emulate_key_press(event)) {
return true;
}
return Gtk::Window::on_key_press_event(event);
}
private: private:
Gtk::VScrollbar _scrollbar; Gtk::VScrollbar _scrollbar;
TextWidget _widget; TextWidget _widget;
@ -1497,7 +1520,7 @@ static GdkFilterReturn GdkSpnavFilter(GdkXEvent *gxevent, GdkEvent *, gpointer)
break; break;
case SPNAV_EVENT_BUTTON: case SPNAV_EVENT_BUTTON:
if(!sev.button.press && sev.button.bnum == SI_APP_FIT_BUTTON) { if(!sev.button.press && sev.button.bnum == 0) {
SS.GW.SpaceNavigatorButtonUp(); SS.GW.SpaceNavigatorButtonUp();
} }
break; break;
@ -1553,6 +1576,17 @@ int main(int argc, char** argv) {
TW->show_all(); TW->show_all();
GW->show_all(); GW->show_all();
#ifdef HAVE_SPACEWARE
#ifdef HAVE_GTK3
// We don't care if it can't be opened; just continue without.
spnav_x11_open(gdk_x11_get_default_xdisplay(),
gdk_x11_window_get_xid(GW->get_window()->gobj()));
#else
spnav_x11_open(gdk_x11_get_default_xdisplay(),
GDK_WINDOW_XWINDOW(GW->get_window()->gobj()));
#endif
#endif
SS.Init(); SS.Init();
if(argc >= 2) { if(argc >= 2) {

View File

@ -902,12 +902,21 @@ public:
}; };
void ImportDxf(const std::string &filename) { void ImportDxf(const std::string &filename) {
dxfRW dxf(filename.c_str());
DxfReadInterface interface; DxfReadInterface interface;
interface.clearBlockTransform(); interface.clearBlockTransform();
if(!dxf.read(&interface, false)) {
Error("Corrupted DXF file!"); std::string data;
if(!ReadFile(filename, &data)) {
Error("Couldn't read from '%s'", filename.c_str());
return;
} }
SS.UndoRemember();
std::stringstream stream(data);
if(!dxfRW().read(stream, &interface, /*ext=*/false)) {
Error("Corrupted DXF file.");
}
if(interface.unknownEntities > 0) { if(interface.unknownEntities > 0) {
Message(ssprintf("%u DXF entities of unknown type were ignored.", Message(ssprintf("%u DXF entities of unknown type were ignored.",
interface.unknownEntities).c_str()); interface.unknownEntities).c_str());
@ -915,12 +924,21 @@ void ImportDxf(const std::string &filename) {
} }
void ImportDwg(const std::string &filename) { void ImportDwg(const std::string &filename) {
dwgR dwg(filename.c_str());
DxfReadInterface interface; DxfReadInterface interface;
interface.clearBlockTransform(); interface.clearBlockTransform();
if(!dwg.read(&interface, false)) {
Error("Corrupted DWG file!"); std::string data;
if(!ReadFile(filename, &data)) {
Error("Couldn't read from '%s'", filename.c_str());
return;
} }
SS.UndoRemember();
std::stringstream stream(data);
if(!dwgR().read(stream, &interface, /*ext=*/false)) {
Error("Corrupted DWG file.");
}
if(interface.unknownEntities > 0) { if(interface.unknownEntities > 0) {
Message(ssprintf("%u DWG entities of unknown type were ignored.", Message(ssprintf("%u DWG entities of unknown type were ignored.",
interface.unknownEntities).c_str()); interface.unknownEntities).c_str());

View File

@ -34,7 +34,8 @@ void SMesh::AddTriangle(STriMeta meta, Vector a, Vector b, Vector c) {
AddTriangle(&t); AddTriangle(&t);
} }
void SMesh::AddTriangle(STriangle *st) { void SMesh::AddTriangle(STriangle *st) {
if(st->meta.color.alpha != 255) isTransparent = true; RgbaColor color = st->meta.color;
if(color.ToARGB32() != 0 && color.alpha != 255) isTransparent = true;
l.Add(st); l.Add(st);
} }

View File

@ -463,6 +463,15 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
pending.operation != DRAGGING_MARQUEE) pending.operation != DRAGGING_MARQUEE)
{ {
SS.GenerateAll(); SS.GenerateAll();
// Activate degraded mode, and regenerate display items without edges.
if(activeGroup.v != 0) {
bool showEdges = SS.GW.showEdges;
SS.GW.showEdges = false;
SK.GetGroup(activeGroup)->GenerateDisplayItems();
SS.GW.showEdges = showEdges;
isDegraded = true;
}
} }
} }
@ -470,6 +479,12 @@ void GraphicsWindow::ClearPending(void) {
pending.points.Clear(); pending.points.Clear();
pending = {}; pending = {};
SS.ScheduleShowTW(); SS.ScheduleShowTW();
// If degraded mode was enabled, we need to regenerate again to get edges back.
if(isDegraded) {
isDegraded = false;
SK.GetGroup(activeGroup)->displayDirty = true;
}
} }
void GraphicsWindow::MouseMiddleOrRightDown(double x, double y) { void GraphicsWindow::MouseMiddleOrRightDown(double x, double y) {
@ -619,7 +634,7 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
} }
} }
if(SS.clipboard.r.n > 0 && LockedInWorkplane()) { if((SS.clipboard.r.n > 0 || SS.clipboard.c.n > 0) && LockedInWorkplane()) {
AddContextMenuItem("Paste", CMNU_PASTE); AddContextMenuItem("Paste", CMNU_PASTE);
AddContextMenuItem("Paste Transformed...", CMNU_PASTE_XFRM); AddContextMenuItem("Paste Transformed...", CMNU_PASTE_XFRM);
} }
@ -892,6 +907,9 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
if(ToolbarMouseDown((int)mx, (int)my)) return; if(ToolbarMouseDown((int)mx, (int)my)) return;
} }
// This will be clobbered by MouseMoved below.
SuggestedConstraint constraintSuggestion = SS.GW.pending.suggestion;
// Make sure the hover is up to date. // Make sure the hover is up to date.
MouseMoved(mx, my, false, false, false, false, false); MouseMoved(mx, my, false, false, false, false, false);
orig.mouse.x = mx; orig.mouse.x = mx;
@ -903,7 +921,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
v = v.Plus(projRight.ScaledBy(mx/scale)); v = v.Plus(projRight.ScaledBy(mx/scale));
v = v.Plus(projUp.ScaledBy(my/scale)); v = v.Plus(projUp.ScaledBy(my/scale));
hRequest hr; hRequest hr = {};
hConstraint hc = {};
switch(pending.operation) { switch(pending.operation) {
case MNU_DATUM_POINT: case MNU_DATUM_POINT:
hr = AddRequest(Request::DATUM_POINT); hr = AddRequest(Request::DATUM_POINT);
@ -958,6 +977,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = DRAGGING_NEW_POINT; pending.operation = DRAGGING_NEW_POINT;
pending.point = lns[1].entity(2); pending.point = lns[1].entity(2);
pending.description = "click to place other corner of rectangle"; pending.description = "click to place other corner of rectangle";
hr = lns[0];
break; break;
} }
case MNU_CIRCLE: case MNU_CIRCLE:
@ -1060,7 +1080,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
c.type = Constraint::COMMENT; c.type = Constraint::COMMENT;
c.disp.offset = v; c.disp.offset = v;
c.comment = "NEW COMMENT -- DOUBLE-CLICK TO EDIT"; c.comment = "NEW COMMENT -- DOUBLE-CLICK TO EDIT";
Constraint::AddConstraint(&c); hc = Constraint::AddConstraint(&c);
break; break;
} }
@ -1127,8 +1147,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
case DRAGGING_NEW_LINE_POINT: { case DRAGGING_NEW_LINE_POINT: {
// Constrain the line segment horizontal or vertical if close enough // Constrain the line segment horizontal or vertical if close enough
if(SS.GW.pending.suggestion != SUGGESTED_NONE) { if(constraintSuggestion != SUGGESTED_NONE) {
Constraint::Constrain(SS.GW.pending.suggestion, Constraint::Constrain(constraintSuggestion,
Entity::NO_ENTITY, Entity::NO_ENTITY, pending.request.entity(0)); Entity::NO_ENTITY, Entity::NO_ENTITY, pending.request.entity(0));
} }
@ -1185,6 +1205,20 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
break; break;
} }
// Activate group with newly created request/constraint
Group *g = NULL;
if(hr.v != 0) {
Request *req = SK.GetRequest(hr);
g = SK.GetGroup(req->group);
}
if(hc.v != 0) {
Constraint *c = SK.GetConstraint(hc);
g = SK.GetGroup(c->group);
}
if(g != NULL) {
g->visible = true;
}
SS.ScheduleShowTW(); SS.ScheduleShowTW();
InvalidateGraphics(); InvalidateGraphics();
} }

View File

@ -827,7 +827,7 @@ public:
static void CreateAllDefaultStyles(void); static void CreateAllDefaultStyles(void);
static void CreateDefaultStyle(hStyle h); static void CreateDefaultStyle(hStyle h);
static void FillDefaultStyle(Style *s, const Default *d = NULL); static void FillDefaultStyle(Style *s, const Default *d = NULL, bool factory = false);
static void FreezeDefaultStyles(void); static void FreezeDefaultStyles(void);
static void LoadFactoryDefaults(void); static void LoadFactoryDefaults(void);

View File

@ -132,7 +132,6 @@ bool SolveSpaceUI::OpenFile(const std::string &filename) {
saveFile = filename; saveFile = filename;
bool success = fileLoaded && ReloadAllImported(/*canCancel=*/true); bool success = fileLoaded && ReloadAllImported(/*canCancel=*/true);
if(success) { if(success) {
RemoveAutosave();
AddToRecentList(filename); AddToRecentList(filename);
} else { } else {
saveFile = ""; saveFile = "";
@ -144,9 +143,6 @@ bool SolveSpaceUI::OpenFile(const std::string &filename) {
} }
void SolveSpaceUI::Exit(void) { void SolveSpaceUI::Exit(void) {
if(!OkayToStartNewFile())
return;
// Recent files // Recent files
for(int i = 0; i < MAX_RECENT; i++) for(int i = 0; i < MAX_RECENT; i++)
CnfFreezeString(RecentFile[i], "RecentFile_" + std::to_string(i)); CnfFreezeString(RecentFile[i], "RecentFile_" + std::to_string(i));
@ -221,9 +217,6 @@ void SolveSpaceUI::Exit(void) {
// And the default styles, colors and line widths and such. // And the default styles, colors and line widths and such.
Style::FreezeDefaultStyles(); Style::FreezeDefaultStyles();
// Exiting cleanly.
RemoveAutosave();
ExitNow(); ExitNow();
} }
@ -418,6 +411,7 @@ bool SolveSpaceUI::OkayToStartNewFile(void) {
return GetFilenameAndSave(false); return GetFilenameAndSave(false);
case DIALOG_NO: case DIALOG_NO:
RemoveAutosave();
return true; return true;
case DIALOG_CANCEL: case DIALOG_CANCEL:
@ -433,8 +427,11 @@ void SolveSpaceUI::UpdateWindowTitle(void) {
static std::string Extension(const std::string &filename) { static std::string Extension(const std::string &filename) {
int dot = filename.rfind('.'); int dot = filename.rfind('.');
if(dot >= 0) if(dot >= 0) {
return filename.substr(dot + 1, filename.length()); std::string ext = filename.substr(dot + 1, filename.length());
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
return ext;
}
return ""; return "";
} }
@ -554,7 +551,10 @@ void SolveSpaceUI::MenuFile(int id) {
ImportDxf(importFile); ImportDxf(importFile);
} else if(Extension(importFile) == "dwg") { } else if(Extension(importFile) == "dwg") {
ImportDwg(importFile); ImportDwg(importFile);
} else oops(); } else {
Error("Can't identify file type from file extension of "
"filename '%s'; try .dxf or .dwg.", importFile.c_str());
}
SS.GenerateAll(SolveSpaceUI::GENERATE_UNTIL_ACTIVE); SS.GenerateAll(SolveSpaceUI::GENERATE_UNTIL_ACTIVE);
SS.ScheduleShowTW(); SS.ScheduleShowTW();

View File

@ -24,6 +24,7 @@
#include <unordered_map> #include <unordered_map>
#include <map> #include <map>
#include <set> #include <set>
#include <sstream>
#ifdef WIN32 #ifdef WIN32
# include <windows.h> // required by GL headers # include <windows.h> // required by GL headers
#endif #endif
@ -135,6 +136,7 @@ class RgbaColor;
#endif #endif
FILE *ssfopen(const std::string &filename, const char *mode); FILE *ssfopen(const std::string &filename, const char *mode);
std::fstream ssfstream(const std::string &filename, std::ios_base::openmode mode);
void ssremove(const std::string &filename); void ssremove(const std::string &filename);
#define MAX_RECENT 8 #define MAX_RECENT 8
@ -374,6 +376,8 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
double a41, double a42, double a43, double a44); double a41, double a42, double a43, double a44);
std::string MakeAcceleratorLabel(int accel); std::string MakeAcceleratorLabel(int accel);
bool FilenameHasExtension(const std::string &str, const char *ext); bool FilenameHasExtension(const std::string &str, const char *ext);
bool ReadFile(const std::string &filename, std::string *data);
bool WriteFile(const std::string &filename, const std::string &data);
void Message(const char *str, ...); void Message(const char *str, ...);
void Error(const char *str, ...); void Error(const char *str, ...);
void CnfFreezeBool(bool v, const std::string &name); void CnfFreezeBool(bool v, const std::string &name);
@ -908,6 +912,7 @@ public:
void GenerateAll(GenerateType type = GENERATE_DIRTY, bool andFindFree = false, void GenerateAll(GenerateType type = GENERATE_DIRTY, bool andFindFree = false,
bool genForBBox = false); bool genForBBox = false);
void SolveGroup(hGroup hg, bool andFindFree); void SolveGroup(hGroup hg, bool andFindFree);
void SolveGroupAndReport(hGroup hg, bool andFindFree);
void MarkDraggedParams(void); void MarkDraggedParams(void);
void ForceReferences(void); void ForceReferences(void);

View File

@ -426,6 +426,7 @@ void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
for(i = start; i < sm->l.n; i++) { for(i = start; i < sm->l.n; i++) {
STriangle *st = &(sm->l.elem[i]); STriangle *st = &(sm->l.elem[i]);
st->meta = meta; st->meta = meta;
if(st->meta.color.alpha != 255) sm->isTransparent = true;
st->an = NormalAt(st->a.x, st->a.y); st->an = NormalAt(st->a.x, st->a.y);
st->bn = NormalAt(st->b.x, st->b.y); st->bn = NormalAt(st->b.x, st->b.y);
st->cn = NormalAt(st->c.x, st->c.y); st->cn = NormalAt(st->c.x, st->c.y);

View File

@ -83,12 +83,13 @@ void Style::CreateDefaultStyle(hStyle h) {
SK.style.Add(&ns); SK.style.Add(&ns);
} }
void Style::FillDefaultStyle(Style *s, const Default *d) { void Style::FillDefaultStyle(Style *s, const Default *d, bool factory) {
if(d == NULL) d = &Defaults[0]; if(d == NULL) d = &Defaults[0];
s->color = CnfThawColor(d->color, CnfColor(d->cnfPrefix)); s->color = (factory) ? d->color : CnfThawColor(d->color, CnfColor(d->cnfPrefix));
s->width = CnfThawFloat((float)(d->width), CnfWidth(d->cnfPrefix)); s->width = (factory) ? d->width : CnfThawFloat((float)(d->width), CnfWidth(d->cnfPrefix));
s->widthAs = UNITS_AS_PIXELS; s->widthAs = UNITS_AS_PIXELS;
s->textHeight = CnfThawFloat(DEFAULT_TEXT_HEIGHT, CnfTextHeight(d->cnfPrefix)); s->textHeight = (factory) ? DEFAULT_TEXT_HEIGHT
: CnfThawFloat(DEFAULT_TEXT_HEIGHT, CnfTextHeight(d->cnfPrefix));
s->textHeightAs = UNITS_AS_PIXELS; s->textHeightAs = UNITS_AS_PIXELS;
s->textOrigin = 0; s->textOrigin = 0;
s->textAngle = 0; s->textAngle = 0;
@ -106,7 +107,7 @@ void Style::LoadFactoryDefaults(void) {
const Default *d; const Default *d;
for(d = &(Defaults[0]); d->h.v; d++) { for(d = &(Defaults[0]); d->h.v; d++) {
Style *s = Get(d->h); Style *s = Get(d->h);
FillDefaultStyle(s, d); FillDefaultStyle(s, d, /*factory=*/true);
} }
SS.backgroundColor = RGBi(0, 0, 0); SS.backgroundColor = RGBi(0, 0, 0);
if(SS.bgImage.fromFile) MemFree(SS.bgImage.fromFile); if(SS.bgImage.fromFile) MemFree(SS.bgImage.fromFile);

View File

@ -463,10 +463,8 @@ int System::Solve(Group *g, int *dof, List<hConstraint> *bad,
if(!rankOk) { if(!rankOk) {
if(!g->allowRedundant) { if(!g->allowRedundant) {
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad); if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad);
return System::REDUNDANT_OKAY;
} }
} } else {
// This is not the full Jacobian, but any substitutions or single-eq // This is not the full Jacobian, but any substitutions or single-eq
// solves removed one equation and one unknown, therefore no effect // solves removed one equation and one unknown, therefore no effect
// on the number of DOF. // on the number of DOF.
@ -492,7 +490,7 @@ int System::Solve(Group *g, int *dof, List<hConstraint> *bad,
} }
} }
} }
}
// System solved correctly, so write the new values back in to the // System solved correctly, so write the new values back in to the
// main parameter table. // main parameter table.
for(i = 0; i < param.n; i++) { for(i = 0; i < param.n; i++) {

View File

@ -988,7 +988,7 @@ void TextWindow::MouseEvent(bool leftClick, bool leftDown, double x, double y) {
break; break;
} }
} }
if(r >= rows) { if(r < 0 || c < 0 || r >= rows || c >= MAX_COLS) {
SetMousePointerToHand(false); SetMousePointerToHand(false);
goto done; goto done;
} }

View File

@ -88,7 +88,9 @@ void TtfFontList::PlotString(const std::string &font, const std::string &str,
[&](const TtfFont &tf) { return tf.FontFileBaseName() == font; }); [&](const TtfFont &tf) { return tf.FontFileBaseName() == font; });
if(!str.empty() && tf != &l.elem[l.n]) { if(!str.empty() && tf != &l.elem[l.n]) {
if(tf->fontFace == NULL) {
tf->LoadFromFile(fontLibrary, /*nameOnly=*/false); tf->LoadFromFile(fontLibrary, /*nameOnly=*/false);
}
tf->PlotString(str, sbl, origin, u, v); tf->PlotString(str, sbl, origin, u, v);
} else { } else {
// No text or no font; so draw a big X for an error marker. // No text or no font; so draw a big X for an error marker.
@ -135,6 +137,7 @@ bool TtfFont::LoadFromFile(FT_Library fontLibrary, bool nameOnly) {
dbp("freetype: loading unicode CMap for file '%s' failed: %s", dbp("freetype: loading unicode CMap for file '%s' failed: %s",
fontFile.c_str(), ft_error_string(fterr)); fontFile.c_str(), ft_error_string(fterr));
FT_Done_Face(fontFace); FT_Done_Face(fontFace);
fontFace = NULL;
return false; return false;
} }
@ -144,6 +147,47 @@ bool TtfFont::LoadFromFile(FT_Library fontLibrary, bool nameOnly) {
if(nameOnly) { if(nameOnly) {
FT_Done_Face(fontFace); FT_Done_Face(fontFace);
fontFace = NULL; fontFace = NULL;
return true;
}
// We always ask Freetype to give us a unit size character.
// It uses fixed point; put the unit size somewhere in the middle of the dynamic
// range of its 26.6 fixed point type, and adjust the factors so that the unit
// matches cap height.
FT_Size_RequestRec sizeRequest;
sizeRequest.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
sizeRequest.width = 1 << 16;
sizeRequest.height = 1 << 16;
sizeRequest.horiResolution = 128;
sizeRequest.vertResolution = 128;
if(int fterr = FT_Request_Size(fontFace, &sizeRequest)) {
dbp("freetype: cannot set character size: %s",
ft_error_string(fterr));
FT_Done_Face(fontFace);
fontFace = NULL;
return false;
}
char chr = 'A';
uint32_t gid = FT_Get_Char_Index(fontFace, 'A');
if (gid == 0) {
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
chr, ft_error_string(gid));
gid = chr;
}
if(gid) {
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
dbp("freetype: cannot load glyph for GID 0x%04x: %s",
gid, ft_error_string(fterr));
FT_Done_Face(fontFace);
fontFace = NULL;
return false;
}
FT_BBox bbox;
FT_Outline_Get_CBox(&fontFace->glyph->outline, &bbox);
capHeight = (double)bbox.yMax;
} }
return true; return true;
@ -211,28 +255,26 @@ static int CubicTo(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *p,
return 0; return 0;
} }
static const FT_Outline_Funcs outline_funcs = {
MoveTo, LineTo, ConicTo, CubicTo, 0, 0
};
void TtfFont::PlotString(const std::string &str, void TtfFont::PlotString(const std::string &str,
SBezierList *sbl, Vector origin, Vector u, Vector v) SBezierList *sbl, Vector origin, Vector u, Vector v)
{ {
if(fontFace == NULL) oops(); if(fontFace == NULL) oops();
FT_Outline_Funcs outlineFuncs;
outlineFuncs.move_to = MoveTo;
outlineFuncs.line_to = LineTo;
outlineFuncs.conic_to = ConicTo;
outlineFuncs.cubic_to = CubicTo;
outlineFuncs.shift = 0;
outlineFuncs.delta = 0;
FT_Pos dx = 0; FT_Pos dx = 0;
for(char32_t chr : ReadUTF8(str)) { for(char32_t cid : ReadUTF8(str)) {
uint32_t gid = FT_Get_Char_Index(fontFace, chr); uint32_t gid = FT_Get_Char_Index(fontFace, cid);
if (gid == 0) { if (gid == 0) {
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID", dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
chr, ft_error_string(gid)); cid, ft_error_string(gid));
} gid = cid;
FT_F26Dot6 scale = fontFace->units_per_EM;
if(int fterr = FT_Set_Char_Size(fontFace, scale, scale, 72, 72)) {
dbp("freetype: cannot set character size: %s",
ft_error_string(fterr));
return;
} }
/* /*
@ -244,7 +286,7 @@ void TtfFont::PlotString(const std::string &str,
* ones, antialiasing mitigates this considerably though. * ones, antialiasing mitigates this considerably though.
*/ */
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) { if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
dbp("freetype: cannot load glyph (gid %d): %s", dbp("freetype: cannot load glyph for GID 0x%04x: %s",
gid, ft_error_string(fterr)); gid, ft_error_string(fterr));
return; return;
} }
@ -274,9 +316,9 @@ void TtfFont::PlotString(const std::string &str,
data.u = u; data.u = u;
data.v = v; data.v = v;
data.beziers = sbl; data.beziers = sbl;
data.factor = 1.0f/(float)scale; data.factor = 1.0 / capHeight;
data.bx = bx; data.bx = bx;
if(int fterr = FT_Outline_Decompose(&fontFace->glyph->outline, &outline_funcs, &data)) { if(int fterr = FT_Outline_Decompose(&fontFace->glyph->outline, &outlineFuncs, &data)) {
dbp("freetype: bezier decomposition failed (gid %d): %s", dbp("freetype: bezier decomposition failed (gid %d): %s",
gid, ft_error_string(fterr)); gid, ft_error_string(fterr));
} }

View File

@ -14,6 +14,7 @@ public:
std::string fontFile; std::string fontFile;
std::string name; std::string name;
FT_FaceRec_ *fontFace; FT_FaceRec_ *fontFace;
double capHeight;
std::string FontFileBaseName() const; std::string FontFileBaseName() const;
bool LoadFromFile(FT_LibraryRec_ *fontLibrary, bool nameOnly = true); bool LoadFromFile(FT_LibraryRec_ *fontLibrary, bool nameOnly = true);

View File

@ -504,6 +504,9 @@ public:
// allowing a paint in between. The extra solves are wasted if they're // allowing a paint in between. The extra solves are wasted if they're
// not displayed. // not displayed.
bool havePainted; bool havePainted;
// Similarly, don't draw edges and outlines, since that's too slow
// for real-time dragging.
bool isDegraded;
// Some state for the context menu. // Some state for the context menu.
struct { struct {
@ -629,14 +632,13 @@ public:
void HitTestMakeSelection(Point2d mp); void HitTestMakeSelection(Point2d mp);
void ClearSelection(void); void ClearSelection(void);
void ClearNonexistentSelectionItems(void); void ClearNonexistentSelectionItems(void);
enum { MAX_SELECTED = 32 };
struct { struct {
hEntity point[MAX_SELECTED]; std::vector<hEntity> point;
hEntity entity[MAX_SELECTED]; std::vector<hEntity> entity;
hEntity anyNormal[MAX_SELECTED]; std::vector<hEntity> anyNormal;
hEntity vector[MAX_SELECTED]; std::vector<hEntity> vector;
hEntity face[MAX_SELECTED]; std::vector<hEntity> face;
hConstraint constraint[MAX_SELECTED]; std::vector<hConstraint> constraint;
int points; int points;
int entities; int entities;
int workplanes; int workplanes;
@ -658,6 +660,7 @@ public:
bool IsSelected(Selection *s); bool IsSelected(Selection *s);
bool IsSelected(hEntity he); bool IsSelected(hEntity he);
void MakeSelected(hEntity he); void MakeSelected(hEntity he);
void MakeSelected(hConstraint hc);
void MakeSelected(Selection *s); void MakeSelected(Selection *s);
void MakeUnselected(hEntity he, bool coincidentPointTrick); void MakeUnselected(hEntity he, bool coincidentPointTrick);
void MakeUnselected(Selection *s, bool coincidentPointTrick); void MakeUnselected(Selection *s, bool coincidentPointTrick);

View File

@ -0,0 +1,27 @@
/* XPM */
static char *solvespace_16x16[] = {
/* columns rows colors chars-per-pixel */
"16 16 5 1 ",
" c black",
". c #1ED500",
"X c #DE00D6",
"o c #CBCBCB",
"O c None",
/* pixels */
"OOO OOOOOOOOOOOO",
"OOO OOOOOOOOOOOO",
"OOO OOOOOOOOOOOO",
"OOO OOOOOXOOOOOO",
"OOO OOOOOXoOOOOO",
"OOO OOOOOXoOOOOO",
"OOO OOOOOXoOOOOO",
"OOO OOOOOXoOOOOO",
"OOO OOOOOXoOOOOO",
"OOO OOXXXXXXXOOO",
"OOO OOOoooooooOO",
"OO...OOOOOOOOOOO",
" ... ",
"OO...OOOOOOOOOOO",
"OOO OOOOOOOOOOOO",
"OOO OOOOOOOOOOOO"
};

View File

@ -0,0 +1,35 @@
/* XPM */
static char *solvespace_24x24[] = {
/* columns rows colors chars-per-pixel */
"24 24 5 1 ",
" c black",
". c #1ED500",
"X c #DE00D6",
"o c #CBCBCB",
"O c None",
/* pixels */
"OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOO OOOOOOOOOOOOOOOO",
"OOOOOOO OOOOOOOOOOOOOOOO",
"OOOOOOO OOOOOOOOOOOOOOOO",
"OOOOOOO OOOOOXOOOOOOOOOO",
"OOOOOOO OOOOOXoOOOOOOOOO",
"OOOOOOO OOOOOXoOOOOOOOOO",
"OOOOOOO OOOOOXoOOOOOOOOO",
"OOOOOOO OOOOOXoOOOOOOOOO",
"OOOOOOO OOOOOXoOOOOOOOOO",
"OOOOOOO OOXXXXXXXOOOOOOO",
"OOOOOOO OOOoooooooOOOOOO",
"OOOOOO...OOOOOOOOOOOOOOO",
"OOOO ... OOOO",
"OOOOOO...OOOOOOOOOOOOOOO",
"OOOOOOO OOOOOOOOOOOOOOOO",
"OOOOOOO OOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOO"
};

View File

@ -0,0 +1,43 @@
/* XPM */
static char *solvespace_32x32[] = {
/* columns rows colors chars-per-pixel */
"32 32 5 1 ",
" c black",
". c #1ED500",
"X c #DE00D6",
"o c #CBCBCB",
"O c None",
/* pixels */
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOXXoOOOOOOOOOOOO",
"OOOOOO OOOOXXXXXXXXXXXXOOOOOOOO",
"OOOOOO OOOOXXXXXXXXXXXXOOOOOOOO",
"OOOOOO OOOOOooooooooooooOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOO......OOOOOOOOOOOOOOOOOOOOOO",
"OOOO......OOOOOOOOOOOOOOOOOOOOOO",
" ...... ",
" ...... ",
"OOOO......OOOOOOOOOOOOOOOOOOOOOO",
"OOOO......OOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOO OOOOOOOOOOOOOOOOOOOOOOOO"
};

View File

@ -0,0 +1,59 @@
/* XPM */
static char *solvespace_48x48[] = {
/* columns rows colors chars-per-pixel */
"48 48 5 1 ",
" c black",
". c #1ED500",
"X c #DE00D6",
"o c #CBCBCB",
"O c None",
/* pixels */
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOXXoOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOXXXXXXXXXXXXOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOXXXXXXXXXXXXOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOooooooooooooOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOO......OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOO......OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOO ...... OOOOOOOO",
"OOOOOOOO ...... OOOOOOOO",
"OOOOOOOOOOOO......OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOO......OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};

View File

@ -61,6 +61,33 @@ bool SolveSpace::FilenameHasExtension(const std::string &str, const char *ext)
return true; return true;
} }
bool SolveSpace::ReadFile(const std::string &filename, std::string *data)
{
FILE *f = ssfopen(filename.c_str(), "rb");
if(f == NULL)
return false;
fseek(f, 0, SEEK_END);
data->resize(ftell(f));
fseek(f, 0, SEEK_SET);
fread(&(*data)[0], 1, data->size(), f);
fclose(f);
return true;
}
bool SolveSpace::WriteFile(const std::string &filename, const std::string &data)
{
FILE *f = ssfopen(filename.c_str(), "wb");
if(f == NULL)
return false;
fwrite(&data[0], 1, data.size(), f);
fclose(f);
return true;
}
void SolveSpace::MakeMatrix(double *mat, void SolveSpace::MakeMatrix(double *mat,
double a11, double a12, double a13, double a14, double a11, double a12, double a13, double a14,
double a21, double a22, double a23, double a24, double a21, double a22, double a23, double a24,

View File

@ -56,6 +56,7 @@ SiHdl SpaceNavigator = SI_NO_HANDLE;
HWND MessageWnd, OkButton; HWND MessageWnd, OkButton;
bool MessageDone; bool MessageDone;
int MessageWidth, MessageHeight;
const char *MessageString; const char *MessageString;
static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam, static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam,
@ -76,21 +77,13 @@ static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam,
case WM_PAINT: { case WM_PAINT: {
PAINTSTRUCT ps; PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); HDC hdc = BeginPaint(hwnd, &ps);
int row = 0, col = 0, i;
SelectObject(hdc, FixedFont); SelectObject(hdc, FixedFont);
SetTextColor(hdc, 0x000000); SetTextColor(hdc, 0x000000);
SetBkMode(hdc, TRANSPARENT); SetBkMode(hdc, TRANSPARENT);
for(i = 0; MessageString[i]; i++) { RECT rc;
if(MessageString[i] == '\n') { SetRect(&rc, 10, 10, MessageWidth, MessageHeight);
col = 0; std::wstring text = Widen(MessageString);
row++; DrawText(hdc, text.c_str(), text.length(), &rc, DT_LEFT | DT_WORDBREAK);
} else {
TextOutW(hdc, col*SS.TW.CHAR_WIDTH + 10,
row*SS.TW.LINE_HEIGHT + 10,
Widen(&(MessageString[i])).c_str(), 1);
col++;
}
}
EndPaint(hwnd, &ps); EndPaint(hwnd, &ps);
break; break;
} }
@ -147,6 +140,8 @@ void SolveSpace::DoMessageBox(const char *str, int rows, int cols, bool error)
const char *title = error ? "SolveSpace - Error" : "SolveSpace - Message"; const char *title = error ? "SolveSpace - Error" : "SolveSpace - Message";
int width = cols*SS.TW.CHAR_WIDTH + 20, int width = cols*SS.TW.CHAR_WIDTH + 20,
height = rows*SS.TW.LINE_HEIGHT + 60; height = rows*SS.TW.LINE_HEIGHT + 60;
MessageWidth = width;
MessageHeight = height;
MessageWnd = CreateWindowClient(0, L"MessageWnd", Widen(title).c_str(), MessageWnd = CreateWindowClient(0, L"MessageWnd", Widen(title).c_str(),
WS_OVERLAPPED | WS_SYSMENU, WS_OVERLAPPED | WS_SYSMENU,
r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL); r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL);
@ -1299,7 +1294,7 @@ static void CreateMainWindows(void)
// We get the desired Alt+Tab behaviour by specifying that the text // We get the desired Alt+Tab behaviour by specifying that the text
// window is a child of the graphics window. // window is a child of the graphics window.
TextWnd = CreateWindowExW(0, TextWnd = CreateWindowExW(0,
L"TextWnd", L"SolveSpace - Browser", WS_THICKFRAME | WS_CLIPCHILDREN, L"TextWnd", L"SolveSpace - Property Browser", WS_THICKFRAME | WS_CLIPCHILDREN,
650, 500, 420, 300, GraphicsWnd, (HMENU)NULL, Instance, NULL); 650, 500, 420, 300, GraphicsWnd, (HMENU)NULL, Instance, NULL);
if(!TextWnd) oops(); if(!TextWnd) oops();

View File

@ -67,7 +67,7 @@ std::wstring Widen(const std::string &in)
return out; return out;
} }
FILE *ssfopen(const std::string &filename, const char *mode) static std::string MakeUNCFilename(const std::string &filename)
{ {
// Prepend \\?\ UNC prefix unless already an UNC path. // Prepend \\?\ UNC prefix unless already an UNC path.
// We never try to fopen paths that are not absolute or // We never try to fopen paths that are not absolute or
@ -76,9 +76,13 @@ FILE *ssfopen(const std::string &filename, const char *mode)
std::string uncFilename = filename; std::string uncFilename = filename;
if(uncFilename.substr(0, 2) != "\\\\") if(uncFilename.substr(0, 2) != "\\\\")
uncFilename = "\\\\?\\" + uncFilename; uncFilename = "\\\\?\\" + uncFilename;
return uncFilename;
}
FILE *ssfopen(const std::string &filename, const char *mode)
{
if(filename.length() != strlen(filename.c_str())) oops(); if(filename.length() != strlen(filename.c_str())) oops();
return _wfopen(Widen(uncFilename).c_str(), Widen(mode).c_str()); return _wfopen(Widen(MakeUNCFilename(filename)).c_str(), Widen(mode).c_str());
} }
void ssremove(const std::string &filename) void ssremove(const std::string &filename)