# 问field的元素交换问题。

``````P = Point2.field(shape=(7))

P[0], P[1] = P[1], P[0]

temp = P[0]
P[0] = P[1]
P[1] = temp
``````

``````P[0].x, P[0].y, P[1].x, P[1].y = P[1].x, P[1].y, P[0].x, P[0].y
``````

``````import taichi as ti

ti.init(ti.cpu)

Color = ti.types.vector(3, ti.f32)
Point = ti.types.vector(2, ti.i32)
Point2 = ti.types.struct(
x=ti.i32, y=ti.i32, c=Color,
)

width = 1024
height = 1024
pixels = Color.field(shape=(width, height))
center = Point([width // 2, height // 2])

@ti.data_oriented
class Triangle:
LEFT = True
RIGHT = False

def __init__(self, P):
self.P = P
self.nTotalScanLine = 0
self.SpanLeft = None
self.SpanRight = None

def SortPoint(self):
if self.P[0].y > self.P[1].y:
self.P[0].x, self.P[0].y, self.P[1].x, self.P[1].y = self.P[1].x, self.P[1].y, self.P[0].x, self.P[0].y
self.P[0].c.x, self.P[0].c.y, self.P[0].c.z, self.P[1].c.x, self.P[1].c.y, self.P[1].c.z = self.P[
1].c.x, self.P[1].c.y, self.P[1].c.z, self.P[0].c.x, self.P[0].c.y, self.P[0].c.z
if self.P[0].y > self.P[2].y:
self.P[0].x, self.P[0].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[0].x, self.P[0].y
self.P[0].c.x, self.P[0].c.y, self.P[0].c.z, self.P[2].c.x, self.P[2].c.y, self.P[2].c.z = self.P[
2].c.x, self.P[2].c.y, self.P[2].c.z, self.P[0].c.x, self.P[0].c.y, self.P[0].c.z
if self.P[1].y > self.P[2].y:
self.P[1].x, self.P[1].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[1].x, self.P[1].y
self.P[1].c.x, self.P[1].c.y, self.P[1].c.z, self.P[2].c.x, self.P[2].c.y, self.P[2].c.z = self.P[
2].c.x, self.P[2].c.y, self.P[2].c.z, self.P[1].c.x, self.P[1].c.y, self.P[1].c.z

def SortPoint2(self):
if self.P[0].y > self.P[1].y:
self.P[0], self.P[1] = self.P[1], self.P[0]
if self.P[0].y > self.P[2].y:
self.P[0], self.P[2] = self.P[2], self.P[0]
if self.P[1].y > self.P[2].y:
self.P[1], self.P[2] = self.P[2], self.P[1]

def Interp(self, m, m0, m1, c0, c1):
color = (m1 - m) / (m1 - m0) * c0 + (m - m0) / (m1 - m0) * c1
return color

def EdgeFlag(self, PStart, PEnd, bFeature):
dx = PEnd.x - PStart.x
dy = PEnd.y - PStart.y
m = dx / dy
x = PStart.x
for y in range(PStart.y, PEnd.y):
color = self.Interp(y, PStart.y, PEnd.y, PStart.c, PEnd.c)
if bFeature:
self.SpanLeft[self.nIndex].x = ti.round(x)
self.SpanLeft[self.nIndex].y = y
self.SpanLeft[self.nIndex].c = color
self.nIndex += 1
else:
self.SpanRight[self.nIndex].x = ti.round(x)
self.SpanRight[self.nIndex].y = y
self.SpanRight[self.nIndex].c = color
self.nIndex += 1
x += m

def Fill(self):
print("before: ", self.P)
self.SortPoint()
# self.SortPoint2()
print("after: ", self.P)
nTotalScanLine = self.P[2].y - self.P[0].y + 1
self.SpanLeft = Point2.field(shape=(nTotalScanLine))
self.SpanRight = Point2.field(shape=(nTotalScanLine))
nDeltz = (self.P[2].x - self.P[0].x) * (self.P[1].y - self.P[0].y) - \
(self.P[2].y - self.P[0].y) * (self.P[1].x - self.P[0].x)
if nDeltz > 0:
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[1], Triangle.LEFT)
self.EdgeFlag(self.P[1], self.P[2], Triangle.LEFT)
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[2], Triangle.RIGHT)
else:
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[2], Triangle.LEFT)
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[1], Triangle.RIGHT)
self.EdgeFlag(self.P[1], self.P[2], Triangle.RIGHT)
for y in range(self.P[0].y, self.P[2].y):
n = y - self.P[0].y
for x in range(self.SpanLeft[n].x, self.SpanRight[n].x):
color = self.Interp(
x, self.SpanLeft[n].x, self.SpanRight[n].x, self.SpanLeft[n].c, self.SpanRight[n].c)
pixels[x, y] = color

