Skip to content

Commit

Permalink
Improved slope calculations, plus fix for horizon colour
Browse files Browse the repository at this point in the history
  • Loading branch information
TobyLobster committed Aug 24, 2018
1 parent a8bd898 commit bc21995
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 81 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"name": "Import LDraw",
"description": "Import LDraw models in .mpd .ldr .l3b and .dat formats",
"author": "Toby Nelson <tobymnelson@gmail.com>",
"version": (1, 1, 5),
"version": (1, 1, 6),
"blender": (2, 76, 0),
"location": "File > Import",
"warning": "",
Expand Down
2 changes: 1 addition & 1 deletion __version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# -*- coding: utf-8 -*-
version = (1, 1, 5)
version = (1, 1, 6)
252 changes: 173 additions & 79 deletions loadldraw/loadldraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,110 @@ def meshOptionsString():
globalWeldDistance = 0.0005
globalPoints = []

# **************************************************************************************
# Dictionary with as keys the part numbers (without any extension for decorations)
# of pieces that have grainy slopes, and as values a set containing the angles (in
# degrees) of the face's normal to the horizontal plane. Use a tuple to represent a
# range within which the angle must lie.
globalSlopeBricks = {
'962':{45},
'2341':{-45},
'2449':{-16},
'2875':{45},
'2876':{(40, 63)},
'3037':{45},
'3038':{45},
'3039':{45},
'3040':{45},
'3041':{45},
'3042':{45},
'3043':{45},
'3044':{45},
'3045':{45},
'3046':{45},
'3048':{45},
'3049':{45},
'3135':{45},
'3297':{63},
'3298':{63},
'3299':{63},
'3300':{63},
'3660':{-45},
'3665':{-45},
'3675':{63},
'3676':{-45},
'3678':{24},
'3684':{15},
'3685':{16},
'3688':{15},
'3747':{-63},
'4089':{-63},
'4161':{63},
'4286':{63},
'4287':{-63},
'4445':{45},
'4460':{16},
'4509':{63},
'4854':{-45},
'4856':{(-60, -70), -45},
'4857':{45},
'4858':{72},
'4861':{45, 63},
'4871':{-45},
'4885':{72},
'6069':{72, 45},
'6153':{(60, 70), (26, 34)},
'6227':{45},
'6270':{45},
'13269':{(40, 63)},
'13548':{45},
'15571':{45},
'18759':{-45},
'22390':{(40, 55)},
'22391':{(40, 55)},
'22889':{-45},
'28192':{45},
'30180':{47},
'30182':{45},
'30183':{-45},
'30249':{35},
'30283':{-45},
'30363':{72},
'30373':{-24},
'30382':{11, 45},
'30390':{-45},
'30499':{16},
'32083':{45},
'43708':{72},
'43710':{72, 45},
'43711':{72, 45},
'47759':{(40, 63)},
'52501':{-45},
'60219':{-45},
'60477':{72},
'60481':{24},
'63341':{45},
'72454':{-45},
'92946':{45},
'93348':{72},
'95188':{65},
'99301':{63},
'303923':{45},
'303926':{45},
'304826':{45},
'329826':{64},
'374726':{-64},
'428621':{64},
'4162628':{17},
'4195004':{45},
}

# Create a regular dictionary of parts with ranges of angles to check
margin = 5 # Allow 5 degrees either way to compensate for measuring inaccuracies
globalSlopeAngles = {}
for part in globalSlopeBricks:
globalSlopeAngles[part] = {(c-margin, c+margin) if type(c) is not tuple else (min(c)-margin,max(c)+margin) for c in globalSlopeBricks[part]}

# **************************************************************************************
def internalPrint(message):
"""Debug print with identification timestamp."""
Expand Down Expand Up @@ -184,11 +288,11 @@ def printError(message):
# **************************************************************************************
class Math:
identityMatrix = mathutils.Matrix((
(1.0, 0.0, 0.0, 0.0),
(0.0, 1.0, 0.0, 0.0),
(0.0, 0.0, 1.0, 0.0),
(0.0, 0.0, 0.0, 1.0)
))
(1.0, 0.0, 0.0, 0.0),
(0.0, 1.0, 0.0, 0.0),
(0.0, 0.0, 1.0, 0.0),
(0.0, 0.0, 0.0, 1.0)
))
rotationMatrix = mathutils.Matrix.Rotation(math.radians(-90), 4, 'X')
reflectionMatrix = mathutils.Matrix((
(1.0, 0.0, 0.0, 0.0),
Expand Down Expand Up @@ -1592,7 +1696,7 @@ def __createNodeBasedMaterial(blenderName, col, isSlopeMaterial=False):
BlenderMaterials.__createCyclesBasic(nodes, links, colour, col["alpha"], col["name"])

if isSlopeMaterial and not Options.instructionsLook:
BlenderMaterials.__createCyclesSlopeTexture(nodes, links, 0.3)
BlenderMaterials.__createCyclesSlopeTexture(nodes, links, 0.6)
elif Options.curvedWalls and not Options.instructionsLook:
BlenderMaterials.__createCyclesConcaveWalls(nodes, links, 0.2)

Expand Down Expand Up @@ -1845,10 +1949,10 @@ def __nodeEmission(nodes, x, y):
node.location = x, y
return node

def __nodeVoronoi(nodes, scale, x, y):
def __nodeVoronoi(nodes, scale, x, y, colouring = 'CELLS'):
node = nodes.new('ShaderNodeTexVoronoi')
node.location = x, y
node.coloring = 'CELLS'
node.coloring = colouring
node.inputs['Scale'].default_value = scale
return node

Expand Down Expand Up @@ -2218,19 +2322,10 @@ def __createBlenderSlopeTextureNodeGroup():
group.outputs.new('NodeSocketVectorDirection', 'Normal')

# create nodes
node_texture_coordinate = group.nodes.new('ShaderNodeTexCoord')
node_texture_coordinate.location = -300, 240

node_voronoi = group.nodes.new('ShaderNodeTexVoronoi')
node_voronoi.coloring = 'INTENSITY'
node_voronoi.inputs['Scale'].default_value = 3.0/Options.scale
node_voronoi.location = -100, 155

node_bump = group.nodes.new('ShaderNodeBump')
node_texture_coordinate = BlenderMaterials.__nodeTexCoord(group.nodes, -300, 240)
node_voronoi = BlenderMaterials.__nodeVoronoi(group.nodes, 3.0/Options.scale, -100, 155, 'INTENSITY')
node_bump = BlenderMaterials.__nodeBumpShader(group.nodes, 0.3, 0.08, 90, 50)
node_bump.invert = True
node_bump.inputs['Strength'].default_value = 0.3
node_bump.inputs['Distance'].default_value = 0.04
node_bump.location = 90, 50

# link nodes together
group.links.new(node_texture_coordinate.outputs['Object'], node_voronoi.inputs['Vector'])
Expand Down Expand Up @@ -3002,75 +3097,70 @@ def addNodeToParentWithGroups(parentObject, groupNames, newObject):
newObject.parent = parentObject
globalObjectsToAdd.append(newObject)

# **************************************************************************************
def isSlopePart(partName):
"""
Checks whether a given part should receive a grainy slope material.
"""

global globalSlopeAngles

# Is it a part which has a sloped face?
partNumber = re.findall(r'\D*\d+', partName)[0]
if partNumber in globalSlopeAngles.keys():
return True

return False

# **************************************************************************************
def isSlopeFace(partName, faceVertices):
"""
Checks whether a given face of a certain part should receive a grainy slope material.
"""

global globalSlopeAngles
global globalPartCenterOverride

# Dictionary with as keys the part numbers (without any extension for decorations)
# of pieces which have grainy slopes and as items a set containing the cotangenses
# of those slopes projected on the x or z axis. Use tuples to represent a range
# within which the cotangens has to lie if it's too difficult to define the exact
# values for all faces
slopeBricks = {'3049':{1}, '3048':{1}, '15571':{1}, '3040':{1}, '3044':{1}, \
'3665':{1}, '28192':{1}, '3039':{1}, '3043':{1}, '3046':{1}, \
'962':{1}, '3045':{1}, '13548':{1}, '3660':{1}, '3676':{1}, \
'3038':{1}, '3042':{1}, '3135':{1}, '3037':{1}, '3041':{1}, \
'4445':{1}, '18759':{1}, '2341':{1}, '4861':{1,1/2}, '4871':{1}, \
'30390':{1}, '30182':{1}, '4854':{1}, '72454':{1}, '4857':{1}, \
'52501':{1}, '22889':{1}, '32083':{1}, '30183':{1}, '60219':{1}, \
'30283':{1}, '30180':{1}, '3300':{1/2}, '3299':{1/2}, '4286':{1/2}, \
'4287':{1/2}, '3298':{1/2}, '4089':{1/2}, '3747':{21/40}, '4161':{1/2}, \
'99301':{1/2}, '3675':{1/2}, '3297':{1/2}, '4509':{1/2}, \
'13269':{1,1/2}, '2876':{1,1/2}, '47759':{1,3/5}, '30382':{1,1/5}, \
'4858':{1/3}, '6069':{1,1/3}, '4885':{1,1/3}, '93348':{1/3}, \
'6153':{1/2}, '4856':{1/3}, '43710':{1,1/3}, '43711':{1,1/3}, \
'60477':{1/3}, '30363':{1/3}, '43708':{1/3}, '30249':{29/20}, \
'60481':{11/5}, '3678':{11/5}, '30373':{11/5}, '2449':{17/5}, \
'4460':{17/5}, '3688':{11/3}, '3685':{17/5}, '92946':{1}, \
'22390':{(1,1/2)}, '22391':{(1,1/2)}}
# Dictionary with as keys the part numbers (without any extensions for decorations)
# of the pieces in slopeBricks for which the default origin does not lie at the
# outside of the part. The values are the coordinates of an appropriate origin
# expressed in LDraw units
partCenterOverride = {'3049':[0,24,40], '3048':[0,24,0], '15571':[0,24,0], \
'962':[0,24,0], '6069':[0,24,0], '60477':[0,24,0], \
'30363':[0,24,0]}

# Step 1: is it a brick which has a slope material?
partNumber = re.findall(r'\D*\d+', partName)[0]
if partNumber not in slopeBricks.keys():
# Step 1: is the area of the polygon too small? (e.g. a tiny face of the Lego logo as seen on studs)
if len(faceVertices) > 3:
# (Twice) the area of a quadrilateral
twice_area = ((faceVertices[2] - faceVertices[0]).cross(faceVertices[3]-faceVertices[1])).length
else:
# (Twice) the area of a triangle
twice_area = ((faceVertices[1] - faceVertices[0]).cross(faceVertices[2]-faceVertices[0])).length

if twice_area < (2.0 * Options.scale * Options.scale):
return False

# Step 2: does the face point outwards?
partCenter = mathutils.Vector([0,0,0])
if partNumber in partCenterOverride.keys():
partCenter = Math.scaleMatrix*mathutils.Vector(partCenterOverride[partNumber])
# Step 2: Calculate angle of face normal to the ground
faceNormal = (faceVertices[1] - faceVertices[0]).cross(faceVertices[2]-faceVertices[0])
faceNormal.normalize()

faceCenter = mathutils.Vector([0,0,0])
for v in faceVertices:
faceCenter += v/len(faceVertices)
# Clamp value to range -1 to 1 (ensure we are in the strict range of the acos function, taking account of rounding errors)
cosine = min(max(faceNormal.y, -1.0), 1.0)

faceNormal = (faceVertices[1] - faceVertices[0]).cross(faceVertices[2]-faceVertices[0])
if faceNormal.dot(faceCenter-partCenter) < 0:
return False
# Calculate angle of face normal to the ground (-90 to 90 degrees)
angleToGroundDegrees = math.degrees(math.acos(cosine)) - 90

# Step 3: does the face make the right angle with the horizontal plane?
slopeCotans = slopeBricks[partNumber]
slopeCotans = {(c,) if type(c) is not tuple else c for c in slopeCotans}
margin = 0.001 # to compensate for rounding errors
# debugPrint("Angle to ground {0}".format(angleToGroundDegrees))

# Step 3: Check angle of normal to ground is within one of the acceptable ranges for this part
partNumber = re.findall(r'\D*\d+', partName)[0]
slopeAngles = globalSlopeAngles[partNumber]

if faceNormal.y == 0:
return False
elif True not in {min(c)-margin <= abs(faceNormal.x/faceNormal.y) <= max(c)+margin for c in slopeCotans}:
if True not in {min(c)-margin <= abs(faceNormal.z/faceNormal.y) <= max(c)+margin for c in slopeCotans}:
return False
if True in { c[0] <= angleToGroundDegrees <= c[1] for c in slopeAngles }:
return True

return True
return False

# **************************************************************************************
def createBlenderObjectsFromNode(node, localMatrix, name, realColourName=Options.defaultColour, blenderParentTransform=Math.identityMatrix, localToWorldSpaceMatrix=Math.identityMatrix, blenderNodeParent=None):
def createBlenderObjectsFromNode(node,
localMatrix,
name,
realColourName=Options.defaultColour,
blenderParentTransform=Math.identityMatrix,
localToWorldSpaceMatrix=Math.identityMatrix,
blenderNodeParent=None):
"""
Creates a Blender Object for the node given and (recursively) for all it's children as required.
Creates and optimises the mesh for each object too.
Expand Down Expand Up @@ -3117,11 +3207,15 @@ def createBlenderObjectsFromNode(node, localMatrix, name, realColourName=Options
assert len(mesh.polygons) == len(geometry.faces)
assert len(geometry.faces) == len(geometry.faceColours)

isSloped = isSlopePart(name)
for i, f in enumerate(mesh.polygons):
if isSlopeFace(name, [geometry.points[j] for j in geometry.faces[i]]):
material = BlenderMaterials.getMaterial(geometry.faceColours[i], True)
else:
material = BlenderMaterials.getMaterial(geometry.faceColours[i], False)
isSlopeMaterial = isSloped and isSlopeFace(name, [geometry.points[j] for j in geometry.faces[i]])
# For debugging purposes, we can make sloped faces blue:
# if isSlopeMaterial:
# faceColor = "1"
# else:
# faceColor = geometry.faceColours[i]
material = BlenderMaterials.getMaterial(geometry.faceColours[i], isSlopeMaterial)

if material is not None:
if mesh.materials.get(material.name) is None:
Expand Down Expand Up @@ -3391,7 +3485,7 @@ def setupRealisticLook():
background = nodes["Background"]
links.new(env_tex.outputs[0],background.inputs[0])
else:
scene.world.horizon_color = (1.0, 1.0, 1.0, 1.0)
scene.world.horizon_color = (1.0, 1.0, 1.0)

if Options.setRenderSettings:
if hasattr(scene.render.layers[0], "cycles"):
Expand Down

5 comments on commit bc21995

@BertVanRaemdonck
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for including the textured slopes feature! I love the way how you've incorporated it more smoothly in the code that I could ever have done, and I dig the way more elegant way you differentiate between exterior and interior faces. Technically, it would fail on a hypothetical part which has slopes in all for quadrants, but I imagine the inside of such a part would be hard to see anyway, so great job!

There's one thing I don't quite agree on though. The condition that doesn't apply a slope texture to faces that are too small. The problem with this is that many parts which have a slope with a pattern on them have small faces too, even though they should be grainy as well. That results in parts with a mess of sections with and without texture (e.g. 3298p10). Because the faces are small, it isn't very noticeable, but still...
That's why in my version I discarded the faces of logos in a different way, namely through their angle. Through a lucky coincidence, none of the faces of the logos has the same exact angle as any of the slopes that do need a grainy material. So as long as you're able to define the angle in the globalSlopeAngles dictionary exactly enough, no slope faces will be selected and tiny faces which do need the texture still get it. I was able to define the angles exactly by using the cotan of the normal instead of the angle in degrees like you did. The angle in degrees always will be an approximation because you often have irrational values, but each cotan is a rational number because of the discrete Lego system. Hence, you can make the margin small (just to account for rounding errors) and have a 'better' detection (and in theory a slightly faster one too, as you don't have to calculate areas or have to do a more expensive trigoniometric calculation).
There's also another way I tried first to get rid of the texture on the logos. I wrote some code to iteratively construct the bounding box of a part as it is read from the .dat file, while preventing the logo files from expanding that bounding box. Afterwards, you can just put as extra condition for a face to be textured that it has to lie inside that bounding box. I managed to get it too work, but in the end deemed it too complicated for what it had to do. Maybe in the future such a method could also be used as a simplified way to detect which parts of pieces are obstructed from view so could be deleted to reduce the amount of polygons in the scene, but that's a big if.

Anyway, I'd like to hear your thoughts on this. Maybe I overlooked something that makes your solution better.

Oh, and because you've smartly removed the need to define a custom offset for the center of some parts, there's no need for the "global globalPartCenterOffset" on line 3122 ;)

@TobyLobster
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. You are right about the small area calculation. However, some parts have not just one or two angles, but a range of angles that need to be sloped, e.g. 22390 has these angles on it's sloped faces:

Part 22390.dat has angle 35.26437222511936
Part 22390.dat has angle 35.264376407738155
Part 22390.dat has angle 36.8769305031079
Part 22390.dat has angle 36.87692623384672
Part 22390.dat has angle 36.183962788801864
Part 22390.dat has angle 37.98603103458218
Part 22390.dat has angle 37.98970117060978
Part 22390.dat has angle 41.4305016785666
Part 22390.dat has angle 41.11161412833911
Part 22390.dat has angle 41.29174742798696
Part 22390.dat has angle 41.30171586227334
Part 22390.dat has angle 41.30172040819056
Part 22390.dat has angle 41.49546007260258
Part 22390.dat has angle 41.291742882764765
Part 22390.dat has angle 41.409925793835754
Part 22390.dat has angle 41.409930347316674
Part 22390.dat has angle 41.515584223234356
Part 22390.dat has angle 43.03532692574822
Part 22390.dat has angle 43.03654639246736
Part 22390.dat has angle 43.03655106480025
Part 22390.dat has angle 44.9866320436922
Part 22390.dat has angle 44.986636872239046
Part 22390.dat has angle 44.999989360079326
Part 22390.dat has angle 45.2823867261005
Part 22390.dat has angle 45.62105363130448
Part 22390.dat has angle 45.94707657411669
Part 22390.dat has angle 45.328976666871796
Part 22390.dat has angle 45.615389768915605
Part 22390.dat has angle 45.947066751065705
Part 22390.dat has angle 45.947071662591014
Part 22390.dat has angle 46.322288149919615
Part 22390.dat has angle 48.69294968222644
Part 22390.dat has angle 49.26737582254765
Part 22390.dat has angle 49.58443359941154
Part 22390.dat has angle 49.58443886696318
Part 22390.dat has angle 49.65175195532677
Part 22390.dat has angle 49.65465319998583
Part 22390.dat has angle 49.92665183049439
Part 22390.dat has angle 49.92665713534973
Part 22390.dat has angle 49.261776165860425
Part 22390.dat has angle 50.700833867421295
Part 22390.dat has angle 51.660736714325395
Part 22390.dat has angle 52.41341019718499
Part 22390.dat has angle 52.41341579607084
Part 22390.dat has angle 52.43917259597478
Part 22390.dat has angle 52.408931316199386
Part 22390.dat has angle 52.408936914516744
Part 22390.dat has angle 52.408992897729235
Part 22390.dat has angle 53.34292465620828

This would become tedious to define precisely for multiple pieces. So a possible alternative approach would be to have a single hardcoded list of the precise angles of the lego logo faces, and exclude just those exact angles (with just a very tiny margin of error to cope with rounding errors). These angles are:

angle 38.941165194148
angle 38.9400938575655
angle 38.94145059391897
angle 38.94172282246328
angle 38.94175794880323
angle 38.94198187962928
angle 38.94203017852763
angle 38.94215751214463
angle 38.94298299079463
angle 38.94352306979337
angle 38.94356697883589
angle 38.94536288197773
angle 38.941990661244716
angle 38.942148730508535
angle 38.942306800124754
angle 38.942315581780434
angle 39.0861822816685
angle 39.0867806528903
angle 39.2989730153777
angle 39.3005705806039
angle 39.3085677811585
angle 39.3328606899523
angle 39.3329445797784
angle 39.3336157020108
angle 39.8284558769989
angle 39.08641107006568
angle 39.08646386749348
angle 39.08668385720145
angle 39.08678505269748
angle 39.8749777052615
angle 39.12907108058735
angle 39.12940566741426
angle 39.12941006988308
angle 39.12993836814232
angle 39.12997358816719
angle 39.12999119818622
angle 39.13000000319735
angle 39.13003962576124
angle 39.13063836944005
angle 39.13064277198595
angle 39.13081006893415
angle 39.17953241119949
angle 39.29739313866108
angle 39.29749463804879
angle 39.29756965942997
angle 39.29868616360409
angle 39.29875677316241
angle 39.29876118626214
angle 39.29878766486655
angle 39.29885827452722
angle 39.29886710073981
angle 39.29889357938427
angle 39.29892888425911
angle 39.29899508094746
angle 39.29907010393657
angle 39.30046025034167
angle 39.30723043730538
angle 39.30728781456975
angle 39.30736726009039
angle 39.30764973378302
angle 39.30819261611239
angle 39.30829413116166
angle 39.30859867719312
angle 39.30878405368722
angle 39.30922984202866
angle 39.30926073835556
angle 39.30974625385565
angle 39.31955438838827
angle 39.31986339786732
angle 39.32054322352627
angle 39.32055646694883
angle 39.32077277653957
angle 39.32084340838753
angle 39.32090962580975
angle 39.32131134618166
angle 39.32375261959234
angle 39.33282978319963
angle 39.33284744419947
angle 39.33290484247979
angle 39.33291367298864
angle 39.33297107132333
angle 39.33298873235887
angle 39.33303288496725
angle 39.33303730022962
angle 39.33304613075521
angle 39.33352298079254
angle 39.33360687141328
angle 39.33419852391256
angle 39.33425150796273
angle 39.33440604500507
angle 39.82994117014508
angle 39.83143538966604
angle 39.83144428392717
angle 39.83145317818946
angle 39.086833450594725
angle 39.87497325530936
angle 39.87498215521393
angle 39.87498660516667
angle 39.89144005470061
angle 39.89294006513387
angle 39.89423980398303
angle 39.89544609051572
angle 39.89573097309116
angle 39.93858813462418
angle 39.93860149688351
angle 39.94157243732448
angle 39.94158134588557
angle 39.129942770644476
angle 39.130013210716186
angle 39.130030820745134
angle 39.130814471490794
angle 39.297424029763505
angle 39.298765599362184
angle 39.306524259442426
angle 39.307181887349174
angle 39.307702697727336
angle 39.308263235261535
angle 39.308272062660166
angle 39.309300462224485
angle 39.321037646337146
angle 39.321514414500285
angle 39.322264889488764
angle 39.332931334009686
angle 39.333006393398875
angle 39.334313322738694
angle 39.874991055119665
angle 39.874995505072974
angle 39.892735314000674
angle 40.0717346102696
angle 40.07038240096841
angle 41.42836545452738
angle 41.42871617305437
angle 41.428966687447854
angle 41.472889975432594
angle 41.472903649136725
angle 41.967381879802645
angle 48.8489961072959
angle 48.84905319460205
angle 48.84909471268375
angle 48.84917255917972
angle 48.84924521601852
angle 48.84968115926526
angle 48.89291548630234
angle 48.89292068061229
angle 48.89313364778616
angle 48.89319597981353
angle 48.89324272888507
angle 48.89325311757358
angle 48.89325831191866
angle 48.89336739328954
angle 48.89337778200397
angle 48.89348166926675
angle 48.89348686363556
angle 48.848975348291646
angle 48.893372587646496
angle 49.04857173818655
angle 49.73057961930101

@TobyLobster
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to bore you with long lists, but a more complete list of angles on the lego logo is in fact:

Angle to ground -90.0
Angle to ground 0.0
Angle to ground 0.06359982644552531
Angle to ground 0.06360064019902723
Angle to ground 13.6265818952687
Angle to ground 13.6548678358497
Angle to ground 13.62796905382352
Angle to ground 13.65428268421644
Angle to ground 13.65445752666949
Angle to ground 13.65525969496231
Angle to ground 13.65613391214535
Angle to ground 13.66137401152119
Angle to ground 13.66253907962377
Angle to ground 13.66320508645029
Angle to ground 13.66332897447127
Angle to ground 13.67968540122203
Angle to ground 13.68059309975476
Angle to ground 13.68062033955185
Angle to ground 13.70089904685237
Angle to ground 13.70142982993545
Angle to ground 13.71457500285291
Angle to ground 13.71526840083449
Angle to ground 13.71529125048599
Angle to ground 13.71607868598845
Angle to ground 13.72047905778551
Angle to ground 13.72052124269571
Angle to ground 13.93803834699925
Angle to ground 13.93804098602152
Angle to ground 13.95874064584956
Angle to ground 13.95874152560259
Angle to ground 13.96635151498134
Angle to ground 13.98648268887726
Angle to ground 13.99056527098881
Angle to ground 13.516727855053503
Angle to ground 13.518266283115707
Angle to ground 13.518800169147951
Angle to ground 13.520305242460509
Angle to ground 13.520308754894756
Angle to ground 13.520744297143224
Angle to ground 13.520749565804323
Angle to ground 13.520806642973767
Angle to ground 13.520810155415404
Angle to ground 13.520837376839893
Angle to ground 13.520841767392525
Angle to ground 13.520861085825032
Angle to ground 13.520861963935644
Angle to ground 13.520928700351192
Angle to ground 13.605220329648972
Angle to ground 13.606312211407825
Angle to ground 13.606430799029951
Angle to ground 13.606711895853067
Angle to ground 13.606817307247795
Angle to ground 13.606951706844157
Angle to ground 13.607043941905403
Angle to ground 13.607575392244271
Angle to ground 13.625546143809984
Angle to ground 13.625547900806083
Angle to ground 13.625576012745242
Angle to ground 13.625576891243398
Angle to ground 13.626582773770593
Angle to ground 13.626586287778196
Angle to ground 13.626612642836847
Angle to ground 13.626906062688363
Angle to ground 13.626907819694551
Angle to ground 13.626949109343926
Angle to ground 13.627278548294058
Angle to ground 13.627603595174918
Angle to ground 13.627969932330558
Angle to ground 13.628139484251903
Angle to ground 13.628140362759595
Angle to ground 13.628627935026572
Angle to ground 13.628629692045564
Angle to ground 13.654271262352154
Angle to ground 13.654326614468829
Angle to ground 13.654343307966883
Angle to ground 13.654678935388986
Angle to ground 13.654689478666526
Angle to ground 13.654710565223027
Angle to ground 13.654833570173494
Angle to ground 13.655197313759558
Angle to ground 13.655202585409853
Angle to ground 13.655206099843454
Angle to ground 13.655211371493948
Angle to ground 13.655373035499693
Angle to ground 13.656128640474236
Angle to ground 13.656285912046599
Angle to ground 13.656723461442184
Angle to ground 13.658452580250682
Angle to ground 13.659414671663654
Angle to ground 13.661056825802746
Angle to ground 13.661848472949373
Angle to ground 13.662374774798977
Angle to ground 13.662377410704352
Angle to ground 13.663033752060514
Angle to ground 13.663039902523636
Angle to ground 13.663050446175063
Angle to ground 13.663053082087998
Angle to ground 13.663068018928513
Angle to ground 13.663350061800458
Angle to ground 13.680286432579194
Angle to ground 13.680431418443348
Angle to ground 13.680535984061407
Angle to ground 13.680608037707614
Angle to ground 13.680672183045345
Angle to ground 13.699442914648742
Angle to ground 13.700790078288264
Angle to ground 13.700805017523905
Angle to ground 13.700820835539147
Angle to ground 13.700882350052979
Angle to ground 13.701428951154512
Angle to ground 13.712519428221412
Angle to ground 13.713907971746167
Angle to ground 13.714090767961082
Angle to ground 13.714190075579822
Angle to ground 13.714203258010244
Angle to ground 13.714466027944425
Angle to ground 13.714480968049841
Angle to ground 13.715475805444896
Angle to ground 13.715563688809667
Angle to ground 13.715573355981789
Angle to ground 13.716156902382338
Angle to ground 13.717309938089286
Angle to ground 13.718043770928418
Angle to ground 13.718058711261563
Angle to ground 13.720293620041062
Angle to ground 13.720332289511234
Angle to ground 13.720370958987772
Angle to ground 13.720498392535092
Angle to ground 13.720979125229604
Angle to ground 13.721081951180594
Angle to ground 13.721082830035073
Angle to ground 13.721109195670891
Angle to ground 13.721117105362211
Angle to ground 13.721218173663686
Angle to ground 13.721219052518677
Angle to ground 13.721224325648663
Angle to ground 13.721248933590175
Angle to ground 13.721255085575947
Angle to ground 13.721386913881418
Angle to ground 13.722432754395982
Angle to ground 13.722598858906665
Angle to ground 13.724495446788922
Angle to ground 13.724680008986226
Angle to ground 13.767710697773381
Angle to ground 13.768393704641454
Angle to ground 13.933998918948603
Angle to ground 13.938045384392026
Angle to ground 13.947016475296877
Angle to ground 13.948029021777202
Angle to ground 13.958658828832299
Angle to ground 13.958659708585017
Angle to ground 13.958660588337736
Angle to ground 13.958661468090455
Angle to ground 13.958742405355622
Angle to ground 13.964221572396255
Angle to ground 13.966765892716609
Angle to ground 13.968270327702655
Angle to ground 13.968279125596965
Angle to ground 13.968387339724487
Angle to ground 13.986505565213065
Angle to ground 13.990545033872877
Angle to ground 14.15457014009985
Angle to ground 14.156541602061608
Angle to ground 18.791435225868
Angle to ground 18.7931794017195
Angle to ground 18.79143161849096
Angle to ground 18.79281144584793
Angle to ground 18.79281324955123
Angle to ground 18.79317399059792
Angle to ground 18.79321367216025
Angle to ground 18.79418767707658
Angle to ground 18.83792811419376
Angle to ground 18.765348694580865
Angle to ground 18.765898735327724
Angle to ground 18.765914966065537
Angle to ground 18.765940213883013
Angle to ground 18.765965461704283
Angle to ground 18.766223350380827
Angle to ground 18.767727408282155
Angle to ground 18.791433422179466
Angle to ground 18.791437029556548
Angle to ground 18.792806034738177
Angle to ground 18.792809642144647
Angle to ground 18.793013460736702
Angle to ground 18.793076590439142
Angle to ground 18.793082001557593
Angle to ground 18.793114468271966
Angle to ground 18.793181205426734
Angle to ground 18.793210064745097
Angle to ground 18.793599666027134
Angle to ground 18.837457221973594
Angle to ground 19.369958278092668
Angle to ground 19.371312163149398
Angle to ground 21.02044631736456
Angle to ground 21.05094355923913
Angle to ground 21.05100027858377
Angle to ground 21.05219687882702
Angle to ground 21.05339348868945
Angle to ground 21.021370107349796
Angle to ground 21.021792674577696
Angle to ground 21.022650617785374
Angle to ground 21.050941729583215
Angle to ground 21.050998448927146
Angle to ground 21.052198708498366
Angle to ground 21.053395318375507
Angle to ground 21.388106601247358
Angle to ground 38.941165194148
Angle to ground 38.9400938575655
Angle to ground 38.94145059391897
Angle to ground 38.94172282246328
Angle to ground 38.94175794880323
Angle to ground 38.94198187962928
Angle to ground 38.94203017852763
Angle to ground 38.94215751214463
Angle to ground 38.94298299079463
Angle to ground 38.94352306979337
Angle to ground 38.94356697883589
Angle to ground 38.94536288197773
Angle to ground 38.941990661244716
Angle to ground 38.942148730508535
Angle to ground 38.942306800124754
Angle to ground 38.942315581780434
Angle to ground 39.0861822816685
Angle to ground 39.0867806528903
Angle to ground 39.2989730153777
Angle to ground 39.3005705806039
Angle to ground 39.3085677811585
Angle to ground 39.3328606899523
Angle to ground 39.3329445797784
Angle to ground 39.3336157020108
Angle to ground 39.8284558769989
Angle to ground 39.08641107006568
Angle to ground 39.08646386749348
Angle to ground 39.08668385720145
Angle to ground 39.08678505269748
Angle to ground 39.8749777052615
Angle to ground 39.12907108058735
Angle to ground 39.12940566741426
Angle to ground 39.12941006988308
Angle to ground 39.12993836814232
Angle to ground 39.12997358816719
Angle to ground 39.12999119818622
Angle to ground 39.13000000319735
Angle to ground 39.13003962576124
Angle to ground 39.13063836944005
Angle to ground 39.13064277198595
Angle to ground 39.13081006893415
Angle to ground 39.17953241119949
Angle to ground 39.29739313866108
Angle to ground 39.29749463804879
Angle to ground 39.29756965942997
Angle to ground 39.29868616360409
Angle to ground 39.29875677316241
Angle to ground 39.29876118626214
Angle to ground 39.29878766486655
Angle to ground 39.29885827452722
Angle to ground 39.29886710073981
Angle to ground 39.29889357938427
Angle to ground 39.29892888425911
Angle to ground 39.29899508094746
Angle to ground 39.29907010393657
Angle to ground 39.30046025034167
Angle to ground 39.30723043730538
Angle to ground 39.30728781456975
Angle to ground 39.30736726009039
Angle to ground 39.30764973378302
Angle to ground 39.30819261611239
Angle to ground 39.30829413116166
Angle to ground 39.30859867719312
Angle to ground 39.30878405368722
Angle to ground 39.30922984202866
Angle to ground 39.30926073835556
Angle to ground 39.30974625385565
Angle to ground 39.31955438838827
Angle to ground 39.31986339786732
Angle to ground 39.32054322352627
Angle to ground 39.32055646694883
Angle to ground 39.32077277653957
Angle to ground 39.32084340838753
Angle to ground 39.32090962580975
Angle to ground 39.32131134618166
Angle to ground 39.32375261959234
Angle to ground 39.33282978319963
Angle to ground 39.33284744419947
Angle to ground 39.33290484247979
Angle to ground 39.33291367298864
Angle to ground 39.33297107132333
Angle to ground 39.33298873235887
Angle to ground 39.33303288496725
Angle to ground 39.33303730022962
Angle to ground 39.33304613075521
Angle to ground 39.33352298079254
Angle to ground 39.33360687141328
Angle to ground 39.33419852391256
Angle to ground 39.33425150796273
Angle to ground 39.33440604500507
Angle to ground 39.82994117014508
Angle to ground 39.83143538966604
Angle to ground 39.83144428392717
Angle to ground 39.83145317818946
Angle to ground 39.086833450594725
Angle to ground 39.87497325530936
Angle to ground 39.87498215521393
Angle to ground 39.87498660516667
Angle to ground 39.89144005470061
Angle to ground 39.89294006513387
Angle to ground 39.89423980398303
Angle to ground 39.89544609051572
Angle to ground 39.89573097309116
Angle to ground 39.93858813462418
Angle to ground 39.93860149688351
Angle to ground 39.94157243732448
Angle to ground 39.94158134588557
Angle to ground 39.129942770644476
Angle to ground 39.130013210716186
Angle to ground 39.130030820745134
Angle to ground 39.130814471490794
Angle to ground 39.297424029763505
Angle to ground 39.298765599362184
Angle to ground 39.306524259442426
Angle to ground 39.307181887349174
Angle to ground 39.307702697727336
Angle to ground 39.308263235261535
Angle to ground 39.308272062660166
Angle to ground 39.309300462224485
Angle to ground 39.321037646337146
Angle to ground 39.321514414500285
Angle to ground 39.322264889488764
Angle to ground 39.332931334009686
Angle to ground 39.333006393398875
Angle to ground 39.334313322738694
Angle to ground 39.874991055119665
Angle to ground 39.874995505072974
Angle to ground 39.892735314000674
Angle to ground 40.0717346102696
Angle to ground 40.07038240096841
Angle to ground 41.42836545452738
Angle to ground 41.42871617305437
Angle to ground 41.428966687447854
Angle to ground 41.472889975432594
Angle to ground 41.472903649136725
Angle to ground 41.967381879802645
Angle to ground 48.8489961072959
Angle to ground 48.84905319460205
Angle to ground 48.84909471268375
Angle to ground 48.84917255917972
Angle to ground 48.84924521601852
Angle to ground 48.84968115926526
Angle to ground 48.89291548630234
Angle to ground 48.89292068061229
Angle to ground 48.89313364778616
Angle to ground 48.89319597981353
Angle to ground 48.89324272888507
Angle to ground 48.89325311757358
Angle to ground 48.89325831191866
Angle to ground 48.89336739328954
Angle to ground 48.89337778200397
Angle to ground 48.89348166926675
Angle to ground 48.89348686363556
Angle to ground 48.848975348291646
Angle to ground 48.893372587646496
Angle to ground 49.04857173818655
Angle to ground 49.73057961930101
Angle to ground 60.43883646556236
Angle to ground 60.43890568785258
Angle to ground 60.43908566649728
Angle to ground 60.43955638458834
Angle to ground 60.43964637558804
Angle to ground 60.47720823053032
Angle to ground 60.47741614338949
Angle to ground 60.47785276473047
Angle to ground 60.47789434802175
Angle to ground 60.47790127857547
Angle to ground 60.47792207024557
Angle to ground 60.47799830648313
Angle to ground 60.47818543255303
Angle to ground 60.439694832383395
Angle to ground 60.440144791790914
Angle to ground 60.477423073841095
Angle to ground 60.477963653625665
Angle to ground 60.477977514764234
Angle to ground 60.478954739957175
Angle to ground 60.569263768727694
Angle to ground 61.0725200955697
Angle to ground 61.3713904313351
Angle to ground 61.3783407075357
Angle to ground 61.3809643929101
Angle to ground 61.3901490262229
Angle to ground 61.3902916660349
Angle to ground 61.07006319796136
Angle to ground 61.07022557324234
Angle to ground 61.07072682392709
Angle to ground 61.07074094377958
Angle to ground 61.07076212357012
Angle to ground 61.07077624343836
Angle to ground 61.07086802273534
Angle to ground 61.07129868298907
Angle to ground 61.07153166556765
Angle to ground 61.07235064823524
Angle to ground 61.24270789734885
Angle to ground 61.24363781562678
Angle to ground 61.37005758052209
Angle to ground 61.37087724140983
Angle to ground 61.37103404854918
Angle to ground 61.37104117616508
Angle to ground 61.37114096295855
Angle to ground 61.37126213306436
Angle to ground 61.37128351607291
Angle to ground 61.37152585785856
Angle to ground 61.37163277394916
Angle to ground 61.37167554048776
Angle to ground 61.37206044196665
Angle to ground 61.37739965664656
Angle to ground 61.37793434117722
Angle to ground 61.37794147036607
Angle to ground 61.37824089776538
Angle to ground 61.37829080261071
Angle to ground 61.37908929096915
Angle to ground 61.37966678186416
Angle to ground 61.37973094817761
Angle to ground 61.37983789232598
Angle to ground 61.37985215157343
Angle to ground 61.37987354045674
Angle to ground 61.37990205899061
Angle to ground 61.37999474440534
Angle to ground 61.38006604106519
Angle to ground 61.38031558065501
Angle to ground 61.38041539704864
Angle to ground 61.38045104583787
Angle to ground 61.38048669466775
Angle to ground 61.38117829001132
Angle to ground 61.38999925512093
Angle to ground 61.39013476227751
Angle to ground 61.39017755413323
Angle to ground 61.39022747803892
Angle to ground 61.39026313802043
Angle to ground 61.39029879804261
Angle to ground 61.39031306206286
Angle to ground 61.39042004242236
Angle to ground 61.39059121175933
Angle to ground 61.39086936393153
Angle to ground 61.39108332882557
Angle to ground 61.39188927641172
Angle to ground 61.071072762125624
Angle to ground 61.071446944431614
Angle to ground 61.071623447054094
Angle to ground 61.071778770175655
Angle to ground 61.83171822415704
Angle to ground 61.83255019225666
Angle to ground 61.83256466146668
Angle to ground 61.86878802017878
Angle to ground 61.86880250650239
Angle to ground 61.86882423600065
Angle to ground 61.88382126632692
Angle to ground 61.88484307042958
Angle to ground 61.92332687180809
Angle to ground 61.92333412789094
Angle to ground 61.370520864471445
Angle to ground 61.370642032174885
Angle to ground 61.371019793322205
Angle to ground 61.371112452413655
Angle to ground 61.371247877733424
Angle to ground 61.371475963807995
Angle to ground 61.371917885311035
Angle to ground 61.372067569816465
Angle to ground 61.377820274376774
Angle to ground 61.377848791037906
Angle to ground 61.377877307725015
Angle to ground 61.377898695257414
Angle to ground 61.379631133969156
Angle to ground 61.380023263049765
Angle to ground 61.380622160592054
Angle to ground 61.381021431994014
Angle to ground 61.390056310694206
Angle to ground 61.390712457273594
Angle to ground 61.390919288942456
Angle to ground 61.831710989750775
Angle to ground 61.868795263339706
Angle to ground 61.868831479170154
Angle to ground 61.868838722341366
Angle to ground 61.883995188020975
Angle to ground 61.884872058277494
Angle to ground 61.923312359647554
Angle to ground 72.2249352748353
Angle to ground 72.2505483680479
Angle to ground 72.2507724164241
Angle to ground 72.22478984794199
Angle to ground 72.22483459455577
Angle to ground 72.22508070287998
Angle to ground 72.25055957040169
Angle to ground 72.25076121394028
Angle to ground 72.25096285969593
Angle to ground 72.25097406230293
Angle to ground 72.53758186013874
Angle to ground 72.53777533150449
Angle to ground 77.3021320762511
Angle to ground 77.30186795705848
Angle to ground 77.30200778419322
Angle to ground 77.30210100312445
Angle to ground 77.32082057497871
Angle to ground 77.32097616698101
Angle to ground 77.32099172628455
Angle to ground 77.32116287986292
Angle to ground 77.32117843939184
Angle to ground 77.53249810511846
Angle to ground 77.53268793435831
Angle to ground 80.967211887948
Angle to ground 80.6617117293226
Angle to ground 80.8058258896094
Angle to ground 80.8066167473136
Angle to ground 80.8073221637969
Angle to ground 80.8078138494476
Angle to ground 80.8078993626572
Angle to ground 80.8081559070182
Angle to ground 80.9474171039846
Angle to ground 80.9610798196573
Angle to ground 80.9814054091627
Angle to ground 80.66110139684943
Angle to ground 80.66116453285815
Angle to ground 80.66120662376568
Angle to ground 80.66122766928993
Angle to ground 80.66135394342268
Angle to ground 80.66139603517635
Angle to ground 80.66143812711806
Angle to ground 80.66150126538315
Angle to ground 80.66154335779493
Angle to ground 80.66173277597514
Angle to ground 80.66177486942121
Angle to ground 80.66179591621477
Angle to ground 80.80494961254084
Angle to ground 80.80516333102113
Angle to ground 80.80518470314004
Angle to ground 80.80520607530818
Angle to ground 80.80522744752557
Angle to ground 80.80527019210811
Angle to ground 80.80529156447324
Angle to ground 80.80533430935128
Angle to ground 80.80535568186417
Angle to ground 80.80544117240831
Angle to ground 80.80554803669668
Angle to ground 80.80685188017875
Angle to ground 80.80693738451711
Angle to ground 80.80695876072488
Angle to ground 80.80704426604876
Angle to ground 80.80706564250295
Angle to ground 80.80708701900639
Angle to ground 80.80712977216112
Angle to ground 80.80719390226284
Angle to ground 80.80721527906198
Angle to ground 80.80760006987401
Angle to ground 80.80777109313857
Angle to ground 80.80779247126844
Angle to ground 80.80783522767607
Angle to ground 80.80785660595382
Angle to ground 80.80787798428085
Angle to ground 80.80796349808196
Angle to ground 80.80798487665547
Angle to ground 80.80800625527829
Angle to ground 80.80802763395039
Angle to ground 80.80807039144247
Angle to ground 80.80811314913177
Angle to ground 80.80813452805032
Angle to ground 80.80817728603537
Angle to ground 80.80819866510186
Angle to ground 80.80828418186073
Angle to ground 80.80830556117368
Angle to ground 80.80854073687019
Angle to ground 80.94685278951835
Angle to ground 80.94711323801431
Angle to ground 80.94737369394099
Angle to ground 80.96105808207491
Angle to ground 80.96110155729153
Angle to ground 80.96679860471306
Angle to ground 80.96686385871402
Angle to ground 80.96695086477587
Angle to ground 80.96708137542691
Angle to ground 80.96714663145369
Angle to ground 80.98088255557013

@BertVanRaemdonck
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized today that using the cotan instead of the angles would break the detection of outward and inward facing angles as you can only distinguish two quadrants instead of four, so it wouldn't be an easy fix. And yeah, those Nexoknight slopes are really complicating things. I did it with providing a range of values for them so I could keep the margins small for all other parts with more precise angles.
Hardcoding the angles of the faces of the logos seems like a tedious method that could in the future interfere with parts which happen to have those exact angles. Maybe a better way to exclude the logo faces would be to look at the appendGeometry function in the LDrawGeometry class. It could possible to either create a new list of attributes like self.faceColours that just holds isStudLogo or to make self.faceColours contain more information (e.g. a certain suffix that indicates that a face can possibly be a textured slope). By passing that extra attribute to the isSlopeFace function, it can be used to replace the face size condition.

@TobyLobster
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spot on, thanks. Latest release has this fix.

Please sign in to comment.