banner



How To Draw A Triangle In Matlab

This is the 4th commodity in my "MATLAB Plots Can Be Cute" series. To view the previous 3 articles, check the post-obit links:

  • MATLAB Plots Can Be Beautiful I - Drawing a Tree
  • MATLAB Plots Tin can Be Beautiful II - Mountains
  • MATLAB Plots Can Be Beautiful 3 - Light Dots

In this article, we will again use MATLAB to generate wallpaper quality plots. More specifically, nosotros will generate plots similar to the post-obit:

example_thumbnail

At first glimpse, the higher up motion-picture show looks more similar a Photoshop product than a MATLAB plot. Upon further inspection, nosotros tin can discover that the above picture consists of just triangles with different colors. Call up that we can indeed plot filled triangles in MATLAB. Hence, it is completely plausible to generate the above picture with MATLAB's plot functions. Actually, the generation procedure is quite simple, and can be summarized in iii steps:

  1. Sample some random points in a 2D canvas.
  2. Triangulate the canvas region with these points.
  3. Colour each triangle.

Next, we will cover the implementation of each footstep in item.

Poisson-Disc Sampling and Random Points Generation

The kickoff pace is to sample random points in a 2d canvas. The well-nigh straightforward sampling method is uniform sampling. Suppose we demand to sample n due north points, and the canvas width and height are stored in canvas_width and canvas_height, respectively. Basically, we can apply unifrnd(0, canvas_width, n, 1) to sample the ten-coordinates and unifrnd(0, canvas_height, n, 1) to sample the y-coordinates. However, this approach has a problem: it may generate two points that are also close to each other, and we cannot enforce the minimal distance between whatsoever also points. If we triangulate the sail using these points, the result does non look very natural.

To tackle this issue, nosotros will utilize Poisson-disc sampling, which will guarantee the minimal distance between whatsoever two points, leading to a more nature pattern. We volition employ Bridson's algorithm to generate the sample points. More details can be establish in this i-folio newspaper. Below is a MATLAB implementation for the 2nd case:

                                    role              points              =              poisson_disc_2d              (w, h, n, r, k)                        %POISSON_DISC_2D Generate 2d points using the Bridson's Poisson-disc            %sampling algorithm.            %Inputs:            %   west - Width of the region.            %   h - Top of the region.            %   n - Maximum number of points.            %   r - Radius of the disc.            %   thou - (Optional) Maximum number of trials. Default value is 30.            %Output:            %   points - n 10 2 matrix where each row represents a bespeak. n may be less            %            than the specified n.            if            nargin <            5            k =            30;            terminate            % Background filigree for fast occupancy search.            grid_size = r /            sqrt(two); n_w =            ceil(westward / grid_size); n_h =            ceil(h / grid_size); grid =            zeros(n_w, n_h);            % Generate the initial point.            points =            zeros(n,            2); points(1, :) = [unifrnd(0, w) unifrnd(0, h)]; active_points = [ane]; n_points_generated =            ane; grid(floor(points(1,one) / grid_size) +            i,            floor(points(ane,ii) / grid_size) +            1) =            one;            % Generate the remaining points            while            ~isempty(active_points) && n_points_generated < n            % Option a random point from the active fix.            idx = randi(size(active_points,            1));     p = points(active_points(idx), :);            % Effort generate a new point from this point within the annulus [r, 2r].            success = false;            for            kk =            ane:k            % Uniformly samples a point within an annulus.            new_r =            sqrt(r * r +            3            * r * r *            rand());         new_theta = unifrnd(0,            pi*2);         new_p = [new_r * cos(new_theta) + p(1)...                  new_r * sin(new_theta) + p(2)];            % Check validity.            if            new_p(one) <            0            || new_p(2) <            0            || new_p(1) > westward || new_p(2) > h            continue;            finish            grid_x =            flooring(new_p(1) / grid_size) +            1;         grid_y =            flooring(new_p(ii) / grid_size) +            1;            if            grid_x <=            0            || grid_y <=            0            || grid_x > n_w || grid_y > n_h            continue;            finish            if            grid(grid_x, grid_y) >            0            continue;            end            % Check eight adjacent grids.            dirs = [-1            -1;-1            0;-ane            1;0            -1;0            one;1            -one;one            0;1            ane];         valid = true;            for            ii =            1:eight            new_grid_x = grid_x + dirs(two,            1);             new_grid_y = grid_y + dirs(2,            ii);            if            new_grid_x ==            0            || new_grid_y ==            0            || new_grid_x > n_w || new_grid_y > n_h            go along;            cease            if            grid(new_grid_x, new_grid_y) ==            0            continue;            end            p = points(filigree(new_grid_x, new_grid_y), :);            if            sqrt((new_p(one) - p(1)).^2            + (new_p(2) - p(2)).^ii) < r                 valid = false;            break;            end            end            if            ~valid            keep;            end            % Add this bespeak.            n_points_generated = n_points_generated +            ane;         grid(grid_x, grid_y) = n_points_generated;         active_points = [active_points; n_points_generated];         points(n_points_generated, :) = new_p;         success = true;            interruption;            terminate            % Remove this point if the generation fails.            if            ~success         active_points(idx,:) = [];            terminate            end            if            n_points_generated < n     points = points(ane:n_points_generated, :);            finish            end                  