pixels.fill(Color([1.0, 1.0, 1.0]))
P = Point2.field(shape=(3))
P[0].x = -300 + center.x
P[0].y = -300 + center.y
P[0].c = Color([1.0, 0.0, 0.0])
P[1].x = 100 + center.x
P[1].y = 300 + center.y
P[1].c = Color([0.0, 1.0, 0.0])
P[2].x = 200 + center.x
P[2].y = -100 + center.y
P[2].c = Color([0.0, 0.0, 1.0])
triangle = Triangle(P)
triangle.Fill()
gui = ti.GUI("10", (width, height))
while gui.running:
gui.set_image(pixels)
gui.show()
``````

``````import taichi as ti

ti.init(ti.cpu)

Color = ti.types.vector(3, ti.f32)
Point = ti.types.vector(2, ti.i32)

width = 1024
height = 1024
pixels = Color.field(shape=(width, height))
center = Point([width // 2, height // 2])

@ti.data_oriented
class Triangle:
LEFT = True
RIGHT = False

def __init__(self, P):
self.P = P
self.nTotalScanLine = 0
self.SpanLeft = None
self.SpanRight = None

def SortPoint(self):
if self.P[0].y > self.P[1].y:
self.P[0].x, self.P[0].y, self.P[1].x, self.P[1].y = self.P[1].x, self.P[1].y, self.P[0].x, self.P[0].y
if self.P[0].y > self.P[2].y:
self.P[0].x, self.P[0].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[0].x, self.P[0].y
if self.P[1].y > self.P[2].y:
self.P[1].x, self.P[1].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[1].x, self.P[1].y

def SortPoint2(self):
if self.P[0].y > self.P[1].y:
self.P[0], self.P[1] = self.P[1], self.P[0]
if self.P[0].y > self.P[2].y:
self.P[0], self.P[2] = self.P[2], self.P[0]
if self.P[1].y > self.P[2].y:
self.P[1], self.P[2] = self.P[2], self.P[1]

def EdgeFlag(self, PStart, PEnd, bFeature):
dx = PEnd.x - PStart.x
dy = PEnd.y - PStart.y
m = dx / dy
x = PStart.x
for y in range(PStart.y, PEnd.y):
if (bFeature):
self.SpanLeft[self.nIndex] = Point(ti.round(x), y)
self.nIndex += 1
else:
self.SpanRight[self.nIndex] = Point(ti.round(x), y)
self.nIndex += 1
x += m

def Fill(self):
print("before: ", self.P)
self.SortPoint()
# self.SortPoint2()
print("after: ", self.P)
nTotalScanLine = self.P[2].y - self.P[0].y + 1
self.SpanLeft = Point.field(shape=(nTotalScanLine))
self.SpanRight = Point.field(shape=(nTotalScanLine))
nDeltz = (self.P[2].x - self.P[0].x) * (self.P[1].y - self.P[0].y) - \
(self.P[2].y - self.P[0].y) * (self.P[1].x - self.P[0].x)
if nDeltz > 0:
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[1], Triangle.LEFT)
self.EdgeFlag(self.P[1], self.P[2], Triangle.LEFT)
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[2], Triangle.RIGHT)
else:
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[2], Triangle.LEFT)
self.nIndex = 0
self.EdgeFlag(self.P[0], self.P[1], Triangle.RIGHT)
self.EdgeFlag(self.P[1], self.P[2], Triangle.RIGHT)
for y in range(self.P[0].y, self.P[2].y):
n = y - self.P[0].y
for x in range(self.SpanLeft[n].x, self.SpanRight[n].x):
color = Color([1.0, 0.0, 0.0])
pixels[x, y] = color

pixels.fill(Color([1.0, 1.0, 1.0]))
P = Point.field(shape=(3))
P[0] = Point([-300, -300]) + center
P[1] = Point([100, 300]) + center
P[2] = Point([200, -100]) + center
triangle = Triangle(P)
triangle.Fill()
gui = ti.GUI("09", (width, height))
while gui.running:
gui.set_image(pixels)
gui.show()
``````

1. 我这边复现了元素无法交换的问题，感觉是因为shallow copy；struct field暂时没有比较优雅的方法，这个我提了一个issue

2. new一个ti.struct可以考虑像下面这样的方式？

``````pt = Point2({'x':1, 'y':2, 'c':Color([1.0, 0.0, 0.0])})
``````
1 Like