1
/***************************************************************************
2
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
29
# include <Inventor/SbBSPTree.h>
32
#include <Base/FileInfo.h>
34
#include "SoFCVectorizeSVGAction.h"
39
class SoVectorizeItem {
42
this->type = UNDEFINED;
45
// quick and easy type system
55
float depth; // for depth sorting
58
class SoVectorizePoint : public SoVectorizeItem {
66
int vidx; // index to BSPtree coordinate
67
float size; // Coin size (pixels)
71
class SoVectorizeTriangle : public SoVectorizeItem {
73
SoVectorizeTriangle() {
74
this->type = TRIANGLE;
76
int vidx[3]; // indices to BSPtree coordinates
80
class SoVectorizeLine : public SoVectorizeItem {
88
this->pattern = 0xffff;
91
int vidx[2]; // indices to BSPtree coordinates
93
uint16_t pattern; // Coin line pattern
94
float width; // Coin line width (pixels)
97
class SoVectorizeText : public SoVectorizeItem {
103
this->justification = LEFT;
113
float fontsize; // size in normalized coordinates
115
SbVec2f pos; // pos in normalized coordinates
117
Justification justification;
120
class SoVectorizeImage : public SoVectorizeItem {
124
this->image.data = nullptr;
128
SbVec2f pos; // pos in normalized coordinates
129
SbVec2f size; // size in normalized coordinates
132
const unsigned char * data;
138
// ----------------------------------------------------------------
140
SoSVGVectorOutput::SoSVGVectorOutput() = default;
142
SoSVGVectorOutput::~SoSVGVectorOutput()
147
SbBool SoSVGVectorOutput::openFile (const char *filename)
149
Base::FileInfo fi(filename);
151
this->file.open(fi.toStdWString().c_str(), std::ios::out | std::ios::binary);
153
this->file.open(fi.filePath().c_str(), std::ios::out | std::ios::binary);
156
return this->file.is_open();
159
void SoSVGVectorOutput::closeFile ()
161
if (this->file.is_open())
165
std::fstream& SoSVGVectorOutput::getFileStream()
170
// ----------------------------------------------------------------
173
class SoFCVectorizeSVGActionP
176
SoFCVectorizeSVGActionP(SoFCVectorizeSVGAction * p) {
180
void printCircle(const SbVec3f & v, const SbColor & c, const float radius) const;
181
void printSquare(const SbVec3f & v, const SbColor & c, const float size) const;
182
void printTriangle(const SbVec3f * v, const SbColor * c) const;
183
void printTriangle(const SoVectorizeTriangle * item) const;
184
void printLine(const SoVectorizeLine * item) const;
185
void printPoint(const SoVectorizePoint * item) const;
186
void printText(const SoVectorizeText * item) const;
187
void printImage(const SoVectorizeImage * item) const;
190
SoFCVectorizeSVGAction * publ;
194
void SoFCVectorizeSVGActionP::printText(const SoVectorizeText * item) const
196
SbVec2f mul = publ->getRotatedViewportSize();
197
SbVec2f add = publ->getRotatedViewportStartpos();
198
float posx = item->pos[0]*mul[0]+add[0];
199
float posy = item->pos[1]*mul[1]+add[1];
201
std::ostream& str = publ->getSVGOutput()->getFileStream();
202
str << "<text x=\"" << posx << "\" y=\"" << posy << "\" "
203
"font-size=\"" << item->fontsize * mul[1] << "px\">"
204
<< item->string.getString() << "</text>" << std::endl;
207
void SoFCVectorizeSVGActionP::printTriangle(const SoVectorizeTriangle * item) const
209
SbVec2f mul = publ->getRotatedViewportSize();
210
SbVec2f add = publ->getRotatedViewportStartpos();
212
const SbBSPTree & bsp = publ->getBSPTree();
218
for (int i = 0; i < 3; i++) {
219
v[i] = bsp.getPoint(item->vidx[i]);
220
v[i][0] = (v[i][0] * mul[0]) + add[0];
221
v[i][1] = ((1.0f-v[i][1]) * mul[1]) + add[1];
222
c[i].setPackedValue(item->col[i], t[i]);
224
this->printTriangle((SbVec3f*)v, (SbColor*)c);
226
/* TODO: Support gradients, e.g.
228
<linearGradient id="verlauf" x1="0%" y1="100%" x2="100%" y2="100%">
229
<stop offset="0%" stop-color="black" stop-opacity="100%" />
230
<stop offset="100%" stop-color="white" stop-opacity="50%" />
234
/* Example: color per vertex
239
point [ 0.000000 0.000000 0.000000,
240
100.000000 50.000000 0.000000,
241
0.000000 100.000000 0.000000 ]
245
diffuseColor [ 1 1 0, 0 0 1, 1 0 0 ]
252
coordIndex [ 0, 1, 2, -1 ]
256
<?xml version="1.0"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
257
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
258
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
260
<linearGradient id="red" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="35" y2="80">
261
<stop offset="0" stop-color="rgb(255,0,0)" stop-opacity="1"/>
262
<stop offset="1" stop-color="rgb(255,0,0)" stop-opacity="0"/>
264
<linearGradient id="blue" gradientUnits="userSpaceOnUse" x1="100" y1="50" x2="0" y2="50">
265
<stop offset="0" stop-color="rgb(0,0,255)" stop-opacity="1"/>
266
<stop offset="1" stop-color="rgb(0,0,255)" stop-opacity="0"/>
268
<linearGradient id="yellow" gradientUnits="userSpaceOnUse" x1="0" y1="100" x2="40" y2="20">
269
<stop offset="0" stop-color="rgb(255,255,0)" stop-opacity="1"/>
270
<stop offset="1" stop-color="rgb(255,255,0)" stop-opacity="0"/>
272
<path id="triangle1" d="M0 0 L100 50 L0 100 z"/>
273
<filter id="colorAdd">
274
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="arithmetic" k2="1" k3="1"/>
277
<feColorMatrix type="matrix" values="
286
<g filter="url(#Matrix1)">
287
<use xlink:href="#triangle1" fill="url(#blue)"/>
288
<use xlink:href="#triangle1" fill="url(#yellow)" filter="url(#colorAdd)"/>
289
<use xlink:href="#triangle1" fill="url(#red)" filter="url(#colorAdd)"/>
293
void SoFCVectorizeSVGActionP::printTriangle(const SbVec3f * v, const SbColor * c) const
295
if (v[0] == v[1] || v[1] == v[2] || v[0] == v[2])
297
uint32_t cc = c->getPackedValue();
299
std::ostream& str = publ->getSVGOutput()->getFileStream();
300
str << "<path d=\"M "
301
<< v[2][0] << "," << v[2][1] << " L "
302
<< v[1][0] << "," << v[1][1] << " "
303
<< v[0][0] << "," << v[0][1] << " z\"" << std::endl
305
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8)
307
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8)
309
<< " stroke-width:" << publ->getLineWidth() << ";" << std::endl
310
<< " stroke-linecap:round;stroke-linejoin:round\"/>" << std::endl;
313
void SoFCVectorizeSVGActionP::printCircle(const SbVec3f & v, const SbColor & c, const float radius) const
321
void SoFCVectorizeSVGActionP::printSquare(const SbVec3f & v, const SbColor & c, const float size) const
329
void SoFCVectorizeSVGActionP::printLine(const SoVectorizeLine * item) const
331
SbVec2f mul = publ->getRotatedViewportSize();
332
SbVec2f add = publ->getRotatedViewportStartpos();
334
const SbBSPTree & bsp = publ->getBSPTree();
340
for (int i = 0; i < 2; i++) {
341
v[i] = bsp.getPoint(item->vidx[i]);
342
v[i][0] = (v[i][0] * mul[0]) + add[0];
343
v[i][1] = ((1.0f-v[i][1]) * mul[1]) + add[1];
344
c[i].setPackedValue(item->col[i], t[i]);
346
uint32_t cc = c[0].getPackedValue();
348
std::ostream& str = publ->getSVGOutput()->getFileStream();
350
<< "x1=\"" << v[0][0] << "\" y1=\"" << v[0][1] << "\" "
351
<< "x2=\"" << v[1][0] << "\" y2=\"" << v[1][1] << "\" "
353
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8) << "\""
354
<< " stroke-linecap=\"square\" "
355
<< " stroke-width=\"" << publ->getLineWidth() << "\" />\n";
358
void SoFCVectorizeSVGActionP::printPoint(const SoVectorizePoint * item) const
364
void SoFCVectorizeSVGActionP::printImage(const SoVectorizeImage * item) const
370
// -------------------------------------------------------
372
SO_ACTION_SOURCE(SoFCVectorizeSVGAction)
374
void SoFCVectorizeSVGAction::initClass()
376
SO_ACTION_INIT_CLASS(SoFCVectorizeSVGAction, SoVectorizeAction);
379
SoFCVectorizeSVGAction::SoFCVectorizeSVGAction()
381
SO_ACTION_CONSTRUCTOR(SoFCVectorizeSVGAction);
382
this->setOutput(new SoSVGVectorOutput);
383
this->p = new SoFCVectorizeSVGActionP(this);
386
SoFCVectorizeSVGAction::~SoFCVectorizeSVGAction()
392
SoFCVectorizeSVGAction::getSVGOutput() const
394
return static_cast<SoSVGVectorOutput*>(SoVectorizeAction::getOutput());
397
void SoFCVectorizeSVGAction::printHeader() const
399
std::ostream& str = this->getSVGOutput()->getFileStream();
400
str << R"(<?xml version="1.0" encoding="UTF-8" standalone="no"?>)" << std::endl;
401
str << "<!-- Created with FreeCAD (https://www.freecad.org) -->" << std::endl;
402
str << "<svg xmlns=\"http://www.w3.org/2000/svg\"" << std::endl;
403
str << R"( xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events")" << std::endl;
404
str << R"( version="1.1" baseProfile="full")" << std::endl;
406
SbVec2f size = getPageSize();
407
if (this->getOrientation() == LANDSCAPE) {
408
SbSwap<float>(size[0], size[1]);
411
str << " width=\"" << size[0] << "mm\" height=\"" << size[1] << "mm\""<< std::endl;
412
str << " viewBox=\"0 0 " << size[0] << " " << size[1] << "\">" << std::endl;
413
} else { //original code used px
414
str << " width=\"" << size[0] << "\" height=\"" << size[1] << "\">" << std::endl;
416
str << "<g>" << std::endl;
419
void SoFCVectorizeSVGAction::printFooter() const
421
std::ostream& str = this->getSVGOutput()->getFileStream();
422
str << "</g>" << std::endl;
426
void SoFCVectorizeSVGAction::printViewport() const
430
void SoFCVectorizeSVGAction::printBackground() const
432
if (!getBackgroundState()) {
435
SbVec2f mul = getRotatedViewportSize();
436
SbVec2f add = getRotatedViewportStartpos();
440
x[1] = mul[0] - add[0];
442
y[1] = mul[1] - add[1];
445
(void)this->getBackgroundColor(bg);
446
uint32_t cc = bg.getPackedValue();
448
std::ostream& str = this->getSVGOutput()->getFileStream();
449
str << "</g>" << std::endl;
450
str << "<path" << std::endl;
452
<< x[0] << "," << y[0] << " L "
453
<< x[1] << "," << y[0] << " L "
454
<< x[1] << "," << y[1] << " L "
455
<< x[0] << "," << y[1] << " L "
456
<< x[0] << "," << y[0] << " z \"" << std::endl;
457
str << " style=\"fill:#"
458
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8)
459
<< ";fill-opacity:1;fill-rule:evenodd;stroke:none;"
460
"stroke-width:" << getLineWidth() << ";stroke-linecap:butt;stroke-linejoin:"
461
"miter;stroke-opacity:1\" />\n";
462
str << "<g>" << std::endl;
465
void SoFCVectorizeSVGAction::printItem(const SoVectorizeItem * item) const
467
switch (item->type) {
468
case SoVectorizeItem::TRIANGLE:
469
this->p->printTriangle(static_cast<const SoVectorizeTriangle*>(item));
471
case SoVectorizeItem::LINE:
472
this->p->printLine(static_cast<const SoVectorizeLine*>(item));
474
case SoVectorizeItem::POINT:
475
this->p->printPoint(static_cast<const SoVectorizePoint*>(item));
477
case SoVectorizeItem::TEXT:
478
this->p->printText(static_cast<const SoVectorizeText*>(item));
480
case SoVectorizeItem::IMAGE:
481
this->p->printImage(static_cast<const SoVectorizeImage*>(item));
484
assert(0 && "unsupported item");