将matlab线图转换为stl

时间:2014-07-16 03:03:10

标签: matlab export lines stl-format

我正在尝试将Voronoi单元格输出为可用于3D打印的格式。

MATLAB从X和Y坐标列表生成voronoi单元格。我的脚本生成了这样一个点列表,但是到达我可以导出的格式似乎有问题。

我的主要希望在于stlwrite,http://www.mathworks.com/matlabcentral/fileexchange/20922-stlwrite-write-binary-or-ascii-stl-file

此功能/脚本需要导出曲面。

function [lines, LineData, pOut] = makeSurfaceFromVorVerts(Lx, Ly, varargin)
    p = inputParser;
    addRequired(p,'Lx',...
        @(x) (isequal(class(x),'double') && isequal(size(x,1),2)));
    addRequired(p,'Ly',...
        @(x) (isequal(class(x),'double') && isequal(size(x,1),2)));
    defaultResolution = 100;
    addOptional(p,'Resolution',defaultResolution,...
        @(x) (isequal(class(x),'double') && isequal(size(x),[1 1])));
    defaultBoundary = [0 110; 0 110];
    addOptional(p,'Boundaries',defaultBoundary,...
        @(x) (isequal(class(x),'double') && isequal(size(x),[2 2])));
    parse(p,Lx,Ly,varargin{:});
    pOut = p;

    LX = p.Results.Lx;
    LY = p.Results.Ly;
    Bounds = p.Results.Boundaries;

    % Strip high values
    reducedXdat = [];
    reducedYdat = [];
    for i=1:size(LX,2)
        if LX(1,i) > Bounds(1,1) && LX(1,i) < Bounds(1,2) && ... % X value of start of line
           LX(2,i) > Bounds(2,1) && LX(2,i) < Bounds(2,2) && ... % Y value of start of line
           LY(1,i) > Bounds(1,1) && LY(1,i) < Bounds(1,2) && ... % X value of end of line
           LY(2,i) > Bounds(2,1) && LY(2,i) < Bounds(2,2),       % Y value of end of line
            reducedXdat = [reducedXdat, LX(:,i)];
            reducedYdat = [reducedYdat, LY(:,i)];
        end
    end

    % Initialise a grid of points
    %sXnew = (Bounds(1,2) - Bounds(1,1)) * p.Results.Resolution;
    %sYnew = (Bounds(2,2) - Bounds(2,1)) * p.Results.Resolution;
    %Z = zeros(sXnew, sYnew,'uint8');


    %for x=1:size(X,1)
    %    for y=1:size(Y,1)
    %        nX = floor(X(x)*p.Results.Resolution);
    %        nY = floor(Y(y)*p.Results.Resolution);
    %        Z(nX,nY) = 1;
    %    end
    %end
    %surface = Z;
    %coords = [X,Y];
    lines = line(reducedXdat,reducedYdat);
    LineData = [reducedXdat; reducedYdat];
end

上面的我的处理脚本获取命令生成的点

[Lx, Ly] = voronoi(xValuesOfCellCentres, yValuesOfCellCentres);

以及一个可选的'boundary'矩阵(还有一个检查分辨率,对于注释部分)然后输出行。

我希望这些线条能够形成表面。我考虑使用二进制Z值创建一个网格(1表示点,0表示其他地方),但我不知道如何也可以包括点之间的位置,即线条所覆盖的位置。

