CLI
英文全稱:COMMON LAYER INTERFACE
中文名稱:通用層介面。
推薦從官方網址看一下其完整的內容:
(https://www.hmilch.net/downloads/cli_format.html)
簡介
通用層介面 (CLI) 是一種通用格式,用於將幾何數據輸入到基於層製造技術 (LMT) 的製造系統模型。適用於樹脂的逐層光固化、粉末的燒結或粘合、片材的切割、熔融材料的固化以及任何其他逐層構建模型的系統。
目的
做有關3D列印相關的專案,想從基礎的切偏資料(cli檔案)入手,但是電腦上沒有軟體能開啟cli檔案(開啟之後資料部分會亂碼)。所以蒐集一些資源,希望從cli檔案中獲取切邊的資料資訊。便於後面的學習。(新手學習,前後用了三天,涉及到某些知識比如檔案讀取等一些問題都是現學現用,可能存在一些問題或者更簡單辦法,希望各位大佬能及時指出,共同進步。)
內容
1.格式的解讀,主要是二進位制檔案的解讀
2.python原始碼
3.Java原始碼
格式
有二進位制資料格式與ASCII資料格式,本文主要是介紹二進位制格式,ASCII格式給出官網的例子。兩種格式的異如下:
相同點:二者標頭檔案是相同的。
不同點:ASCII格式有幾何資訊開始標誌,二進位制沒有開始標誌,頭資訊結束之後直接就是資料。
1.ASCII資料格式
下面是官網給的例子
$$HEADERSTART
// This is a example for the use of the Layer Format //
$$ASCII
$$UNITS/1 // all coordinates are given in mm //
// $$UNITS/0.01 all coordinates are given in units 0.01 mm //
$$DATE/070493 // 7. April 1993 //
$$LAYERS/100 // 100 layers //
$$HEADEREND
$$GEOMETRYSTART // start of GEOMETRY-section//
$$LAYER/5.5 // Layer at height z = 5.5 mm//
$$POLYLINE/0,0,5,1.00,2.02,3.30,3.42,5.23,5.01,1.57,5.6,1.00,2.02
$$HATCHES/0,2,10.2,10.4,12.34,12.5,8.8,9.3,15.7,13.2
$$POLYLINE/0,1,10,1.2,4.01,...........
..
..
$$LAYER/5.6
$$POLYLINE/0,0,200,10.23,12.34,..........................
..........
..
..
$$LAYER/15.5
$$POLYLINE/0,0,200,13.23,12.34,..........................
..........
..
..
$$GEOMETRYEND
2.二進位制資料格式
給一個我已經讀出來的例子,例子中是一個簡單的立方體,編號0.01.cli
其中的換行是我人為換的,並不是開始就是這樣。
程式碼
python
此程式碼是我從該網站得來的,非常感謝寶哥的開源。python原始碼
但是由於他的程式碼是一行顯示的,後面我經過排版,修復其中幾個小問題才能跑起來,不過也存在一個問題。直接執行報錯,程式碼為:
byt_int, = struct.unpack("h", byts)
報錯原因是
struct.error: unpack requires a buffer of 2 bytes
但是在報錯地方打上斷點,程式就能執行了,並且能準確讀出資訊,由於我對python程式碼不是很熟悉,簡單搜一下沒有解決這個問題,就暫時先擱置了,如果有大佬知道還望不吝賜教。下面給出具體程式碼。
import struct
class Que: # 定義一個佇列的類
def __init__(self):
self.L = []
def creat_que(self, num): # 建立佇列
for i in range(0, num):
self.L.append(str(b'x')) #
return self.L
def push(self, item): # 在末尾增加一個,開頭刪除一個,實現棧操作
self.L.append(item)
if self.L.__len__() > 11:
self.L.pop(0)
return self.L
def str_head(self):
st = [item.replace("b'", '') # 從連結串列L中將b'刪去
for item in self.L]
st = [item.replace("'", '') # 從連結串列L中將'刪去
for item in st]
st = ''.join(st) # 連線字串
return st # 返回一個字串
def b2int(self): # 將讀取到的二進位制位元組轉化為 unsign int (2個位元組)
un_int, = struct.unpack("h", self.L[0]) # h在python中是整型
return un_int
que_headerend = Que() # 例項化一個物件來處理$$HEADEREND
que_headerend.creat_que(11) # 建立一個包含11個元素的佇列,用於判斷是不是頭部資訊結束
que_layer = Que() # 例項化一個物件來
que_layer.creat_que(2) # 佇列,用於尋找128/129
class Structure:
def __init__(self, f_dir, f_w): # CI,id,dir,n,p1x,p1y,... pnx,pny
self.UNIT = 0 # 單位
self.LAYERS = 0 # 多少層
self.f = f_dir # 二進位制檔案???
self.f_ascii = f_w # 輸出檔案???
self.head = {}
self.CI_start = 0 # 128/129???
self.layer_thick = 0 # 層厚
self.CI_layer = 0 # 128/129???
self.id = 0 # 標識
self.dir = 0 # 順時針還是逆時針???
self.n = 0 # 點的個數
self.pn = [] # 座標
def rep(self, byts): # 格式替換
s = str(byts).replace("b", '')
s = s.replace("'", '')
return s
def get_head(self): # 獲取檔案頭,返回一個字典
f = self.f
byts = ' '
d_Ls = []
L = []
while byts: # 開始迴圈讀取二進位制資料
byts = f.read(1) #標頭檔案一次讀一個位元組
que_headerend.push(str(byts)) # 末尾增加一個剛讀到的字元,刪去一個前面的字元
s = que_headerend.str_head() # 記住s裡中最多有11個資料
byt = self.rep(byts) # 轉換成無符號整型
L.append(byt) # L中新增這個資料
if s == "$$HEADEREND": # 如果發現了頭結束,說明頭結束了,去得到一些資訊(如層厚等)
# print("$$HEADEREND FOUND!")
sL = ''.join(L) #
sL = sL.replace("\\n", '') # 去掉換行符號,得到下面的字串
'''sL = $$HEADERSTART$$BINARY$$UNITS/00000000.010000$$VERSION/200$$LABEL/1,part1$$DATE/200620$$DIMENSION
/00000072.796799,00000032.592602,00000019.950001,00000132.546799,00000092.342598,00000025.799999
$$LAYERS/000040$$HEADEREND '''
Ls = sL.split("$$") # 用$$分割成單獨的
''' Ls = ['', 'HEADERSTART', 'BINARY', 'UNITS/00000000.010000', 'VERSION/200', 'LABEL/1,part1', 'DATE/200620',
'DIMENSION/00000072.796799,00000032.592602,00000019.950001,00000132.546799,00000092.342598,00000025.799999',
'LAYERS/000040', 'HEADEREND'] '''
Ls = [s for s in Ls if '/' in s] # 如果有/就儲存,沒有就刪去
''' Ls = ['UNITS/00000000.010000', 'VERSION/200', 'LABEL/1,part1', 'DATE/200620', 'DIMENSION/00000072.796799,00000032.592602,
00000019.950001,00000132.546799,00000092.342598,00000025.799999', 'LAYERS/000040'] '''
Ls = [item.split('/') for item in Ls] # 用/分割成小陣列
''' Ls = [['UNITS', '00000000.010000'], ['VERSION', '200'], ['LABEL', '1,part1'], ['DATE', '200620'],
['DIMENSION', '00000072.796799,00000032.592602,00000019.950001,00000132.546799,00000092.342598,00000025.799999'],
['LAYERS', '000040']] '''
d_Ls = dict(Ls) # 轉化成字典
''' d_Ls = {'UNITS': '00000000.010000', 'VERSION': '200', 'LABEL': '1,part1', 'DATE': '200620', 'DIMENSION':
'00000072.796799,00000032.592602,00000019.950001,00000132.546799,00000092.342598,00000025.799999', 'LAYERS': '000040'} '''
self.UNIT = float(d_Ls['UNITS']) # 得到單位
self.LAYERS = int(d_Ls['LAYERS']) # 得到層數
return d_Ls
break
def get_layer(self):
f1 = self.f_ascii
byts = ' '
byt = 0
L = []
n = 1
while byts:
byts = self.f.read(2) # 因為資料是我無符號整型,所以要一次讀兩個位元組
byt_int, = struct.unpack("h", byts) # 進行格式轉換成無符號整型
if byt_int == 128: # 如果是128
f1.write(str(byt_int)) # 寫入128
f1.write('\n') # 換行
byts = self.f.read(2) # 讀兩個
byt_int, = struct.unpack("h", byts) # 轉換格式
f1.write(str(byt_int * self.UNIT)) # 寫入層厚
f1.write('\n')
elif byt_int == 129: # 寫入129
f1.write(str(byt_int))
f1.write('\n') # 寫入層厚mm
byts = self.f.read(2)
byt_int, = struct.unpack("h", byts)
f1.write(str(byt_int * self.UNIT))
f1.write('\n') # 寫入內/外輪廓(0:內輪廓;1:外輪廓)
byts = self.f.read(2)
byt_int, = struct.unpack("h", byts)
f1.write(str(byt_int))
f1.write('\n') # 寫入頂點的個數
byts = self.f.read(2)
byt_int, = struct.unpack("h", byts)
f1.write(str(byt_int))
f1.write('\n')
m = 2 * byt_int
while m > 0:
byts = self.f.read(2)
byt_int, = struct.unpack("h", byts)
cod = byt_int * self.UNIT
cod = round(cod, 2)
f1.write(str(cod))
f1.write(',')
m -= 1
f1.write('\n')
return 1
#下面要替換成自己的檔案路徑
f = open('D:/py_dir/CLI/tt.cli', 'rb')
f_ascii = open('D:/py_dir/CLI/tt1.cli', 'w')
structure = Structure(f, f_ascii)
d = structure.get_head()
n = structure.get_layer()
layers = structure.LAYERSf.close()
f.closed() #一定要記得關閉資料
f_ascii.close() #一定要記得關閉資料
java
原始碼在放在我寫的blog裡面了[http://www.welcomefsjblog.top/archives/3d列印cli格式檔案的讀取]
用了差不多一天才寫出來,果然是個小垃圾。期間遇到很多問題,查了一些書或者有些從別人部落格上看的,因為好多所以有些網址都忘了,非常不好意思白嫖了那麼多大佬的解決辦法。
程式碼還是有很多可以優化的地方,因為我的目的也不是得到這個輸出的檔案,而是直接在程式中對資料進行加工處理,在這只是給出程式碼給後面想讀取cli檔案的朋友提供直接的方法,避免走彎路而已。(自己確實走了很多彎路,相關資料不是很多)。
還是推薦各位去看官網的詳細說明,本篇只是用到了無符號整型,以及沒有任何的填充資訊,所以程式碼跑起來不一定能夠成功,只是提供一種思路而已,不至於無從下手。