「ガッツでC.G.!サポートツール」で LINE&PAINT CG を描くと、1データあたり 100KB~200KBぐらいになります。8ビットPCの頃に比べると、超贅沢なデータ量ですね。
M5Atom でCG描画アプリを実行するときは、このデータをフラッシュメモリ(SPIFFS)に格納するわけですが、フラッシュメモリのデータ格納容量が2MB程度しか確保できなくて、そうすると 100KB だと 20枚程度が限界になってしまうのですよね。
MI68 で展示していた PIC 画像表示とLINE&PAINT CG です。
PIC 画像は電脳倶楽部に収録されていたものです。LINE&PAINT データは自分で画像をトレースして作成しました。 pic.twitter.com/7e9lq85A1R— Nochi(ドウスル?▮) (@shikarunochi) October 13, 2022
外付けでSDカードを接続するのもアリですが、ミニチュアモニタで使っている 240×240 1.3インチディスプレイはCSピンを持ってないため、SDカードとLCDでSPI接続共有するのが難しく、M5Atom だとピンが足りないわけです。
そんなわけで、少しでもファイルサイズを小さくしたい。
「ガッツでC.G.!サポートツール」は線を引くときにかなり贅沢にポイント座標を取得してます。
こういう風になってるところも多いです。
このとき、(X1,Y1)-(X2,Y2)の角度と(X1,Y1)-(X3,Y3)の角度が同じであれば(X2,Y2)は省略することが可能ですね。
生成済みの描画データに対して、この処理を行うツールを Python で書いてみました。
import sys
import os
if len(sys.argv) > 1:
fileName = sys.argv[1]
else:
fileName = "MagicalMirai2018.dat"
#print("ファイル名を指定してください")
#sys.exit()
cgData = open(fileName, encoding="utf-8")
file, ext = os.path.splitext(fileName)
dietData = open(file + "_diet.dat", mode='w', encoding="utf-8")
line = cgData.readline() #1行目はタイトル
dietData.write(line)
#直線になっている場合、途中の点を省略する。
lineMode = False
while line:
line = cgData.readline()
print("line:" + line)
lineData = line.rstrip().split(',')
#-10から始まっていたら、LINEモード。LINEは1行1LINE
if len(lineData) == 0:
continue
if line.startswith('-10'):
lineMode = True
dietData.write(lineData.pop(0))
dietData.write(',')
elif line.startswith('-1'):
lineMode = False
dietData.write(line)
elif lineMode == False:
dietData.write(line)
if lineMode == True:
dietData.write(lineData.pop(0)) #color
dietData.write(',')
index = 0
while(1):
if index + 5 >= len(lineData):
dietData.write(",".join(lineData))
dietData.write("\n")
break
#(x1,y1)-(x2,y2)の傾きと、(x1,y1)-(x3,y3)の傾きが同じであれば(x2,y2)を削除できる。
x1 = int(lineData[index + 0])
y1 = int(lineData[index + 1])
x2 = int(lineData[index + 2])
y2 = int(lineData[index + 3])
x3 = int(lineData[index + 4])
y3 = int(lineData[index + 5])
if(y1 - y2 == 0) and (y1 - y3 == 0):
#両方傾きゼロだけ特別扱い
del lineData[index+2]
del lineData[index+2] #詰まっているので同じINDEX
elif(y1 - y2 == 0) or (y1 - y3 == 0):
#分母ゼロなので割れない
index = index + 2
elif (x1-x2) / (y1 - y2) == (x1-x3) / (y1 -y3):
del lineData[index+2]
del lineData[index+2] #詰まっているので同じINDEX
else:
index = index + 2
dietData.close()
cgData.close()
元ファイル:MagicalMirai2018.dat : 194,551 byte
実行後ファイル:MagicalMirai2018.diet.dat :126,695 byte
小さくなった!(その分、描画の時も少々クイックになります)
最初からこの処理を「ガッツでC.G.!サポートツール」の線引き処理に組み込んどけばよいのですよね…。
var point = [Math.round(mouse.x),Math.round(mouse.y)];
//前回と傾きが同じだった場合、前回のポイントは削除する。
if(curDrawData.length >=2){
point1 = curDrawData[curDrawData.length-2];
point2 = curDrawData[curDrawData.length-1];
x1 = point1[0];
y1 = point1[1];
x2 = point2[0];
y2 = point1[1];
x3 = point[0];
y3 = point[1];
if((y1 - y2 == 0) && (y1 - y3 == 0)){
//両方傾きゼロだけ特別扱い
curDrawData.pop();
}else if((y1 - y2 == 0) || (y1 - y3 == 0)){
//分母ゼロなので割れない
}else if((x1-x2) / (y1 - y2) == (x1 - x3) / (y1 - y3)){
curDrawData.pop();
}
}
curDrawData.push(point);
…ということで、こちらも先ほど組み込み終わりました!
(2024.05追記)
その後…上の方法だと元データとずれが発生することが発覚し、方式を変更しました。
ということで、「(X1,Y1)-(X2,Y2)と(X2,Y2)-(X3,Y3)で実際に描画するドット集合と、(X1,Y1)-(X3,Y3)で描画するドット集合が一致する場合に(X2,Y2)は省略可能」のロジックに変えてみました。これでバッチリ!のはずだ! (色味の違いは撮影状況によるものなので気にしないで…) pic.twitter.com/RYFxA3vSHv
— Nochi(ドウスル?▮) (@shikarunochi) May 8, 2024
変更後のプログラム。
import sys
import os
def linePixelSet(x1,y1,x2,y2):
startX = x1
startY = y1
endX = x2
endY = y2
pixelSet = {(startX,startY)}
dx = abs(endX - startX)
sx = 1 if (startX < endX)else -1
dy = abs(endY - startY)
sy = 1 if (startY < endY)else -1
err = int((dx if (dx > dy) else -dy) / 2)
while True:
pixelSet.add((startX,startY))
if startX == endX and startY == endY:
break
e2 = err
if e2 > -dx:
err = err - dy
startX = startX + sx
if e2 < dy :
err = err + dx
startY = startY + sy
return pixelSet
if len(sys.argv) > 1:
fileName = sys.argv[1]
else:
fileName = "MagicalMirai2018.dat"
#print("ファイル名を指定してください")
#sys.exit()
cgData = open(fileName, encoding="utf-8")
file, ext = os.path.splitext(fileName)
dietData = open(file + "_diet.dat", mode='w', encoding="utf-8")
line = cgData.readline() #1行目はタイトル
dietData.write(line)
#直線になっている場合、途中の点を省略する。
lineMode = False
while line:
line = cgData.readline()
print("line:" + line)
lineData = line.rstrip().split(',')
#-10から始まっていたら、LINEモード。LINEは1行1LINE
if len(lineData) == 0:
continue
if line.startswith('-10'):
lineMode = True
dietData.write(lineData.pop(0))
dietData.write(',')
elif line.startswith('-1'):
lineMode = False
dietData.write(line)
elif lineMode == False:
dietData.write(line)
if lineMode == True:
dietData.write(lineData.pop(0)) #color
dietData.write(',')
index = 0
while(1):
if index + 5 >= len(lineData):
dietData.write(",".join(lineData))
dietData.write("\n")
break
#(x1,y1)-(x2,y2)の傾きと、(x1,y1)-(x3,y3)の傾きが同じであれば(x2,y2)を削除できる。
#(x1,y1)-(x2,y2)と(x2,y2)-(x3,y3)で塗るドットと、(x1,y1)-(x3,y3)で塗るドットが同一であれば(x2,y2)を削除できる。
x1 = int(lineData[index + 0])
y1 = int(lineData[index + 1])
x2 = int(lineData[index + 2])
y2 = int(lineData[index + 3])
x3 = int(lineData[index + 4])
y3 = int(lineData[index + 5])
oldPixelSet = linePixelSet(x1,y1,x2,y2)|linePixelSet(x2,y2,x3,y3)
newPixelSet = linePixelSet(x1,y1,x3,y3)
if oldPixelSet == newPixelSet: #集合の比較
del lineData[index+2]
del lineData[index+2] #詰まっているので同じINDEX
else:
index = index + 2
dietData.close()
cgData.close()
これでバッチリ!!!
