2009-07-08 09:44:13 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// The file format-specific stuff for all of the 2d vector output formats.
|
2013-07-28 22:08:34 +00:00
|
|
|
//
|
|
|
|
// Copyright 2008-2013 Jonathan Westhues.
|
2009-07-08 09:44:13 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2015-12-25 08:29:08 +00:00
|
|
|
#include <libdxfrw.h>
|
2009-07-08 09:44:13 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Routines for DXF export
|
|
|
|
//-----------------------------------------------------------------------------
|
2015-12-25 08:29:08 +00:00
|
|
|
class DxfWriteInterface : public DRW_Interface {
|
2016-06-29 16:47:23 +00:00
|
|
|
public:
|
2015-12-25 08:29:08 +00:00
|
|
|
DxfFileWriter *writer;
|
2016-06-29 16:47:23 +00:00
|
|
|
dxfRW *dxf;
|
|
|
|
|
|
|
|
std::set<std::string> messages;
|
2015-12-25 08:29:08 +00:00
|
|
|
|
2016-01-06 12:40:17 +00:00
|
|
|
static DRW_Coord toCoord(const Vector &v) {
|
|
|
|
return DRW_Coord(v.x, v.y, v.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector xfrm(Vector v) {
|
|
|
|
return writer->Transform(v);
|
|
|
|
}
|
|
|
|
|
2016-05-18 18:42:33 +00:00
|
|
|
void writeTextstyles() override {
|
2016-01-06 12:40:17 +00:00
|
|
|
DRW_Textstyle ts;
|
|
|
|
ts.name = "unicode";
|
|
|
|
ts.font = "unicode";
|
|
|
|
dxf->writeTextstyle(&ts);
|
|
|
|
}
|
|
|
|
|
2016-05-18 18:42:33 +00:00
|
|
|
void writeLayers() override {
|
2016-02-19 03:31:10 +00:00
|
|
|
DRW_Layer layer;
|
2016-04-12 23:57:49 +00:00
|
|
|
|
2016-02-19 03:31:10 +00:00
|
|
|
layer.name = "dimensions";
|
|
|
|
dxf->writeLayer(&layer);
|
|
|
|
layer.name = "text";
|
|
|
|
dxf->writeLayer(&layer);
|
2016-04-12 23:57:49 +00:00
|
|
|
|
2016-08-07 12:42:05 +00:00
|
|
|
std::set<uint32_t> usedStyles;
|
|
|
|
|
|
|
|
for(DxfFileWriter::BezierPath &path : writer->paths) {
|
|
|
|
for(SBezier *sb : path.beziers) {
|
|
|
|
usedStyles.insert((uint32_t)sb->auxA);
|
2016-03-14 16:14:24 +00:00
|
|
|
}
|
2016-08-07 12:42:05 +00:00
|
|
|
}
|
2016-04-12 23:57:49 +00:00
|
|
|
|
2016-08-07 12:42:05 +00:00
|
|
|
for(uint32_t v : usedStyles) {
|
|
|
|
Style *s = Style::Get(hStyle{v});
|
2016-03-14 16:14:24 +00:00
|
|
|
layer.name = s->DescriptionString();
|
|
|
|
dxf->writeLayer(&layer);
|
|
|
|
}
|
2016-02-19 03:31:10 +00:00
|
|
|
}
|
|
|
|
|
2016-05-18 18:42:33 +00:00
|
|
|
void writeLTypes() override {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
for(uint32_t i = 0; i <= (uint32_t)StipplePattern::LAST; i++) {
|
|
|
|
StipplePattern st = (StipplePattern)i;
|
2016-03-03 02:51:13 +00:00
|
|
|
DRW_LType type;
|
|
|
|
// LibreCAD requires the line type to have one of these exact names,
|
|
|
|
// or otherwise it overwrites it with its own (continuous) style.
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
type.name = DxfFileWriter::lineTypeName(st);
|
2016-03-03 02:51:13 +00:00
|
|
|
double sw = 1.0;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
switch(st) {
|
|
|
|
case StipplePattern::CONTINUOUS:
|
2016-03-03 02:51:13 +00:00
|
|
|
break;
|
|
|
|
|
2016-05-26 19:20:39 +00:00
|
|
|
case StipplePattern::SHORT_DASH:
|
|
|
|
type.path.push_back(sw);
|
|
|
|
type.path.push_back(-sw * 2.0);
|
|
|
|
break;
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DASH:
|
2016-03-03 02:51:13 +00:00
|
|
|
type.path.push_back(sw);
|
|
|
|
type.path.push_back(-sw);
|
|
|
|
break;
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::LONG_DASH:
|
2016-03-03 02:51:13 +00:00
|
|
|
type.path.push_back(sw * 2.0);
|
|
|
|
type.path.push_back(-sw);
|
|
|
|
break;
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DASH_DOT:
|
2016-03-03 02:51:13 +00:00
|
|
|
type.path.push_back(sw);
|
|
|
|
type.path.push_back(-sw);
|
|
|
|
type.path.push_back(0.0);
|
|
|
|
type.path.push_back(-sw);
|
|
|
|
break;
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DOT:
|
2016-03-03 02:51:13 +00:00
|
|
|
type.path.push_back(sw);
|
|
|
|
type.path.push_back(0.0);
|
|
|
|
break;
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DASH_DOT_DOT:
|
2016-03-03 02:51:13 +00:00
|
|
|
type.path.push_back(sw);
|
|
|
|
type.path.push_back(-sw);
|
|
|
|
type.path.push_back(0.0);
|
|
|
|
type.path.push_back(-sw);
|
|
|
|
type.path.push_back(0.0);
|
|
|
|
type.path.push_back(-sw);
|
|
|
|
break;
|
Enable exhaustive switch coverage warnings as an error, and use them.
Specifically, this enables -Wswitch=error on GCC/Clang and its MSVC
equivalent; the exact way it is handled varies slightly, but what
they all have in common is that in a switch statement over an
enumeration, any enumerand that is not explicitly (via case:) or
implicitly (via default:) handled in the switch triggers an error.
Moreover, we also change the switch statements in three ways:
* Switch statements that ought to be extended every time a new
enumerand is added (e.g. Entity::DrawOrGetDistance(), are changed
to explicitly list every single enumerand, and not have a
default: branch.
Note that the assertions are kept because it is legal for
a enumeration to have a value unlike any of its defined
enumerands, and we can e.g. read garbage from a file, or
an uninitialized variable. This requires some rearranging if
a default: branch is undesired.
* Switch statements that ought to only ever see a few select
enumerands, are changed to always assert in the default: branch.
* Switch statements that do something meaningful for a few
enumerands, and ignore everything else, are changed to do nothing
in a default: branch, under the assumption that changing them
every time an enumerand is added or removed would just result
in noise and catch no bugs.
This commit also removes the {Request,Entity,Constraint}::UNKNOWN and
Entity::DATUM_POINT enumerands, as those were just fancy names for
zeroes. They mess up switch exhaustiveness checks and most of the time
were not the best way to implement what they did anyway.
2016-05-25 06:55:50 +00:00
|
|
|
|
|
|
|
case StipplePattern::FREEHAND:
|
|
|
|
case StipplePattern::ZIGZAG:
|
2016-06-29 16:47:23 +00:00
|
|
|
// Not implemented; exported as continuous.
|
|
|
|
break;
|
2016-03-03 02:51:13 +00:00
|
|
|
}
|
|
|
|
dxf->writeLineType(&type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-21 11:11:41 +00:00
|
|
|
void writePolylines() {
|
|
|
|
PolylineBuilder builder;
|
|
|
|
|
|
|
|
for(DxfFileWriter::BezierPath &path : writer->paths) {
|
|
|
|
for(SBezier *sb : path.beziers) {
|
|
|
|
if(sb->deg != 1) continue;
|
2016-06-24 09:06:30 +00:00
|
|
|
builder.AddEdge(sb->ctrl[0], sb->ctrl[1], (uint32_t)sb->auxA);
|
2016-03-21 11:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 09:06:30 +00:00
|
|
|
DRW_LWPolyline polyline;
|
2016-03-21 11:11:41 +00:00
|
|
|
|
2016-06-24 09:06:30 +00:00
|
|
|
auto startFunc = [&](PolylineBuilder::Vertex *start,
|
|
|
|
PolylineBuilder::Vertex *next,
|
|
|
|
PolylineBuilder::Edge *e) {
|
|
|
|
hStyle hs = { e->kind };
|
|
|
|
polyline = {};
|
|
|
|
assignEntityDefaults(&polyline, hs);
|
|
|
|
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));
|
|
|
|
};
|
2016-03-21 11:11:41 +00:00
|
|
|
|
2016-06-24 09:06:30 +00:00
|
|
|
auto nextFunc = [&](PolylineBuilder::Vertex *next, PolylineBuilder::Edge *e) {
|
|
|
|
polyline.vertlist.push_back(new DRW_Vertex2D(next->pos.x, next->pos.y, 0.0));
|
|
|
|
};
|
2016-03-21 11:11:41 +00:00
|
|
|
|
2016-06-24 09:06:30 +00:00
|
|
|
auto endFunc = [&]() {
|
|
|
|
dxf->writeLWPolyline(&polyline);
|
|
|
|
};
|
2016-03-21 11:11:41 +00:00
|
|
|
|
2016-06-24 09:06:30 +00:00
|
|
|
auto aloneFunc = [&](PolylineBuilder::Edge *e) {
|
|
|
|
hStyle hs = { e->kind };
|
|
|
|
writeLine(e->a->pos, e->b->pos, hs);
|
|
|
|
};
|
|
|
|
|
|
|
|
builder.Generate(startFunc, nextFunc, aloneFunc, endFunc);
|
2016-03-21 11:11:41 +00:00
|
|
|
}
|
|
|
|
|
2016-05-18 18:42:33 +00:00
|
|
|
void writeEntities() override {
|
2016-03-21 11:11:41 +00:00
|
|
|
writePolylines();
|
|
|
|
|
2015-12-28 10:50:38 +00:00
|
|
|
for(DxfFileWriter::BezierPath &path : writer->paths) {
|
|
|
|
for(SBezier *sb : path.beziers) {
|
2016-03-21 11:11:41 +00:00
|
|
|
if(sb->deg == 1) continue;
|
2015-12-28 10:50:38 +00:00
|
|
|
writeBezier(sb);
|
|
|
|
}
|
2015-12-25 08:29:08 +00:00
|
|
|
}
|
2016-01-06 12:40:17 +00:00
|
|
|
|
|
|
|
if(writer->constraint) {
|
|
|
|
Constraint *c;
|
|
|
|
for(c = writer->constraint->First(); c; c = writer->constraint->NextAfter(c)) {
|
2016-03-24 13:55:36 +00:00
|
|
|
if(!writer->NeedToOutput(c)) continue;
|
2016-01-06 12:40:17 +00:00
|
|
|
switch(c->type) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case Constraint::Type::PT_PT_DISTANCE: {
|
2016-01-06 12:40:17 +00:00
|
|
|
Vector ap = SK.GetEntity(c->ptA)->PointGetNum();
|
|
|
|
Vector bp = SK.GetEntity(c->ptB)->PointGetNum();
|
|
|
|
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(c->disp.offset);
|
|
|
|
writeAlignedDimension(xfrm(ap), xfrm(bp), xfrm(ref),
|
2016-05-17 05:08:24 +00:00
|
|
|
xfrm(ref), c->Label(), c->GetStyle(), c->valA);
|
2016-01-06 12:40:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case Constraint::Type::PT_LINE_DISTANCE: {
|
2016-01-06 12:40:17 +00:00
|
|
|
Vector pt = SK.GetEntity(c->ptA)->PointGetNum();
|
|
|
|
Entity *line = SK.GetEntity(c->entityA);
|
|
|
|
Vector lA = SK.GetEntity(line->point[0])->PointGetNum();
|
|
|
|
Vector lB = SK.GetEntity(line->point[1])->PointGetNum();
|
|
|
|
Vector dl = lB.Minus(lA);
|
|
|
|
|
|
|
|
Vector closest = pt.ClosestPointOnLine(lA, dl);
|
|
|
|
|
|
|
|
if(pt.Equals(closest)) break;
|
|
|
|
|
|
|
|
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(c->disp.offset);
|
|
|
|
Vector refClosest = ref.ClosestPointOnLine(lA, dl);
|
|
|
|
|
|
|
|
double ddl = dl.Dot(dl);
|
|
|
|
if(fabs(ddl) > LENGTH_EPS * LENGTH_EPS) {
|
|
|
|
double t = refClosest.Minus(lA).Dot(dl) / ddl;
|
|
|
|
if(t < 0.0) {
|
|
|
|
refClosest = lA;
|
|
|
|
} else if(t > 1.0) {
|
|
|
|
refClosest = lB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector xdl = xfrm(lB).Minus(xfrm(lA));
|
|
|
|
writeLinearDimension(xfrm(pt), xfrm(refClosest), xfrm(ref),
|
|
|
|
xfrm(ref), c->Label(),
|
2016-05-17 05:08:24 +00:00
|
|
|
atan2(xdl.y, xdl.x) / PI * 180.0 + 90.0, 0.0,
|
|
|
|
c->GetStyle(), c->valA);
|
2016-01-06 12:40:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case Constraint::Type::DIAMETER: {
|
2016-01-06 12:40:17 +00:00
|
|
|
Entity *circle = SK.GetEntity(c->entityA);
|
|
|
|
Vector center = SK.GetEntity(circle->point[0])->PointGetNum();
|
|
|
|
Quaternion q = SK.GetEntity(circle->normal)->NormalGetNum();
|
|
|
|
Vector n = q.RotationN().WithMagnitude(1);
|
|
|
|
double r = circle->CircleGetRadiusNum();
|
|
|
|
|
|
|
|
Vector ref = center.Plus(c->disp.offset);
|
|
|
|
// Force the label into the same plane as the circle.
|
|
|
|
ref = ref.Minus(n.ScaledBy(n.Dot(ref) - n.Dot(center)));
|
|
|
|
|
|
|
|
Vector rad = ref.Minus(center).WithMagnitude(r);
|
|
|
|
if(/*isRadius*/c->other) {
|
|
|
|
writeRadialDimension(
|
|
|
|
xfrm(center), xfrm(center.Plus(rad)),
|
2016-05-17 05:08:24 +00:00
|
|
|
xfrm(ref), c->Label(), c->GetStyle(), c->valA);
|
2016-01-06 12:40:17 +00:00
|
|
|
} else {
|
|
|
|
writeDiametricDimension(
|
|
|
|
xfrm(center.Minus(rad)), xfrm(center.Plus(rad)),
|
2016-05-17 05:08:24 +00:00
|
|
|
xfrm(ref), c->Label(), c->GetStyle(), c->valA);
|
2016-01-06 12:40:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case Constraint::Type::ANGLE: {
|
2016-01-06 12:40:17 +00:00
|
|
|
Entity *a = SK.GetEntity(c->entityA);
|
|
|
|
Entity *b = SK.GetEntity(c->entityB);
|
|
|
|
|
|
|
|
Vector a0 = a->VectorGetStartPoint();
|
|
|
|
Vector b0 = b->VectorGetStartPoint();
|
|
|
|
Vector da = a->VectorGetNum();
|
|
|
|
Vector db = b->VectorGetNum();
|
|
|
|
if(/*otherAngle*/c->other) {
|
|
|
|
a0 = a0.Plus(da);
|
|
|
|
da = da.ScaledBy(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool skew = false;
|
|
|
|
Vector ref = c->disp.offset;
|
|
|
|
Vector pi = Vector::AtIntersectionOfLines(a0, a0.Plus(da), b0, b0.Plus(db),
|
|
|
|
&skew);
|
|
|
|
if(!skew) ref = pi.Plus(c->disp.offset);
|
|
|
|
|
2016-05-07 10:30:26 +00:00
|
|
|
Vector norm = da.Cross(db);
|
|
|
|
Vector dna = norm.Cross(da).WithMagnitude(1.0);
|
|
|
|
|
|
|
|
double thetaf = acos(da.DirectionCosineWith(db));
|
2016-05-18 18:42:33 +00:00
|
|
|
|
2016-05-07 10:30:26 +00:00
|
|
|
// Calculate median
|
|
|
|
Vector m = da.WithMagnitude(1.0).ScaledBy(cos(thetaf/2)).Plus(
|
|
|
|
dna.ScaledBy(sin(thetaf/2)));
|
|
|
|
Vector rm = ref.Minus(pi);
|
|
|
|
|
|
|
|
// Test which side we have to place an arc
|
|
|
|
if(m.Dot(rm) < 0) {
|
|
|
|
da = da.ScaledBy(-1); dna = dna.ScaledBy(-1);
|
|
|
|
db = db.ScaledBy(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector bisect = da.WithMagnitude(1.0).ScaledBy(cos(thetaf / 2.0)).Plus(
|
|
|
|
dna.ScaledBy(sin(thetaf / 2.0)));
|
|
|
|
|
|
|
|
ref = pi.Plus(bisect.WithMagnitude(c->disp.offset.Magnitude()));
|
|
|
|
|
|
|
|
// Get lines agian to write exact line.
|
|
|
|
a0 = a->VectorGetStartPoint();
|
|
|
|
b0 = b->VectorGetStartPoint();
|
|
|
|
da = a->VectorGetNum();
|
|
|
|
db = b->VectorGetNum();
|
|
|
|
|
2016-01-06 12:40:17 +00:00
|
|
|
writeAngularDimension(
|
|
|
|
xfrm(a0), xfrm(a0.Plus(da)), xfrm(b0), xfrm(b0.Plus(db)), xfrm(ref),
|
2016-05-17 05:08:24 +00:00
|
|
|
xfrm(ref), c->Label(), c->GetStyle(), c->valA);
|
2016-01-06 12:40:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case Constraint::Type::COMMENT: {
|
2016-05-07 10:54:44 +00:00
|
|
|
Style *st = SK.style.FindById(c->GetStyle());
|
2016-01-06 12:40:17 +00:00
|
|
|
writeText(xfrm(c->disp.offset), c->Label(),
|
2016-05-07 10:54:44 +00:00
|
|
|
Style::TextHeight(c->GetStyle()) / SS.GW.scale,
|
|
|
|
st->textAngle, st->textOrigin, c->GetStyle());
|
2016-01-06 12:40:17 +00:00
|
|
|
break;
|
|
|
|
}
|
Enable exhaustive switch coverage warnings as an error, and use them.
Specifically, this enables -Wswitch=error on GCC/Clang and its MSVC
equivalent; the exact way it is handled varies slightly, but what
they all have in common is that in a switch statement over an
enumeration, any enumerand that is not explicitly (via case:) or
implicitly (via default:) handled in the switch triggers an error.
Moreover, we also change the switch statements in three ways:
* Switch statements that ought to be extended every time a new
enumerand is added (e.g. Entity::DrawOrGetDistance(), are changed
to explicitly list every single enumerand, and not have a
default: branch.
Note that the assertions are kept because it is legal for
a enumeration to have a value unlike any of its defined
enumerands, and we can e.g. read garbage from a file, or
an uninitialized variable. This requires some rearranging if
a default: branch is undesired.
* Switch statements that ought to only ever see a few select
enumerands, are changed to always assert in the default: branch.
* Switch statements that do something meaningful for a few
enumerands, and ignore everything else, are changed to do nothing
in a default: branch, under the assumption that changing them
every time an enumerand is added or removed would just result
in noise and catch no bugs.
This commit also removes the {Request,Entity,Constraint}::UNKNOWN and
Entity::DATUM_POINT enumerands, as those were just fancy names for
zeroes. They mess up switch exhaustiveness checks and most of the time
were not the best way to implement what they did anyway.
2016-05-25 06:55:50 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
// Other types of constraints do not have a DXF dimension equivalent.
|
|
|
|
break;
|
2016-01-06 12:40:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-25 08:29:08 +00:00
|
|
|
}
|
|
|
|
|
2016-05-07 10:54:44 +00:00
|
|
|
int findDxfColor(const RgbaColor &src) {
|
|
|
|
int best = 0;
|
|
|
|
double minDist = VERY_POSITIVE;
|
|
|
|
Vector srcv = Vector::From(src.redF(), src.greenF(), src.blueF());
|
|
|
|
for(int i = 1; i < 256; i++) {
|
|
|
|
RgbaColor dst = RGBi(DRW::dxfColors[i][0], DRW::dxfColors[i][1], DRW::dxfColors[i][2]);
|
|
|
|
Vector dstv = Vector::From(dst.redF(), dst.greenF(), dst.blueF());
|
|
|
|
double dist = srcv.Minus(dstv).Magnitude();
|
|
|
|
if(dist < minDist || best == 0) {
|
|
|
|
best = i;
|
|
|
|
minDist = dist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2016-04-12 23:57:49 +00:00
|
|
|
void assignEntityDefaults(DRW_Entity *entity, hStyle hs) {
|
2016-03-03 02:51:13 +00:00
|
|
|
Style *s = Style::Get(hs);
|
2016-05-25 12:08:19 +00:00
|
|
|
RgbaColor color = s->Color(hs, /*forExport=*/true);
|
2016-05-07 10:54:44 +00:00
|
|
|
entity->color24 = color.ToPackedIntBGRA();
|
|
|
|
entity->color = findDxfColor(color);
|
2016-03-14 16:14:24 +00:00
|
|
|
entity->layer = s->DescriptionString();
|
2016-04-13 08:43:06 +00:00
|
|
|
entity->lineType = DxfFileWriter::lineTypeName(s->stippleType);
|
2016-03-03 02:51:13 +00:00
|
|
|
entity->ltypeScale = Style::StippleScaleMm(s->h);
|
2016-03-21 11:11:41 +00:00
|
|
|
entity->setWidthMm(Style::WidthMm(hs.v));
|
2016-06-29 16:47:23 +00:00
|
|
|
|
|
|
|
if(s->stippleType == StipplePattern::FREEHAND) {
|
|
|
|
messages.insert("freehand lines were replaced with continuous lines");
|
|
|
|
} else if(s->stippleType == StipplePattern::ZIGZAG) {
|
|
|
|
messages.insert("zigzag lines were replaced with continuous lines");
|
|
|
|
}
|
2015-12-28 10:50:38 +00:00
|
|
|
}
|
|
|
|
|
2016-05-07 10:54:44 +00:00
|
|
|
void assignDimensionDefaults(DRW_Dimension *dimension, hStyle hs) {
|
|
|
|
assignEntityDefaults(dimension, hs);
|
2016-02-19 03:31:10 +00:00
|
|
|
dimension->layer = "dimensions";
|
|
|
|
}
|
|
|
|
|
2016-04-12 23:57:49 +00:00
|
|
|
void writeLine(const Vector &p0, const Vector &p1, hStyle hs) {
|
2015-12-25 08:29:08 +00:00
|
|
|
DRW_Line line;
|
2016-04-12 23:57:49 +00:00
|
|
|
assignEntityDefaults(&line, hs);
|
2016-01-06 12:40:17 +00:00
|
|
|
line.basePoint = toCoord(p0);
|
|
|
|
line.secPoint = toCoord(p1);
|
2015-12-25 08:29:08 +00:00
|
|
|
dxf->writeLine(&line);
|
|
|
|
}
|
|
|
|
|
2016-04-12 23:57:49 +00:00
|
|
|
void writeArc(const Vector &c, double r, double sa, double ea, hStyle hs) {
|
2015-12-25 08:29:08 +00:00
|
|
|
DRW_Arc arc;
|
2016-04-12 23:57:49 +00:00
|
|
|
assignEntityDefaults(&arc, hs);
|
2015-12-25 08:29:08 +00:00
|
|
|
arc.radious = r;
|
2016-01-06 12:40:17 +00:00
|
|
|
arc.basePoint = toCoord(c);
|
2015-12-25 08:29:08 +00:00
|
|
|
arc.staangle = sa;
|
|
|
|
arc.endangle = ea;
|
|
|
|
dxf->writeArc(&arc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeBezierAsPwl(SBezier *sb) {
|
|
|
|
List<Vector> lv = {};
|
|
|
|
sb->MakePwlInto(&lv, SS.ExportChordTolMm());
|
2016-04-12 23:57:49 +00:00
|
|
|
hStyle hs = { (uint32_t)sb->auxA };
|
2015-12-25 08:29:08 +00:00
|
|
|
DRW_LWPolyline polyline;
|
2016-04-12 23:57:49 +00:00
|
|
|
assignEntityDefaults(&polyline, hs);
|
2015-12-25 08:29:08 +00:00
|
|
|
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;
|
|
|
|
polyline.vertlist.push_back(vertex);
|
|
|
|
}
|
|
|
|
dxf->writeLWPolyline(&polyline);
|
|
|
|
lv.Clear();
|
|
|
|
}
|
|
|
|
|
2015-12-28 08:03:51 +00:00
|
|
|
void makeKnotsFor(DRW_Spline *spline) {
|
|
|
|
// QCad/LibreCAD require this for some reason.
|
|
|
|
if(spline->degree == 3) {
|
|
|
|
spline->nknots = 8;
|
|
|
|
spline->knotslist.push_back(0.0);
|
|
|
|
spline->knotslist.push_back(0.0);
|
|
|
|
spline->knotslist.push_back(0.0);
|
|
|
|
spline->knotslist.push_back(0.0);
|
|
|
|
spline->knotslist.push_back(1.0);
|
|
|
|
spline->knotslist.push_back(1.0);
|
|
|
|
spline->knotslist.push_back(1.0);
|
|
|
|
spline->knotslist.push_back(1.0);
|
|
|
|
} else if(spline->degree == 2) {
|
|
|
|
spline->nknots = 6;
|
|
|
|
spline->knotslist.push_back(0.0);
|
|
|
|
spline->knotslist.push_back(0.0);
|
|
|
|
spline->knotslist.push_back(0.0);
|
|
|
|
spline->knotslist.push_back(1.0);
|
|
|
|
spline->knotslist.push_back(1.0);
|
|
|
|
spline->knotslist.push_back(1.0);
|
2016-05-18 22:51:36 +00:00
|
|
|
} else ssassert(false, "Unexpected degree of spline");
|
2015-12-28 08:03:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void writeSpline(SBezier *sb) {
|
|
|
|
bool isRational = sb->IsRational();
|
2016-04-12 23:57:49 +00:00
|
|
|
hStyle hs = { (uint32_t)sb->auxA };
|
2015-12-28 08:03:51 +00:00
|
|
|
DRW_Spline spline;
|
2016-04-12 23:57:49 +00:00
|
|
|
assignEntityDefaults(&spline, hs);
|
2015-12-28 08:03:51 +00:00
|
|
|
spline.flags = (isRational) ? 0x04 : 0x08;
|
|
|
|
spline.degree = sb->deg;
|
|
|
|
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));
|
|
|
|
if(isRational) spline.weightlist.push_back(sb->weight[i]);
|
|
|
|
}
|
|
|
|
dxf->writeSpline(&spline);
|
|
|
|
}
|
|
|
|
|
2015-12-25 08:29:08 +00:00
|
|
|
void writeBezier(SBezier *sb) {
|
2016-04-12 23:57:49 +00:00
|
|
|
hStyle hs = { (uint32_t)sb->auxA };
|
2015-12-25 08:29:08 +00:00
|
|
|
Vector c;
|
|
|
|
Vector n = Vector::From(0.0, 0.0, 1.0);
|
|
|
|
double r;
|
|
|
|
|
|
|
|
if(sb->deg == 1) {
|
|
|
|
// Line
|
2016-04-12 23:57:49 +00:00
|
|
|
writeLine(sb->ctrl[0], sb->ctrl[1], hs);
|
2015-12-25 08:29:08 +00:00
|
|
|
} else if(sb->IsInPlane(n, 0) && sb->IsCircle(n, &c, &r)) {
|
|
|
|
// Circle perpendicular to camera
|
|
|
|
double theta0 = atan2(sb->ctrl[0].y - c.y, sb->ctrl[0].x - c.x);
|
|
|
|
double theta1 = atan2(sb->ctrl[2].y - c.y, sb->ctrl[2].x - c.x);
|
|
|
|
double dtheta = WRAP_SYMMETRIC(theta1 - theta0, 2.0 * PI);
|
|
|
|
if(dtheta < 0.0) swap(theta0, theta1);
|
|
|
|
|
2016-04-12 23:57:49 +00:00
|
|
|
writeArc(c, r, theta0, theta1, hs);
|
2015-12-28 08:03:51 +00:00
|
|
|
} else if(sb->IsRational()) {
|
|
|
|
// Rational bezier
|
|
|
|
// We'd like to export rational beziers exactly, but the resulting DXF
|
|
|
|
// files can only be read by AutoCAD; LibreCAD/QCad simply do not
|
|
|
|
// implement the feature. So, export as piecewise linear for compatiblity.
|
|
|
|
writeBezierAsPwl(sb);
|
2015-12-25 08:29:08 +00:00
|
|
|
} else {
|
|
|
|
// Any other curve
|
2015-12-28 08:03:51 +00:00
|
|
|
writeSpline(sb);
|
2015-12-25 08:29:08 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-28 10:50:38 +00:00
|
|
|
|
2016-01-06 12:40:17 +00:00
|
|
|
void writeAlignedDimension(Vector def1, Vector def2, Vector dimp,
|
2016-05-17 05:08:24 +00:00
|
|
|
Vector textp, const std::string &text, hStyle hs, double actual) {
|
2016-01-06 12:40:17 +00:00
|
|
|
DRW_DimAligned dim;
|
2016-05-07 10:54:44 +00:00
|
|
|
assignDimensionDefaults(&dim, hs);
|
2016-01-06 12:40:17 +00:00
|
|
|
dim.setDef1Point(toCoord(def1));
|
|
|
|
dim.setDef2Point(toCoord(def2));
|
|
|
|
dim.setDimPoint(toCoord(dimp));
|
|
|
|
dim.setTextPoint(toCoord(textp));
|
|
|
|
dim.setText(text);
|
2016-05-17 05:08:24 +00:00
|
|
|
dim.setActualMeasurement(actual);
|
2016-01-06 12:40:17 +00:00
|
|
|
dxf->writeDimension(&dim);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeLinearDimension(Vector def1, Vector def2, Vector dimp,
|
|
|
|
Vector textp, const std::string &text,
|
2016-05-17 05:08:24 +00:00
|
|
|
double angle, double oblique, hStyle hs, double actual) {
|
2016-01-06 12:40:17 +00:00
|
|
|
DRW_DimLinear dim;
|
2016-05-07 10:54:44 +00:00
|
|
|
assignDimensionDefaults(&dim, hs);
|
2016-01-06 12:40:17 +00:00
|
|
|
dim.setDef1Point(toCoord(def1));
|
|
|
|
dim.setDef2Point(toCoord(def2));
|
|
|
|
dim.setDimPoint(toCoord(dimp));
|
|
|
|
dim.setTextPoint(toCoord(textp));
|
|
|
|
dim.setText(text);
|
|
|
|
dim.setAngle(angle);
|
|
|
|
dim.setOblique(oblique);
|
2016-05-17 05:08:24 +00:00
|
|
|
dim.setActualMeasurement(actual);
|
2016-01-06 12:40:17 +00:00
|
|
|
dxf->writeDimension(&dim);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeRadialDimension(Vector center, Vector radius,
|
2016-05-17 05:08:24 +00:00
|
|
|
Vector textp, const std::string &text, hStyle hs, double actual) {
|
2016-01-06 12:40:17 +00:00
|
|
|
DRW_DimRadial dim;
|
2016-05-07 10:54:44 +00:00
|
|
|
assignDimensionDefaults(&dim, hs);
|
2016-01-06 12:40:17 +00:00
|
|
|
dim.setCenterPoint(toCoord(center));
|
|
|
|
dim.setDiameterPoint(toCoord(radius));
|
|
|
|
dim.setTextPoint(toCoord(textp));
|
|
|
|
dim.setText(text);
|
2016-05-17 05:08:24 +00:00
|
|
|
dim.setActualMeasurement(actual);
|
2016-01-06 12:40:17 +00:00
|
|
|
dxf->writeDimension(&dim);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeDiametricDimension(Vector def1, Vector def2,
|
2016-05-17 05:08:24 +00:00
|
|
|
Vector textp, const std::string &text, hStyle hs, double actual) {
|
2016-01-06 12:40:17 +00:00
|
|
|
DRW_DimDiametric dim;
|
2016-05-07 10:54:44 +00:00
|
|
|
assignDimensionDefaults(&dim, hs);
|
2016-01-06 12:40:17 +00:00
|
|
|
dim.setDiameter1Point(toCoord(def1));
|
|
|
|
dim.setDiameter2Point(toCoord(def2));
|
|
|
|
dim.setTextPoint(toCoord(textp));
|
|
|
|
dim.setText(text);
|
2016-05-17 05:08:24 +00:00
|
|
|
dim.setActualMeasurement(actual);
|
2016-01-06 12:40:17 +00:00
|
|
|
dxf->writeDimension(&dim);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeAngularDimension(Vector fl1, Vector fl2, Vector sl1, Vector sl2, Vector dimp,
|
2016-05-17 05:08:24 +00:00
|
|
|
Vector textp, const std::string &text, hStyle hs, double actual) {
|
2016-01-06 12:40:17 +00:00
|
|
|
DRW_DimAngular dim;
|
2016-05-07 10:54:44 +00:00
|
|
|
assignDimensionDefaults(&dim, hs);
|
2016-01-06 12:40:17 +00:00
|
|
|
dim.setFirstLine1(toCoord(fl1));
|
|
|
|
dim.setFirstLine2(toCoord(fl2));
|
|
|
|
dim.setSecondLine1(toCoord(sl1));
|
|
|
|
dim.setSecondLine2(toCoord(sl2));
|
|
|
|
dim.setDimPoint(toCoord(dimp));
|
|
|
|
dim.setTextPoint(toCoord(textp));
|
|
|
|
dim.setText(text);
|
2016-05-17 05:08:24 +00:00
|
|
|
dim.setActualMeasurement(actual * PI / 180.0);
|
2016-01-06 12:40:17 +00:00
|
|
|
dxf->writeDimension(&dim);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeText(Vector textp, const std::string &text,
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
double height, double angle, Style::TextOrigin origin, hStyle hs) {
|
2016-01-06 12:40:17 +00:00
|
|
|
DRW_Text txt;
|
2016-05-07 10:54:44 +00:00
|
|
|
assignEntityDefaults(&txt, hs);
|
2016-02-19 03:31:10 +00:00
|
|
|
txt.layer = "text";
|
2016-01-06 12:40:17 +00:00
|
|
|
txt.style = "unicode";
|
|
|
|
txt.basePoint = toCoord(textp);
|
|
|
|
txt.secPoint = txt.basePoint;
|
|
|
|
txt.text = text;
|
|
|
|
txt.height = height;
|
|
|
|
txt.angle = angle;
|
|
|
|
txt.alignH = DRW_Text::HCenter;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
if((uint32_t)origin & (uint32_t)Style::TextOrigin::LEFT) {
|
2016-01-06 12:40:17 +00:00
|
|
|
txt.alignH = DRW_Text::HLeft;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
} else if((uint32_t)origin & (uint32_t)Style::TextOrigin::RIGHT) {
|
2016-01-06 12:40:17 +00:00
|
|
|
txt.alignH = DRW_Text::HRight;
|
|
|
|
}
|
|
|
|
txt.alignV = DRW_Text::VMiddle;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
if((uint32_t)origin & (uint32_t)Style::TextOrigin::TOP) {
|
2016-01-06 12:40:17 +00:00
|
|
|
txt.alignV = DRW_Text::VTop;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
} else if((uint32_t)origin & (uint32_t)Style::TextOrigin::BOT) {
|
2016-01-06 12:40:17 +00:00
|
|
|
txt.alignV = DRW_Text::VBaseLine;
|
|
|
|
}
|
|
|
|
dxf->writeText(&txt);
|
|
|
|
}
|
2015-12-25 08:29:08 +00:00
|
|
|
};
|
|
|
|
|
2016-01-06 12:40:17 +00:00
|
|
|
bool DxfFileWriter::OutputConstraints(IdList<Constraint,hConstraint> *constraint) {
|
|
|
|
this->constraint = constraint;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void DxfFileWriter::StartFile() {
|
2015-12-28 10:50:38 +00:00
|
|
|
paths.clear();
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2015-07-10 11:54:39 +00:00
|
|
|
void DxfFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
2015-12-28 10:50:38 +00:00
|
|
|
BezierPath path = {};
|
|
|
|
paths.push_back(path);
|
2009-10-30 10:38:34 +00:00
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void DxfFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void DxfFileWriter::Triangle(STriangle *tr) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void DxfFileWriter::Bezier(SBezier *sb) {
|
2015-12-28 10:50:38 +00:00
|
|
|
paths.back().beziers.push_back(sb);
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void DxfFileWriter::FinishAndCloseFile() {
|
2016-10-09 14:58:07 +00:00
|
|
|
dxfRW dxf;
|
|
|
|
|
2016-06-29 16:47:23 +00:00
|
|
|
DxfWriteInterface interface = {};
|
|
|
|
interface.writer = this;
|
|
|
|
interface.dxf = &dxf;
|
2016-10-09 14:58:07 +00:00
|
|
|
|
2016-10-09 19:58:44 +00:00
|
|
|
std::stringstream stream;
|
2016-10-09 14:58:07 +00:00
|
|
|
dxf.write(stream, &interface, DRW::AC1021, /*bin=*/false);
|
2015-12-28 10:50:38 +00:00
|
|
|
paths.clear();
|
2016-01-06 12:40:17 +00:00
|
|
|
constraint = NULL;
|
2016-06-29 16:47:23 +00:00
|
|
|
|
2016-10-09 19:58:44 +00:00
|
|
|
if(!WriteFile(filename, stream.str())) {
|
|
|
|
Error("Couldn't write to '%s'", filename.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-29 16:47:23 +00:00
|
|
|
if(!interface.messages.empty()) {
|
|
|
|
std::string text = "Some aspects of the drawing have no DXF equivalent and "
|
|
|
|
"were not exported:\n";
|
|
|
|
for(const std::string &message : interface.messages) {
|
|
|
|
text += " * " + message + "\n";
|
|
|
|
}
|
|
|
|
Message(text.c_str());
|
|
|
|
}
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 13:55:36 +00:00
|
|
|
bool DxfFileWriter::NeedToOutput(Constraint *c) {
|
|
|
|
switch(c->type) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case Constraint::Type::PT_PT_DISTANCE:
|
|
|
|
case Constraint::Type::PT_LINE_DISTANCE:
|
|
|
|
case Constraint::Type::DIAMETER:
|
|
|
|
case Constraint::Type::ANGLE:
|
|
|
|
case Constraint::Type::COMMENT:
|
2016-03-24 13:55:36 +00:00
|
|
|
return c->IsVisible();
|
Enable exhaustive switch coverage warnings as an error, and use them.
Specifically, this enables -Wswitch=error on GCC/Clang and its MSVC
equivalent; the exact way it is handled varies slightly, but what
they all have in common is that in a switch statement over an
enumeration, any enumerand that is not explicitly (via case:) or
implicitly (via default:) handled in the switch triggers an error.
Moreover, we also change the switch statements in three ways:
* Switch statements that ought to be extended every time a new
enumerand is added (e.g. Entity::DrawOrGetDistance(), are changed
to explicitly list every single enumerand, and not have a
default: branch.
Note that the assertions are kept because it is legal for
a enumeration to have a value unlike any of its defined
enumerands, and we can e.g. read garbage from a file, or
an uninitialized variable. This requires some rearranging if
a default: branch is undesired.
* Switch statements that ought to only ever see a few select
enumerands, are changed to always assert in the default: branch.
* Switch statements that do something meaningful for a few
enumerands, and ignore everything else, are changed to do nothing
in a default: branch, under the assumption that changing them
every time an enumerand is added or removed would just result
in noise and catch no bugs.
This commit also removes the {Request,Entity,Constraint}::UNKNOWN and
Entity::DATUM_POINT enumerands, as those were just fancy names for
zeroes. They mess up switch exhaustiveness checks and most of the time
were not the best way to implement what they did anyway.
2016-05-25 06:55:50 +00:00
|
|
|
|
|
|
|
default: // See writeEntities().
|
|
|
|
break;
|
2016-03-24 13:55:36 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
const char *DxfFileWriter::lineTypeName(StipplePattern stippleType) {
|
2016-04-13 08:43:06 +00:00
|
|
|
switch(stippleType) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::CONTINUOUS: return "CONTINUOUS";
|
2016-05-26 19:20:39 +00:00
|
|
|
case StipplePattern::SHORT_DASH: return "DASHED";
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DASH: return "DASHED";
|
|
|
|
case StipplePattern::LONG_DASH: return "DASHEDX2";
|
|
|
|
case StipplePattern::DASH_DOT: return "DASHDOT";
|
|
|
|
case StipplePattern::DASH_DOT_DOT: return "DIVIDE";
|
|
|
|
case StipplePattern::DOT: return "DOT";
|
2016-04-13 08:43:06 +00:00
|
|
|
|
2016-06-29 16:47:23 +00:00
|
|
|
case StipplePattern::FREEHAND:
|
|
|
|
case StipplePattern::ZIGZAG:
|
|
|
|
/* no corresponding DXF line type */
|
2016-10-12 14:36:52 +00:00
|
|
|
break;
|
2016-06-29 16:47:23 +00:00
|
|
|
}
|
2016-10-12 14:36:52 +00:00
|
|
|
|
|
|
|
return "CONTINUOUS";
|
2016-04-13 08:43:06 +00:00
|
|
|
}
|
|
|
|
|
2009-07-08 09:44:13 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Routines for EPS output
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-04-04 11:21:30 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
static std::string MakeStipplePattern(StipplePattern pattern, double scale, char delimiter,
|
2016-04-04 14:31:44 +00:00
|
|
|
bool inkscapeWorkaround = false) {
|
2016-04-04 11:21:30 +00:00
|
|
|
scale /= 2.0;
|
|
|
|
|
2016-04-04 14:31:44 +00:00
|
|
|
// Inkscape ignores all elements that are exactly zero instead of drawing
|
|
|
|
// them as dots.
|
|
|
|
double zero = inkscapeWorkaround ? 1e-6 : 0;
|
|
|
|
|
2016-04-04 11:21:30 +00:00
|
|
|
std::string result;
|
|
|
|
switch(pattern) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::CONTINUOUS:
|
2016-04-04 11:21:30 +00:00
|
|
|
return "";
|
|
|
|
|
2016-05-26 19:20:39 +00:00
|
|
|
case StipplePattern::SHORT_DASH:
|
|
|
|
result = ssprintf("%.3f_%.3f", scale, scale * 2.0);
|
|
|
|
break;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DASH:
|
2016-04-04 11:21:30 +00:00
|
|
|
result = ssprintf("%.3f_%.3f", scale, scale);
|
|
|
|
break;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DASH_DOT:
|
2016-04-04 14:31:44 +00:00
|
|
|
result = ssprintf("%.3f_%.3f_%.6f_%.3f",
|
|
|
|
scale, scale * 0.5, zero, scale * 0.5);
|
2016-04-04 11:21:30 +00:00
|
|
|
break;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DASH_DOT_DOT:
|
2016-04-04 14:31:44 +00:00
|
|
|
result = ssprintf("%.3f_%.3f_%.6f_%.3f_%.6f_%.3f",
|
|
|
|
scale, scale * 0.5, zero,
|
|
|
|
scale * 0.5, scale * 0.5, zero);
|
2016-04-04 11:21:30 +00:00
|
|
|
break;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::DOT:
|
2016-04-04 14:31:44 +00:00
|
|
|
result = ssprintf("%.6f_%.3f", zero, scale * 0.5);
|
2016-04-04 11:21:30 +00:00
|
|
|
break;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case StipplePattern::LONG_DASH:
|
2016-04-04 11:21:30 +00:00
|
|
|
result = ssprintf("%.3f_%.3f", scale * 2.0, scale * 0.5);
|
|
|
|
break;
|
2016-04-04 14:31:44 +00:00
|
|
|
|
Enable exhaustive switch coverage warnings as an error, and use them.
Specifically, this enables -Wswitch=error on GCC/Clang and its MSVC
equivalent; the exact way it is handled varies slightly, but what
they all have in common is that in a switch statement over an
enumeration, any enumerand that is not explicitly (via case:) or
implicitly (via default:) handled in the switch triggers an error.
Moreover, we also change the switch statements in three ways:
* Switch statements that ought to be extended every time a new
enumerand is added (e.g. Entity::DrawOrGetDistance(), are changed
to explicitly list every single enumerand, and not have a
default: branch.
Note that the assertions are kept because it is legal for
a enumeration to have a value unlike any of its defined
enumerands, and we can e.g. read garbage from a file, or
an uninitialized variable. This requires some rearranging if
a default: branch is undesired.
* Switch statements that ought to only ever see a few select
enumerands, are changed to always assert in the default: branch.
* Switch statements that do something meaningful for a few
enumerands, and ignore everything else, are changed to do nothing
in a default: branch, under the assumption that changing them
every time an enumerand is added or removed would just result
in noise and catch no bugs.
This commit also removes the {Request,Entity,Constraint}::UNKNOWN and
Entity::DATUM_POINT enumerands, as those were just fancy names for
zeroes. They mess up switch exhaustiveness checks and most of the time
were not the best way to implement what they did anyway.
2016-05-25 06:55:50 +00:00
|
|
|
case StipplePattern::FREEHAND:
|
|
|
|
case StipplePattern::ZIGZAG:
|
|
|
|
ssassert(false, "Freehand and zigzag export not implemented");
|
2016-04-04 11:21:30 +00:00
|
|
|
}
|
|
|
|
std::replace(result.begin(), result.end(), '_', delimiter);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void EpsFileWriter::StartFile() {
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"%%!PS-Adobe-2.0\r\n"
|
|
|
|
"%%%%Creator: SolveSpace\r\n"
|
|
|
|
"%%%%Title: title\r\n"
|
|
|
|
"%%%%Pages: 0\r\n"
|
|
|
|
"%%%%PageOrder: Ascend\r\n"
|
|
|
|
"%%%%BoundingBox: 0 0 %d %d\r\n"
|
|
|
|
"%%%%HiResBoundingBox: 0 0 %.3f %.3f\r\n"
|
|
|
|
"%%%%EndComments\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"gsave\r\n"
|
|
|
|
"\r\n",
|
|
|
|
(int)ceil(MmToPts(ptMax.x - ptMin.x)),
|
|
|
|
(int)ceil(MmToPts(ptMax.y - ptMin.y)),
|
|
|
|
MmToPts(ptMax.x - ptMin.x),
|
|
|
|
MmToPts(ptMax.y - ptMin.y));
|
|
|
|
}
|
|
|
|
|
2015-07-10 11:54:39 +00:00
|
|
|
void EpsFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
|
|
|
fprintf(f, "newpath\r\n");
|
|
|
|
prevPt = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void EpsFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
StipplePattern pattern = Style::PatternType(hs);
|
2016-04-04 11:21:30 +00:00
|
|
|
double stippleScale = MmToPts(Style::StippleScaleMm(hs));
|
|
|
|
|
2009-10-30 10:38:34 +00:00
|
|
|
fprintf(f, " %.3f setlinewidth\r\n"
|
|
|
|
" %.3f %.3f %.3f setrgbcolor\r\n"
|
|
|
|
" 1 setlinejoin\r\n" // rounded
|
|
|
|
" 1 setlinecap\r\n" // rounded
|
2016-04-04 11:21:30 +00:00
|
|
|
" [%s] 0 setdash\r\n"
|
2009-10-30 10:38:34 +00:00
|
|
|
" gsave stroke grestore\r\n",
|
|
|
|
MmToPts(lineWidth),
|
2016-04-04 11:21:30 +00:00
|
|
|
strokeRgb.redF(), strokeRgb.greenF(), strokeRgb.blueF(),
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
MakeStipplePattern(pattern, stippleScale, ' ').c_str());
|
2009-10-30 10:38:34 +00:00
|
|
|
if(filled) {
|
|
|
|
fprintf(f, " %.3f %.3f %.3f setrgbcolor\r\n"
|
|
|
|
" gsave fill grestore\r\n",
|
Replaced RGB-color integers with dedicated data structure
RGB colors were represented using a uint32_t with the red, green and blue
values stuffed into the lower three octets (i.e. 0x00BBGGRR), like
Microsoft's COLORREF. This approach did not lend itself to type safety,
however, so this change replaces it with an RgbColor class that provides
the same infomation plus a handful of useful methods to work with it. (Note
that sizeof(RgbColor) == sizeof(uint32_t), so this change should not lead
to memory bloat.)
Some of the new methods/fields replace what were previously macro calls;
e.g. RED(c) is now c.red, REDf(c) is now c.redF(). The .Equals() method is
now used instead of == to compare colors.
RGB colors still need to be represented as packed integers in file I/O and
preferences, so the methods .FromPackedInt() and .ToPackedInt() are
provided. Also implemented are Cnf{Freeze,Thaw}Color(), type-safe wrappers
around Cnf{Freeze,Thaw}Int() that facilitate I/O with preferences.
(Cnf{Freeze,Thaw}Color() are defined outside of the system-dependent code
to minimize the footprint of the latter; because the same can be done with
Cnf{Freeze,Thaw}Bool(), those are also moved out of the system code with
this commit.)
Color integers were being OR'ed with 0x80000000 in some places for two
distinct purposes: One, to indicate use of a default color in
glxFillMesh(); this has been replaced by use of the .UseDefault() method.
Two, to indicate to TextWindow::Printf() that the format argument of a
"%Bp"/"%Fp" specifier is an RGB color rather than a color "code" from
TextWindow::bgColors[] or TextWindow::fgColors[] (as the specifier can
accept either); instead, we define a new flag "z" (as in "%Bz" or "%Fz") to
indicate an RGBcolor pointer, leaving "%Bp"/"%Fp" to indicate a color code
exclusively.
(This also allows TextWindow::meta[][].bg to be a char instead of an int,
partly compensating for the new .bgRgb field added immediately after.)
In array declarations, RGB colors could previously be specified as 0 (often
in a terminating element). As that no longer works, we define NULL_COLOR,
which serves much the same purpose for RgbColor variables as NULL serves
for pointers.
2013-10-16 20:00:58 +00:00
|
|
|
fillRgb.redF(), fillRgb.greenF(), fillRgb.blueF());
|
2009-10-30 10:38:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EpsFileWriter::MaybeMoveTo(Vector st, Vector fi) {
|
|
|
|
if(!prevPt.Equals(st)) {
|
|
|
|
fprintf(f, " %.3f %.3f moveto\r\n",
|
|
|
|
MmToPts(st.x - ptMin.x), MmToPts(st.y - ptMin.y));
|
|
|
|
}
|
|
|
|
prevPt = fi;
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EpsFileWriter::Triangle(STriangle *tr) {
|
|
|
|
fprintf(f,
|
|
|
|
"%.3f %.3f %.3f setrgbcolor\r\n"
|
|
|
|
"newpath\r\n"
|
|
|
|
" %.3f %.3f moveto\r\n"
|
|
|
|
" %.3f %.3f lineto\r\n"
|
|
|
|
" %.3f %.3f lineto\r\n"
|
|
|
|
" closepath\r\n"
|
2009-10-30 10:38:34 +00:00
|
|
|
"gsave fill grestore\r\n",
|
Replaced RGB-color integers with dedicated data structure
RGB colors were represented using a uint32_t with the red, green and blue
values stuffed into the lower three octets (i.e. 0x00BBGGRR), like
Microsoft's COLORREF. This approach did not lend itself to type safety,
however, so this change replaces it with an RgbColor class that provides
the same infomation plus a handful of useful methods to work with it. (Note
that sizeof(RgbColor) == sizeof(uint32_t), so this change should not lead
to memory bloat.)
Some of the new methods/fields replace what were previously macro calls;
e.g. RED(c) is now c.red, REDf(c) is now c.redF(). The .Equals() method is
now used instead of == to compare colors.
RGB colors still need to be represented as packed integers in file I/O and
preferences, so the methods .FromPackedInt() and .ToPackedInt() are
provided. Also implemented are Cnf{Freeze,Thaw}Color(), type-safe wrappers
around Cnf{Freeze,Thaw}Int() that facilitate I/O with preferences.
(Cnf{Freeze,Thaw}Color() are defined outside of the system-dependent code
to minimize the footprint of the latter; because the same can be done with
Cnf{Freeze,Thaw}Bool(), those are also moved out of the system code with
this commit.)
Color integers were being OR'ed with 0x80000000 in some places for two
distinct purposes: One, to indicate use of a default color in
glxFillMesh(); this has been replaced by use of the .UseDefault() method.
Two, to indicate to TextWindow::Printf() that the format argument of a
"%Bp"/"%Fp" specifier is an RGB color rather than a color "code" from
TextWindow::bgColors[] or TextWindow::fgColors[] (as the specifier can
accept either); instead, we define a new flag "z" (as in "%Bz" or "%Fz") to
indicate an RGBcolor pointer, leaving "%Bp"/"%Fp" to indicate a color code
exclusively.
(This also allows TextWindow::meta[][].bg to be a char instead of an int,
partly compensating for the new .bgRgb field added immediately after.)
In array declarations, RGB colors could previously be specified as 0 (often
in a terminating element). As that no longer works, we define NULL_COLOR,
which serves much the same purpose for RgbColor variables as NULL serves
for pointers.
2013-10-16 20:00:58 +00:00
|
|
|
tr->meta.color.redF(), tr->meta.color.greenF(), tr->meta.color.blueF(),
|
2009-07-08 09:44:13 +00:00
|
|
|
MmToPts(tr->a.x - ptMin.x), MmToPts(tr->a.y - ptMin.y),
|
|
|
|
MmToPts(tr->b.x - ptMin.x), MmToPts(tr->b.y - ptMin.y),
|
|
|
|
MmToPts(tr->c.x - ptMin.x), MmToPts(tr->c.y - ptMin.y));
|
|
|
|
|
|
|
|
// same issue with cracks, stroke it to avoid them
|
|
|
|
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
|
|
|
|
fprintf(f,
|
2009-10-30 10:38:34 +00:00
|
|
|
"1 setlinejoin\r\n"
|
|
|
|
"1 setlinecap\r\n"
|
2009-07-08 09:44:13 +00:00
|
|
|
"%.3f setlinewidth\r\n"
|
2009-10-30 10:38:34 +00:00
|
|
|
"gsave stroke grestore\r\n",
|
|
|
|
MmToPts(sw));
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 10:38:34 +00:00
|
|
|
void EpsFileWriter::Bezier(SBezier *sb) {
|
2009-07-08 09:44:13 +00:00
|
|
|
Vector c, n = Vector::From(0, 0, 1);
|
|
|
|
double r;
|
2009-10-30 10:38:34 +00:00
|
|
|
if(sb->deg == 1) {
|
|
|
|
MaybeMoveTo(sb->ctrl[0], sb->ctrl[1]);
|
|
|
|
fprintf(f, " %.3f %.3f lineto\r\n",
|
|
|
|
MmToPts(sb->ctrl[1].x - ptMin.x),
|
|
|
|
MmToPts(sb->ctrl[1].y - ptMin.y));
|
|
|
|
} else if(sb->IsCircle(n, &c, &r)) {
|
2009-07-08 09:44:13 +00:00
|
|
|
Vector p0 = sb->ctrl[0], p1 = sb->ctrl[2];
|
|
|
|
double theta0 = atan2(p0.y - c.y, p0.x - c.x),
|
|
|
|
theta1 = atan2(p1.y - c.y, p1.x - c.x),
|
|
|
|
dtheta = WRAP_SYMMETRIC(theta1 - theta0, 2*PI);
|
2009-10-30 10:38:34 +00:00
|
|
|
MaybeMoveTo(p0, p1);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
2009-10-30 11:18:54 +00:00
|
|
|
" %.3f %.3f %.3f %.3f %.3f %s\r\n",
|
2009-07-08 09:44:13 +00:00
|
|
|
MmToPts(c.x - ptMin.x), MmToPts(c.y - ptMin.y),
|
|
|
|
MmToPts(r),
|
2009-10-30 11:18:54 +00:00
|
|
|
theta0*180/PI, theta1*180/PI,
|
|
|
|
dtheta < 0 ? "arcn" : "arc");
|
2009-07-08 09:44:13 +00:00
|
|
|
} else if(sb->deg == 3 && !sb->IsRational()) {
|
2009-10-30 10:38:34 +00:00
|
|
|
MaybeMoveTo(sb->ctrl[0], sb->ctrl[3]);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
2009-10-30 10:38:34 +00:00
|
|
|
" %.3f %.3f %.3f %.3f %.3f %.3f curveto\r\n",
|
2009-07-08 09:44:13 +00:00
|
|
|
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y),
|
|
|
|
MmToPts(sb->ctrl[2].x - ptMin.x), MmToPts(sb->ctrl[2].y - ptMin.y),
|
2009-10-30 10:38:34 +00:00
|
|
|
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y));
|
2009-07-08 09:44:13 +00:00
|
|
|
} else {
|
2009-10-30 10:38:34 +00:00
|
|
|
BezierAsNonrationalCubic(sb);
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void EpsFileWriter::FinishAndCloseFile() {
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"\r\n"
|
|
|
|
"grestore\r\n"
|
|
|
|
"\r\n");
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Routines for PDF output, some extra complexity because we have to generate
|
|
|
|
// a correct xref table.
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-05-05 05:54:05 +00:00
|
|
|
void PdfFileWriter::StartFile() {
|
2015-03-29 00:30:52 +00:00
|
|
|
if((ptMax.x - ptMin.x) > 200*25.4 ||
|
2009-12-15 14:51:21 +00:00
|
|
|
(ptMax.y - ptMin.y) > 200*25.4)
|
|
|
|
{
|
|
|
|
Message("PDF page size exceeds 200 by 200 inches; many viewers may "
|
|
|
|
"reject this file.");
|
|
|
|
}
|
|
|
|
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"%%PDF-1.1\r\n"
|
|
|
|
"%%%c%c%c%c\r\n",
|
|
|
|
0xe2, 0xe3, 0xcf, 0xd3);
|
2015-03-29 00:30:52 +00:00
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[1] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"1 0 obj\r\n"
|
|
|
|
" << /Type /Catalog\r\n"
|
|
|
|
" /Outlines 2 0 R\r\n"
|
|
|
|
" /Pages 3 0 R\r\n"
|
|
|
|
" >>\r\n"
|
|
|
|
"endobj\r\n");
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[2] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"2 0 obj\r\n"
|
|
|
|
" << /Type /Outlines\r\n"
|
|
|
|
" /Count 0\r\n"
|
|
|
|
" >>\r\n"
|
|
|
|
"endobj\r\n");
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[3] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"3 0 obj\r\n"
|
|
|
|
" << /Type /Pages\r\n"
|
|
|
|
" /Kids [4 0 R]\r\n"
|
|
|
|
" /Count 1\r\n"
|
|
|
|
" >>\r\n"
|
|
|
|
"endobj\r\n");
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[4] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"4 0 obj\r\n"
|
|
|
|
" << /Type /Page\r\n"
|
|
|
|
" /Parent 3 0 R\r\n"
|
|
|
|
" /MediaBox [0 0 %.3f %.3f]\r\n"
|
|
|
|
" /Contents 5 0 R\r\n"
|
|
|
|
" /Resources << /ProcSet 7 0 R\r\n"
|
|
|
|
" /Font << /F1 8 0 R >>\r\n"
|
|
|
|
" >>\r\n"
|
|
|
|
" >>\r\n"
|
|
|
|
"endobj\r\n",
|
|
|
|
MmToPts(ptMax.x - ptMin.x),
|
|
|
|
MmToPts(ptMax.y - ptMin.y));
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[5] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"5 0 obj\r\n"
|
|
|
|
" << /Length 6 0 R >>\r\n"
|
|
|
|
"stream\r\n");
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
bodyStart = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void PdfFileWriter::FinishAndCloseFile() {
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
uint32_t bodyEnd = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
|
|
|
|
fprintf(f,
|
|
|
|
"endstream\r\n"
|
|
|
|
"endobj\r\n");
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[6] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"6 0 obj\r\n"
|
|
|
|
" %d\r\n"
|
|
|
|
"endobj\r\n",
|
|
|
|
bodyEnd - bodyStart);
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[7] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"7 0 obj\r\n"
|
|
|
|
" [/PDF /Text]\r\n"
|
|
|
|
"endobj\r\n");
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[8] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"8 0 obj\r\n"
|
|
|
|
" << /Type /Font\r\n"
|
|
|
|
" /Subtype /Type1\r\n"
|
|
|
|
" /Name /F1\r\n"
|
|
|
|
" /BaseFont /Helvetica\r\n"
|
|
|
|
" /Encoding /WinAnsiEncoding\r\n"
|
|
|
|
" >>\r\n"
|
|
|
|
"endobj\r\n");
|
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
xref[9] = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"9 0 obj\r\n"
|
|
|
|
" << /Creator (SolveSpace)\r\n"
|
|
|
|
" >>\r\n");
|
2015-03-29 00:30:52 +00:00
|
|
|
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
uint32_t xrefStart = (uint32_t)ftell(f);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"xref\r\n"
|
|
|
|
"0 10\r\n"
|
|
|
|
"0000000000 65535 f\r\n");
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-07-08 09:44:13 +00:00
|
|
|
int i;
|
|
|
|
for(i = 1; i <= 9; i++) {
|
|
|
|
fprintf(f, "%010d %05d n\r\n", xref[i], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(f,
|
|
|
|
"\r\n"
|
|
|
|
"trailer\r\n"
|
|
|
|
" << /Size 10\r\n"
|
|
|
|
" /Root 1 0 R\r\n"
|
|
|
|
" /Info 9 0 R\r\n"
|
|
|
|
" >>\r\n"
|
|
|
|
"startxref\r\n"
|
|
|
|
"%d\r\n"
|
|
|
|
"%%%%EOF\r\n",
|
|
|
|
xrefStart);
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-07-10 11:54:39 +00:00
|
|
|
void PdfFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
StipplePattern pattern = Style::PatternType(hs);
|
2016-04-04 11:21:30 +00:00
|
|
|
double stippleScale = MmToPts(Style::StippleScaleMm(hs));
|
|
|
|
|
2009-10-30 10:38:34 +00:00
|
|
|
fprintf(f, "1 J 1 j " // round endcaps and joins
|
2016-04-04 11:21:30 +00:00
|
|
|
"%.3f w [%s] 0 d "
|
2009-10-30 10:38:34 +00:00
|
|
|
"%.3f %.3f %.3f RG\r\n",
|
|
|
|
MmToPts(lineWidth),
|
2016-04-04 11:21:30 +00:00
|
|
|
MakeStipplePattern(pattern, stippleScale, ' ').c_str(),
|
Replaced RGB-color integers with dedicated data structure
RGB colors were represented using a uint32_t with the red, green and blue
values stuffed into the lower three octets (i.e. 0x00BBGGRR), like
Microsoft's COLORREF. This approach did not lend itself to type safety,
however, so this change replaces it with an RgbColor class that provides
the same infomation plus a handful of useful methods to work with it. (Note
that sizeof(RgbColor) == sizeof(uint32_t), so this change should not lead
to memory bloat.)
Some of the new methods/fields replace what were previously macro calls;
e.g. RED(c) is now c.red, REDf(c) is now c.redF(). The .Equals() method is
now used instead of == to compare colors.
RGB colors still need to be represented as packed integers in file I/O and
preferences, so the methods .FromPackedInt() and .ToPackedInt() are
provided. Also implemented are Cnf{Freeze,Thaw}Color(), type-safe wrappers
around Cnf{Freeze,Thaw}Int() that facilitate I/O with preferences.
(Cnf{Freeze,Thaw}Color() are defined outside of the system-dependent code
to minimize the footprint of the latter; because the same can be done with
Cnf{Freeze,Thaw}Bool(), those are also moved out of the system code with
this commit.)
Color integers were being OR'ed with 0x80000000 in some places for two
distinct purposes: One, to indicate use of a default color in
glxFillMesh(); this has been replaced by use of the .UseDefault() method.
Two, to indicate to TextWindow::Printf() that the format argument of a
"%Bp"/"%Fp" specifier is an RGB color rather than a color "code" from
TextWindow::bgColors[] or TextWindow::fgColors[] (as the specifier can
accept either); instead, we define a new flag "z" (as in "%Bz" or "%Fz") to
indicate an RGBcolor pointer, leaving "%Bp"/"%Fp" to indicate a color code
exclusively.
(This also allows TextWindow::meta[][].bg to be a char instead of an int,
partly compensating for the new .bgRgb field added immediately after.)
In array declarations, RGB colors could previously be specified as 0 (often
in a terminating element). As that no longer works, we define NULL_COLOR,
which serves much the same purpose for RgbColor variables as NULL serves
for pointers.
2013-10-16 20:00:58 +00:00
|
|
|
strokeRgb.redF(), strokeRgb.greenF(), strokeRgb.blueF());
|
2009-10-30 10:38:34 +00:00
|
|
|
if(filled) {
|
|
|
|
fprintf(f, "%.3f %.3f %.3f rg\r\n",
|
Replaced RGB-color integers with dedicated data structure
RGB colors were represented using a uint32_t with the red, green and blue
values stuffed into the lower three octets (i.e. 0x00BBGGRR), like
Microsoft's COLORREF. This approach did not lend itself to type safety,
however, so this change replaces it with an RgbColor class that provides
the same infomation plus a handful of useful methods to work with it. (Note
that sizeof(RgbColor) == sizeof(uint32_t), so this change should not lead
to memory bloat.)
Some of the new methods/fields replace what were previously macro calls;
e.g. RED(c) is now c.red, REDf(c) is now c.redF(). The .Equals() method is
now used instead of == to compare colors.
RGB colors still need to be represented as packed integers in file I/O and
preferences, so the methods .FromPackedInt() and .ToPackedInt() are
provided. Also implemented are Cnf{Freeze,Thaw}Color(), type-safe wrappers
around Cnf{Freeze,Thaw}Int() that facilitate I/O with preferences.
(Cnf{Freeze,Thaw}Color() are defined outside of the system-dependent code
to minimize the footprint of the latter; because the same can be done with
Cnf{Freeze,Thaw}Bool(), those are also moved out of the system code with
this commit.)
Color integers were being OR'ed with 0x80000000 in some places for two
distinct purposes: One, to indicate use of a default color in
glxFillMesh(); this has been replaced by use of the .UseDefault() method.
Two, to indicate to TextWindow::Printf() that the format argument of a
"%Bp"/"%Fp" specifier is an RGB color rather than a color "code" from
TextWindow::bgColors[] or TextWindow::fgColors[] (as the specifier can
accept either); instead, we define a new flag "z" (as in "%Bz" or "%Fz") to
indicate an RGBcolor pointer, leaving "%Bp"/"%Fp" to indicate a color code
exclusively.
(This also allows TextWindow::meta[][].bg to be a char instead of an int,
partly compensating for the new .bgRgb field added immediately after.)
In array declarations, RGB colors could previously be specified as 0 (often
in a terminating element). As that no longer works, we define NULL_COLOR,
which serves much the same purpose for RgbColor variables as NULL serves
for pointers.
2013-10-16 20:00:58 +00:00
|
|
|
fillRgb.redF(), fillRgb.greenF(), fillRgb.blueF());
|
2009-10-30 10:38:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
prevPt = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void PdfFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
|
|
|
if(filled) {
|
|
|
|
fprintf(f, "b\r\n");
|
|
|
|
} else {
|
|
|
|
fprintf(f, "S\r\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PdfFileWriter::MaybeMoveTo(Vector st, Vector fi) {
|
|
|
|
if(!prevPt.Equals(st)) {
|
|
|
|
fprintf(f, "%.3f %.3f m\r\n",
|
|
|
|
MmToPts(st.x - ptMin.x), MmToPts(st.y - ptMin.y));
|
|
|
|
}
|
|
|
|
prevPt = fi;
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PdfFileWriter::Triangle(STriangle *tr) {
|
|
|
|
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
|
|
|
|
|
|
|
|
fprintf(f,
|
2009-10-30 10:38:34 +00:00
|
|
|
"1 J 1 j\r\n"
|
2009-07-08 09:44:13 +00:00
|
|
|
"%.3f %.3f %.3f RG\r\n"
|
|
|
|
"%.3f %.3f %.3f rg\r\n"
|
|
|
|
"%.3f w\r\n"
|
|
|
|
"%.3f %.3f m\r\n"
|
|
|
|
"%.3f %.3f l\r\n"
|
|
|
|
"%.3f %.3f l\r\n"
|
|
|
|
"b\r\n",
|
Replaced RGB-color integers with dedicated data structure
RGB colors were represented using a uint32_t with the red, green and blue
values stuffed into the lower three octets (i.e. 0x00BBGGRR), like
Microsoft's COLORREF. This approach did not lend itself to type safety,
however, so this change replaces it with an RgbColor class that provides
the same infomation plus a handful of useful methods to work with it. (Note
that sizeof(RgbColor) == sizeof(uint32_t), so this change should not lead
to memory bloat.)
Some of the new methods/fields replace what were previously macro calls;
e.g. RED(c) is now c.red, REDf(c) is now c.redF(). The .Equals() method is
now used instead of == to compare colors.
RGB colors still need to be represented as packed integers in file I/O and
preferences, so the methods .FromPackedInt() and .ToPackedInt() are
provided. Also implemented are Cnf{Freeze,Thaw}Color(), type-safe wrappers
around Cnf{Freeze,Thaw}Int() that facilitate I/O with preferences.
(Cnf{Freeze,Thaw}Color() are defined outside of the system-dependent code
to minimize the footprint of the latter; because the same can be done with
Cnf{Freeze,Thaw}Bool(), those are also moved out of the system code with
this commit.)
Color integers were being OR'ed with 0x80000000 in some places for two
distinct purposes: One, to indicate use of a default color in
glxFillMesh(); this has been replaced by use of the .UseDefault() method.
Two, to indicate to TextWindow::Printf() that the format argument of a
"%Bp"/"%Fp" specifier is an RGB color rather than a color "code" from
TextWindow::bgColors[] or TextWindow::fgColors[] (as the specifier can
accept either); instead, we define a new flag "z" (as in "%Bz" or "%Fz") to
indicate an RGBcolor pointer, leaving "%Bp"/"%Fp" to indicate a color code
exclusively.
(This also allows TextWindow::meta[][].bg to be a char instead of an int,
partly compensating for the new .bgRgb field added immediately after.)
In array declarations, RGB colors could previously be specified as 0 (often
in a terminating element). As that no longer works, we define NULL_COLOR,
which serves much the same purpose for RgbColor variables as NULL serves
for pointers.
2013-10-16 20:00:58 +00:00
|
|
|
tr->meta.color.redF(), tr->meta.color.greenF(), tr->meta.color.blueF(),
|
|
|
|
tr->meta.color.redF(), tr->meta.color.greenF(), tr->meta.color.blueF(),
|
2009-07-08 09:44:13 +00:00
|
|
|
MmToPts(sw),
|
|
|
|
MmToPts(tr->a.x - ptMin.x), MmToPts(tr->a.y - ptMin.y),
|
|
|
|
MmToPts(tr->b.x - ptMin.x), MmToPts(tr->b.y - ptMin.y),
|
|
|
|
MmToPts(tr->c.x - ptMin.x), MmToPts(tr->c.y - ptMin.y));
|
|
|
|
}
|
|
|
|
|
2009-10-30 10:38:34 +00:00
|
|
|
void PdfFileWriter::Bezier(SBezier *sb) {
|
|
|
|
if(sb->deg == 1) {
|
|
|
|
MaybeMoveTo(sb->ctrl[0], sb->ctrl[1]);
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
2009-10-30 10:38:34 +00:00
|
|
|
"%.3f %.3f l\r\n",
|
|
|
|
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y));
|
|
|
|
} else if(sb->deg == 3 && !sb->IsRational()) {
|
|
|
|
MaybeMoveTo(sb->ctrl[0], sb->ctrl[3]);
|
|
|
|
fprintf(f,
|
|
|
|
"%.3f %.3f %.3f %.3f %.3f %.3f c\r\n",
|
2009-07-08 09:44:13 +00:00
|
|
|
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y),
|
|
|
|
MmToPts(sb->ctrl[2].x - ptMin.x), MmToPts(sb->ctrl[2].y - ptMin.y),
|
|
|
|
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y));
|
|
|
|
} else {
|
2009-10-30 10:38:34 +00:00
|
|
|
BezierAsNonrationalCubic(sb);
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Routines for SVG output
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-05-05 05:54:05 +00:00
|
|
|
void SvgFileWriter::StartFile() {
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f,
|
|
|
|
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" "
|
|
|
|
"\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\r\n"
|
|
|
|
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
|
|
|
|
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
|
|
|
"width='%.3fmm' height='%.3fmm' "
|
|
|
|
"viewBox=\"0 0 %.3f %.3f\">\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"<title>Exported SVG</title>\r\n"
|
|
|
|
"\r\n",
|
2015-04-12 21:24:55 +00:00
|
|
|
(ptMax.x - ptMin.x), (ptMax.y - ptMin.y),
|
|
|
|
(ptMax.x - ptMin.x), (ptMax.y - ptMin.y));
|
2016-04-04 14:31:44 +00:00
|
|
|
|
|
|
|
fprintf(f, "<style><![CDATA[\r\n");
|
|
|
|
fprintf(f, "polygon {\r\n");
|
|
|
|
fprintf(f, "shape-rendering:crispEdges;\r\n");
|
|
|
|
// crispEdges turns of anti-aliasing, which tends to cause hairline
|
|
|
|
// cracks between triangles; but there still is some cracking, so
|
|
|
|
// specify a stroke width too, hope for around a pixel
|
|
|
|
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
|
|
|
|
fprintf(f, "stroke-width:%f;\r\n", sw);
|
|
|
|
fprintf(f, "}\r\n");
|
|
|
|
for(int i = 0; i < SK.style.n; i++) {
|
|
|
|
Style *s = &SK.style.elem[i];
|
2016-05-25 12:08:19 +00:00
|
|
|
RgbaColor strokeRgb = Style::Color(s->h, /*forExport=*/true);
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
StipplePattern pattern = Style::PatternType(s->h);
|
2016-04-04 14:31:44 +00:00
|
|
|
double stippleScale = Style::StippleScaleMm(s->h);
|
|
|
|
|
|
|
|
fprintf(f, ".s%x {\r\n", s->h.v);
|
|
|
|
fprintf(f, "stroke:#%02x%02x%02x;\r\n", strokeRgb.red, strokeRgb.green, strokeRgb.blue);
|
|
|
|
// don't know why we have to take a half of the width
|
|
|
|
fprintf(f, "stroke-width:%f;\r\n", Style::WidthMm(s->h.v) / 2.0);
|
|
|
|
fprintf(f, "stroke-linecap:round;\r\n");
|
|
|
|
fprintf(f, "stroke-linejoin:round;\r\n");
|
|
|
|
std::string patternStr = MakeStipplePattern(pattern, stippleScale, ',',
|
|
|
|
/*inkscapeWorkaround=*/true);
|
|
|
|
if(!patternStr.empty()) {
|
|
|
|
fprintf(f, "stroke-dasharray:%s;\r\n", patternStr.c_str());
|
|
|
|
}
|
|
|
|
fprintf(f, "fill:none;\r\n");
|
|
|
|
fprintf(f, "}\r\n");
|
|
|
|
}
|
|
|
|
fprintf(f, "]]></style>\r\n");
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2015-07-10 11:54:39 +00:00
|
|
|
void SvgFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
|
|
|
fprintf(f, "<path d='");
|
|
|
|
prevPt = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void SvgFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
2016-01-27 05:13:04 +00:00
|
|
|
std::string fill;
|
2009-10-30 10:38:34 +00:00
|
|
|
if(filled) {
|
2016-04-04 14:31:44 +00:00
|
|
|
fill = ssprintf("fill='#%02x%02x%02x'",
|
Replaced RGB-color integers with dedicated data structure
RGB colors were represented using a uint32_t with the red, green and blue
values stuffed into the lower three octets (i.e. 0x00BBGGRR), like
Microsoft's COLORREF. This approach did not lend itself to type safety,
however, so this change replaces it with an RgbColor class that provides
the same infomation plus a handful of useful methods to work with it. (Note
that sizeof(RgbColor) == sizeof(uint32_t), so this change should not lead
to memory bloat.)
Some of the new methods/fields replace what were previously macro calls;
e.g. RED(c) is now c.red, REDf(c) is now c.redF(). The .Equals() method is
now used instead of == to compare colors.
RGB colors still need to be represented as packed integers in file I/O and
preferences, so the methods .FromPackedInt() and .ToPackedInt() are
provided. Also implemented are Cnf{Freeze,Thaw}Color(), type-safe wrappers
around Cnf{Freeze,Thaw}Int() that facilitate I/O with preferences.
(Cnf{Freeze,Thaw}Color() are defined outside of the system-dependent code
to minimize the footprint of the latter; because the same can be done with
Cnf{Freeze,Thaw}Bool(), those are also moved out of the system code with
this commit.)
Color integers were being OR'ed with 0x80000000 in some places for two
distinct purposes: One, to indicate use of a default color in
glxFillMesh(); this has been replaced by use of the .UseDefault() method.
Two, to indicate to TextWindow::Printf() that the format argument of a
"%Bp"/"%Fp" specifier is an RGB color rather than a color "code" from
TextWindow::bgColors[] or TextWindow::fgColors[] (as the specifier can
accept either); instead, we define a new flag "z" (as in "%Bz" or "%Fz") to
indicate an RGBcolor pointer, leaving "%Bp"/"%Fp" to indicate a color code
exclusively.
(This also allows TextWindow::meta[][].bg to be a char instead of an int,
partly compensating for the new .bgRgb field added immediately after.)
In array declarations, RGB colors could previously be specified as 0 (often
in a terminating element). As that no longer works, we define NULL_COLOR,
which serves much the same purpose for RgbColor variables as NULL serves
for pointers.
2013-10-16 20:00:58 +00:00
|
|
|
fillRgb.red, fillRgb.green, fillRgb.blue);
|
2009-10-30 10:38:34 +00:00
|
|
|
}
|
2016-04-12 23:57:49 +00:00
|
|
|
std::string cls = ssprintf("s%x", hs.v);
|
2016-04-04 14:31:44 +00:00
|
|
|
fprintf(f, "' class='%s' %s/>\r\n", cls.c_str(), fill.c_str());
|
2009-10-30 10:38:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SvgFileWriter::MaybeMoveTo(Vector st, Vector fi) {
|
2009-07-08 09:44:13 +00:00
|
|
|
// SVG uses a coordinate system with the origin at top left, +y down
|
2009-10-30 10:38:34 +00:00
|
|
|
if(!prevPt.Equals(st)) {
|
|
|
|
fprintf(f, "M%.3f %.3f ", (st.x - ptMin.x), (ptMax.y - st.y));
|
|
|
|
}
|
|
|
|
prevPt = fi;
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SvgFileWriter::Triangle(STriangle *tr) {
|
|
|
|
fprintf(f,
|
|
|
|
"<polygon points='%.3f,%.3f %.3f,%.3f %.3f,%.3f' "
|
2016-04-04 14:31:44 +00:00
|
|
|
"stroke='#%02x%02x%02x' "
|
|
|
|
"fill='#%02x%02x%02x'/>\r\n",
|
2009-07-08 09:44:13 +00:00
|
|
|
(tr->a.x - ptMin.x), (ptMax.y - tr->a.y),
|
|
|
|
(tr->b.x - ptMin.x), (ptMax.y - tr->b.y),
|
|
|
|
(tr->c.x - ptMin.x), (ptMax.y - tr->c.y),
|
Replaced RGB-color integers with dedicated data structure
RGB colors were represented using a uint32_t with the red, green and blue
values stuffed into the lower three octets (i.e. 0x00BBGGRR), like
Microsoft's COLORREF. This approach did not lend itself to type safety,
however, so this change replaces it with an RgbColor class that provides
the same infomation plus a handful of useful methods to work with it. (Note
that sizeof(RgbColor) == sizeof(uint32_t), so this change should not lead
to memory bloat.)
Some of the new methods/fields replace what were previously macro calls;
e.g. RED(c) is now c.red, REDf(c) is now c.redF(). The .Equals() method is
now used instead of == to compare colors.
RGB colors still need to be represented as packed integers in file I/O and
preferences, so the methods .FromPackedInt() and .ToPackedInt() are
provided. Also implemented are Cnf{Freeze,Thaw}Color(), type-safe wrappers
around Cnf{Freeze,Thaw}Int() that facilitate I/O with preferences.
(Cnf{Freeze,Thaw}Color() are defined outside of the system-dependent code
to minimize the footprint of the latter; because the same can be done with
Cnf{Freeze,Thaw}Bool(), those are also moved out of the system code with
this commit.)
Color integers were being OR'ed with 0x80000000 in some places for two
distinct purposes: One, to indicate use of a default color in
glxFillMesh(); this has been replaced by use of the .UseDefault() method.
Two, to indicate to TextWindow::Printf() that the format argument of a
"%Bp"/"%Fp" specifier is an RGB color rather than a color "code" from
TextWindow::bgColors[] or TextWindow::fgColors[] (as the specifier can
accept either); instead, we define a new flag "z" (as in "%Bz" or "%Fz") to
indicate an RGBcolor pointer, leaving "%Bp"/"%Fp" to indicate a color code
exclusively.
(This also allows TextWindow::meta[][].bg to be a char instead of an int,
partly compensating for the new .bgRgb field added immediately after.)
In array declarations, RGB colors could previously be specified as 0 (often
in a terminating element). As that no longer works, we define NULL_COLOR,
which serves much the same purpose for RgbColor variables as NULL serves
for pointers.
2013-10-16 20:00:58 +00:00
|
|
|
tr->meta.color.red, tr->meta.color.green, tr->meta.color.blue,
|
|
|
|
tr->meta.color.red, tr->meta.color.green, tr->meta.color.blue);
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 10:38:34 +00:00
|
|
|
void SvgFileWriter::Bezier(SBezier *sb) {
|
2009-07-08 09:44:13 +00:00
|
|
|
Vector c, n = Vector::From(0, 0, 1);
|
|
|
|
double r;
|
2009-10-30 10:38:34 +00:00
|
|
|
if(sb->deg == 1) {
|
|
|
|
MaybeMoveTo(sb->ctrl[0], sb->ctrl[1]);
|
|
|
|
fprintf(f, "L%.3f,%.3f ",
|
|
|
|
(sb->ctrl[1].x - ptMin.x), (ptMax.y - sb->ctrl[1].y));
|
|
|
|
} else if(sb->IsCircle(n, &c, &r)) {
|
2009-07-08 09:44:13 +00:00
|
|
|
Vector p0 = sb->ctrl[0], p1 = sb->ctrl[2];
|
|
|
|
double theta0 = atan2(p0.y - c.y, p0.x - c.x),
|
|
|
|
theta1 = atan2(p1.y - c.y, p1.x - c.x),
|
|
|
|
dtheta = WRAP_SYMMETRIC(theta1 - theta0, 2*PI);
|
|
|
|
// The arc must be less than 180 degrees, or else it couldn't have
|
2009-10-30 11:18:54 +00:00
|
|
|
// been represented as a single rational Bezier. So large-arc-flag
|
|
|
|
// must be false. sweep-flag is determined by the sign of dtheta.
|
|
|
|
// Note that clockwise and counter-clockwise are backwards in SVG's
|
|
|
|
// mirrored csys.
|
2009-10-30 10:38:34 +00:00
|
|
|
MaybeMoveTo(p0, p1);
|
2009-10-30 11:18:54 +00:00
|
|
|
fprintf(f, "A%.3f,%.3f 0 0,%d %.3f,%.3f ",
|
2009-10-30 10:38:34 +00:00
|
|
|
r, r,
|
2009-10-30 11:18:54 +00:00
|
|
|
(dtheta < 0) ? 1 : 0,
|
2009-10-30 10:38:34 +00:00
|
|
|
p1.x - ptMin.x, ptMax.y - p1.y);
|
2009-07-08 09:44:13 +00:00
|
|
|
} else if(!sb->IsRational()) {
|
2009-10-30 10:38:34 +00:00
|
|
|
if(sb->deg == 2) {
|
|
|
|
MaybeMoveTo(sb->ctrl[0], sb->ctrl[2]);
|
|
|
|
fprintf(f, "Q%.3f,%.3f %.3f,%.3f ",
|
2009-07-08 09:44:13 +00:00
|
|
|
sb->ctrl[1].x - ptMin.x, ptMax.y - sb->ctrl[1].y,
|
2009-10-30 10:38:34 +00:00
|
|
|
sb->ctrl[2].x - ptMin.x, ptMax.y - sb->ctrl[2].y);
|
2009-07-08 09:44:13 +00:00
|
|
|
} else if(sb->deg == 3) {
|
2009-10-30 10:38:34 +00:00
|
|
|
MaybeMoveTo(sb->ctrl[0], sb->ctrl[3]);
|
|
|
|
fprintf(f, "C%.3f,%.3f %.3f,%.3f %.3f,%.3f ",
|
2009-07-08 09:44:13 +00:00
|
|
|
sb->ctrl[1].x - ptMin.x, ptMax.y - sb->ctrl[1].y,
|
|
|
|
sb->ctrl[2].x - ptMin.x, ptMax.y - sb->ctrl[2].y,
|
2009-10-30 10:38:34 +00:00
|
|
|
sb->ctrl[3].x - ptMin.x, ptMax.y - sb->ctrl[3].y);
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
2009-10-30 10:38:34 +00:00
|
|
|
BezierAsNonrationalCubic(sb);
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void SvgFileWriter::FinishAndCloseFile() {
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f, "\r\n</svg>\r\n");
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Routines for HPGL output
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
double HpglFileWriter::MmToHpglUnits(double mm) {
|
|
|
|
return mm*40;
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void HpglFileWriter::StartFile() {
|
2009-07-08 09:44:13 +00:00
|
|
|
fprintf(f, "IN;\r\n");
|
|
|
|
fprintf(f, "SP1;\r\n");
|
|
|
|
}
|
|
|
|
|
2015-07-10 11:54:39 +00:00
|
|
|
void HpglFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void HpglFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HpglFileWriter::Triangle(STriangle *tr) {
|
|
|
|
}
|
|
|
|
|
2009-10-30 10:38:34 +00:00
|
|
|
void HpglFileWriter::Bezier(SBezier *sb) {
|
|
|
|
if(sb->deg == 1) {
|
|
|
|
fprintf(f, "PU%d,%d;\r\n",
|
|
|
|
(int)MmToHpglUnits(sb->ctrl[0].x),
|
|
|
|
(int)MmToHpglUnits(sb->ctrl[0].y));
|
|
|
|
fprintf(f, "PD%d,%d;\r\n",
|
|
|
|
(int)MmToHpglUnits(sb->ctrl[1].x),
|
|
|
|
(int)MmToHpglUnits(sb->ctrl[1].y));
|
|
|
|
} else {
|
|
|
|
BezierAsPwl(sb);
|
|
|
|
}
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void HpglFileWriter::FinishAndCloseFile() {
|
2009-07-08 09:44:13 +00:00
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
2010-01-14 04:47:17 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Routines for G Code output. Slightly complicated by our ability to generate
|
|
|
|
// multiple passes, and to specify the feeds and depth; those parameters get
|
|
|
|
// set in the configuration screen.
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-05-05 05:54:05 +00:00
|
|
|
void GCodeFileWriter::StartFile() {
|
2015-03-27 15:31:23 +00:00
|
|
|
sel = {};
|
2010-01-14 04:47:17 +00:00
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void GCodeFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2010-01-14 04:47:17 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void GCodeFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2010-01-14 04:47:17 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
void GCodeFileWriter::Triangle(STriangle *tr) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void GCodeFileWriter::Bezier(SBezier *sb) {
|
|
|
|
if(sb->deg == 1) {
|
|
|
|
sel.AddEdge(sb->ctrl[0], sb->ctrl[1]);
|
|
|
|
} else {
|
|
|
|
BezierAsPwl(sb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void GCodeFileWriter::FinishAndCloseFile() {
|
2015-03-27 15:31:23 +00:00
|
|
|
SPolygon sp = {};
|
2010-01-14 04:47:17 +00:00
|
|
|
sel.AssemblePolygon(&sp, NULL);
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < SS.gCode.passes; i++) {
|
|
|
|
double depth = (SS.gCode.depth / SS.gCode.passes)*(i+1);
|
|
|
|
|
|
|
|
SContour *sc;
|
|
|
|
for(sc = sp.l.First(); sc; sc = sp.l.NextAfter(sc)) {
|
|
|
|
if(sc->l.n < 2) continue;
|
|
|
|
|
|
|
|
SPoint *pt = sc->l.First();
|
|
|
|
fprintf(f, "G00 X%s Y%s\r\n",
|
2015-11-06 08:40:12 +00:00
|
|
|
SS.MmToString(pt->p.x).c_str(), SS.MmToString(pt->p.y).c_str());
|
2010-01-14 04:47:17 +00:00
|
|
|
fprintf(f, "G01 Z%s F%s\r\n",
|
2015-11-06 08:40:12 +00:00
|
|
|
SS.MmToString(depth).c_str(), SS.MmToString(SS.gCode.plungeFeed).c_str());
|
2010-01-14 04:47:17 +00:00
|
|
|
|
|
|
|
pt = sc->l.NextAfter(pt);
|
|
|
|
for(; pt; pt = sc->l.NextAfter(pt)) {
|
|
|
|
fprintf(f, "G01 X%s Y%s F%s\r\n",
|
2015-11-06 08:40:12 +00:00
|
|
|
SS.MmToString(pt->p.x).c_str(), SS.MmToString(pt->p.y).c_str(),
|
|
|
|
SS.MmToString(SS.gCode.feed).c_str());
|
2010-01-14 04:47:17 +00:00
|
|
|
}
|
|
|
|
// Move up to a clearance plane 5mm above the work.
|
2015-03-29 00:30:52 +00:00
|
|
|
fprintf(f, "G00 Z%s\r\n",
|
2015-11-06 08:40:12 +00:00
|
|
|
SS.MmToString(SS.gCode.depth < 0 ? +5 : -5).c_str());
|
2010-01-14 04:47:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sp.Clear();
|
|
|
|
sel.Clear();
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-08 09:44:13 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Routine for STEP output; just a wrapper around the general STEP stuff that
|
|
|
|
// can also be used for surfaces or 3d curves.
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-05-05 05:54:05 +00:00
|
|
|
void Step2dFileWriter::StartFile() {
|
2015-03-27 15:31:23 +00:00
|
|
|
sfw = {};
|
2009-07-08 09:44:13 +00:00
|
|
|
sfw.f = f;
|
|
|
|
sfw.WriteHeader();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Step2dFileWriter::Triangle(STriangle *tr) {
|
|
|
|
}
|
|
|
|
|
2015-07-10 11:54:39 +00:00
|
|
|
void Step2dFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-10-30 10:38:34 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-10 11:54:39 +00:00
|
|
|
void Step2dFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
|
2016-04-12 23:57:49 +00:00
|
|
|
bool filled, RgbaColor fillRgb, hStyle hs)
|
2009-09-22 05:46:30 +00:00
|
|
|
{
|
2009-07-08 09:44:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 10:38:34 +00:00
|
|
|
void Step2dFileWriter::Bezier(SBezier *sb) {
|
2009-07-08 09:44:13 +00:00
|
|
|
int c = sfw.ExportCurve(sb);
|
|
|
|
sfw.curves.Add(&c);
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void Step2dFileWriter::FinishAndCloseFile() {
|
2009-07-08 09:44:13 +00:00
|
|
|
sfw.WriteWireframe();
|
|
|
|
sfw.WriteFooter();
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|