Copying attributes

R

red

Hi,

I'm writing a script for Blender and need to build a face array. My
engine needs that all faces must be triangles, so I convert quads to
triangles by dividing them into two triangles. Here is the function:

def build_face_table(mesh):
face_table = {}
i = 0
for f in mesh.faces:
if len(f.v) == 3: # triangle
face_table = f
i += 1
elif len(f.v) == 4: # quad
f1 = NMesh.Face()
f2 = NMesh.Face()

f1.mat = f.mat
## f1.normal = copy.deepcopy(f.normal)
f1.normal = NMesh.Vert(f.normal[0], f.normal[1], f.normal[2])
f1.v.append(f.v[0])
f1.v.append(f.v[1])
f1.v.append(f.v[2])

f2.mat = f.mat
f2.v.append(f.v[2])
f2.v.append(f.v[3])
f2.v.append(f.v[0])

face_table = f1
i += 1
face_table = f2
i += 1
else:
message = "Can't build face from 2 vertices."
Draw.PupMenu("Face Table Error%t|"+message)
return
return face_table

Everything seems be ok, but i'm getting:

Traceback (most recent call last):
File "<string>", line 169, in write
File "<string>", line 102, in build_face_table
AttributeError: normal

I was wondering why? Though the face has an attribute called "normal"!
Just simply test:

nv = f.normal

and it works! But why my new faces (f1 and f2) no?

Greetings.
 
T

Terry Hancock

Everything seems be ok, but i'm getting:

Traceback (most recent call last):
File "<string>", line 169, in write
File "<string>", line 102, in build_face_table
AttributeError: normal

I was wondering why?

I'm not sure either, yet, but can you indicate which line in your
listing is 102 in the source file? That might be helpful.

Cheers,
Terry
 
R

red

Terry said:
I'm not sure either, yet, but can you indicate which line in your
listing is 102 in the source file? That might be helpful.

Yeah, right.

101: ## f1.normal = copy.deepcopy(f.normal)
102: f1.normal = NMesh.Vert(f.normal[0], f.normal[1], f.normal[2])

I've tried with deepcopy, but the result is exactly the same.
 
R

red

Terry said:
I'm not sure either, yet, but can you indicate which line in your
listing is 102 in the source file? That might be helpful.

101: ## f1.normal = copy.deepcopy(f.normal)
102: f1.normal = NMesh.Vert(f.normal[0], f.normal[1], f.normal[2])

I've tried with deepcopy, but the result is exactly same.
 
T

Terry Hancock

Terry said:
I'm not sure either, yet, but can you indicate which line in your
listing is 102 in the source file? That might be helpful.

101: ## f1.normal = copy.deepcopy(f.normal)
102: f1.normal = NMesh.Vert(f.normal[0], f.normal[1], f.normal[2])

I've tried with deepcopy, but the result is exactly same.

Okay, well you do realize that the traceback means that it is not
*your copy* that lacks the normal attribute, but the object you
are passing it (f). This is the loop variable, which is looping through
mesh.faces. "mesh" was passed into the function. So the question
is, is "mesh" what you think it is? It clearly has an attribute called
"faces", because you didn't get an error there. But is "faces" a list,
dictionary, or tuple (or something more obscure)? And whatever it
is that you are iterating over, the elements of it don't appear to have
a "normal" attribute, so they probably aren't what you thought they
were.

Without knowing the Blender API, I probably can't help more than
that (we'd also have to see where the "mesh" variable came from,
I think).

Anyway, the trace back had to occur on the first reference to f.normal:
"f.normal[0]". So that's what you should be checking into. The deepcopy
has nothing to do with it.

Cheers,
Terry
 
T

Terry Hancock

But is "faces" a list,
dictionary, or tuple (or something more obscure)?

Lest it be unclear why this matters:
.... print d
....
a
c
b
.... print d
....
1
2
3

As you can see, looping through a dictionary
gives you its keys, not its values. It is possible to
define even more bizarre behavior for user-defined
collection classes, and "mesh" is probably a C
extension type.

<sigh>

I've been wanting to learn the Blender API, too. But
I haven't done so yet, so I'm not really sure what "mesh"
will be.
 
B

Bengt Richter

Hi,