Note: the above implementation is not optimized. The line active_points(idx,:) = [] takes linear time and can be farther optimized. It is also possible to utilize MEX to develop an even faster implementation.

The ii figures below bear witness the departure betwixt compatible sampling and Poisson-disc sampling. We tin observe that Poisson-disc sampling produces a more nature design for triangulation.

With our implementation of Poisson-disc sampling, we tin can write down the MATLAB code for generating the points every bit follows:

          x_min =            -0.05            * canvas_width; x_max =            1.05            * canvas_width; y_min =            -0.05            * canvas_height; y_max =            1.05            * canvas_height; points = poisson_disc_2d(canvas_width *            1.1, canvas_height *            ane.1, max_n_points, r);            % Shift to center.            10 = points(:,            ane); y = points(:,            2); x = x -            0.05            * canvas_width; y = y -            0.05            * canvas_height;            % Set four corners.            x = [10; x_min; x_min; x_max; x_max]; y = [y; y_min; y_max; y_min; y_max]; n_points =            size(x,            1);                  

Note that to avoid artifacts cases by boundary points, nosotros sample the points in a slightly larger surface area. We besides manually put four corner points just in case the sampling algorithm fails to generate points near the corners. We demand to adapt max_n_points according to our pick of r, the minimal distance between whatever 2 points.

Triangulation

Given the generated points, we tin now triangulate the second canvas. Luckily, MATLAB has a built-in function named delaunay that implements the Delaunay triangulation[1]. The documentation tin can exist found here. Therefore, the triangulation step can be done with a single office telephone call:

                      % Triangulation            % =============            tri = delaunay(ten, y);                  

Each row of the variable tri represents a triangle defined past indices with respect to the points defined past the coordinate vectors x and y. For instance, if tri(i,:) = [i five 3], it ways the first triangle's three vertices are given by the showtime, the 5th, and the tertiary sample points. The figure beneath shows what these triangles look like:

Ane interesting characteristic of the Delaunay triangulation is that it maximizes the minimum angle of all the angles of the triangles in the triangulation[ane]. Therefore, the resulting triangles usually practice not take extremely astute angles.

Drawing

We now arrive at the final office: nosotros need to depict and color these triangles. Because the indices of the vertices are already stored in tri, nosotros can just use patch to draw all the triangles in one batch. More details almost the patch role tin be found here. Before calling patch, we still have one more matter to do: determine the colour of each triangle. Here, to make our implementation more flexible, nosotros practise non directly compute the colors. Instead, we compute a scalar value for each triangle, and then use colormap to map these scalar values to the desired colors (similar to imagesc). These scalar values are calculated every bit follows:

  1. Compute the centroids of these triangles.
  2. Evaluate the design function which outputs a scalar for each centroid.
  3. Normalize the outputs of the pattern function to [ 0 , 1 ] [0, 1] .
  4. Add some Gaussian racket for a piffling bit of variations.

