LDraw.org Discussion Forums

Full Version: Export of .mpd to single 'stand-alone' .ldr file ?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3

Can anyone point me in the direction of an application or utility which will take a multi-part ldraw file (i.e. an .mpd file) and convert it into a single 'standalone' LDR file ?

i.e. something which takes an mpd file and outputs the 'absolute' position and rotation of each part in the model referenced to the origin - not to another part of the model.

Hope that makes sense...

I've had a go writing a conversion myself but got bogged down - has to be recursive I think for multiple 'nested' models.

If no such thing exists could any one give me some tips (not code necessarily) but the method I would need follow to acheive what I'm after ?


Interesting idea, I don't know of a tool that can do this in a single step (maybe MPDCenter?) but it shouldn't be to hard to do yourself especially when you already set something up.

The trick is to recursively scan for type 1 lines while keeping a 'parent' matrix in mind. Then based on how these type 1 lines resolve (part or model) do one of two things:

If it's a part (resolved to LDraw location) copy the line to the output ldr while using the line's matrix multiplied with the parent matrix (order is important -> newLineMat = LineMat * parentMat, then go on with the next line.

If it's a non part (outside ldraw location) multiply the parent matrix with the line's matrix (newParentMat = LineMat * parentMat (keep the org parent matrix for the next line) and go recursively inside the referenced (sub)model using the resulting matrix as it's parent matrix.

While doing this you should handle submodels in the mpd like any other 'standalone' model. So don't go recursivly into them unless they are referenced from the main mpd model.

Hope this is somewhat clear/helps

ps I'm asuming the mpd only holds references to official parts and model only custom files. If not so you need to do more work to preserve non type 1 lines and exclude unofficial parts etc.
Thanks Roland for the prompt reply.

I took a look at MPDCenter - not heard of it before - but doesn't seem to do what I need.

I think I have to start at the 'deepest' nested model and work backwards ?

So if I start with

Model Depth 0
--Sub Model 1 (Depth 1)
----Sub Model 1a (Depth 2)
--Sub Model 2 (Depth 1)

The 1st step is to 'merge' Sub Model 1a (at Depth 2) with Sub Model 1 (at Depth 1)

So I end up with:

Model Depth 0
--Sub Model Depth1 (now including parts from Sub Model Depth 1a)
--Sub Model 2 (Depth 1)

The merging of X,Y,Z I can handle - its the matrix math where I struggle.

It's been a month or so since I looked at this last - now coming back to it for another go...

If the submodel is a single dat file (unlikely) then I can get it to work (I think) but if the submodel has multiple parts (very likely) these child parts are not transformed by the 'parent' line because they are potentially offset from the parent position. i.e. if you transformed each dat file in the submodel by the parent line you don't get the correct result....

I think this is because the parent line is effectively the rotation centre (or 'pseudo' origin) for the child model...
Rob Wrote:I think I have to start at the 'deepest' nested model and work backwards ?

It depends on what you want if you want a single flattened ldr containing the visual same model as the level 0 one it's best to start at top level and go recursively through all it's branches, this will automatically account for multiple references to the same submodel (e.g. model 1a could be referenced using a completely different position from model 3 or something). The merging you speak of will essentially be done like a zipper this way.

Rob Wrote:The merging of X,Y,Z I can handle - its the matrix math where I struggle.

You are essentially right about what you call a 'pseudo' origin cause the x y z in combination with the other 9 number makeup a transformation matrix which describe how to place/rotate the referenced part/model in the referring document.

So you have to use all 12 numbers in a single 4x4 matrix (see LDraw spec documents for more info on this), you don't need to handle them separately.

By multiplying these matrices with the ones of higher levels you adjust their transformation to the absolute space of the top level document. 'spitting' these new lines (with adjusted 12 numbers) into a new ldr results in a flattened version of the original set of ldr/mpd's.

As for the matrix math, depending on the program/script language you use multiplying two matrices is fairly simple, there are probably even default libraries for it. But you would only be needing a multiplying function which is little more then two for loops, source for those can be found all over the net.

You might also need to look deeper in the inner workings of MPD's to correctly handle the submodels of a single mpd file.
If you're willing to try to get the LDLoader portion of LDView to compile on your system, it could be fairly easily written:
  1. Use LDLoader to load the MPD file into an LDLMainModel object.
  2. Create a (recursive) function called flatten() that takes an already opened FILE*, an LDLModel* object, and a const float * matrix as its inputs.
  3. Pass the LDLMainModel object from step one, along with TCVector::getIdentityMatrix() into flatten(). (LDLMainModel is a subclass of LDLModel.)
  4. Inside flatten(), iterate through the first model->getActiveLineCount() file lines in the model using model->getFileLines() to get the array of lines.
  5. For each file line, check to see if it's a model line (type 1) (fileLine->getLineType() == LDLLineTypeModel)
  6. If it is a model line, create a local variable by typecasting from LDLFileLine* to LDLModelLine*.
  7. Call modelLine->getMatrix() to get the model line's matrix, then use TCVector::multMatrix(matrix, modelLineMatrix, newMatrix) to get the modified matrix (newMatrix is a local variable of type float[16]).
  8. Check to see if it's a part: modelLine->getModel()->isPart()
  9. If it's a part, write out a line to the output file as "1 modelLine->getColorNumber() newMatrix[0] newMatrix[1] newMatrix[2] newMatrix[4] newMatrix[5] newMatrix[6] newMatrix[8] newMatrix[9] newMatrix[10] modelLine->getModel()->getFilename()"
  10. If it's not a part, call flatten() with file, modelLine->getModel() and newMatrix.
  11. If the file line isn't a model line, ignore it.

The above could be improved. For example, you could support all line types, instead of just line type 1, but you'd have to very carefully avoid writing out the MPD-specific comments, and you'd have to have separate logic for each line type. Since I assume you want to just flatten an MPD that is made up of parts, the above algorithm should do the trick.

Note also that you don't have to use LDLoader from LDView to do this, but doing so would remove all the LDraw parsing requirements, since it would do all that. LDLoader is C++. If you're interested, send me an email that includes what OS (Windows, Mac, or Linux), and I'll try to get you up and running with LDLoader.
Hi Travis,

Thanks for the reply.

I'm going to take another look at the stuff I did a while back - I think I was close but not quite there and the code got pretty involved (at least for me). The reason for the original post was I didn't want to re-invent the wheel if someone had already done it somewhere that I could use.

FYI - I'm on Windows and using VB.net for my work.

I'll give it a new try based on your method outlined above. (I already have a class which does lots of stuff with Ldraw files, and VB.net has some matrix libraries which I have used before)

(Not sure how to PM you - your email is hidden...)

Interesting idea, indeed.

I need to have a look at my code in MPDCenter.

I am right that you like to have the models inlined until the parts appear, or do you like to have it broken down to quads only ? :-)

I go and try with the parts!
Hi Michael,

The order in which the parts appear is not important (I can sort them how I like later).

Starting from with a single MPD file, which may contain 'in-line' ldr files or links to 'external' ldr files (but in the same folder/directory as the source MPD File).

I want to end up with a single ldr file which contains all the parts for the complete model in the absolute position and rotation relative to 0,0,0 (not relative to any other part). So the final element of each line (line type 1) should be a .dat file which exists in the LDRAW parts folder.

Send email to the LDView email address, and it will get to me.
That is the same I thought about.

Please see my first result compared to the mpd content file.

I did not make much tests right now, so this function still needs to be processed.

I hope this is nearly similar to what you are looking for.
Pages: 1 2 3