我希望我可以采取一些相关的中间步骤,创建一个基于拉伸绘制线条的框架(通过此脚本,将额外的线条切割为无穷大,或者voronoi(X,Y) ,但我不能解决它。

1 个答案:

答案 0 :(得分:0)

找到了一种方法。

更改了脚本,新脚本粘贴在底部。

工作流程:

  1. Matlab(创建线图,然后for i=1:size(lineHandles,1), set(lineHandles(i),'lineWidth',4),end)。根据需要更改线宽。)
  2. 另存为.png文件。
  3. Gimp(将文件裁剪为漂亮的矩形)
  4. InkScape(打开png文件,单击图像,菜单路径 - &gt;跟踪位图 - &gt;颜色量化(2种颜色) - &gt;将路径拖到一边(当你有这个时,它会显示底部状态栏中的路径选择)。单击图像并删除。将路径(带节点)放回到页面上(顶部工具栏中有一个x / y坐标设置,将它们都设置为0。
  5. 另存为.dxf文件。要更好地输入这些内容,请使用http://www.thingiverse.com/thing:14221处提供的扩展程序。这应该通过将.py和.inx文件复制到/ usr / share / inkscape / extensions(或类似)来安装。
  6. 使用命令import("/path/to/filename.dxf");
  7. 在OpenSCAD中打开
  8. 此对象可以使用linear_extrude(height = x)进行挤压,其中x是以mm为单位的高度(其他长度可能是可配置的)
  9. 使用CGAL渲染(F6是OpenSCAD中的快捷方式。)
  10. 导出到.stl文件(菜单设计&gt;导出为STL ...)
  11. MATLAB脚本(根据需要进行编辑并根据需要获取输出,如果您需要行处理,则需要将几乎所有输出参数放入(或重新排序):

    %voronoiScriptHex generates voronoi cells in a hexagonal tesselation grid
    %   [X, Y, Fig, Axis, Lx, Ly, lH, lD] = voronoiScript(Bnd, Spc, D, ...)
    %   
    %   Output variables
    %       X is the x coordinate of the voronoi cell centres
    %       Y is the y coordinate of the voronoi cell centres
    %       Fig is the handle of the figure generated
    %       Axis is the handle of the axes used
    %       Lx gives the start and end x coordinates of the voronoi lines
    %       Ly gives the start and end y coordinates of the voronoi lines
    %       lH is the set of handles for the voronoi lines
    %       lD is constructed from [Lx; Ly], it is a [4 by Length] array
    %
    %   Bnd specifies the boundaries for the region to be covered. It should be
    %   either one number, or a pair of numbers in a [1x2] vector, specifying
    %   [maxX, maxY]. 0 is taken as the minimum value.
    %
    %   Spc specifies the average spacing. For a hex grid, it only accepts one
    %   value.
    %
    %   D specifies the variation from a uniform grid. It is multiplied by a 
    %   random number between -0.5 and 0.5 and added to the [x,y] coordinates
    %   of a point. If size(D) = [1x2], then the values are for [Dx, Dy].
    %
    %   Optional arguments can be used to place some points exactly on the grid
    %   they would lie on with D[x/y] = 0. The first should be 'PartFixed' -
    %   this is a boolean and if true, some points are fixed to the grid.
    %
    %   The second argument is 'FractionFixed'. This is an integer value
    %   (double class variables are accepted, but floor(arg) must be equal to
    %   (arg)). It specifies inversely how often points should be fixed, eg a
    %   value of 1 fixes every point, whilst a value of 5 fixes 1/5 of the
    %   points.
    %
    %   PlotScatter is another boolean value, which sets if a scatter plot of
    %   the X,Y values corresponding to the cell centres should be included in
    %   the figure.
    
    function [X, Y, Figure, Axis, Lx, Ly, lineHandles, lineData] = ...
        voronoiScriptHex(Boundary, Spacing, Delta, varargin)
    
        p = inputParser;
        p.FunctionName = 'voronoiScript';
        addRequired(p, 'Boundary', @checkTypes);
        addRequired(p, 'Spacing', @isnumeric);
        addRequired(p, 'Delta', @checkTypes);
        defaultPart = false;
        addOptional(p, 'PartFixed', defaultPart, @islogical);
        defaultFraction = 2;
        addOptional(p, 'FractionFixed', defaultFraction, @isAnInt);
        defaultScatter = false;
        addOptional(p, 'PlotScatter', defaultScatter, @islogical);
        parse(p, Boundary, Spacing, Delta, varargin{:});
    
    
        % Get values for boundaries and delta
        % (Can be vectors or scalars)
        if isequal(size(p.Results.Boundary),[1,2])
            % Boundary is a vector [maxX, maxY]
            BoundaryY = p.Results.Boundary(1,2);
        else
            BoundaryY = p.Results.Boundary(1,1);
        end
        if isequal(size(p.Results.Delta),[1,2])
            % Delta is a vector [dX, dY]
            DeltaY = p.Results.Delta(1,2);
        else
            DeltaY = p.Results.Delta(1,1);
        end
    
        Spacing = p.Results.Spacing;
        BoundaryX = p.Results.Boundary(1,1);
        DeltaX = p.Results.Delta(1,1);
        D1 = [2*Spacing*cosd(30), Spacing];
        numP = [ceil(BoundaryX/D1(1,1)) ceil(BoundaryY/D1(1,2))];
    
        D2 = D1 ./ 2;
    
        % Create the values
        counter = 1;
        xList(numP(1,1)*numP(1,2)) = 0;
        yList(numP(1,1)*numP(1,2)) = 0;
        for x=1:numP(1,1)
            for y = 1:numP(1,2)
                xList(counter) = (getPointValue(x, D1(1,1), DeltaX)-D2(1,1));
                xList(counter+1) = getPointValue(x, D1(1,1), DeltaX);
                yList(counter) = (getPointValue(y, D1(1,2), DeltaY)-D2(1,2));
                yList(counter+1) = getPointValue(y, D1(1,2), DeltaY);
                counter = counter + 2;
            end
        end
    
        % Set some of the points to be without random change
        if (p.Results.PartFixed),
            for counter=1:p.Results.FractionFixed:size(xList,2),
                [x, y] = getXYfromC(counter, numP(1,2));
                xList(counter) = x*Spacing;
                yList(counter) = y*Spacing;
            end
        end
    
        X = xList;
        Y = yList;
    
        % Set manual ticks for the figure axes
        ticksX = zeros(1,numP(1,1)+1);
        for i=1:numP(1,1)+1,
            ticksX(i) = i*D1(1,1);
        end
        ticksY = zeros(1,numP(1,2)+1);
        for i=1:numP(1,2)+1,
            ticksY(i) = i*D1(1,2);
        end
    
        BoundCoeff = 1.08;
        Bounds = [0 BoundCoeff*BoundaryX; 0 BoundCoeff*BoundaryY];
    
        % Give the figure a handle that is returned, and set axes values
        Figure = figure;
        Axis = axes;
        axis equal;
        minor = 'off';
        gridtoggle = 'off';
        set(Axis,'XTickMode','manual','YTickMode','manual', ...
            'XGrid',gridtoggle,'YGrid',gridtoggle, ...
            'XMinorGrid',minor,'YMinorGrid',minor, ...
            'XTick',ticksX,'YTick',ticksY, ...
            'XMinorTick',minor,'YMinorTick',minor, ...
            'XLim',[0 Bounds(1,2)],'YLim',[0 Bounds(2,2)]);
    
        %set(Axis,'XLim',[0 Bounds(1,2)],'YLim',[0 Bounds(2,2)]);
    
        % Create the voronoi cells, returning the line points
        [Lx, Ly] = voronoi(X,Y);
    
        % Strip high values
        counter = 1;
        reducedXdat = zeros(2,size(Lx,2));
        reducedYdat = zeros(2,size(Lx,2));
        for i=1:size(Lx,2)
            if Lx(1,i) > Bounds(1,1) && Lx(1,i) < Bounds(1,2) && ... % X value of start of line
               Lx(2,i) > Bounds(2,1) && Lx(2,i) < Bounds(2,2) && ... % Y value of start of line
               Ly(1,i) > Bounds(1,1) && Ly(1,i) < Bounds(1,2) && ... % X value of end of line
               Ly(2,i) > Bounds(2,1) && Ly(2,i) < Bounds(2,2),       % Y value of end of line
                reducedXdat(:,counter) = Lx(:,i);
                reducedYdat(:,counter) = Ly(:,i);
                counter = counter + 1;
            end
        end
        Lx = reducedXdat(:,1:counter-1);
        Ly = reducedYdat(:,1:counter-1);
    
        % Plot the voronoi lines
        lineHandles = line(Lx, Ly);
    
        % Set colours to black
        if (1)
            for i=1:size(lineHandles,1)
                set(lineHandles(i),...
                    'LineWidth',3, ...
                    'LineSmoothing','on', ...
                    'Color',[0 0 0]);
            end
        end
    
        lineData = [Lx; Ly];
        if (p.Results.PlotScatter)
            hold on;
            scatter(X,Y);
        end
    end
    
    function bool = checkTypes(arg)
        bool = (isequal(class(arg),'double') && ...
            (isequal(size(arg),[1,1]) || isequal(size(arg),[1,2])));
    end
    
    function bool = isAnInt(arg)
        bool = (isequal(floor(arg),arg) && ...
            isequal(size(arg),[1,1]) && ...
            isnumeric(arg));
    end
    
    function val = getPointValue(intV, spacing, delta)
        val = (((rand(1)-0.5)*delta)+(intV*spacing));
    end
    
    function [x,y] = getXYfromC(counter, sizeY)
        x = floor(counter/sizeY)+1;
        y = counter - ((x-1)*sizeY);
    end
    

    SCAD脚本文件,用于将voronoi单元放置在一对圆柱体内,用于3D打印网格。根据需要编辑路径或更改形状等:

    $fn = 360;
    inkFile = "/path/to/my/file";
    scl = 1.05; // Scale variable
    transVec = [-100, -98, 0]; // Move the imported image pattern so that it's centred.
    union(){
        makeRing([0,0,3],inR=96, outR=99, height=6);
        makeRing([0,0,1.5], inR=99, outR=102, height=3);
    
        intersection() {
            #linear_extrude(height = 6.05, convexity=40, center=false) // Removing the # will get rid of the overlay, which helps see where the grid is. 
                scale([scl, scl, 1])
                translate(transVec)
                import(inkFile);
            makeCylinder([0,0,3], 96, 6, $fn=360);
        }
    }
    module makeCylinder(centre, radius, height) {
        translate(centre){
            cylinder(h = height, r = radius, center=true);
        }
    }
    module makeRing(centre,inR, outR, height) {
        difference() {
            makeCylinder(centre, outR, height);
            makeCylinder(centre, inR, height+0.1);
        }
    }