I'm writing a script for Blender and need to build a face array. My
engine needs that all faces must be triangles, so I convert quads to
triangles by dividing them into two triangles. Here is the function:

def build_face_table(mesh):
face_table = {}
# face_table = [] ??
Irrelevant nit: Why a dict? You seem to be building it with all the keys as integers of xrange(last_i),
in which case appending a face_table list to build it and later accessing face_table[key]
will go faster than your current dict. OTOH, if you will be deleting various elements later,
your dict may be best.
i = 0
for f in mesh.faces:
if len(f.v) == 3: # triangle
face_table = f

# face_table.append(f) # no need for i counting
i += 1
elif len(f.v) == 4: # quad
f1 = NMesh.Face()
f2 = NMesh.Face()

f1.mat = f.mat
## f1.normal = copy.deepcopy(f.normal)
f1.normal = NMesh.Vert(f.normal[0], f.normal[1], f.normal[2])
f is a quad at this point, right? So unless the quad is restricted to a plane, it couldn't
have a normal in general. Could that be it? BTW, if it is not a plane, one choice of diagonal
may be better than the other in getting two triangles that fit the underlying 3D surface best.

If there is a normal, why wouldn't ft.normal = f.normal[::] work?
Is normal more than a 3-tuple or list to record unit vector components in some coordinate system?
f1.v.append(f.v[0])
f1.v.append(f.v[1])
f1.v.append(f.v[2])
Why append, and is there restricted property magic behind f1.v so that plain old
f1.v = f.v[:3]
wouldn't work?
# or f1.v = [f.v[0], f.v[1], f.v[2]] if you want to be consistent with f2 below
f2.mat = f.mat
# f2.normal = ?? # could this face be picked up later indirectly and cause the missing normal exception?
f2.v.append(f.v[2])
f2.v.append(f.v[3])
f2.v.append(f.v[0])
Why appends? Does f2.v ever grow beyond 3 items? E.g.,
f2.v = [f.v[2], f.v[3], f.v[0]] # are quad vertices listed clockwise or ccw and
# are triangles in a sequence totally independent, or
# is there some systematic vertex sharing in the order
# that something might depend on, or benefit optimization-wise from?
face_table = f1

#face_table.append(f1) ??
i += 1
face_table = f2

#face_table.append(f2) ??
i += 1
else:
message = "Can't build face from 2 vertices."
Why is len(f.v)>4 not just a 3D surface point cluster, in which case it might
be possible to find an internal point to slice radiating triangles from. E.g.,
imagine an almost-plane small pentagon on a large sphere, and slice from its "center"
to each peripheral pair of vertices to make triangles.
Draw.PupMenu("Face Table Error%t|"+message)
return
return face_table
# do you need it as a dict? Unless you modify it, a list will get you
# the same elements as your dict by writing face_table[some_index]

If you need to iterate and have both index key and value, you can use your dict like
for i, face in sorted(face_table.items()): # leave out sorted call if order does not matter
# ...
or use the more efficient list version of face_table like
for i, face in enumerate(facetable): # will naturally be in sort order
# ...
Everything seems be ok, but i'm getting:

Traceback (most recent call last):
File "<string>", line 169, in write
File "<string>", line 102, in build_face_table
AttributeError: normal

I was wondering why? Though the face has an attribute called "normal"!
Just simply test:

nv = f.normal

and it works! But why my new faces (f1 and f2) no?
Did it work on a quad face? What about putting in a debug print before places you use
f.normal, e.g.
assert hasattr(f, 'normal'), 'This "f"\n----\n%r\n----\ndid not have a normal attribute!!' % f

If f.repr doesn't give you enough info, you can format something better in the assert message string.
Greetings.

BTW, I don't know Blender at all, just reading between the lines ;-)
Hope I triggered a useful thought.

Regards,
Bengt Richter
 
B

Bengt Richter

]
Did it work on a quad face? What about putting in a debug print before places you use
f.normal, e.g.
assert hasattr(f, 'normal'), 'This "f"\n----\n%r\n----\ndid not have a normal attribute!!' % f

If f.repr doesn't give you enough info, you can format something better in the assert message string.
f.__repr__ was what I meant (as called due to %r in format), sorry.

Regards,
Bengt Richter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top