SylvainLS Posted August 11, 2016 Author Posted August 11, 2016 Update 2016-08-11 Added: 15070 / 15070.dat Plate 1x1 with Tooth Perpendicular Corrected: 2586 / 2586.dat Minifig Shield Ovoid 3846 / 3846.dat Minifig Shield Triangular 3876 / 3876.dat Minifig Shield Round 3957 / 3957b.dat Antenna 4H with Flat Top 10049 / 10049.dat Minifig Shield Broad with Spiked Bottom and Cutout Corner 64647 / 64647.dat Minifig Plume/Flame Triple 75902 / 75902.dat Minifig Shield Round Bowed 87692 / 87692.dat Minifig Plume Triple 87693 / 87693.dat Minifig Plume Small 87694 / 87694.dat Minifig Plume Large 92747 / 92747.dat Minifig Shield Oval 93251 / 93251.dat Minifig Shield Scarab 98367 / 98367.dat Minifig Shield Rectangular Curved with Stud Shields are aligned on the handle, except for 98367 which is aligned on its stud (0.008cm lower than the handle). Quote
SylvainLS Posted August 13, 2016 Author Posted August 13, 2016 Update 2016-08-13 Added: 99562 / 96910.dat Gold Ingot Corrected: 2530 / 2530.dat Minifig Sword Cutlass 4499 / 4499.dat Minifig Bow with Arrow 6126 / 6126a.dat Minifig Flame with Pegs 10053 / 10053.dat Minifig Small Sword with Curved Blade 92231 / 93231.dat Minifig Long Bow with Arrow 95673 / 95673.dat Minifig Sword Roman Gladius Quote
SylvainLS Posted August 15, 2016 Author Posted August 15, 2016 (edited) New Howto! Hi all! I’ve added a howto (in the first post) for the brave ones who would want to plunge into it. Feel free to comment on how it all looks like Greek to you Edit: Okay… The forum ate a few bits and keeps mangling some of the text at each edit. I hope I corrected and foolproofed it now… Edited August 15, 2016 by SylvainLS Quote
TotiGonzales Posted August 20, 2016 Posted August 20, 2016 Hey Sylvain! I love your how-to! It took me a couple of days to get my head around the quaternions but now I think I understand them a little bit. I even accomplished a full correct translation using your tutorial. Though there sill ar a couple things I don't get... maybe I'm just a little bit slow with maths. I was wondering how do you get √2/2 (which is 1) from this: cos(a/2) = sin(a/2) = cos(π/4) = sin(π/4) = √2/2? And than how you get this: cos(π/2) = 0, sin(π/2) = 1? Because by typing it into my calculator I get something completely different... And lastly do you build your quaternion off of this form: q = cos(a/2) + sin(a/2).(ax.i + ay.j + az.k)? And if yes what happens with the rest of the factors? (I feel that all this questions have a really simple answer and I'm just being dumb, but as I said I've been trying to get my head around this for a couple days now and I need to finally know!) But other than that, as I said, I was able to use your examples and calculation to translate a part without any problems and I think that it would be very easy for everybody alse that has this problem with the translation. It's just me that would like to understand how it works. With regards, Theodor. Quote
SylvainLS Posted August 20, 2016 Author Posted August 20, 2016 Hey Sylvain! I love your how-to! It took me a couple of days to get my head around the quaternions but now I think I understand them a little bit. I even accomplished a full correct translation using your tutorial. Thanks! It’s great if it helped you. Though there sill ar a couple things I don't get... maybe I'm just a little bit slow with maths. I was wondering how do you get √2/2 (which is 1) from this: cos(a/2) = sin(a/2) = cos(π/4) = sin(π/4) = √2/2? Sorry, habits. √2/2 is 1/√2 but mathematicians don’t like square roots in the denominator, well, at least my teachers didn’t. I used the Unicode fraction characters (so, basically, I wrote √(1/2) ) but the forum transformed some of them to {amp}frac12; which does not work everywhere. (And it keeps tranforming my “α” (alpha) into “a”!) And I don’t “get” 1/√2, it’s just the value of sine and cosine for π/4 (45°). A square with sides of 1/√2 has a diagonal of 1 (the radius of the trigonometric circle). And than how you get this: cos(π/2) = 0, sin(π/2) = 1? Because by typing it into my calculator I get something completely different... Again, simple trigonometry. cosine and sine of π/2 = 90° are a given. Maybe your calculator is waiting for angles in degrees, not radians? And lastly do you build your quaternion off of this form: q = cos(a/2) + sin(a/2).(ax.i + ay.j + az.k)? And if yes what happens with the rest of the factors? (I feel that all this questions have a really simple answer and I'm just being dumb, but as I said I've been trying to get my head around this for a couple days now and I need to finally know!) The quaternions are only used for the rotations. A quaternion that represents a rotation is of the form q = cos(angle/2) + sin(angle/2).(ax.i + ay.j + az.k). It’s doubly unitary: its length is cos²(angle/2) + sin²(angle/2).(ax² + ay² + az²) = 1 and also ax² + ay² + az² = 1 (the length of the unitary vector defining the axis). When you multiply rotation-quaternions, you get a rotation-quaternion. If you know the angle angle and the axis (ax, ay, az) of the rotation, you can write q. If you have a quaternion that you know represents a rotation (as, for example, the result we get from combining several rotation-quarternions), its general form will be q = a + b.i + c.j + d.k. As it is a rotation quaternion, you know it can be written as q = cos(angle/2) + sin(angle/2).(ax.i + ay.j + az.k). Therefore ax = b / sin(angle/2), ay = c / sin(angle/2), az = d / sin(angle/2) and a = cos(angle/2), so angle = 2.Acos(a). Hence we get the angle, ax, ay, az to put in ldraw.xml. But other than that, as I said, I was able to use your examples and calculation to translate a part without any problems and I think that it would be very easy for everybody alse that has this problem with the translation. It's just me that would like to understand how it works. So, rotations are a b… I hope my explanations are not more confusing :skeptic: Quote
TotiGonzales Posted August 20, 2016 Posted August 20, 2016 Thank you very much for explaining to me every thing I asked about. As I thought all my problems were pretty easy to solve. (I can't believe it didn't came to my mind that π/2 is 90° and that my calculator needed the degrees!) Now, I took another look at your examples and (I really don't mean to make you flip out or so, but...) this is as far as I got: p.q = (0 + i) . (√2/2 + √2/2 j) = √2/2 i + √2/2 i.j = 0 + √2/2 ( i + k ). I really can't figure out how √2/2 i + √2/2 i.j becomes 0 + √2/2 ( i + k )! ( the (i + k )...) I'm sure it's just some 5th grade math that I'm missing but I'm sick of getting quaternions nightmares because I try to get my head around this before I go to sleep. So I'll just ask you. I hope these won't be just my problems with this calculation and other people that would like to get into part translation in the future will find your explanation for their (and my) problems here too. Quote
SylvainLS Posted August 20, 2016 Author Posted August 20, 2016 Now, I took another look at your examples and (I really don't mean to make you flip out or so, but...) this is as far as I got: p.q = (0 + i) . (√2/2 + √2/2 j) = √2/2 i + √2/2 i.j = 0 + √2/2 ( i + k ). I really can't figure out how √2/2 i + √2/2 i.j becomes 0 + √2/2 ( i + k )! ( the (i + k )...) By definition, i.j = k, so √2/2.i + √2/2.i.j = √2/2.( i + i.j ) = √2/2.( i + k ) I'm sure it's just some 5th grade math that I'm missing but I'm sick of getting quaternions nightmares because I try to get my head around this before I go to sleep. So I'll just ask you. The thing is, you’re overthinking it You don’t have to understand why or how, you just apply the rules: The definition: i.i = j.j = k.k = i.j.k = -1 Its corollaries: i.j = k = -j.i j.k = i = -k.j k.i = j = -i.k You apply them until you get only a scalar and simple i, j, k components. And that’s not 5th grade maths. Trigonometry is taught to 14-15 year-olds here (what we call “troisième” (third), should be 9th grade), and easily forgotten. And quaternions are college/university level stuff. (Well, my high school teacher introduced us to quaternions during the last year but he was a madman ) I hope these won't be just my problems with this calculation and other people that would like to get into part translation in the future will find your explanation for their (and my) problems here too. Yes, I didn’t want to go too far into the maths but I may have shortened a bit too much Quote
TotiGonzales Posted August 21, 2016 Posted August 21, 2016 Of corse i.j=k !!! I just had to look back a couple of lines! Thank you very much! Now I finally understand it all. Your how-to is perfect the way it is right now, I'm just too curious... Quote
SylvainLS Posted August 22, 2016 Author Posted August 22, 2016 (edited) Update 2016-08-22 Added: 95646 / 95646.dat Electric Mindstorms EV3 95650 / 95650.dat Electric Mindstorms EV3 Color Sensor 95652 / 95652.dat Electric Mindstorms EV3 Ultrasonic Sensor 95654 / 95654.dat Electric Mindstorms EV3 Infrared Sensor 99380 / 99380.dat Electric Mindstorms EV3 Gyroscopic Sensor 95648 / 95648.dat Electric Mindstorms EV3 Touch Sensor 74665 / 99385c01.dat Electric Mindstorms EV3 Touch Sensor Body Assembly 99386 / 99386.dat Electric Mindstorms EV3 Touch Sensor Button 95658 / 95658.dat Electric Mindstorms EV3 Large Motor 54725 / 99550c01.dat Electric Mindstorms EV3 Large Motor Case 74042 / 99617c01.dat Electric Mindstorms EV3 Large Motor Drive Hub Double 99455 / 99455.dat Electric Mindstorms EV3 Medium Motor 59158 / 99535c01.dat Electric Mindstorms EV3 Medium Motor Body Assembly 74043 / 99543.dat Electric Mindstorms EV3 Medium Motor Thanks Jarema! 95648, 95658, and 99455 are assemblies in LDD. They are disassembled when exporting. Importing them (as assemblies) doesn’t work. The components are correctly imported though. I thought I would have to fumble with the Assembly XML element, but, actually, the ones that exist (torso, steering wheel, control stick/lever) don’t work: the separated components are “assembled” (replaced by the assembly) in LDD when they are correctly placed in the LDR file (as when exported ), but the LDraw ready-made assemblies aren’t imported. Edited August 22, 2016 by SylvainLS Quote
SylvainLS Posted August 23, 2016 Author Posted August 23, 2016 Update 2016-08-23 Corrected: 60410 / 933c01.dat Electric Mindstorms NXT RJ12 Style Blug w/ Cable End (Complete) Added*: 55804 / 55804.dat Electric Mindstorm NXT Cable 20cm 55805 / 55805.dat Electric Mindstorm NXT Cable 35cm 55806 / 55806.dat Electric Mindstorm NXT Cable 50cm 11145 / 11145.dat Electric Mindstorm EV3 Cable 25cm 11146 / 11146.dat Electric Mindstorm EV3 Cable 35cm 11147 / 11147.dat Electric Mindstorm EV3 Cable 50cm * The cables are loose assemblies in LDD (the plugs can be moved at will), they are exported as two plugs. As they are loose, we can’t state the relative positions of their components in an Assembly XML element. So they can’t be imported. (Besides they’re 6 assemblies with the exact same two components.) Quote
BEAVeR Posted August 24, 2016 Posted August 24, 2016 What a delight to see this topic! I have been updating the ldraw.xml file myself whenever I needed to. I'll see which part mappings I have that I can contribute... To help me do the part mappings, I wrote a simple program to do the equivalent rotation thing for me, so that I don't have to mess around with matrices or quaternions. I rewrote it in Python with only the most basic of functions. This way, you can plug it into an online compiler like https://repl.it/languages/python and simply hit the run button without any installing or programming knowledge required. I wrote instructions on how to use it, so once you hit run everything should go by itself. I hope this can help people who are less savvy with these kinds of things to contribute! So here's what you do: 1. Go the the website I just mentionned 2. Paste the code from the spoiler below into the left window from math import cos, acos, sin, pi def multiply_matrices(matrix_1, matrix_2): """Calculates the matrix-matrix product between matrix_1 and matrix_2. If their dimensions aren't correct, None is returned""" if len(matrix_1[0]) != len(matrix_2): matrix_out = None else: matrix_out = [[0 for i in range(len(matrix_2[0]))] for j in range(len(matrix_1))] for row in range(len(matrix_out)): for col in range(len(matrix_out[0])): for i in range(len(matrix_1[0])): matrix_out[row][col] += matrix_1[row][i]*matrix_2[i][col] return matrix_out def trace(matrix): """Calculates the trace (sum of the diagonal elements) of a square matrix""" trace = 0 for i in range(len(matrix)): trace += matrix[i][i] return trace def rotation_matrix(axis, angle): """Returns a 3x3 rotation matrix that corresponds to the given rotation about the axis ("x", "y" or "z") with the given angle in radians""" axis_indeces = {"x":0, "y":1, "z":2} ax_ind = axis_indeces[axis] rot_mat = [[0,0,0],[0,0,0],[0,0,0]] rot_mat[ax_ind][ax_ind] = 1 for i in range(1,3): col = ax_ind + i if col > 2: col -= 3 rot_mat[col][col] = cos(angle) sin_row = range(3) sin_row.remove(col) sin_row.remove(ax_ind) sin_row = sin_row.pop() if i == 1: rot_mat[sin_row][col] = sin(angle) else: rot_mat[sin_row][col] = -sin(angle) return rot_mat def equivalent_rotation(axes, angles): """Returns the equivalent axis (in x,y,z coordinates) and the equivalent angle (in radians) corresponding to the sequence of rotations given by the arguments. "axes" is a list of all the axes around which is being rotated (e.g. ["x", "y", "z"]) in order of occurence, and "angles" is a list of equal length with the angles (in degrees) of the corresponding rotations""" rot_mat = [[1,0,0],[0,1,0],[0,0,1]] for i in range(len(axes)): rot_mat = multiply_matrices(rot_mat, rotation_matrix(axes[i], angles[i]*pi/180)) eq_angle = acos((trace(rot_mat)-1)/2.0) eq_axis = [rot_mat[2][1] - rot_mat[1][2], rot_mat[0][2] - rot_mat[2][0], rot_mat[1][0] - rot_mat[0][1]] eq_axis = [eq_axis_coord/(2.0*sin(eq_angle)) for eq_axis_coord in eq_axis] return eq_axis, eq_angle def generate_rotation_code(eq_axis, eq_angle): """Returns a string containing the code for the xml file for the given rotation that is entered by means of eq_axis, which is a list containing the three cartesian coordinates of the equivalent axis of rotation, and eq_angle, a number that gives the angle of the equivalent rotation. If the eq_axis can be scaled to a vector with only integers as coordinates, the function returns the integer version""" max_el = float(max(eq_axis)) if max_el != 0: new_eq_axis = [coord/max_el for coord in eq_axis] all_ints = True for coord in new_eq_axis: if int(coord) != coord: all_ints = False if all_ints == True: eq_axis = new_eq_axis if all_ints == True: eq_axis = [int(coord) for coord in eq_axis] else: eq_axis = [round(coord, 6) for coord in eq_axis] eq_angle = round(eq_angle, 6) eq_rot_data = eq_axis eq_rot_data.append(eq_angle) return 'ax="{0}" ay="{1}" az="{2}" angle="{3}"'.format(*eq_rot_data) # Code for the text based interface print """Below you can enter the consecutive rotations you want to reduce to an \ equivalent rotation about a single axis. You will be prompted to enter the \ axis each time: this requires you to input either x, y or z (without \ quotation marks and the like). You will also be prompted to enter the \ angle of the rotation about each axis. Give this angle in degrees. You \ can enter up to 3 consecutive rotations. You can also input less. Hitting \ enter without filling anything in a certain field will make the program \ go on with the information you provided""" print nb_rots = 0 axes = [] angles = [] cont = True while nb_rots < 3 and cont == True: axes.append(raw_input("Please enter the axis of rotation: ")) if axes[-1] == "": cont = False del axes[-1] else: angles.append(float(raw_input("Please enter the angle of the rotation: "))) if angles[-1] == "": cont = False del axes[-1] del angles[-1] nb_rots += 1 [eq_axis, eq_angle] = equivalent_rotation(axes, angles) print print generate_rotation_code(eq_axis, eq_angle) 3. Hit the "run" button 4. Follow the instructions the program gives you 5. Paste the code you obtain from the program right into the ldraw.xml file on the place where it belongs. Don't be afraid to ask any questions though! O, and thanks again for putting together this document, everyone! Quote
SylvainLS Posted August 24, 2016 Author Posted August 24, 2016 (edited) […]I'll see which part mappings I have that I can contribute... If the task seems daunting, feel free to post me your ldraw.xml file, I can easily find the diffs. To help me do the part mappings, I wrote a simple program to do the equivalent rotation thing for me, so that I don't have to mess around with matrices or quaternions.[…] One little problem with your code: the forum ate all the leading spaces. That’s not good with Python Another little problem is multiplying matrices can lead to errors or at least approximations (floating point computations). And another big problem: where’s the fun in automating that? O, and thanks again for putting together this document, everyone! You’re welcome! Edited August 24, 2016 by SylvainLS Quote
SylvainLS Posted August 31, 2016 Author Posted August 31, 2016 Update 2016-08-31 Corrected: 6255 / 6255.dat Plant 1 x 1 x 0.667 Round with 3 Large Leaves 63965 / 63965.dat Bar 6L with Thick Stop Added: 15530 / 15530.dat Minifig Hat Police 20430 / 20430.dat Cylinder 2 x 4 x 4 24445 / 24445.dat Tile 1 x 2 with Minifig Head Post 24593 / 24593.dat Cylinder Half 2 x 4 x 2 with 1 x 2 cutout 24607 / 24607.dat Windscreen 2 x 10 x 3 Note: the new ones are new unofficial LDraw parts. Quote
djm Posted September 15, 2016 Posted September 15, 2016 Another transformation for inclusion in the next release. <!-- Electric Mindstorms EV3 IR-Beacon / Remote Handset --> <Transformation ldraw="72156.dat" tx="2.0" ty="0.08" tz="1.6" ax="0" ay="1" az="0" angle="1.570796"/> Regards, David Quote
SylvainLS Posted September 15, 2016 Author Posted September 15, 2016 Please note I’m in the process of cleaning, verifying, and correcting the whole mess file. Importing assemblies is the last ditch (see http://www.eurobrick...howtopic=140239 ). Don’t fear, I won’t wait for that to publish the result, I’m just waiting for a few new files in the LDraw Unofficial Library to write the big announcement. Quote
SylvainLS Posted September 16, 2016 Author Posted September 16, 2016 (edited) Giant Overhaul! The file has been cleaned. The existing transformations have all been tested and corrected. A lot of new transformatins have been added. As far as I can tell, all the possible conversions are included. That’s about 2600 parts (depending on how you count them), 64 assemblies. 1075 LDD parts remain unconverted: they are missing in LDraw (at least, I couldn’t find them). You’ll need the latest LDraw Unofficial Library, especially for the assemblies (new parts have just been submitted for them). Here are a few files if you want to help or comment: The working assemblies. The assemblies for which parts are missing (dark grey are missing, white is the rest of the parts of the assembly we already have the LDraw parts for). The parts for which a variant is used instead (red and orange: the missing variant, dark grey: the substitute, brown: substitutes that are also wrong). And, finally, the list of LDD parts that I know no LDraw equivalent for: CSV (columns: LDD ID, LDD name, guessed BrickLink ID, BrickLink name). As I added in the first post, LDraw assumes technic holes/pins/axles in bricks are at the same height as studs. They should be 0.12 mm higher. LDD places them 0.2 mm higher. The old version of ldraw.xml used to add those 0.2 mm to a great number of parts (pins and axles mainly, but also beams and technic panels), not all, and arbitrarily. The picture below shows a 2L Axle (red) and Pin and Axle (blue) in a Technic Brick with Axle Hole. The axles parts have been rotated a quarter turn each level up (that is the higher ones are 270°, the lower ones are 0°). The left part uses the old conversion that added 0.2 mm, the right part uses the new conversion. Disclaimer: I’m prone to tpyos and other herrors, also, sometimes, after looking at a lot of parts and lines of XML, I might not have seen obvious errors. So, if you find an error, be indulgent and post it here. Thank you. Edited September 16, 2016 by SylvainLS Quote
djm Posted September 16, 2016 Posted September 16, 2016 Stunning! That must have been a labour of love. Well done. If my eyes don't deceive me, I think there is a spurious "w" in the file, immediately below the definition for 76276.dat. Regards, David Quote
SylvainLS Posted September 16, 2016 Author Posted September 16, 2016 Stunning! That must have been a labour of love. Well done. I was fed up with little errors, the untidyness (that I uselessly kept to make comparisons easy), and had time on my hands. If my eyes don't deceive me, I think there is a spurious "w" in the file, immediately below the definition for 76276.dat. Thanks. Corrected. Quote
SylvainLS Posted September 23, 2016 Author Posted September 23, 2016 (edited) Update 2016-09-23 Added: 21271 / 21271.dat Minifig Hoverboard 24085 / 24085.dat Minifig Mop Edited September 23, 2016 by SylvainLS Mop just added Quote
SylvainLS Posted September 30, 2016 Author Posted September 30, 2016 (edited) Update 2016-09-30 Added: 21229 / 21229.dat Fence Spindled 4 x 4 x 2 Quarter Round with 3 Studs 96487 / 96487.dat Plant Flower with 5 Serrated Petals with Pin Added some LDraw colors for import (rubbers and the like; imported as plain). Edited September 30, 2016 by SylvainLS Quote
SylvainLS Posted October 2, 2016 Author Posted October 2, 2016 Update 2016-10-02 Added new unofficial parts: 47404 / 47404.dat Boat Base 10 x 12 64645 / 64645.dat Boat Base 10 x 16 Stern / Bow 64651 / 64651.dat Boat Base 13 x 16 Stern / Bow (47404.dat has little problems though.) Quote
TotiGonzales Posted October 3, 2016 Posted October 3, 2016 So... I really needed this piece: Part#: 15362 Name: CLAW 7 MODULES WITH CROSS AXEL. It wasn't inside LDraw's parts folder (not even inside the Unofficial parts Folder), but I found it here http://www.digital-bricks.de/en/index.php?site=1392 . I inserted a new line for it in the XML file (witch wasn't as straight forward as I expected, you should add a "template" for adding new parts in your original post) and it works/looks perfect if you would ask me. The question is: how could we make parts like this one accessible for everyone that needs them trough the XML file or through this forum? Teodor PS: On the website listed above are a lot of unavailable parts free for download. Quote
SylvainLS Posted October 3, 2016 Author Posted October 3, 2016 (Durn! Can’t cut the quotes anymore.) About a template: Could you develop on what more is needed than a simple copy-paste of a transformation line (either one in the file or one of the examples in the howto)? About digital-bricks.de: I didn’t add/use them for several reasons, mainly because I simply forgot about them , and they are all-in-one files not using LDraw primitives, so they don’t fit well. As for making them available, what I can do is add them in ldraw.xml. Leave me a few days…. Quote
TotiGonzales Posted October 3, 2016 Posted October 3, 2016 It wasn't hard to find the right composition of the transformation line, but I first had to copy one of the existing ones or I could have copied one from the how to, doesn't matter, and than paste ti in. Than I had to adjust all the fields and figure out what goes where. If you could just add this here into your how to, it would be for everyone, I suppose, much easier to write a new transformation: <!-- Part name and partnumber.dat --> <!-- OFICIAL LEGO PART NAME and number --> <Transformation ldraw="LDraw part name.dat" tx="0" ty="0" tz="0" ax="1" ay="0" az="0" angle="0" /> Please correct it if that isn't right! Quote
SylvainLS Posted October 3, 2016 Author Posted October 3, 2016 That’s right but “!-- … --” are just comments you know Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.