+++ /dev/null
-# .gitattributes for SolveSpace
-
-# Set default behaviour, in case users don't have core.autocrlf set.
-* text=auto
-
-# Explicitly declare text files we want to always be normalized and converted
-# to native line endings on checkout.
-*.cpp text
-*.h text
-*.txt text
-
-# Declare files that will always have CRLF line endings on checkout.
-*.sln text eol=crlf
-
-# Denote all files that are truly binary and should not be modified.
-*.gz binary
-*.ico binary
-*.jpg binary
-*.lib binary
-*.png binary
-
-# end .gitattributes
+++ /dev/null
-/CMakeCache.txt
-/build*/
-*.trace # OpenGL apitrace files
-/debian/tmp/
-/debian/*.log
-/debian/*.substvars
-/debian/*.debhelper
-/debian/files
-/debian/solvespace/
-/debian/libslvs1/
-/debian/libslvs1-dev/
-/obj-*/
+++ /dev/null
-[submodule "extlib/zlib"]
- path = extlib/zlib
- url = https://github.com/madler/zlib
- ignore = dirty
-[submodule "extlib/libpng"]
- path = extlib/libpng
- url = https://github.com/glennrp/libpng
-[submodule "extlib/libfreetype"]
- path = extlib/libfreetype
- url = http://git.sv.nongnu.org/r/freetype/freetype2.git
-[submodule "extlib/libdxfrw"]
- path = extlib/libdxfrw
- url = https://github.com/solvespace/libdxfrw.git
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/build-debian.sh; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/build-macos.sh; fi
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
api_key:
secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM=
repo: solvespace/solvespace
tags: true
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"
-
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
* 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
---
# 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)
+# and instead uncomment the following, adding the complete git hash of the checkout you are using:
+# set(GIT_COMMIT_HASH 0000000000000000000000000000000000000000)
project(solvespace)
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)
if(NOT WIN32 AND NOT APPLE)
### Building for Linux
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:
apt-get install libpng12-dev libjson-c-dev libfreetype6-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:
-version: 2.1.{build}
+version: 2.2.{build}
clone_depth: 1
before_build:
- git submodule update --init
- path: build\src\RelWithDebInfo\solvespace.pdb
name: solvespace.pdb
deploy:
- # Releases to solvespace/solvespace
- provider: GitHub
auth_token:
secure: P9/pf2nM+jlWKe7pCjMp41HycBNP/+5AsmE/TETrDUoBOa/9WFHelqdVFrbRn9IC
artifact: solvespace.exe
on:
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
bitPos = 0;
}
-dwgBuffer::dwgBuffer(std::ifstream *stream, DRW_TextCodec *dc){
+dwgBuffer::dwgBuffer(std::istream *stream, DRW_TextCodec *dc){
filestr = new dwgFileStream(stream);
decoder = dc;
maxSize = filestr->size();
class dwgFileStream: public dwgBasicStream{
public:
- dwgFileStream(std::ifstream *s){
+ dwgFileStream(std::istream *s){
stream =s;
stream->seekg (0, std::ios::end);
sz = stream->tellg();
virtual bool good(){return stream->good();}
virtual dwgBasicStream* clone(){return new dwgFileStream(stream);}
private:
- std::ifstream *stream;
+ std::istream *stream;
duint64 sz;
};
class dwgBuffer {
public:
- dwgBuffer(std::ifstream *stream, DRW_TextCodec *decoder = NULL);
+ dwgBuffer(std::istream *stream, DRW_TextCodec *decoder = NULL);
dwgBuffer(duint8 *buf, int size, DRW_TextCodec *decoder= NULL);
dwgBuffer( const dwgBuffer& org );
dwgBuffer& operator=( const dwgBuffer& org );
class dwgReader {
friend class dwgR;
public:
- dwgReader(std::ifstream *stream, dwgR *p){
+ dwgReader(std::istream *stream, dwgR *p){
fileBuf = new dwgBuffer(stream);
parent = p;
decoder.setVersion(DRW::AC1021, false);//default 2007 in utf8(no convert)
class dwgReader15 : public dwgReader {
public:
- dwgReader15(std::ifstream *stream, dwgR *p):dwgReader(stream, p){ }
+ dwgReader15(std::istream *stream, dwgR *p):dwgReader(stream, p){ }
virtual ~dwgReader15() {}
bool readMetaData();
bool readFileHeader();
class dwgReader18 : public dwgReader {
public:
- dwgReader18(std::ifstream *stream, dwgR *p):dwgReader(stream, p){
+ dwgReader18(std::istream *stream, dwgR *p):dwgReader(stream, p){
objData = NULL;
}
virtual ~dwgReader18(){
//reader for AC1021 aka v2007, chapter 5
class dwgReader21 : public dwgReader {
public:
- dwgReader21(std::ifstream *stream, dwgR *p):dwgReader(stream, p){
+ dwgReader21(std::istream *stream, dwgR *p):dwgReader(stream, p){
objData = NULL;
dataSize = 0;
}
class dwgReader24 : public dwgReader18 {
public:
- dwgReader24(std::ifstream *stream, dwgR *p):dwgReader18(stream, p){ }
+ dwgReader24(std::istream *stream, dwgR *p):dwgReader18(stream, p){ }
virtual ~dwgReader24(){}
bool readFileHeader();
bool readDwgHeader(DRW_Header& hdr);
class dwgReader27 : public dwgReader18 {
public:
- dwgReader27(std::ifstream *stream, dwgR *p):dwgReader18(stream, p){ }
+ dwgReader27(std::istream *stream, dwgR *p):dwgReader18(stream, p){ }
virtual ~dwgReader27(){}
bool readFileHeader();
bool readDwgHeader(DRW_Header& hdr);
};
enum TYPE type;
public:
- dxfReader(std::ifstream *stream){
+ dxfReader(std::istream *stream){
filestr = stream;
type = INVALID;
}
virtual bool readBool() = 0;
protected:
- std::ifstream *filestr;
+ std::istream *filestr;
std::string strData;
double doubleData;
signed int intData; //32 bits integer
class dxfReaderBinary : public dxfReader {
public:
- dxfReaderBinary(std::ifstream *stream):dxfReader(stream){skip = false; }
+ dxfReaderBinary(std::istream *stream):dxfReader(stream){skip = false; }
virtual ~dxfReaderBinary() {}
virtual bool readCode(int *code);
virtual bool readString(std::string *text);
class dxfReaderAscii : public dxfReader {
public:
- dxfReaderAscii(std::ifstream *stream):dxfReader(stream){skip = true; }
+ dxfReaderAscii(std::istream *stream):dxfReader(stream){skip = true; }
virtual ~dxfReaderAscii(){}
virtual bool readCode(int *code);
virtual bool readString(std::string *text);
return (filestr->good());
}
-dxfWriterAscii::dxfWriterAscii(std::ofstream *stream):dxfWriter(stream){
+dxfWriterAscii::dxfWriterAscii(std::ostream *stream):dxfWriter(stream){
filestr->precision(16);
}
class dxfWriter {
public:
- dxfWriter(std::ofstream *stream){filestr = stream; /*count =0;*/}
+ dxfWriter(std::ostream *stream){filestr = stream; /*count =0;*/}
virtual ~dxfWriter(){}
virtual bool writeString(int code, std::string text) = 0;
bool writeUtf8String(int code, std::string text);
void setCodePage(std::string *c){encoder.setCodePage(c, true);}
std::string getCodePage(){return encoder.getCodePage();}
protected:
- std::ofstream *filestr;
+ std::ostream *filestr;
private:
DRW_TextCodec encoder;
};
class dxfWriterBinary : public dxfWriter {
public:
- dxfWriterBinary(std::ofstream *stream):dxfWriter(stream){}
+ dxfWriterBinary(std::ostream *stream):dxfWriter(stream){}
virtual ~dxfWriterBinary() {}
virtual bool writeString(int code, std::string text);
virtual bool writeInt16(int code, int data);
class dxfWriterAscii : public dxfWriter {
public:
- dxfWriterAscii(std::ofstream *stream);
+ dxfWriterAscii(std::ostream *stream);
virtual ~dxfWriterAscii(){}
virtual bool writeString(int code, std::string text);
virtual bool writeInt16(int code, int data);
secObjects
};*/
-dwgR::dwgR(const char* name){
+dwgR::dwgR(){
DRW_DBGSL(DRW_dbg::NONE);
- fileName = name;
reader = NULL;
// writer = NULL;
applyExt = false;
}
/*reads metadata and loads image preview*/
-bool dwgR::getPreview(){
+bool dwgR::getPreview(std::istream &stream){
bool isOk = false;
- std::ifstream filestr;
- isOk = openFile(&filestr);
+ isOk = open(&stream);
if (!isOk)
return false;
} else
error = DRW::BAD_READ_METADATA;
- filestr.close();
if (reader != NULL) {
delete reader;
reader = NULL;
return isOk;
}
-bool dwgR::testReader(){
- bool isOk = false;
-
- std::ifstream filestr;
- filestr.open (fileName.c_str(), std::ios_base::in | std::ios::binary);
- if (!filestr.is_open() || !filestr.good() ){
- error = DRW::BAD_OPEN;
- return isOk;
- }
-
- dwgBuffer fileBuf(&filestr);
- duint8 *tmpStrData = new duint8[fileBuf.size()];
- fileBuf.getBytes(tmpStrData, fileBuf.size());
- dwgBuffer dataBuf(tmpStrData, fileBuf.size());
- fileBuf.setPosition(0);
- DRW_DBG("\ndwgR::testReader filebuf size: ");DRW_DBG(fileBuf.size());
- DRW_DBG("\ndwgR::testReader dataBuf size: ");DRW_DBG(dataBuf.size());
- DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
- DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
- DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
- DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
- DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
- DRW_DBG("\n dataBuf first byte : ");DRW_DBGH(dataBuf.getRawChar8());
- fileBuf.setBitPos(4);
- dataBuf.setBitPos(4);
- DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
- DRW_DBG("\n dataBuf first byte : ");DRW_DBGH(dataBuf.getRawChar8());
- DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
- DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
- DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
- DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
- fileBuf.setBitPos(6);
- dataBuf.setBitPos(6);
- DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
- DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
- DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
- DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
- DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
- DRW_DBG("\n dataBuf first byte : ");DRW_DBGH(dataBuf.getRawChar8());
- fileBuf.setBitPos(0);
- dataBuf.setBitPos(0);
- DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
- DRW_DBG("\n dataBuf first byte : ");DRW_DBGH(dataBuf.getRawChar8());
- DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
- DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
- DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
- DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
-
- delete[]tmpStrData;
- filestr.close();
- DRW_DBG("\n\n");
- return isOk;
-}
-
-/*start reading dwg file header and, if can read it, continue reading all*/
-bool dwgR::read(DRW_Interface *interface_, bool ext){
- bool isOk = false;
+bool dwgR::read(std::istream &stream, DRW_Interface *interface_, bool ext){
applyExt = ext;
iface = interface_;
-//testReader();return false;
+ bool isOk = false;
- std::ifstream filestr;
- isOk = openFile(&filestr);
+ isOk = open(&stream);
if (!isOk)
return false;
} else
error = DRW::BAD_READ_METADATA;
- filestr.close();
if (reader != NULL) {
delete reader;
reader = NULL;
return isOk;
}
-/* Open the file and stores it in filestr, install the correct reader version.
- * If fail opening file, error are set as DRW::BAD_OPEN
- * If not are DWG or are unsupported version, error are set as DRW::BAD_VERSION
- * and closes filestr.
- * Return true on succeed or false on fail
-*/
-bool dwgR::openFile(std::ifstream *filestr){
- bool isOk = false;
- DRW_DBG("dwgR::read 1\n");
- filestr->open (fileName.c_str(), std::ios_base::in | std::ios::binary);
- if (!filestr->is_open() || !filestr->good() ){
- error = DRW::BAD_OPEN;
- return isOk;
- }
-
+bool dwgR::open(std::istream *stream){
char line[7];
- filestr->read (line, 6);
+ stream->read (line, 6);
line[6]='\0';
DRW_DBG("dwgR::read 2\n");
DRW_DBG("dwgR::read line version: ");
// reader = new dwgReader09(&filestr, this);
}else if (strcmp(line, "AC1012") == 0){
version = DRW::AC1012;
- reader = new dwgReader15(filestr, this);
+ reader = new dwgReader15(stream, this);
} else if (strcmp(line, "AC1014") == 0) {
version = DRW::AC1014;
- reader = new dwgReader15(filestr, this);
+ reader = new dwgReader15(stream, this);
} else if (strcmp(line, "AC1015") == 0) {
version = DRW::AC1015;
- reader = new dwgReader15(filestr, this);
+ reader = new dwgReader15(stream, this);
} else if (strcmp(line, "AC1018") == 0){
version = DRW::AC1018;
- reader = new dwgReader18(filestr, this);
+ reader = new dwgReader18(stream, this);
} else if (strcmp(line, "AC1021") == 0) {
version = DRW::AC1021;
- reader = new dwgReader21(filestr, this);
+ reader = new dwgReader21(stream, this);
} else if (strcmp(line, "AC1024") == 0) {
version = DRW::AC1024;
- reader = new dwgReader24(filestr, this);
+ reader = new dwgReader24(stream, this);
} else if (strcmp(line, "AC1027") == 0) {
version = DRW::AC1027;
- reader = new dwgReader27(filestr, this);
+ reader = new dwgReader27(stream, this);
} else
version = DRW::UNKNOWNV;
if (reader == NULL) {
error = DRW::BAD_VERSION;
- filestr->close();
- } else
- isOk = true;
-
- return isOk;
+ return false;
+ }
+ return true;
}
/********* Reader Process *********/
class dwgR {
public:
- dwgR(const char* name);
+ dwgR();
~dwgR();
//read: return true if all ok
- bool read(DRW_Interface *interface_, bool ext);
- bool getPreview();
+ bool read(std::istream &stream, DRW_Interface *interface_, bool ext);
+ bool getPreview(std::istream &stream);
DRW::Version getVersion(){return version;}
DRW::error getError(){return error;}
-bool testReader();
void setDebug(DRW::DBG_LEVEL lvl);
private:
- bool openFile(std::ifstream *filestr);
+ bool open(std::istream *stream);
bool processDwg();
private:
DRW::Version version;
secObjects
};*/
-dxfRW::dxfRW(const char* name){
+dxfRW::dxfRW(){
DRW_DBGSL(DRW_dbg::NONE);
- fileName = name;
reader = NULL;
writer = NULL;
applyExt = false;
}
}
-bool dxfRW::read(DRW_Interface *interface_, bool ext){
- drw_assert(fileName.empty() == false);
- bool isOk = false;
+bool dxfRW::read(std::istream &stream, DRW_Interface *interface_, bool ext){
applyExt = ext;
- std::ifstream filestr;
- if ( interface_ == NULL )
- return isOk;
- DRW_DBG("dxfRW::read 1def\n");
- filestr.open (fileName.c_str(), std::ios_base::in | std::ios::binary);
- if (!filestr.is_open())
- return isOk;
- if (!filestr.good())
- return isOk;
+
+ if(interface_ == NULL)
+ return false;
char line[22];
char line2[22] = "AutoCAD Binary DXF\r\n";
line2[20] = (char)26;
line2[21] = '\0';
- filestr.read (line, 22);
- filestr.close();
+ stream.read (line, 22);
iface = interface_;
DRW_DBG("dxfRW::read 2\n");
if (strcmp(line, line2) == 0) {
- filestr.open (fileName.c_str(), std::ios_base::in | std::ios::binary);
binFile = true;
- //skip sentinel
- filestr.seekg (22, std::ios::beg);
- reader = new dxfReaderBinary(&filestr);
+ reader = new dxfReaderBinary(&stream);
DRW_DBG("dxfRW::read binary file\n");
} else {
binFile = false;
- filestr.open (fileName.c_str(), std::ios_base::in);
- reader = new dxfReaderAscii(&filestr);
+ stream.seekg(0, std::ios::beg);
+ reader = new dxfReaderAscii(&stream);
}
- isOk = processDxf();
- filestr.close();
+ bool isOk = processDxf();
delete reader;
reader = NULL;
return isOk;
}
-bool dxfRW::write(DRW_Interface *interface_, DRW::Version ver, bool bin){
- bool isOk = false;
- std::ofstream filestr;
+bool dxfRW::write(std::ostream &stream, DRW_Interface *interface_, DRW::Version ver, bool bin){
version = ver;
binFile = bin;
iface = interface_;
if (binFile) {
- filestr.open (fileName.c_str(), std::ios_base::out | std::ios::binary | std::ios::trunc);
//write sentinel
- filestr << "AutoCAD Binary DXF\r\n" << (char)26 << '\0';
- writer = new dxfWriterBinary(&filestr);
+ stream << "AutoCAD Binary DXF\r\n" << (char)26 << '\0';
+ writer = new dxfWriterBinary(&stream);
DRW_DBG("dxfRW::read binary file\n");
} else {
- filestr.open (fileName.c_str(), std::ios_base::out | std::ios::trunc);
- writer = new dxfWriterAscii(&filestr);
+ writer = new dxfWriterAscii(&stream);
std::string comm = std::string("dxfrw ") + std::string(DRW_VERSION);
writer->writeString(999, comm);
}
writer->writeString(0, "ENDSEC");
}
writer->writeString(0, "EOF");
- filestr.flush();
- filestr.close();
- isOk = true;
+ stream.flush();
delete writer;
writer = NULL;
- return isOk;
+ return true;
}
bool dxfRW::writeEntity(DRW_Entity *ent) {
class dxfRW {
public:
- dxfRW(const char* name);
+ dxfRW();
~dxfRW();
void setDebug(DRW::DBG_LEVEL lvl);
/// reads the file specified in constructor
* @param ext should the extrusion be applied to convert in 2D?
* @return true for success
*/
- bool read(DRW_Interface *interface_, bool ext);
+ bool read(std::istream &stream, DRW_Interface *interface_, bool ext);
void setBinary(bool b) {binFile = b;}
- bool write(DRW_Interface *interface_, DRW::Version ver, bool bin);
+ bool write(std::ostream &stream, DRW_Interface *interface_, DRW::Version ver, bool bin);
bool writeLineType(DRW_LType *ent);
bool writeLayer(DRW_Layer *ent);
bool writeDimstyle(DRW_Dimstyle *ent);
set(fixups)
foreach(lib ${platform_BUNDLED_LIBS})
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)
+ string(REGEX REPLACE "^.+:\n" "" canonical_lib ${canonical_lib})
add_custom_command(TARGET solvespace POST_BUILD
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
$<TARGET_FILE:solvespace>
if(NSString *nsChr = [event charactersIgnoringModifiers])
chr = [nsChr characterAtIndex:0];
- if(chr == NSDeleteCharacter) /* map delete back to backspace */
- chr = '\b';
if(chr >= NSF1FunctionKey && chr <= NSF12FunctionKey)
chr = SolveSpace::GraphicsWindow::FUNCTION_KEY_BASE + (chr - NSF1FunctionKey);
label = [[NSString stringWithUTF8String:entry->label]
stringByReplacingOccurrencesOfString:@"&" withString:@""];
- unichar accel_char = entry->accel &
+ unichar accelChar = entry->accel &
~(GraphicsWindow::SHIFT_MASK | GraphicsWindow::CTRL_MASK);
- if(accel_char > GraphicsWindow::FUNCTION_KEY_BASE &&
- accel_char <= GraphicsWindow::FUNCTION_KEY_BASE + 12)
- accel_char = NSF1FunctionKey + (accel_char - GraphicsWindow::FUNCTION_KEY_BASE - 1);
- NSString *accel = [NSString stringWithCharacters:&accel_char length:1];
+ if(accelChar > GraphicsWindow::FUNCTION_KEY_BASE &&
+ accelChar <= GraphicsWindow::FUNCTION_KEY_BASE + 12) {
+ accelChar = NSF1FunctionKey + (accelChar - GraphicsWindow::FUNCTION_KEY_BASE - 1);
+ } else if(accelChar == GraphicsWindow::DELETE_KEY) {
+ accelChar = NSBackspaceCharacter;
+ }
+ NSString *accel = [NSString stringWithCharacters:&accelChar length:1];
menuItem = [levels[entry->level] addItemWithTitle:label
action:NULL keyEquivalent:[accel lowercaseString]];
if(defExtension != "") {
extensionIndex = [extensions indexOfObject:
[NSString stringWithUTF8String:defExtension.c_str()]];
+ if(extensionIndex == -1) {
+ extensionIndex = 0;
+ }
}
[button selectItemAtIndex:extensionIndex];
[TW setFrameAutosaveName:@"TextWindow"];
[TW setFloatingPanel:YES];
[TW setBecomesKeyOnlyIfNeeded:YES];
- [GW addChildWindow:TW ordered:NSWindowAbove];
-
- // Without this, graphics window is also hidden when the text window is shown
- // (and is its child window). We replicate the standard behavior manually, in
- // the application delegate;
- [TW setHidesOnDeactivate:NO];
NSScrollView *scrollView = [[NSScrollView alloc] init];
[TW setContentView:scrollView];
[scrollView setBackgroundColor:[NSColor blackColor]];
[scrollView setHasVerticalScroller:YES];
+ [scrollView setScrollerKnobStyle:NSScrollerKnobStyleLight];
[[scrollView contentView] setCopiesOnScroll:YES];
TWView = [[TextWindowView alloc] init];
void ShowTextWindow(bool visible) {
if(visible)
- [GW addChildWindow:TW ordered:NSWindowAbove];
+ [TW orderFront:nil];
else
- [TW orderOut:GW];
+ [TW close];
}
void GetTextWindowSize(int *w, int *h) {
void SolveSpace::DoMessageBox(const char *str, int rows, int cols, bool error) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:(error ? NSWarningAlertStyle : NSInformationalAlertStyle)];
- [[alert addButtonWithTitle:@"OK"] setKeyEquivalent: @"\033"];
+ [alert addButtonWithTitle:@"OK"];
/* do some additional formatting of the message these are
heuristics, but they are made failsafe and lead to nice results. */
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
- (void)applicationWillTerminate:(NSNotification *)aNotification;
-- (void)applicationWillBecomeActive:(NSNotification *)aNotification;
-- (void)applicationWillResignActive:(NSNotification *)aNotification;
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename;
- (IBAction)preferences:(id)sender;
@end
SolveSpace::SS.Exit();
}
-- (void)applicationWillBecomeActive:(NSNotification *)aNotification {
- if(SolveSpace::SS.GW.showTextWindow) {
- [GW addChildWindow:TW ordered:NSWindowAbove];
- }
-}
-
-- (void)applicationWillResignActive:(NSNotification *)aNotification {
- [TW setAnimationBehavior:NSWindowAnimationBehaviorNone];
- [TW orderOut:nil];
- [TW setAnimationBehavior:NSWindowAnimationBehaviorDefault];
-}
-
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
return SolveSpace::SS.OpenFile([filename UTF8String]);
}
((gs.workplanes == 1 && gs.n == 3) ||
(gs.n == 2)))
{
- c.entityA = gs.entity[0];
+ if(gs.entities > 0)
+ c.entityA = gs.entity[0];
c.ptA = gs.point[0];
c.ptB = gs.point[1];
} else if(gs.lineSegments == 1 &&
((gs.workplanes == 1 && gs.n == 2) ||
(gs.n == 1)))
{
- int i = SK.GetEntity(gs.entity[0])->IsWorkplane() ? 1 : 0;
- Entity *line = SK.GetEntity(gs.entity[i]);
- c.entityA = gs.entity[1-i];
+ Entity *line;
+ if(SK.GetEntity(gs.entity[0])->IsWorkplane()) {
+ line = SK.GetEntity(gs.entity[1]);
+ c.entityA = gs.entity[0];
+ } else {
+ line = SK.GetEntity(gs.entity[0]);
+ }
c.ptA = line->point[0];
c.ptB = line->point[1];
} else if(SS.GW.LockedInWorkplane()
found = true;
e->tag = 1;
- DRW_LWPolyline polyline;
+ DRW_Polyline polyline;
assignEntityDefaults(&polyline, e->style);
- polyline.vertlist.push_back(new DRW_Vertex2D(start->pos.x, start->pos.y, 0.0));
- polyline.vertlist.push_back(new DRW_Vertex2D(next->pos.x, next->pos.y, 0.0));
+ polyline.vertlist.push_back(
+ 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)) {
- 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) {
Vector dna = norm.Cross(da).WithMagnitude(1.0);
double thetaf = acos(da.DirectionCosineWith(db));
-
+
// Calculate median
Vector m = da.WithMagnitude(1.0).ScaledBy(cos(thetaf/2)).Plus(
dna.ScaledBy(sin(thetaf/2)));
List<Vector> lv = {};
sb->MakePwlInto(&lv, SS.ExportChordTolMm());
hStyle hs = { (uint32_t)sb->auxA };
- DRW_LWPolyline polyline;
+ DRW_Polyline polyline;
assignEntityDefaults(&polyline, hs);
for(int i = 0; i < lv.n; i++) {
Vector *v = &lv.elem[i];
- DRW_Vertex2D *vertex = new DRW_Vertex2D();
- vertex->x = v->x;
- vertex->y = v->y;
+ DRW_Vertex *vertex = new DRW_Vertex(v->x, v->y, v->z, 0.0);
polyline.vertlist.push_back(vertex);
}
- dxf->writeLWPolyline(&polyline);
+ dxf->writePolyline(&polyline);
lv.Clear();
}
spline.ncontrol = sb->deg + 1;
makeKnotsFor(&spline);
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]);
}
dxf->writeSpline(&spline);
paths.back().beziers.push_back(sb);
}
-void DxfFileWriter::FinishAndCloseFile(void) {
- dxfRW dxf(filename.c_str());
+void DxfFileWriter::FinishAndCloseFile() {
+ dxfRW dxf;
+
DxfWriteInterface interface(this, &dxf);
- dxf.write(&interface, DRW::AC1021, false);
+ std::stringstream stream;
+ dxf.write(stream, &interface, DRW::AC1021, /*bin=*/false);
paths.clear();
constraint = NULL;
+
+ if(!WriteFile(filename, stream.str())) {
+ Error("Couldn't write to '%s'", filename.c_str());
+ return;
+ }
}
bool DxfFileWriter::NeedToOutput(Constraint *c) {
// The group falls inside the range, so really solve it,
// and then regenerate the mesh based on the solved stuff.
if(genForBBox) {
- SolveGroup(g->h, andFindFree);
+ SolveGroupAndReport(g->h, andFindFree);
} else {
g->GenerateLoops();
g->GenerateShellAndMesh();
}
}
+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) {
int i;
// Clear out the system to be solved.
g->solved.remove.Clear();
int how = sys.Solve(g, &(g->solved.dof),
&(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;
FreeAllTemporary();
}
// not our own previous group.
srcg = SK.GetGroup(opA);
- GenerateForStepAndRepeat<SShell>(&(srcg->thisShell), &thisShell);
- GenerateForStepAndRepeat<SMesh> (&(srcg->thisMesh), &thisMesh);
+ if(!srcg->suppress) {
+ GenerateForStepAndRepeat<SShell>(&(srcg->thisShell), &thisShell);
+ GenerateForStepAndRepeat<SMesh> (&(srcg->thisMesh), &thisMesh);
+ }
} else if(type == EXTRUDE && haveSrc) {
Group *src = SK.GetGroup(opA);
Vector translate = Vector::From(h.param(0), h.param(1), h.param(2));
#include "../unix/gloffscreen.h"
#ifdef HAVE_SPACEWARE
-# include <spnav.h>
-# ifndef SI_APP_FIT_BUTTON
-# define SI_APP_FIT_BUTTON 31
-# endif
+#include <spnav.h>
#endif
namespace SolveSpace {
for(const char *const *ssPattern = ssFilter->patterns; *ssPattern; ssPattern++) {
std::string pattern = "*." + std::string(*ssPattern);
filter->add_pattern(pattern);
+ filter->add_pattern(Glib::ustring(pattern).uppercase());
if(active == "")
active = pattern.substr(2);
if("*." + active == pattern)
break;
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();
}
break;
};
void ImportDxf(const std::string &filename) {
- SS.UndoRemember();
- dxfRW dxf(filename.c_str());
DxfReadInterface interface;
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) {
Message(ssprintf("%u DXF entities of unknown type were ignored.",
interface.unknownEntities).c_str());
}
void ImportDwg(const std::string &filename) {
- SS.UndoRemember();
- dwgR dwg(filename.c_str());
DxfReadInterface interface;
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) {
Message(ssprintf("%u DWG entities of unknown type were ignored.",
interface.unknownEntities).c_str());
AddTriangle(&t);
}
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);
}
pending.operation != DRAGGING_MARQUEE)
{
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;
+ }
}
}
pending.points.Clear();
pending = {};
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) {
static std::string Extension(const std::string &filename) {
int dot = filename.rfind('.');
- if(dot >= 0)
- return filename.substr(dot + 1, filename.length());
+ if(dot >= 0) {
+ std::string ext = filename.substr(dot + 1, filename.length());
+ std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+ return ext;
+ }
return "";
}
ImportDxf(importFile);
} else if(Extension(importFile) == "dwg") {
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.ScheduleShowTW();
#include <unordered_map>
#include <map>
#include <set>
+#include <sstream>
#ifdef WIN32
# include <windows.h> // required by GL headers
#endif
#endif
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);
#define MAX_RECENT 8
double a41, double a42, double a43, double a44);
std::string MakeAcceleratorLabel(int accel);
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 Error(const char *str, ...);
void CnfFreezeBool(bool v, const std::string &name);
void GenerateAll(GenerateType type = GENERATE_DIRTY, bool andFindFree = false,
bool genForBBox = false);
void SolveGroup(hGroup hg, bool andFindFree);
+ void SolveGroupAndReport(hGroup hg, bool andFindFree);
void MarkDraggedParams(void);
void ForceReferences(void);
for(i = start; i < sm->l.n; i++) {
STriangle *st = &(sm->l.elem[i]);
st->meta = meta;
+ if(st->meta.color.alpha != 255) sm->isTransparent = true;
st->an = NormalAt(st->a.x, st->a.y);
st->bn = NormalAt(st->b.x, st->b.y);
st->cn = NormalAt(st->c.x, st->c.y);
if(!rankOk) {
if(!g->allowRedundant) {
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad);
- return System::REDUNDANT_OKAY;
}
- }
-
- // This is not the full Jacobian, but any substitutions or single-eq
- // solves removed one equation and one unknown, therefore no effect
- // on the number of DOF.
- if(dof) *dof = mat.n - mat.m;
-
- // If requested, find all the free (unbound) variables. This might be
- // more than the number of degrees of freedom. Don't always do this,
- // because the display would get annoying and it's slow.
- for(i = 0; i < param.n; i++) {
- Param *p = &(param.elem[i]);
- p->free = false;
-
- if(andFindFree) {
- if(p->tag == 0) {
- p->tag = VAR_DOF_TEST;
- WriteJacobian(0);
- EvalJacobian();
- int rank = CalculateRank();
- if(rank == mat.m) {
- p->free = true;
+ } else {
+ // This is not the full Jacobian, but any substitutions or single-eq
+ // solves removed one equation and one unknown, therefore no effect
+ // on the number of DOF.
+ if(dof) *dof = mat.n - mat.m;
+
+ // If requested, find all the free (unbound) variables. This might be
+ // more than the number of degrees of freedom. Don't always do this,
+ // because the display would get annoying and it's slow.
+ for(i = 0; i < param.n; i++) {
+ Param *p = &(param.elem[i]);
+ p->free = false;
+
+ if(andFindFree) {
+ if(p->tag == 0) {
+ p->tag = VAR_DOF_TEST;
+ WriteJacobian(0);
+ EvalJacobian();
+ int rank = CalculateRank();
+ if(rank == mat.m) {
+ p->free = true;
+ }
+ p->tag = 0;
}
- p->tag = 0;
}
}
}
-
// System solved correctly, so write the new values back in to the
// main parameter table.
for(i = 0; i < param.n; i++) {
break;
}
}
- if(r >= rows) {
+ if(r < 0 || c < 0 || r >= rows || c >= MAX_COLS) {
SetMousePointerToHand(false);
goto done;
}
[&](const TtfFont &tf) { return tf.FontFileBaseName() == font; });
if(!str.empty() && tf != &l.elem[l.n]) {
- tf->LoadFromFile(fontLibrary, /*nameOnly=*/false);
+ if(tf->fontFace == NULL) {
+ tf->LoadFromFile(fontLibrary, /*nameOnly=*/false);
+ }
tf->PlotString(str, sbl, origin, u, v);
} else {
// No text or no font; so draw a big X for an error marker.
dbp("freetype: loading unicode CMap for file '%s' failed: %s",
fontFile.c_str(), ft_error_string(fterr));
FT_Done_Face(fontFace);
+ fontFace = NULL;
return false;
}
if(nameOnly) {
FT_Done_Face(fontFace);
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;
outlineFuncs.delta = 0;
FT_Pos dx = 0;
- for(char32_t chr : ReadUTF8(str)) {
- uint32_t gid = FT_Get_Char_Index(fontFace, chr);
+ for(char32_t cid : ReadUTF8(str)) {
+ uint32_t gid = FT_Get_Char_Index(fontFace, cid);
if (gid == 0) {
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
- chr, ft_error_string(gid));
- }
-
- // 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));
- return;
+ cid, ft_error_string(gid));
+ gid = cid;
}
/*
* ones, antialiasing mitigates this considerably though.
*/
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));
return;
}
data.u = u;
data.v = v;
data.beziers = sbl;
- data.factor = 1.0f/(float)(1 << 16);
+ data.factor = 1.0 / capHeight;
data.bx = bx;
if(int fterr = FT_Outline_Decompose(&fontFace->glyph->outline, &outlineFuncs, &data)) {
dbp("freetype: bezier decomposition failed (gid %d): %s",
std::string fontFile;
std::string name;
FT_FaceRec_ *fontFace;
+ double capHeight;
std::string FontFileBaseName() const;
bool LoadFromFile(FT_LibraryRec_ *fontLibrary, bool nameOnly = true);
// allowing a paint in between. The extra solves are wasted if they're
// not displayed.
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.
struct {
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,
double a11, double a12, double a13, double a14,
double a21, double a22, double a23, double a24,
HWND MessageWnd, OkButton;
bool MessageDone;
+int MessageWidth, MessageHeight;
const char *MessageString;
static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam,
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
- int row = 0, col = 0, i;
SelectObject(hdc, FixedFont);
SetTextColor(hdc, 0x000000);
SetBkMode(hdc, TRANSPARENT);
- for(i = 0; MessageString[i]; i++) {
- if(MessageString[i] == '\n') {
- col = 0;
- row++;
- } else {
- TextOutW(hdc, col*SS.TW.CHAR_WIDTH + 10,
- row*SS.TW.LINE_HEIGHT + 10,
- Widen(&(MessageString[i])).c_str(), 1);
- col++;
- }
- }
+ RECT rc;
+ SetRect(&rc, 10, 10, MessageWidth, MessageHeight);
+ std::wstring text = Widen(MessageString);
+ DrawText(hdc, text.c_str(), text.length(), &rc, DT_LEFT | DT_WORDBREAK);
EndPaint(hwnd, &ps);
break;
}
const char *title = error ? "SolveSpace - Error" : "SolveSpace - Message";
int width = cols*SS.TW.CHAR_WIDTH + 20,
height = rows*SS.TW.LINE_HEIGHT + 60;
+ MessageWidth = width;
+ MessageHeight = height;
MessageWnd = CreateWindowClient(0, L"MessageWnd", Widen(title).c_str(),
WS_OVERLAPPED | WS_SYSMENU,
r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL);
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.
// We never try to fopen paths that are not absolute or
std::string uncFilename = filename;
if(uncFilename.substr(0, 2) != "\\\\")
uncFilename = "\\\\?\\" + uncFilename;
+ return uncFilename;
+}
+FILE *ssfopen(const std::string &filename, const char *mode)
+{
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)