leocad/common/lc_lxf.cpp

205 lines
7 KiB
C++

#include "lc_global.h"
#include "lc_lxf.h"
#include "lc_library.h"
#include "lc_application.h"
#include "lc_mainwindow.h"
#include "piece.h"
#include "lc_file.h"
#include <QDomDocument>
static bool lcLoadLDrawXML(std::map<int, int>& MaterialTable, std::map<int, std::string>& BrickTable, std::map<std::string, std::pair<lcVector3, lcVector4>>& TransformTable)
{
QFile File(lcGetPiecesLibrary()->mLibraryDir.absoluteFilePath(QLatin1String("ldraw.xml")));
QByteArray Data;
if (File.open(QIODevice::ReadOnly))
Data = File.readAll();
else
{
QResource Resource(":/resources/ldraw.xml");
if (Resource.isValid())
{
if (Resource.isCompressed())
Data = qUncompress(Resource.data(), Resource.size());
else
Data = QByteArray::fromRawData((const char*)Resource.data(), Resource.size());
}
}
if (Data.isEmpty())
return false;
QDomDocument Document;
Document.setContent(QString::fromUtf8(Data));
QDomElement Root = Document.documentElement();
if (Root.tagName() != QLatin1String("LDrawMapping"))
return false;
for (QDomNode Node = Root.firstChild(); !Node.isNull(); Node = Node.nextSibling())
{
QDomElement Element = Node.toElement();
QString ElementName = Element.tagName();
if (ElementName == QLatin1String("Material"))
{
int LDrawColor = Element.attribute(QLatin1String("ldraw")).toInt();
int LegoColor = Element.attribute(QLatin1String("lego")).toInt();
MaterialTable[LegoColor] = LDrawColor;
}
else if (ElementName == QLatin1String("Brick"))
{
QString LDrawID = Element.attribute(QLatin1String("ldraw"));
int LegoID = Element.attribute(QLatin1String("lego")).toInt();
BrickTable.insert(std::make_pair(LegoID, LDrawID.toStdString()));
}
else if (ElementName == QLatin1String("Transformation"))
{
QString LDrawID = Element.attribute(QLatin1String("ldraw"));
lcVector3 Translation;
lcVector4 AxisAngle;
Translation[0] = Element.attribute(QLatin1String("tx")).toFloat();
Translation[1] = Element.attribute(QLatin1String("ty")).toFloat();
Translation[2] = Element.attribute(QLatin1String("tz")).toFloat();
AxisAngle[0] = Element.attribute(QLatin1String("ax")).toFloat();
AxisAngle[1] = Element.attribute(QLatin1String("ay")).toFloat();
AxisAngle[2] = Element.attribute(QLatin1String("az")).toFloat();
AxisAngle[3] = Element.attribute(QLatin1String("angle")).toFloat();
TransformTable.insert(std::make_pair(LDrawID.toStdString(), std::make_pair(Translation, AxisAngle)));
}
}
return true;
}
bool lcImportLXFMLFile(const QString& FileData, lcArray<lcPiece*>& Pieces, lcArray<lcArray<lcPiece*>>& Groups)
{
std::map<int, int> MaterialTable;
std::map<int, std::string> BrickTable;
std::map<std::string, std::pair<lcVector3, lcVector4>> TransformTable;
if (!lcLoadLDrawXML(MaterialTable, BrickTable, TransformTable))
return false;
QDomDocument Document;
Document.setContent(FileData);
QDomElement Root = Document.documentElement();
if (Root.tagName() != QLatin1String("LXFML"))
return false;
for (QDomNode SectionNode = Root.firstChild(); !SectionNode.isNull(); SectionNode = SectionNode.nextSibling())
{
QDomElement SectionElement = SectionNode.toElement();
if (SectionElement.tagName() != QLatin1String("Bricks"))
continue;
for (QDomNode BrickNode = SectionElement.firstChild(); !BrickNode.isNull(); BrickNode = BrickNode.nextSibling())
{
QDomElement BrickElement = BrickNode.toElement();
if (BrickElement.tagName() != QLatin1String("Brick"))
continue;
int NumBrickPieces = 0;
for (QDomNode PartNode = BrickElement.firstChild(); !PartNode.isNull(); PartNode = PartNode.nextSibling())
{
QDomElement PartElement = PartNode.toElement();
if (PartElement.tagName() != QLatin1String("Part"))
continue;
bool BoneFound = false;
lcMatrix44 WorldMatrix;
for (QDomNode BoneNode = PartElement.firstChild(); !BoneNode.isNull(); BoneNode = BoneNode.nextSibling())
{
QDomElement BoneElement = BoneNode.toElement();
if (BoneElement.tagName() != QLatin1String("Bone"))
continue;
QString BoneTransform = BoneElement.attribute(QLatin1String("transformation"));
QStringList BoneElements = BoneTransform.split(',');
if (BoneElements.size() != 12)
continue;
WorldMatrix[0][0] = BoneElements[0].toFloat();
WorldMatrix[0][1] = BoneElements[1].toFloat();
WorldMatrix[0][2] = BoneElements[2].toFloat();
WorldMatrix[0][3] = 0.0f;
WorldMatrix[1][0] = BoneElements[3].toFloat();
WorldMatrix[1][1] = BoneElements[4].toFloat();
WorldMatrix[1][2] = BoneElements[5].toFloat();
WorldMatrix[1][3] = 0.0f;
WorldMatrix[2][0] = BoneElements[6].toFloat();
WorldMatrix[2][1] = BoneElements[7].toFloat();
WorldMatrix[2][2] = BoneElements[8].toFloat();
WorldMatrix[3][3] = 0.0f;
WorldMatrix[3][0] = BoneElements[9].toFloat();
WorldMatrix[3][1] = BoneElements[10].toFloat();
WorldMatrix[3][2] = BoneElements[11].toFloat();
WorldMatrix[3][3] = 1.0f;
BoneFound = true;
break;
}
if (!BoneFound)
continue;
QString LegoID = PartElement.attribute(QLatin1String("designID"));
int Material = PartElement.attribute(QLatin1String("materials")).split(',').first().toInt();
PieceInfo* Info = nullptr;
const auto BrickIt = BrickTable.find(LegoID.toInt());
if (BrickIt != BrickTable.end())
Info = lcGetPiecesLibrary()->FindPiece(BrickIt->second.c_str(), nullptr, true, false);
else
Info = lcGetPiecesLibrary()->FindPiece(LegoID.toLatin1() + ".dat", nullptr, true, false);
const auto ColorIt = MaterialTable.find(Material);
int ColorCode = 16;
if (ColorIt != MaterialTable.end())
ColorCode = ColorIt->second;
const auto TransformIt = TransformTable.find(BrickIt != BrickTable.end() ? BrickIt->second : LegoID.toStdString());
if (TransformIt != TransformTable.end())
{
const lcVector4& AxisAngle = TransformIt->second.second;
const lcVector3& TransformTranslation = TransformIt->second.first;
lcMatrix44 Transform = lcMatrix44FromAxisAngle(lcVector3(AxisAngle[0], AxisAngle[1], AxisAngle[2]), -AxisAngle[3]);
Transform.SetTranslation(lcMul30(-TransformTranslation, Transform));
WorldMatrix = lcMul(Transform, WorldMatrix);
}
WorldMatrix = lcMatrix44(lcVector4(WorldMatrix[0][0], -WorldMatrix[0][1], -WorldMatrix[0][2], 0.0f), lcVector4(-WorldMatrix[1][0], WorldMatrix[1][1], WorldMatrix[1][2], 0.0f),
lcVector4(-WorldMatrix[2][0], WorldMatrix[2][1], WorldMatrix[2][2], 0.0f), lcVector4(WorldMatrix[3][0] * 25.0f, -WorldMatrix[3][1] * 25.0f, -WorldMatrix[3][2] * 25.0f, 1.0f));
lcPiece* Piece = new lcPiece(nullptr);
Piece->SetPieceInfo(Info, QString(), false);
Piece->Initialize(lcMatrix44LDrawToLeoCAD(WorldMatrix), 1);
Piece->SetColorCode(ColorCode);
Pieces.Add(Piece);
NumBrickPieces++;
}
if (NumBrickPieces > 1)
{
lcArray<lcPiece*> Group;
for (int PieceIdx = Pieces.GetSize() - NumBrickPieces; PieceIdx < Pieces.GetSize(); PieceIdx++)
Group.Add(Pieces[PieceIdx]);
Groups.Add(Group);
}
}
}
return true;
}