0

ボロノイ セルを 3D 印刷に使用できる形式に出力しようとしています。

MATLAB は、X 座標と Y 座標のリストからボロノイ セルを生成します。私のスクリプトはこのような点のリストを生成しますが、エクスポートできる形式にするのは難しいようです。

私の主な希望は、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);

オプションの「境界」マトリックスとともに(コメントセクションの解像度のチェックもあります)、次に行を出力します。

これらの線が表面を形成することを望みます。バイナリ Z 値 (ポイントは 1、それ以外は 0) を使用してメッシュを作成することを検討しましたが、ポイント間の位置、つまり線で覆われた位置を含める方法がわかりません。

voronoi(X,Y)描画された線の押し出しに基づいてフレームを作成するために、私が取ることができるいくつかの関連する中間ステップがあることを期待しています(余分な線を無限に切り取ったこのスクリプトによって、またはアウト。

4

1 に答える 1

0

これを行う方法を見つけました。

スクリプトを変更しました。新しいスクリプトを下部に貼り付けます。

ワークフローは次のようになります。

  1. Matlab (ライン プロットを作成してからfor i=1:size(lineHandles,1), set(lineHandles(i),'lineWidth',4),end)。必要に応じて線幅を変更してください。)
  2. .png ファイルとして保存します。
  3. Gimp(ファイルを素敵な長方形にトリミング)
  4. InkScape (png ファイルを開き、画像をクリックし、メニューの [パス] -> [ビットマップのトレース] -> [カラー量子化 (2 色)] -> パスを横にドラッグします (これを選択すると、下部のステータス バーにパスが表示されます)。画像をクリックして、パス (ノードを含む) をページに戻します (上部のツールバーに x/y 座標設定があり、両方を 0 に設定します。
  5. .dxf ファイルとして保存します。これらをより適切に入力するには、http://www.thingiverse.com/thing:14221で提供されている拡張機能を使用します。これは、.py および .inx ファイルを /usr/share/inkscape/extensions (または同様のもの) にコピーしてインストールする必要があります。
  6. コマンドを使用して OpenSCAD で開くimport("/path/to/filename.dxf");
  7. このオブジェクトは を使用して押し出すことができますlinear_extrude(height = x)。x は mm 単位の高さです (他の長さはおそらく構成可能です)。
  8. CGAL を使用してレンダリングします (OpenSCAD では F6 がショートカットです)。
  9. .stl ファイルにエクスポート (メニュー [デザイン] > [STL としてエクスポート...])

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

グリッドを 3D プリントするために、一対の円柱内にボロノイ セルを配置するための SCAD スクリプト ファイル。必要に応じてパスを編集したり、形状を変更したりします。

$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);
    }
}
于 2014-07-24T06:51:30.373 に答える