add vcglib

This commit is contained in:
yuanlin zhong committed 2025-11-03 17:46:44 +08:00
1 parent 6f6c0c8eb7
commit af8100f851
1537 files changed
+634197

No files matched your search

File diff suppressed because it is too large. Load diff
+139
View File
@@ -0,0 +1,139 @@
#ifndef POLY_TRIANGULATOR_H
#define POLY_TRIANGULATOR_H
#include "util_dae.h"
#include <wrap/gl/glu_tesselator.h>
namespace vcg {
namespace tri {
namespace io {
// These two classes is used for temporary storing of the
// collected data of the polgons during the reading of files.
template<typename VERTEX_TYPE>
class MyPolygon
{
public:
typedef VERTEX_TYPE BaseVertexType;
int _nvert;
std::vector<VERTEX_TYPE*> _pv;
std::vector< vcg::TexCoord2<float> > _txc;
MyPolygon(int n)
:_nvert(n),_pv(_nvert),_txc(_nvert)
{
}
};
template<typename POLYGONAL_TYPE>
class PolygonalMesh
{
public:
typedef POLYGONAL_TYPE FaceType;
enum PERWEDGEATTRIBUTETYPE {NONE = 0,NORMAL = 1,MULTITEXTURECOORD = 2,MULTICOLOR = 4};
typedef typename FaceType::BaseVertexType VertexType;
typedef VertexType* VertexPointer;
typedef typename std::vector<VertexType>::iterator VertexIterator;
typedef typename std::vector<FaceType>::iterator PolygonIterator;
vcg::Box3<float> bbox;
std::vector<VertexType> vert;
std::vector<FaceType> _pols;
void generatePointsVector(std::vector<std::vector<vcg::Point3f> >& v)
{
for(typename PolygonalMesh::PolygonIterator itp = _pols.begin();itp != _pols.end();++itp)
{
v.push_back(std::vector<vcg::Point3f>());
for(typename std::vector<VertexPointer>::iterator itv = itp->_pv.begin();itv != itp->_pv.end();++itv)
{
v[v.size() - 1].push_back((*itv)->P());
}
}
}
void usePerWedgeAttributes(PERWEDGEATTRIBUTETYPE att,const unsigned int multitexture = 1,const unsigned int multicolor = 1)
{
if (att != NONE)
{
for(PolygonIterator itp = _pols.begin();itp != _pols.end();++itp)
{
if (att & MULTICOLOR) itp->usePerWedgeColor(multicolor);
if (att & MULTITEXTURECOORD) itp->usePerWedgeMultiTexture(multitexture);
if (att & NORMAL) itp->usePerWedgeNormal();
}
}
}
template<class TRIMESH>
void triangulate(TRIMESH& mesh)
{
std::vector<std::vector<vcg::Point3f> > pl;
mesh.vert.resize(vert.size());
int multicoor = 0;
//PolygonalMesh's points has been copied in TriangularMesh
for(size_t jj = 0;jj < mesh.vert.size();++jj)
mesh.vert[jj].P() = vert[jj].P();
bool texen = mesh.face.IsWedgeTexEnabled();
unsigned int totaltri = 0;
for(size_t ii = 0;ii < _pols.size();++ii)
totaltri += _pols[ii]._nvert - 2;
mesh.face.resize(totaltri);
//transform the polygonal mesh in a vector<vector<Point>>
generatePointsVector(pl);
int trioff = 0;
//foreach Polygon
for(size_t ii = 0;ii < pl.size();++ii)
{
std::vector<int> tx;
std::vector<std::vector<vcg::Point3f> > pl2(1);
pl2[0] = pl[ii];
vcg::glu_tesselator::tesselate(pl2,tx);
size_t ntri = tx.size() / 3;
assert(tx.size() % 3 == 0);
int polvert = 0;
//foreach triangle
for(size_t tr = 0;tr < ntri;++tr)
{
//typename TRIMESH::FaceType& f = mesh.face[tr];
//typename TRIMESH::FaceType& f = mesh.face[tr];
for(unsigned int tt = 0;tt < 3; ++tt)
{
mesh.face[trioff + tr].V(tt) = &(mesh.vert[_pols[ii]._pv[tx[3 * tr + tt]] - &(vert[0])]);
//vcg::Point3f ppp = mesh.face[tr].V(tt)->P();
if (texen)
{
/* f.WT(multicoor).U() = _pols[ii]._txc[polvert].U();
f.WT(multicoor).V() = _pols[ii]._txc[polvert].V();
f.WT(multicoor).N() = _pols[ii]._txc[polvert].N();*/
}
polvert = (polvert + 1) % _pols[ii]._nvert;
}
//mesh.face.push_back(f);
}
trioff += ntri;
}
assert(trioff == totaltri);
}
};
}
}
}
#endif
+442
View File
@@ -0,0 +1,442 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004-2008 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef __VCGLIB_UTILDAE
#define __VCGLIB_UTILDAE
#include <wrap/io_trimesh/additionalinfo.h>
#include <vcg/complex/algorithms/update/normal.h>
#include <vcg/complex/algorithms/update/position.h>
#include <wrap/io_trimesh/io_mask.h>
#include <QDomDocument>
#include <QFile>
#include <QXmlStreamWriter>
#include <QStringList>
#include <QMap>
#include <vcg/space/point3.h>
#include <vcg/space/texcoord2.h>
#include <vcg/space/color4.h>
#include <vcg/space/texcoord2.h>
#include <wrap/callback.h>
#include <vector>
namespace vcg {
namespace tri {
namespace io {
class InfoDAE : public AdditionalInfo
{
public:
InfoDAE() :AdditionalInfo(){
doc = NULL;
textureIdMap.clear();
}
~InfoDAE(){
if(doc!=NULL) delete doc;
}
QDomDocument* doc;
QMap<QString,int> textureIdMap;
};
class UtilDAE
{
public:
enum DAEError
{
E_NOERROR, // 0
E_CANTOPEN, // 1
E_NOGEOMETRYLIBRARY, // 2
E_NOMESH, // 3
E_NOVERTEXPOSITION, // 4
E_NO3DVERTEXPOSITION, // 5
E_NO3DSCENE, // 6
E_INCOMPATIBLECOLLADA141FORMAT, //7
E_UNREFERENCEBLEDCOLLADAATTRIBUTE, // 8
E_NOPOLYGONALMESH, //9
E_CANTSAVE, //10
E_NOACCESSORELEMENT
};
static const char *ErrorMsg(int error)
{
static const char * dae_error_msg[] =
{
"No errors",
"Can't open file",
"File without a geometry library",
"There isn't mesh in file",
"The meshes in file haven't the vertex position attribute",
"The importer assumes that the OpenMeshType uses a 3D point for the vertex position",
"There isn't any scene in Collada file",
"The input file is not compatible with COLLADA 1.41 standard format",
"Collada file is trying to reference an attribute that is not in the file",
"This version of Collada Importer support only triangular and polygonal mesh file"
};
if(error>9 || error<0) return "Unknown error";
else return dae_error_msg[error];
};
protected:
// This function take care of removing the standard '#' from the beginning of the url
// For example
// <instance_geometry url="#shape0-lib">
// means that you have to search in the <library_geometries> for a node <geometry> with id = "shape0-lib"
// you have to call this function to get the right reference name
inline static void referenceToANodeAttribute(const QDomNode n,const QString& attr,QString& url_st)
{
url_st = n.toElement().attribute(attr);
int sz = url_st.size() - 1;
url_st = url_st.right(sz);
assert(url_st.size() != 0);
}
inline static QDomNode findNodeBySpecificAttributeValue(const QDomNodeList& ndl,const QString& attrname,const QString& attrvalue)
{
int ndl_size = ndl.size();
int ind = 0;
while(ind < ndl_size)
{
QString st = ndl.at(ind).toElement().attribute(attrname);
if (st == attrvalue)
return ndl.at(ind);
++ind;
}
return QDomNode();
}
inline static QDomNode findNodeBySpecificAttributeValue(const QDomNode n,const QString& tag,const QString& attrname,const QString& attrvalue)
{
return findNodeBySpecificAttributeValue(n.toElement().elementsByTagName(tag),attrname,attrvalue);
}
inline static QDomNode findNodeBySpecificAttributeValue(const QDomDocument n,const QString& tag,const QString& attrname,const QString& attrvalue)
{
return findNodeBySpecificAttributeValue(n.elementsByTagName(tag),attrname,attrvalue);
}
inline static bool isThereTag(const QDomNodeList& list)
{
return ((list.size() > 0) ? true : false);
}
inline static bool isThereTag(const QDomNode n,const QString& tagname)
{
return isThereTag(n.toElement().elementsByTagName(tagname));
}
inline static bool isThereTag(const QDomDocument n,const QString& tagname)
{
return isThereTag(n.elementsByTagName(tagname));
}
// Very important function that given a <vertices> element find one of the its attribute (like position, color etc)
inline static QDomNode attributeSourcePerSimplex(const QDomNode n,const QDomDocument startpoint,const QString& sem)
{
QDomNodeList vertattr = n.toElement().elementsByTagName("input");
for(int ind = 0;ind < vertattr.size();++ind)
{
if (vertattr.at(ind).toElement().attribute("semantic") == sem)
{
QString url;
referenceToANodeAttribute(vertattr.at(ind),"source",url);
return findNodeBySpecificAttributeValue(startpoint,"source","id",url);
}
}
return QDomNode();
}
// This function is used to build up a list of strings that are scalar values.
inline static void valueStringList(QStringList& res,const QDomNode srcnode,const QString& tag)
{
QDomNodeList list = srcnode.toElement().elementsByTagName(tag);
//assert(list.size() == 1);
QString nd = list.at(0).firstChild().nodeValue();
res = nd.simplified().split(" ",QString::SkipEmptyParts);
if(res.empty())
{
qDebug("Warning valueStringList returned and empty list. nothing inside element with tag '%s'", qPrintable(tag));
return;
}
if (res.last() == "")
res.removeLast();
// int emptyCount = res.removeAll(QString(""));
// if(emptyCount>0) qDebug("- - - - - - - - valueStringList: Removed %i null strings when parsing tag %s",emptyCount,qPrintable(tag));
// for(int i =0;i<res.size();++i)
// qDebug("- - - - - - - - - - - - %3i = '%s'",i,qPrintable(res.at(i)));
}
/*inline static bool removeChildNode(QDomNodeList*/
inline static bool removeChildNodeList(QDomNodeList& nodelst,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
{
for(int jj = 0;jj < nodelst.size();++jj)
{
removeChildNode(nodelst.at(jj),tag,attribname,attribvalue);
}
return true;
}
inline static bool removeChildNode(QDomNode node,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
{
QDomNodeList clst = node.childNodes();
for(int ii = 0;ii < clst.size();++ii)
{
QDomNode oldchild = node.childNodes().at(ii);
if (tag != "")
{
if ((attribname != "") && (attribvalue != ""))
{
if (clst.at(ii).toElement().attribute(attribname) == attribvalue)
node.removeChild(oldchild);
}
else
{
QString nm = clst.at(ii).nodeName();
if (clst.at(ii).nodeName() == tag)
{
node.removeChild(oldchild);
}
}
}
else node.removeChild(oldchild);
}
return true;
}
static void ParseRotationMatrix(vcg::Matrix44f& m,const std::vector<QDomNode>& t)
{
vcg::Matrix44f rotTmp;
vcg::Matrix44f tmp;
rotTmp.SetIdentity();
tmp.SetIdentity();
for(unsigned int ii = 0;ii < t.size();++ii)
{
QString rt = t[ii].firstChild().nodeValue();
QStringList rtl = rt.split(" ");
if (rtl.last() == "") rtl.removeLast();
assert(rtl.size() == 4);
tmp.SetRotateDeg(rtl.at(3).toFloat(),vcg::Point3f(rtl.at(0).toFloat(),rtl.at(1).toFloat(),rtl.at(2).toFloat()));
rotTmp = rotTmp*tmp;
}
m = m * rotTmp;
}
static void ParseTranslation(vcg::Matrix44f& m,const QDomNode t)
{
assert(t.toElement().tagName() == "translate");
QDomNode tr = t.firstChild();
QString coord = tr.nodeValue();
QStringList coordlist = coord.split(" ");
if (coordlist.last() == "")
coordlist.removeLast();
assert(coordlist.size() == 3);
m[0][0] = 1.0f;
m[1][1] = 1.0f;
m[2][2] = 1.0f;
m[3][3] = 1.0f;
m[0][3] = coordlist.at(0).toFloat();
m[1][3] = coordlist.at(1).toFloat();
m[2][3] = coordlist.at(2).toFloat();
}
static void ParseMatrixNode(vcg::Matrix44f& m,const QDomNode t)
{
assert(t.toElement().tagName() == "matrix");
QDomNode tr = t.firstChild();
QString coord = tr.nodeValue().simplified();
qDebug("Parsing matrix node; text value is '%s'",qPrintable(coord));
QStringList coordlist = coord.split(" ");
if (coordlist.last() == "")
coordlist.removeLast();
assert(coordlist.size() == 16);
for(int i=0;i<4;++i)
{
m[i][0] = coordlist.at(i*4+0).toFloat();
m[i][1] = coordlist.at(i*4+1).toFloat();
m[i][2] = coordlist.at(i*4+2).toFloat();
m[i][3] = coordlist.at(i*4+3).toFloat();
}
}
static void TransfMatrix(const QDomNode parentnode,const QDomNode presentnode,vcg::Matrix44f& m)
{
if (presentnode == parentnode) return;
else
{
QDomNode par = presentnode.parentNode();
std::vector<QDomNode> rotlist;
QDomNode trans;
for(int ch = 0;ch < par.childNodes().size();++ch)
{
if (par.childNodes().at(ch).nodeName() == "rotate")
rotlist.push_back(par.childNodes().at(ch));
else if (par.childNodes().at(ch).nodeName() == "translate")
{
trans = par.childNodes().at(ch);
}
}
vcg::Matrix44f tmp;
tmp.SetIdentity();
if (!trans.isNull()) ParseTranslation(tmp,trans);
ParseRotationMatrix(tmp,rotlist);
m = m * tmp;
TransfMatrix(parentnode,par,m);
}
}
inline static int findOffSetForASingleSimplex(QDomNode node)
{
QDomNodeList wedatts = node.toElement().elementsByTagName("input");
int max = 0;
if (wedatts.size() == 0) return -1;
else
{
for(int ii = 0;ii < wedatts.size();++ii)
{
int tmp = wedatts.at(ii).toElement().attribute("offset").toInt();
if (tmp > max) max = tmp;
}
}
return max + 1;
}
inline static int findStringListAttribute(QStringList& list,const QDomNode node,const QDomNode poly,const QDomDocument startpoint,const char* token)
{
int offset = 0;
if (!node.isNull())
{
offset = node.toElement().attribute("offset").toInt();
QDomNode st = attributeSourcePerSimplex(poly,startpoint,token);
valueStringList(list,st,"float_array");
}
return offset;
}
/* Very important procedure
it has the task to find the name of the image node corresponding to a given material id,
it assuemes that the material name that is passed have already been bound with the current bindings
*/
inline static QDomNode textureFinder(QString& boundMaterialName, QString &textureFileName, const QDomDocument doc)
{
boundMaterialName.remove('#');
//library_material -> material -> instance_effect
QDomNodeList lib_mat = doc.elementsByTagName("library_materials");
if (lib_mat.size() != 1)
return QDomNode();
QDomNode material = findNodeBySpecificAttributeValue(lib_mat.at(0),QString("material"),QString("id"),boundMaterialName);
if (material.isNull())
return QDomNode();
QDomNodeList in_eff = material.toElement().elementsByTagName("instance_effect");
if (in_eff.size() == 0)
return QDomNode();
QString url = in_eff.at(0).toElement().attribute("url");
if ((url.isNull()) || (url == ""))
return QDomNode();
url = url.remove('#');
qDebug("====== searching among library_effects the effect with id '%s' ",qPrintable(url));
//library_effects -> effect -> instance_effect
QDomNodeList lib_eff = doc.elementsByTagName("library_effects");
if (lib_eff.size() != 1)
return QDomNode();
QDomNode effect = findNodeBySpecificAttributeValue(lib_eff.at(0),QString("effect"),QString("id"),url);
if (effect.isNull())
return QDomNode();
QDomNodeList init_from = effect.toElement().elementsByTagName("init_from");
if (init_from.size() == 0)
return QDomNode();
QString img_id = init_from.at(0).toElement().text();
if ((img_id.isNull()) || (img_id == ""))
return QDomNode();
//library_images -> image
QDomNodeList libraryImageNodeList = doc.elementsByTagName("library_images");
qDebug("====== searching among library_images the effect with id '%s' ",qPrintable(img_id));
if (libraryImageNodeList.size() != 1)
return QDomNode();
QDomNode imageNode = findNodeBySpecificAttributeValue(libraryImageNodeList.at(0),QString("image"),QString("id"),img_id);
QDomNodeList initfromNode = imageNode.toElement().elementsByTagName("init_from");
textureFileName= initfromNode.at(0).firstChild().nodeValue();
qDebug("====== the image '%s' has a %i init_from nodes text '%s'",qPrintable(img_id),initfromNode.size(),qPrintable(textureFileName));
return imageNode;
}
static int indexTextureByImgNode(const QDomDocument doc,const QDomNode node)
{
QDomNodeList libim = doc.elementsByTagName(QString("library_images"));
if (libim.size() != 1)
return -1;
QDomNodeList imgs = libim.at(0).toElement().elementsByTagName("image");
int ii = 0;
bool found = false;
while((ii < imgs.size()) && (!found))
{
if (imgs.at(ii) == node)
found = true;
else ++ii;
}
if (found)
return ii;
else
return -1;
}
struct WedgeAttribute
{
QDomNode wnsrc;
QStringList wn;
int offnm;
QDomNode wtsrc;
QStringList wt;
int stridetx;
int offtx;
QDomNode wcsrc;
QStringList wc;
int stridecl;
int offcl;
};
};
}
}
}
#endif
+77
View File
@@ -0,0 +1,77 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004-2008 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include <wrap/dae/xmldocumentmanaging.h>
#include <cassert>
XMLNode::XMLNode(XMLTag* tag)
:_tag(tag)
{
}
XMLNode::~XMLNode()
{
delete _tag;
}
XMLLeafNode::XMLLeafNode(XMLLeafTag* leaftag)
:XMLNode(leaftag)
{
}
XMLLeafNode::~XMLLeafNode()
{
}
void XMLLeafNode::applyProcedure(XMLVisitor& v)
{
v(*this);
}
XMLInteriorNode::XMLInteriorNode(XMLTag* tag)
:XMLNode(tag)
{
}
XMLNode* XMLInteriorNode::son(int ii)
{
assert((ii > 0) && (ii < _sons.size()));
return _sons[ii];
}
QVector< XMLNode* > XMLInteriorNode::sons()
{
return _sons;
}
XMLInteriorNode::~XMLInteriorNode()
{
for(QVector< XMLNode* >::iterator it = _sons.begin();it != _sons.end();++it)
delete (*it);
}
void XMLInteriorNode::applyProcedure(XMLVisitor& v)
{
v(*this);
}
+216
View File
@@ -0,0 +1,216 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004-2008 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef _XML_DOCUMENT_MANAGING_H
#define _XML_DOCUMENT_MANAGING_H
#include <vector>
#include <set>
#include <QDomDocument>
#include<QFile>
#include<QVector>
#include <QXmlStreamWriter>
#include <QString>
class XMLTag
{
public:
typedef std::pair<QString,QString> TagAttribute;
typedef QVector<TagAttribute> TagAttributes;
QString _tagname;
TagAttributes _attributes;
XMLTag(const QString& tagname = QString(),const TagAttributes& attr = TagAttributes())
:_tagname(tagname),_attributes(attr)
{
}
virtual ~XMLTag()
{
}
};
class XMLLeafTag : public XMLTag
{
public:
QVector<QString> _text;
XMLLeafTag(const QString& tagname = QString(),const QVector<QString>& text = QVector<QString>())
:XMLTag(tagname),_text(text)
{
}
virtual ~XMLLeafTag()
{
}
};
class XMLDocumentWriter;
class XMLVisitor;
class XMLNode
{
public:
XMLNode(XMLTag* tag);
virtual ~XMLNode();
virtual void applyProcedure(XMLVisitor& v) = 0;
XMLTag* _tag;
};
class XMLInteriorNode : public XMLNode
{
public:
XMLInteriorNode(XMLTag* tag);
XMLNode* son(int ii);
QVector< XMLNode* > sons();
void applyProcedure(XMLVisitor& v);
~XMLInteriorNode();
QVector< XMLNode* > _sons;
};
class XMLLeafNode : public XMLNode
{
public:
XMLLeafNode(XMLLeafTag* leaftag);
void applyProcedure(XMLVisitor& v);
virtual ~XMLLeafNode();
};
class XMLDocument
{
public:
XMLDocument(XMLInteriorNode* root)
:_root(root)
{
}
~XMLDocument()
{
delete (_root);
}
XMLInteriorNode* _root;
};
class XMLVisitor
{
public:
virtual void operator()(XMLLeafNode& leaf) = 0;
virtual void operator()(XMLInteriorNode& intnode) = 0;
};
class XMLDocumentWriter : public XMLVisitor
{
private:
QXmlStreamWriter _stream;
QFile _file;
bool _error;
void writeText(XMLLeafNode& node)
{
XMLLeafTag* leaftag = static_cast<XMLLeafTag*>(node._tag);
for(QVector<QString>::iterator it = leaftag->_text.begin();it != leaftag->_text.end();++it)
{
QString tmp = "";
if (it != leaftag->_text.begin())
tmp = QString(" ");
_stream.writeCharacters(tmp + *it);
}
}
void writeAttributes(XMLNode& node)
{
QXmlStreamAttributes attr;
for(XMLTag::TagAttributes::iterator it = node._tag->_attributes.begin();it != node._tag->_attributes.end();++it)
attr.append(it->first,it->second);
_stream.writeAttributes(attr);
}
void recursiveStep(XMLInteriorNode& intnode)
{
QVector< XMLNode* > sons = intnode.sons();
for(QVector< XMLNode* >::iterator its = sons.begin();its != sons.end();++its)
(*its)->applyProcedure(*this);
}
public:
void operator()(XMLLeafNode& node)
{
_stream.writeStartElement(node._tag->_tagname);
writeAttributes(node);
writeText(node);
_stream.writeEndElement();
}
void operator()(XMLInteriorNode& intnode)
{
_stream.writeStartElement(intnode._tag->_tagname);
writeAttributes(intnode);
recursiveStep(intnode);
_stream.writeEndElement();
}
void operator()(XMLDocument& doc)
{
_stream.writeStartDocument();
operator()(*(doc._root));
_stream.writeEndDocument();
}
void write(XMLDocument& doc)
{
(*this)(doc);
}
bool isReliable() const
{
return !_error;
}
XMLDocumentWriter(const char* filename,const bool autoformatting = true)
:_stream(),_file(filename),_error(false)
{
if (!_file.open(QIODevice::WriteOnly | QIODevice::Text))
_error = true;
_stream.setDevice(&_file);
_stream.setAutoFormatting(autoformatting);
}
virtual ~XMLDocumentWriter()
{
_file.close();
}
};
#endif