.stl 3D模型文件的读取计算,方法和程序实现(matlab版C++版python版)
0. 背景描述
3D模型、3D打印中很常見的一種文件格式.STL文件,其描述的主要就是其表面點(diǎn)所組成的三角面片的點(diǎn)坐標(biāo)信息(vertex),和法向量(normal)。 如果單純查看的話,很多軟件都可以打開,諸如SolidWorks、3DMax,win10自帶3d查看器、MITK等。win10自帶的3D查看器,較為推薦。而我最早一般是用基于vtk的醫(yī)學(xué)可視化軟件,進(jìn)行讀取查看。
如果想要訪問獲取.STL文件中的點(diǎn)坐標(biāo)數(shù)據(jù),來進(jìn)行后續(xù)更為自由的計(jì)算和處理,最好是需要程序?qū)崿F(xiàn)的。其中須知,.STL文件一般有兩種文件模式,即ASCII文本型和Binary二進(jìn)制形式。其中ASCII形式的文件,很多文本查看軟件便可打開,如記事本、notepad++、sublime等等。推薦notepad++,其大文件的打開速度很優(yōu)秀。
想對(duì)這兩種文件模式下的STL文件進(jìn)行統(tǒng)一的讀取計(jì)算,讀取stl,返回表面點(diǎn)坐標(biāo)(可附加計(jì)算內(nèi)部點(diǎn)坐標(biāo))。程序操作如下:
1. C++版
基于vtk進(jìn)行C++的簡(jiǎn)單實(shí)現(xiàn)即可,vtk的大牛們已經(jīng)寫好了vtkSTLReader的類,程序?qū)崿F(xiàn)demo見另外的link:URL.
2. Python版
同樣類似于C++版,還是基于vtk實(shí)現(xiàn),程序?qū)崿F(xiàn)demo見另外的link:URL.
3. Matlab版
MATLAB的版本程序最麻煩,詳見下面的stlGeneralAccess函數(shù),支持二進(jìn)制和文本型兩類STL的訪問和計(jì)算,并且?guī)晚?xiàng)目中的同門實(shí)現(xiàn)了計(jì)算內(nèi)部點(diǎn)坐標(biāo)的程序部分(方法參考了程序注釋中的REFS.2),如果沒有這個(gè)需要的,把對(duì)應(yīng)的代碼(計(jì)算inNodes部分)刪掉或者注釋掉即可。
NOTE: 程序邏輯也比較簡(jiǎn)單,就是讀入STL文件,判斷是ASCII還是Binary,然后分別處理,先獲得三角面片的關(guān)系和點(diǎn)坐標(biāo),然后針對(duì)點(diǎn)坐標(biāo)進(jìn)行去重整理,得到純粹的表面點(diǎn)即邊界點(diǎn)的坐標(biāo),之后利用文獻(xiàn)2(REFS.2)的方法計(jì)算得到內(nèi)部點(diǎn)。
function [x, y, z, bdNodes, inNodes] = stlGeneralAccess(filename, dimSize) % This function reads an STL file in binary format or ascii format. % It returns the coordinates of both boundary nodes and interior nodes % of the 3D polyhedron. % % partial REFs: % 1. stlread() by Doron Harlev for binary STL file via mathswork.com % 2. https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html % % Examples: % close all % clear all % clc% [x, y, z, bdNodes, inNodes] = stlGeneralAccess('./Region1.stl'); % if 0 % patch(x, y, z); % else % scatter3(bdNodes(:,1), bdNodes(:,2), bdNodes(:,3), 'MarkerFaceColor',[.75 .75 .0]); % hold on % scatter3(inNodes(:,1), inNodes(:,2), inNodes(:,3),'MarkerFaceColor',[.5 .0 .0]); % end % % Where % filename --- Full path of the input STL file. % dimSize --- [3*1]. The dimSize of coordinate, covering the 3D polyhedron. % x --- [3*numFacet]. X Position of three points in a triangular facet. % y --- [3*numFacet]. Y Position of three points in a triangular facet. % z --- [3*numFacet]. Z Position of three points in a triangular facet. % bdNodes --- [num_bdNodes*3]. The coordinates of boundary nodes. % inNodes --- [num_inNodes*3]. The coordinates of interior nodes. % % FUNCTION stlGeneralAccess. Version 6.1 Written by JeffZhang. AUG,2020. % E-mail: jfsufeng@gmail.com || jfzhang2018@zju.edu.cn % Dsp.CN:該函數(shù)支持STL文件的二進(jìn)制形式和文本形式的通用訪問和計(jì)算,可計(jì)算得到邊界點(diǎn)和內(nèi)部點(diǎn)if nargin < 1error('Too few input arguments') end if nargout > 5error('Too many output arguments') end fid=fopen(filename); if fid == -1error('File could not be opened, pls check the path.') end disp('>>>stlGeneralAccess.[START]') %tic;toc; nline = 0; binary = -1; ascii = -1; binaryOrText = -1; stlLines={}; while ~feof(fid)tline = fgetl(fid);nline = nline + 1;if contains(tline, 'endfacet')ascii = 1;binary = 0;endif nline >= 50break;end endif ascii == 1 && binary ==0disp('FileMode: text');binaryOrText = 0; elsedisp('FileMode: binary');binaryOrText = 1; endnum_facet = 0; frewind(fid) switch binaryOrTextcase 0while ~feof(fid)stlLines=[stlLines;fgets(fid)];end%norm = [];ver1=[];ver2=[];ver3=[];x=[];y=[];z=[];nmRow=[];%x=zeros(3,num_facet); y=zeros(3,num_facet); z=zeros(3,num_facet);for i = 1:size(stlLines,1)%tline = fgetl(fid);tl = stlLines{i};id = strfind(tl,'facet normal');if ~isempty(id)%if contains(tl,'facet normal')nmRow=[nmRow;i];num_facet = num_facet+1;%tk = tl(id+13:end); %15 or id+13(better&more stable)%nm = strsplit(tk,' ');%norm = [norm; str2double(nm)]; %% skipif i+2 <= size(stlLines,1) && i+3 <= size(stlLines,1) && i+4 <= size(stlLines,1)ver1Str = stlLines{i+2};ver2Str = stlLines{i+3};ver3Str = stlLines{i+4};id1 = strfind(ver1Str,'vertex');id2 = strfind(ver2Str,'vertex');id3 = strfind(ver3Str,'vertex');if isempty(id1) || isempty(id2) || isempty(id3)%if ~contains(ver1Str,'vertex')||~contains(ver2Str,'vertex')||~contains(ver3Str,'vertex')error('Exception0x0815 of vertex.')end tk1 = ver1Str(id1+7:end); %11 or id1+7(better&more stable)tk2 = ver2Str(id2+7:end);tk3 = ver3Str(id3+7:end);nm1 = strsplit(tk1,' ');nm2 = strsplit(tk2,' ');nm3 = strsplit(tk3,' ');ver1 = [ver1; str2double(nm1)];ver2 = [ver2; str2double(nm2)];ver3 = [ver3; str2double(nm3)];x=[x;ver1(end,1) ver2(end,1) ver3(end,1)]; %% For patch validationy=[y;ver1(end,2) ver2(end,2) ver3(end,2)];z=[z;ver1(end,3) ver2(end,3) ver3(end,3)];endendendx=x';y=y';z=z';case 1ftitle=fread(fid,80,'uchar=>schar'); % Read file titlenum_facet=fread(fid,1,'int32'); % Read number of Facetsfprintf('\nTitle: %s\n', char(ftitle'));fprintf('Num Facets: %d\n', num_facet);x=zeros(3,num_facet); y=zeros(3,num_facet); z=zeros(3,num_facet);ver1=zeros(num_facet,3); ver2=zeros(num_facet,3); ver3=zeros(num_facet,3);for i=1:num_facetnorm=fread(fid,3,'float32'); % normal coordinates, ignored for nowver1(i,:)=fread(fid,3,'float32'); % vertex 1ver2(i,:)=fread(fid,3,'float32'); % vertex 2ver3(i,:)=fread(fid,3,'float32'); % vertex 3col=fread(fid,1,'uint16'); % color bytesx(:,i)=[ver1(i,1); ver2(i,1); ver3(i,1)]; % convert to matlab "patch" compatible formaty(:,i)=[ver1(i,2); ver2(i,2); ver3(i,2)];z(:,i)=[ver1(i,3); ver2(i,3); ver3(i,3)];endend fclose(fid);bdVertexes=[ver1;ver2;ver3]; bdNodes=unique(bdVertexes, 'rows');%% 缺少圖像Size,Spacing等信息,所以這里只是做個(gè)臨時(shí)demo,屆時(shí)傳入實(shí)際的Size[3]和Spacing[3]即可如果posCrd坐標(biāo)計(jì)算的話 % 如果直接只用idxCrd坐標(biāo)的話,直接完美使用,不用傳參. imSize = [512 512 300]; imSpacing = [1 1 1]; % [.5 0.5 0.5] origin = [0. 0. 0.]; if nargin < 2disp('Default dimSize below.')dimSize = imSize endminX_bd = min(bdNodes(:,1)); maxX_bd = max(bdNodes(:,1)); minY_bd = min(bdNodes(:,2)); maxY_bd = max(bdNodes(:,2)); minZ_bd = min(bdNodes(:,3)); maxZ_bd = max(bdNodes(:,3)); % posCrd = origin + idxCrd*imSpacing, for medical image computing; % 如果用posCrd來計(jì)算;則步長(zhǎng)h(i)=imSpacing(i);rangeSz(i) = imSize(i)*imSpacing(i); inNodesPre=[]; inNodes=[]; for i= 1:1:dimSize(1)for j= 1:1:dimSize(2)for k= 1:1:dimSize(3)tmpX = origin(1) + i * imSpacing(1);tmpY = origin(2) + j * imSpacing(2);tmpZ = origin(3) + k * imSpacing(3);if tmpX >= minX_bd && tmpX <= maxX_bd && ...tmpY >= minY_bd && tmpY <= maxY_bd && ...tmpZ >= minZ_bd && tmpZ <= maxZ_bdinNodesPre = [inNodesPre; tmpX tmpY tmpZ];endendend endif isempty(inNodesPre)fprintf('\n!ERROR!Warning:The dimSize may be not suitable.\n') end%% fix x,evaluate y,z. (pnpoly method) for i= 1:1:size(inNodesPre,1)polyEdge2dId = find((bdNodes(:,1)>= inNodesPre(i, 1)-.5)&(bdNodes(:,1)<= inNodesPre(i, 1)+.4));vertY = bdNodes(polyEdge2dId,2);vertZ = bdNodes(polyEdge2dId,3);testY = inNodesPre(i,2);testZ = inNodesPre(i,3);c = 0;for k=1:1:length(vertY)if k == 1j = length(vertY);elsej = k - 1;endif ( ((vertZ(k)>testZ) ~= (vertZ(j)>testZ)) && ...(testY < (vertY(j)-vertY(k)) * (testZ-vertZ(k)) / (vertZ(j)-vertZ(k)) + vertY(k)) )c = ~c;endendif ~mod(c,2)%disp('even -- outside')else%disp('uneven -- inside')inNodes = [inNodes; inNodesPre(i,:)];end end disp('>>>stlGeneralAccess.[OVER]')end最后附兩個(gè)該函數(shù)調(diào)用的demo效果:
?
?
?
此文暫結(jié)~ 后續(xù)的更新可以到我的mathworks-FileExchange去check&update.
URL1:?https://www.mathworks.com/matlabcentral/fileexchange/79191-stlgeneralaccess
URL2:?https://github.com/JeffJFZ/stlGeneralAccess
?
總結(jié)
以上是生活随笔為你收集整理的.stl 3D模型文件的读取计算,方法和程序实现(matlab版C++版python版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cap流程图_工艺流程图(中英文标准模板
- 下一篇: python爬取b站排行榜_抓取+硒元素