1 #include "lc_global.h"
2 #include "lc_lxf.h"
3 #include "lc_library.h"
4 #include "lc_application.h"
5 #include "lc_mainwindow.h"
6 #include "piece.h"
7 #include "lc_file.h"
8 #include <QDomDocument>
9
lcLoadLDrawXML(std::map<int,int> & MaterialTable,std::map<int,std::string> & BrickTable,std::map<std::string,std::pair<lcVector3,lcVector4>> & TransformTable)10 static bool lcLoadLDrawXML(std::map<int, int>& MaterialTable, std::map<int, std::string>& BrickTable, std::map<std::string, std::pair<lcVector3, lcVector4>>& TransformTable)
11 {
12 QFile File(lcGetPiecesLibrary()->mLibraryDir.absoluteFilePath(QLatin1String("ldraw.xml")));
13 QByteArray Data;
14
15 if (File.open(QIODevice::ReadOnly))
16 Data = File.readAll();
17 else
18 {
19 QFile DefaultFile(":/resources/ldraw.xml");
20
21 if (DefaultFile.open(QIODevice::ReadOnly))
22 Data = DefaultFile.readAll();
23 }
24
25 if (Data.isEmpty())
26 return false;
27
28 QDomDocument Document;
29 Document.setContent(QString::fromUtf8(Data));
30
31 QDomElement Root = Document.documentElement();
32 if (Root.tagName() != QLatin1String("LDrawMapping"))
33 return false;
34
35 for (QDomNode Node = Root.firstChild(); !Node.isNull(); Node = Node.nextSibling())
36 {
37 QDomElement Element = Node.toElement();
38 QString ElementName = Element.tagName();
39
40 if (ElementName == QLatin1String("Material"))
41 {
42 int LDrawColor = Element.attribute(QLatin1String("ldraw")).toInt();
43 int LegoColor = Element.attribute(QLatin1String("lego")).toInt();
44
45 MaterialTable[LegoColor] = LDrawColor;
46 }
47 else if (ElementName == QLatin1String("Brick"))
48 {
49 QString LDrawID = Element.attribute(QLatin1String("ldraw"));
50 int LegoID = Element.attribute(QLatin1String("lego")).toInt();
51
52 BrickTable.insert(std::make_pair(LegoID, LDrawID.toStdString()));
53 }
54 else if (ElementName == QLatin1String("Transformation"))
55 {
56 QString LDrawID = Element.attribute(QLatin1String("ldraw"));
57
58 lcVector3 Translation;
59 lcVector4 AxisAngle;
60
61 Translation[0] = Element.attribute(QLatin1String("tx")).toFloat();
62 Translation[1] = Element.attribute(QLatin1String("ty")).toFloat();
63 Translation[2] = Element.attribute(QLatin1String("tz")).toFloat();
64 AxisAngle[0] = Element.attribute(QLatin1String("ax")).toFloat();
65 AxisAngle[1] = Element.attribute(QLatin1String("ay")).toFloat();
66 AxisAngle[2] = Element.attribute(QLatin1String("az")).toFloat();
67 AxisAngle[3] = Element.attribute(QLatin1String("angle")).toFloat();
68
69 TransformTable.insert(std::make_pair(LDrawID.toStdString(), std::make_pair(Translation, AxisAngle)));
70 }
71 }
72
73 return true;
74 }
75
lcImportLXFMLFile(const QString & FileData,std::vector<lcPiece * > & Pieces,std::vector<std::vector<lcPiece * >> & Groups)76 bool lcImportLXFMLFile(const QString& FileData, std::vector<lcPiece*>& Pieces, std::vector<std::vector<lcPiece*>>& Groups)
77 {
78 std::map<int, int> MaterialTable;
79 std::map<int, std::string> BrickTable;
80 std::map<std::string, std::pair<lcVector3, lcVector4>> TransformTable;
81
82 if (!lcLoadLDrawXML(MaterialTable, BrickTable, TransformTable))
83 return false;
84
85 QDomDocument Document;
86 Document.setContent(FileData);
87
88 QDomElement Root = Document.documentElement();
89 if (Root.tagName() != QLatin1String("LXFML"))
90 return false;
91
92 for (QDomNode SectionNode = Root.firstChild(); !SectionNode.isNull(); SectionNode = SectionNode.nextSibling())
93 {
94 QDomElement SectionElement = SectionNode.toElement();
95 if (SectionElement.tagName() != QLatin1String("Bricks"))
96 continue;
97
98 for (QDomNode BrickNode = SectionElement.firstChild(); !BrickNode.isNull(); BrickNode = BrickNode.nextSibling())
99 {
100 QDomElement BrickElement = BrickNode.toElement();
101 if (BrickElement.tagName() != QLatin1String("Brick"))
102 continue;
103
104 int NumBrickPieces = 0;
105
106 for (QDomNode PartNode = BrickElement.firstChild(); !PartNode.isNull(); PartNode = PartNode.nextSibling())
107 {
108 QDomElement PartElement = PartNode.toElement();
109 if (PartElement.tagName() != QLatin1String("Part"))
110 continue;
111
112 bool BoneFound = false;
113 lcMatrix44 WorldMatrix;
114
115 for (QDomNode BoneNode = PartElement.firstChild(); !BoneNode.isNull(); BoneNode = BoneNode.nextSibling())
116 {
117 QDomElement BoneElement = BoneNode.toElement();
118 if (BoneElement.tagName() != QLatin1String("Bone"))
119 continue;
120
121 QString BoneTransform = BoneElement.attribute(QLatin1String("transformation"));
122 QStringList BoneElements = BoneTransform.split(',');
123
124 if (BoneElements.size() != 12)
125 continue;
126
127 WorldMatrix[0][0] = BoneElements[0].toFloat();
128 WorldMatrix[0][1] = BoneElements[1].toFloat();
129 WorldMatrix[0][2] = BoneElements[2].toFloat();
130 WorldMatrix[0][3] = 0.0f;
131 WorldMatrix[1][0] = BoneElements[3].toFloat();
132 WorldMatrix[1][1] = BoneElements[4].toFloat();
133 WorldMatrix[1][2] = BoneElements[5].toFloat();
134 WorldMatrix[1][3] = 0.0f;
135 WorldMatrix[2][0] = BoneElements[6].toFloat();
136 WorldMatrix[2][1] = BoneElements[7].toFloat();
137 WorldMatrix[2][2] = BoneElements[8].toFloat();
138 WorldMatrix[3][3] = 0.0f;
139 WorldMatrix[3][0] = BoneElements[9].toFloat();
140 WorldMatrix[3][1] = BoneElements[10].toFloat();
141 WorldMatrix[3][2] = BoneElements[11].toFloat();
142 WorldMatrix[3][3] = 1.0f;
143
144 BoneFound = true;
145 break;
146 }
147
148 if (!BoneFound)
149 continue;
150
151 QString LegoID = PartElement.attribute(QLatin1String("designID"));
152 int Material = PartElement.attribute(QLatin1String("materials")).split(',').first().toInt();
153
154 PieceInfo* Info = nullptr;
155 const auto BrickIt = BrickTable.find(LegoID.toInt());
156 if (BrickIt != BrickTable.end())
157 Info = lcGetPiecesLibrary()->FindPiece(BrickIt->second.c_str(), nullptr, true, false);
158 else
159 Info = lcGetPiecesLibrary()->FindPiece(LegoID.toLatin1() + ".dat", nullptr, true, false);
160
161 const auto ColorIt = MaterialTable.find(Material);
162 int ColorCode = 16;
163 if (ColorIt != MaterialTable.end())
164 ColorCode = ColorIt->second;
165
166 const auto TransformIt = TransformTable.find(BrickIt != BrickTable.end() ? BrickIt->second : (LegoID.toStdString() + ".dat"));
167 if (TransformIt != TransformTable.end())
168 {
169 const lcVector4& AxisAngle = TransformIt->second.second;
170 const lcVector3& TransformTranslation = TransformIt->second.first;
171
172 lcMatrix44 Transform = lcMatrix44FromAxisAngle(lcVector3(AxisAngle[0], AxisAngle[1], AxisAngle[2]), -AxisAngle[3]);
173 Transform.SetTranslation(lcMul30(-TransformTranslation, Transform));
174
175 WorldMatrix = lcMul(Transform, WorldMatrix);
176 }
177
178 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),
179 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));
180
181 lcPiece* Piece = new lcPiece(nullptr);
182 Piece->SetPieceInfo(Info, QString(), false);
183 Piece->Initialize(lcMatrix44LDrawToLeoCAD(WorldMatrix), 1);
184 Piece->SetColorCode(ColorCode);
185 Pieces.push_back(Piece);
186 NumBrickPieces++;
187 }
188
189 if (NumBrickPieces > 1)
190 {
191 std::vector<lcPiece*> Group;
192 for (size_t PieceIdx = Pieces.size() - NumBrickPieces; PieceIdx < Pieces.size(); PieceIdx++)
193 Group.push_back(Pieces[PieceIdx]);
194 Groups.push_back(Group);
195 }
196 }
197 }
198
199 return true;
200 }
201