Hi guys,
Iβm having difficulties computing the normal of a polygon (more than 3 vertices) based on the Newellβs method.
ππ₯=βπ=0π(π¦πβπ¦π+1)(π§π+π§π+1)
ππ¦=βπ=0π(π§πβπ§π+1)(π₯π+π₯π+1)
ππ§=βπ=0π(π₯πβπ₯π+1)(π¦π+π¦π+1)
It seems pretty straightforward and Iβve seen various implementations (in Java (line 123), in C++ or in Python) and yet mine gives me very strange results:
def computePolyNormal(face):
#Calculate normal with Newell's method
nml = PVector()
for i in range(face.getVertexCount() - 1):
p0 = face.getVertex(i) #current vertex
p1 = face.getVertex(i+1) #next vertex
nml.x += (p0.y - p1.y) * (p0.z + p1.z)
nml.y += (p0.z - p1.z) * (p0.x + p1.x)
nml.z += (p0.x - p1.x) * (p0.y + p1.y)
nml.normalize()
(Normals pointing towards strange directions)
Can someone help me find whatβs wrong with this code ?
Please note that for the sake of clarity and simplicity Iβm showing triangle faces but ideally the Newellβs formula should work for more complex polygons.
add_library('peasycam')
def setup():
global tetrahedron, centroid
hint(DISABLE_DEPTH_TEST)
size(1000, 600, P3D)
fill(55, 180, 220)
smooth(8)
cam = PeasyCam(this, 100)
tetrahedron = createShape(GROUP)
#First face
f1 = createShape()
f1.beginShape(TRIANGLES)
f1.vertex(10, 10, 0)
f1.vertex(40, 30, 0)
f1.vertex(2, 35, 0)
f1.endShape()
#Second face
f2 = createShape()
f2.beginShape(TRIANGLES)
f2.vertex(10, 10, 0)
f2.vertex(40, 30, 0)
f2.vertex(17, 25, 40)
f2.endShape()
#Third face
f3 = createShape()
f3.beginShape(TRIANGLES)
f3.vertex(40, 30, 0)
f3.vertex(2, 35, 0)
f3.vertex(17, 25, 40)
f3.endShape()
#Fourth face
f4 = createShape()
f4.beginShape(TRIANGLES)
f4.vertex(10, 10, 0)
f4.vertex(2, 35, 0)
f4.vertex(17, 25, 40)
f4.endShape()
tetrahedron.addChild(f1)
tetrahedron.addChild(f2)
tetrahedron.addChild(f3)
tetrahedron.addChild(f4)
#Compute centroid
centroid = PVector()
count = 0
for i in range(tetrahedron.getChildCount()):
face = tetrahedron.getChild(i)
for v in range(face.getVertexCount()):
vert = face.getVertex(v)
centroid.x += vert.x
centroid.y += vert.y
centroid.z += vert.z
count += 1
centroid.div(count)
def draw():
background(255)
strokeWeight(2)
#Rotate
rotateX(HALF_PI)
rotate(frameCount*.004)
#Tanslate to the center of the screen
pushMatrix()
translate(-centroid.x, -centroid.y, -centroid.z)
#Display Tetrahedron
shape(tetrahedron)
#Display normals
for i in range(tetrahedron.getChildCount()):
face = tetrahedron.getChild(i)
computePolyNormal(face)
#computeTriangleNormal(face) #Work but only for triangle faces
popMatrix()
def computePolyNormal(face):
#Calculate normal with Newell's method
nml = PVector()
for i in range(face.getVertexCount() - 1):
p0 = face.getVertex(i) #current vertex
p1 = face.getVertex(i+1) #next vertex
nml.x += (p0.y - p1.y) * (p0.z + p1.z)
nml.y += (p0.z - p1.z) * (p0.x + p1.x)
nml.z += (p0.x - p1.x) * (p0.y + p1.y)
#Normalizing then scaling-up to see a line
nml.normalize().mult(10)
#Center of the polygon
center = PVector()
for i in range(face.getVertexCount()):
center.x += face.getVertex(i).x
center.y += face.getVertex(i).y
center.z += face.getVertex(i).z
center.div(face.getVertexCount())
#line
stroke(30, 255, 100)
line(center.x, center.y, center.z, center.x + nml.x, center.y + nml.y, center.z + nml.z)
def computeTriangleNormal(face):
#Vertices of the face
v1 = face.getVertex(0)
v2 = face.getVertex(1)
v3 = face.getVertex(2)
#Center of the face
center = PVector((v1.x + v2.x + v3.x) / 3, (v1.y + v2.y + v3.y) / 3, (v1.z + v2.z + v3.z) / 3)
#Normal
a = v2.sub(v1)
b = v3.sub(v1)
nml = a.cross(b).normalize().mult(10)
#Check if normal is heading inwards or outwards
d = PVector.dot(center - centroid, nml)
if d < 0:
#If inwards -> reverse
nml.mult(-1)
stroke(30, 255, 100)
else:
stroke(255, 50, 100)
#line
line(center.x, center.y, center.z, center.x + nml.x, center.y + nml.y, center.z + nml.z)