In MATLAB, the in a higher place steps are implemented as follows:

                      % Compute the centroids of the triangles.            c_x = mean(x(tri),            ii); c_y = mean(y(tri),            2);            % Evaluate the value for each confront.            cc = pattern_func(c_x, c_y); cc = cc - min(cc); cc = cc / max(cc); cc = cc + variation *            randn(size(cc,            1),            1);                  

The simplest pattern_func is the linear one: 10 + y. You lot tin generate more interesting color patterns by tweaking this function. Check the last role of this article for some interesting pattern functions.

We can now call patch to draw these triangles:

                      % Use patch to draw the triangles.            patch('Faces', tri,            'Vertices', [x y],            'FaceVertexCData', cc, ...            'FaceColor',            'flat',            'EdgeColor',            'none');                  

Finally, nosotros color and so using a custom color map:

          h = unifrnd(0,            1) *            ones(n_colors,            1); south =            linspace(ane,            0.2, n_colors)'; v =            linspace(0,            1, n_colors)'; colormap(hsv2rgb([h s v]));                  

To save the plot as a high-resolution motion-picture show, just utilise:

          gear up(gcf,            'PaperPositionMode',            'auto'); print(gcf,            'triangles.png',            '-dpng',            '-r300');                  

Putting Everything Together

Now we tin can put everything together and finalize our MATLAB script:

          clear();            % Configurations            % ==============            canvas_width =            1080; canvas_height =            720; r =            40; n_colors =            100; variation =            0.02; max_n_points =            floor(canvas_height * canvas_width / r / r) +            1; pattern_func = @(x, y) x + y;            % Points Generation            % =================            x_min =            -0.05            * canvas_width; x_max =            1.05            * canvas_width; y_min =            -0.05            * canvas_height; y_max =            1.05            * canvas_height; points = poisson_disc_2d(canvas_width *            1.1, canvas_height *            one.1, max_n_points, r);            % Shift to center.            x = points(:,            1); y = points(:,            2); x = x -            0.05            * canvas_width; y = y -            0.05            * canvas_height;            % Gear up four corners.            x = [x; x_min; x_min; x_max; x_max]; y = [y; y_min; y_max; y_min; y_max]; n_points =            size(x,            1);            % Triangulation            % =============            tri = delaunay(x, y);            % Drawing            % =======            hf = figure('Position', [fifty            50            canvas_width canvas_height]); axis('equal'); set(gca,            'Position', [0            0            1            1]); axis([0            canvas_width            0            canvas_height]); axis('off');            % Compute the centroids of the triangles.            c_x = mean(ten(tri),            two); c_y = mean(y(tri),            two);            % Evaluate the value for each face.            cc = pattern_func(c_x, c_y); cc = cc - min(cc); cc = cc / max(cc); cc = cc + variation *            randn(size(cc,            ane),            1);            % Utilize patch to describe the triangles.            patch('Faces', tri,            'Vertices', [x y],            'FaceVertexCData', cc, ...            'FaceColor',            'flat',            'EdgeColor',            'none');            % Apply the colour map.            h = unifrnd(0,            1) *            ones(n_colors,            ane); s =            linspace(i,            0.2, n_colors)'; v =            linspace(0,            1, n_colors)'; colormap(hsv2rgb([h southward 5]));                  

Bonus: Changing Design Functions

Nosotros can alter the pattern part pattern_func to generate more interesting color patterns:

(x - canvas_width / 2).^2 - (y - canvas_height / 2).^2

sin(i.v * pi * 10 / canvas_width) .* cos(i.i * pi * y / canvas_height)

abs(x - canvas_width / ii + canvas_width / canvas_height * (y - canvas_height / 2))


  1. https://en.wikipedia.org/wiki/Delaunay_triangulation ↩ ↩

Source: https://research.wmz.ninja/articles/2018/06/matlab-plots-can-be-beautiful-iv.html

Posted by: roseselven54.blogspot.com

0 Response to "How To Draw A Triangle In Matlab"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel