/*************************************************************************** * Copyright (c) 2008 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include #endif #include #include "SoFCVectorizeSVGAction.h" using namespace Gui; class SoVectorizeItem { public: SoVectorizeItem() { this->type = UNDEFINED; this->depth = 0.0f; } // quick and easy type system enum Type { UNDEFINED, LINE, TRIANGLE, TEXT, POINT, IMAGE }; int type; float depth; // for depth sorting }; class SoVectorizePoint : public SoVectorizeItem { public: SoVectorizePoint() { this->type = POINT; this->vidx = 0; this->size = 1.0f; this->col = 0; } int vidx; // index to BSPtree coordinate float size; // Coin size (pixels) uint32_t col; }; class SoVectorizeTriangle : public SoVectorizeItem { public: SoVectorizeTriangle() { this->type = TRIANGLE; } int vidx[3]; // indices to BSPtree coordinates uint32_t col[3]; }; class SoVectorizeLine : public SoVectorizeItem { public: SoVectorizeLine() { this->type = LINE; vidx[0] = 0; vidx[1] = 0; col[0] = 0; col[1] = 0; this->pattern = 0xffff; this->width = 1.0f; } int vidx[2]; // indices to BSPtree coordinates uint32_t col[2]; uint16_t pattern; // Coin line pattern float width; // Coin line width (pixels) }; class SoVectorizeText : public SoVectorizeItem { public: SoVectorizeText() { this->type = TEXT; this->fontsize = 10; this->col = 0; this->justification = LEFT; } enum Justification { LEFT, RIGHT, CENTER }; SbName fontname; float fontsize; // size in normalized coordinates SbString string; SbVec2f pos; // pos in normalized coordinates uint32_t col; Justification justification; }; class SoVectorizeImage : public SoVectorizeItem { public: SoVectorizeImage() { this->type = IMAGE; this->image.data = nullptr; this->image.nc = 0; } SbVec2f pos; // pos in normalized coordinates SbVec2f size; // size in normalized coordinates struct Image { const unsigned char * data; SbVec2s size; int nc; } image; }; // ---------------------------------------------------------------- SoSVGVectorOutput::SoSVGVectorOutput() = default; SoSVGVectorOutput::~SoSVGVectorOutput() { closeFile(); } SbBool SoSVGVectorOutput::openFile (const char *filename) { Base::FileInfo fi(filename); #ifdef _MSC_VER this->file.open(fi.toStdWString().c_str(), std::ios::out | std::ios::binary); #else this->file.open(fi.filePath().c_str(), std::ios::out | std::ios::binary); #endif return this->file.is_open(); } void SoSVGVectorOutput::closeFile () { if (this->file.is_open()) this->file.close(); } std::fstream& SoSVGVectorOutput::getFileStream() { return this->file; } // ---------------------------------------------------------------- namespace Gui { class SoFCVectorizeSVGActionP { public: SoFCVectorizeSVGActionP(SoFCVectorizeSVGAction * p) { this->publ = p; } void printCircle(const SbVec3f & v, const SbColor & c, const float radius) const; void printSquare(const SbVec3f & v, const SbColor & c, const float size) const; void printTriangle(const SbVec3f * v, const SbColor * c) const; void printTriangle(const SoVectorizeTriangle * item) const; void printLine(const SoVectorizeLine * item) const; void printPoint(const SoVectorizePoint * item) const; void printText(const SoVectorizeText * item) const; void printImage(const SoVectorizeImage * item) const; private: SoFCVectorizeSVGAction * publ; }; } void SoFCVectorizeSVGActionP::printText(const SoVectorizeText * item) const { SbVec2f mul = publ->getRotatedViewportSize(); SbVec2f add = publ->getRotatedViewportStartpos(); float posx = item->pos[0]*mul[0]+add[0]; float posy = item->pos[1]*mul[1]+add[1]; std::ostream& str = publ->getSVGOutput()->getFileStream(); str << "fontsize * mul[1] << "px\">" << item->string.getString() << "" << std::endl; } void SoFCVectorizeSVGActionP::printTriangle(const SoVectorizeTriangle * item) const { SbVec2f mul = publ->getRotatedViewportSize(); SbVec2f add = publ->getRotatedViewportStartpos(); const SbBSPTree & bsp = publ->getBSPTree(); SbVec3f v[3]; SbColor c[3]; float t[3]; for (int i = 0; i < 3; i++) { v[i] = bsp.getPoint(item->vidx[i]); v[i][0] = (v[i][0] * mul[0]) + add[0]; v[i][1] = ((1.0f-v[i][1]) * mul[1]) + add[1]; c[i].setPackedValue(item->col[i], t[i]); } this->printTriangle((SbVec3f*)v, (SbColor*)c); } /* TODO: Support gradients, e.g. */ /* Example: color per vertex #Inventor V2.1 ascii Separator { Coordinate3 { point [ 0.000000 0.000000 0.000000, 100.000000 50.000000 0.000000, 0.000000 100.000000 0.000000 ] } Material { diffuseColor [ 1 1 0, 0 0 1, 1 0 0 ] } MaterialBinding { value PER_VERTEX } IndexedFaceSet { coordIndex [ 0, 1, 2, -1 ] } } */ void SoFCVectorizeSVGActionP::printTriangle(const SbVec3f * v, const SbColor * c) const { if (v[0] == v[1] || v[1] == v[2] || v[0] == v[2]) return; uint32_t cc = c->getPackedValue(); std::ostream& str = publ->getSVGOutput()->getFileStream(); str << "> 8) << "; stroke:#" << std::hex << std::setw(6) << std::setfill('0') << (cc >> 8) << ";" << std::endl << " stroke-width:" << publ->getLineWidth() << ";" << std::endl << " stroke-linecap:round;stroke-linejoin:round\"/>" << std::endl; } void SoFCVectorizeSVGActionP::printCircle(const SbVec3f & v, const SbColor & c, const float radius) const { // todo Q_UNUSED(v); Q_UNUSED(c); Q_UNUSED(radius); } void SoFCVectorizeSVGActionP::printSquare(const SbVec3f & v, const SbColor & c, const float size) const { // todo Q_UNUSED(v); Q_UNUSED(c); Q_UNUSED(size); } void SoFCVectorizeSVGActionP::printLine(const SoVectorizeLine * item) const { SbVec2f mul = publ->getRotatedViewportSize(); SbVec2f add = publ->getRotatedViewportStartpos(); const SbBSPTree & bsp = publ->getBSPTree(); SbVec3f v[2]; SbColor c[2]; float t[2]; for (int i = 0; i < 2; i++) { v[i] = bsp.getPoint(item->vidx[i]); v[i][0] = (v[i][0] * mul[0]) + add[0]; v[i][1] = ((1.0f-v[i][1]) * mul[1]) + add[1]; c[i].setPackedValue(item->col[i], t[i]); } uint32_t cc = c[0].getPackedValue(); std::ostream& str = publ->getSVGOutput()->getFileStream(); str << "> 8) << "\"" << " stroke-linecap=\"square\" " << " stroke-width=\"" << publ->getLineWidth() << "\" />\n"; } void SoFCVectorizeSVGActionP::printPoint(const SoVectorizePoint * item) const { // todo Q_UNUSED(item); } void SoFCVectorizeSVGActionP::printImage(const SoVectorizeImage * item) const { // todo Q_UNUSED(item); } // ------------------------------------------------------- SO_ACTION_SOURCE(SoFCVectorizeSVGAction) void SoFCVectorizeSVGAction::initClass() { SO_ACTION_INIT_CLASS(SoFCVectorizeSVGAction, SoVectorizeAction); } SoFCVectorizeSVGAction::SoFCVectorizeSVGAction() : m_backgroundState(true), m_lineWidth(1.0), m_usemm(false) { SO_ACTION_CONSTRUCTOR(SoFCVectorizeSVGAction); this->setOutput(new SoSVGVectorOutput); this->p = new SoFCVectorizeSVGActionP(this); } SoFCVectorizeSVGAction::~SoFCVectorizeSVGAction() { delete this->p; } SoSVGVectorOutput * SoFCVectorizeSVGAction::getSVGOutput() const { return static_cast(SoVectorizeAction::getOutput()); } void SoFCVectorizeSVGAction::printHeader() const { std::ostream& str = this->getSVGOutput()->getFileStream(); str << R"()" << std::endl; str << "" << std::endl; str << "getOrientation() == LANDSCAPE) { SbSwap(size[0], size[1]); } if (getUseMM()) { str << " width=\"" << size[0] << "mm\" height=\"" << size[1] << "mm\""<< std::endl; str << " viewBox=\"0 0 " << size[0] << " " << size[1] << "\">" << std::endl; } else { //original code used px str << " width=\"" << size[0] << "\" height=\"" << size[1] << "\">" << std::endl; } str << "" << std::endl; } void SoFCVectorizeSVGAction::printFooter() const { std::ostream& str = this->getSVGOutput()->getFileStream(); str << "" << std::endl; str << ""; } void SoFCVectorizeSVGAction::printViewport() const { } void SoFCVectorizeSVGAction::printBackground() const { if (!getBackgroundState()) { return; } SbVec2f mul = getRotatedViewportSize(); SbVec2f add = getRotatedViewportStartpos(); float x[2],y[2]; x[0] = add[0]; x[1] = mul[0] - add[0]; y[0] = add[1]; y[1] = mul[1] - add[1]; SbColor bg; (void)this->getBackgroundColor(bg); uint32_t cc = bg.getPackedValue(); std::ostream& str = this->getSVGOutput()->getFileStream(); str << "" << std::endl; str << "> 8) << ";fill-opacity:1;fill-rule:evenodd;stroke:none;" "stroke-width:" << getLineWidth() << ";stroke-linecap:butt;stroke-linejoin:" "miter;stroke-opacity:1\" />\n"; str << "" << std::endl; } void SoFCVectorizeSVGAction::printItem(const SoVectorizeItem * item) const { switch (item->type) { case SoVectorizeItem::TRIANGLE: this->p->printTriangle(static_cast(item)); break; case SoVectorizeItem::LINE: this->p->printLine(static_cast(item)); break; case SoVectorizeItem::POINT: this->p->printPoint(static_cast(item)); break; case SoVectorizeItem::TEXT: this->p->printText(static_cast(item)); break; case SoVectorizeItem::IMAGE: this->p->printImage(static_cast(item)); break; default: assert(0 && "unsupported item"); break; } }