[Original] C # basic concepts of contour line-1 and triangular mesh division

Source: Internet
Author: User

Reprinted, please indicate the author and the source. Thank you.

In the past two days, I had a project, and I needed to draw an contour. I thought it was a very simple task. I didn't think that I had no idea how to do it for a week, finally, I drew a line bar. The basic idea is to first divide the triangle, then track the contour, and finally draw the line. The contour line is not smooth. In this example, the figure looks smooth because the points are intensive, there is no intention to fill in the contour, because the project does not have this requirement, (and in my project, the height points are grid-like distribution, rather than discrete points, so my work is simple, however, contour TracingAlgorithm). First:

Example image (the yellow circle represents the light source, and the elevation value is the illumination of the light source)

Figure 1

Figure 2

Figure 3

Contour Annotation

Effect 1: The elevation value is laid down.

Effect 2: The elevation value is below the line

Effect 3: The elevation value is not rotated in the contour direction.

Effect 4: labeling in a small closed contour circle

There are many theories for creating contour lines. However, we usually use a triangular mesh section + Contour Tracking. There are many papers on the Internet for reference:

Gridded network partitioning algorithm

Knowledge about node partitioning

Automatic Generation of triangular mesh contour lines and program implementation

Here is a drawing and filling of the contourSource code(C # Algorithm for Contour Tracking and filling Based on Triangle network)

Here are some sources for triangular mesh partitioning.Code, Has the implementation of various languages

Here are some other contour drawing methods

Here is the URL of the paper, which contains many paper addresses.

Basically, the method andProgramThe theory provided in implementation is enough to guide the assignment, but unfortunately, a considerable number of programmers may not be able to come up with a clear idea at once, I am one of them and read a lotArticleOnly then can you understand, oh! This is the case. In addition, the old saying goes: "It's better to spend thousands of times in your eyes than once in your hands." The so-called paper has to get a glimpse of the end. I am absolutely aware that this matter should be done, read algorithms, and read code, it may be difficult to understand the principles at once. Many times people use an algorithm (or data structure). You may not agree with it, but when you do it yourself, only then can we find that there is such a wonderful way to use it (or you can only use it), and low-handed eyes will always be a common problem for programmers.

OK, go to the topic

In my project, it is calculated inside a space. If n lamps are arranged, We need to calculate the illuminance of each point in the space, at the same time, the contour of illumination is drawn, and the calculated illuminance is not within the scope of this article. Therefore, we assume that the space is divided into a matrix, and the illuminance values at each point in the matrix have been obtained. As a result, I naturally thought of the keyword "using a grid to draw an contour" and found that there was very little relevant information, so I had to change the keyword to "draw an contour ", as a result, I found a lot of papers on how to draw the contour method, but basically I brought another word in front of it: Triangle network. Why do we need a triangular network? Let's take a look at a situation when using a grid to draw.

Figure 1

When using a grid to draw an contour, assuming that we start from the left of the grid to find the direction of the contour, the contour can be "out" in three directions ", it is very difficult to judge and determine the trend of the contour line, and it is very likely that there will be a jagged contour line (as shown in)

Figure 2

When using a tin to draw an contour

Figure 3

Here I have a problem that has not been solved yet, but I have not found a theoretical basis for solving the problem. When using a grid, we need to determine the trend of the contour, in this paper, we propose a principle: assume that the "ENTRANCE" of the contour is on the left (Fig 1a), then in the grid, if there are multiple "egresses" of the contour lines (Figure 1b, C, and D), you should first see which point (B, c, d) the trend from the contour line to a is more likely to be selected ), the second is to see which point is the closest to the point. But in fact, this is too costly. Anyone who wants to write a code to judge the trend is definitely a headache. So the actual practice is: In the process of tracing from left to right, if the X value of a vertex is close to the X value of a vertex, the X value of a vertex is equal to the X value of a vertex, if the distance between A and A is small, the distance is equal. If the distance is the same, the algorithm can only be determined by the trend (see rule Grid Contour Generation Algorithm and Its Application 1.2.2 ). Actually, from the programmer's point of view, as long as you explicitly indicate that a function will be used in the program, there is no difference between using N + 1 times a year and using 1 time, therefore, if you want to write a program to cover all the possibilities, it seems inevitable to judge the trend.

Although the triangle simplifies the difficulty of tracing the contour in the mesh, it does not completely solve the problem of judging the trend. Why? When using a triangle, there may be only two "egresses". The principle in the grid can basically be used to determine which vertex to take, but theoretically there is still a vertex on the edge of vertex A, to B, the X value and the distance of C are equal. See

Figure 4

In Figure 4, Triangle ABC is an isosceles triangle, which means that the distance between A and B and C is equal, and the X values of B and C are equal... theoretically, if A is the starting point, which trend should we talk about? Don't let people live...

Okay. Now let's meditate on "Amen" together. Turn to the probability of asking for help. Don't let this happen. Anyway, I don't want to deal with this situation. Let's talk about the bug. The value indicates that, in most papers, how to deal with this situation is not mentioned. Some papers have pointed out that: "the three sides of a triangle cannot have an equivalent point of the same value, and the other side must have an equivalent point of the same value" (see how to automatically draw an contour line based on discrete points (contour lines) triangle Method (1. B), but I am skeptical about this statement, but I am not going to deal with this situation now (in fact, I am not dealing with the distance and X value in the Code ).

With the theory as the basis, the next thing to do is to convert the matrix into a tin. How to convert it is a problem: in fact, many times, the paper on the premise that data (such as illumination, height, precipitation, etc.) is discrete data, that is, not rule distribution, therefore, in these papers, we are talking about dividing these discrete points into triangles. Of course, if we can split the discrete points out of a triangle, then the rule points will be closed. However, these requirements do not exist in my project. Therefore, what I need to do is split each grid in the matrix into two Cartesian triangles. The first rate is cut from the upper left corner to the lower right corner ,:

Figure 5

The switch is a bit confidential, which can be determined by the actual situation.

Here, we need to give the data structure of triangles, edges, and points:

Vpoint represents a point, which consists of X and Y axis coordinates and elevation values.

Public class vpoint {public float X {Get; set;} public float y {Get; set;} public decimal value {Get; set;} public override bool equals (Object OBJ) {If (obj is vpoint) {var TMP = OBJ as vpoint; return this. X = TMP. X & this. y = TMP. y;} return false;} public override int gethashcode () {return base. gethashcode ();}}

Edge represents an edge, which consists of two points. here we need to explain a little. In Figure 5, one side of some triangles is the border of the entire Triangle network, that is, the four sides of the space, the open equivalent start and end points will inevitably fall on the edge of these outermost layers. Therefore, we need to mark these outermost layers. How can we mark them? Obviously, all the other edges in the Triangle network belong to two triangles at the same time. Therefore, our edge object has two attributes: trangle1 and trangle2, these two attributes identify the two triangles to which the edge object belongs. These edge objects on the outermost layer are relatively poor. They only belong to one trangle, and the value of the trangle2 attribute must be null, for more information, see trangle.

Public class edge {public vpoint P1 {Get; set;} public vpoint P2 {Get; set;} public triangle triangle1 {Get; set;} public triangle2 {Get; set ;} public bool isborder {get {return triangle2 = NULL;} public override bool equals (Object OBJ) {If (obj is edge) {edge TMP = OBJ as edge; return this. p1 = TMP. p1 & this. p2 = TMP. p2;} return false;} public override int gethashcode () {return base. gethashcode ();}}

Trangle represents a triangle consisting of three sides. I always call the horizontal side A, the vertical side B, and the oblique side C, other attribute values will be used later. We will not describe them here,Of course, the Code has not been finalized yet, and some attributes may be killed, leaving only necessary.

Public class triangle {private edge a, B, c; // <summary> // adjacent edge // </Summary> Public edge a {get {return this. a;} set {This. A = value; If (this. a. triangle1 = NULL) {This. a. triangle1 = This;} else {This. a. triangle2 = This ;}}/// <summary> /// peer /// </Summary> Public edge B {get {return this. b;} set {This. B = value; If (this. b. triangle1 = NULL) {This. b. triangle1 = This;} else {This. b. triangle2 = This ;}}/// <summary> /// diagonal edge /// </Summary> Public edge c {get {return this. c;} set {This. C = value; If (this. c. triangle1 = NULL) {This. c. triangle1 = This;} else {This. c. triangle2 = This ;}}/// <summary> // whether to use,-1: temporary use; 0: unused; 1: use /// </Summary> Public int usedstatus {Get; set;} public edge borderedge {get {If (this. a. isborder) {return this. a;} If (thi S. b. isborder) {return this. b;} return NULL;} public edge [] get2otheredge (edge relativeedge) {edge [] edges = new edge [2]; If (relativeedge = This. a) {edges [0] = This. b; edges [1] = This. c;} else if (relativeedge = This. b) {edges [0] = This. a; edges [1] = This. c;} else {edges [0] = This. a; edges [1] = This. b;} return edges;} public vpoint findpoint (float X, float y) {If (this. a! = NULL) {If (this. a. p1.x = x & this. a. p1.y = y) {return this. a. p1;} If (this. a. p2.x = x & this. a. p2.y = y) {return this. a. p2 ;}} if (this. b! = NULL) {If (this. b. p1.x = x & this. b. p1.y = y) {return this. b. p1;} If (this. b. p2.x = x & this. b. p2.y = y) {return this. b. p2 ;}} if (this. c! = NULL) {If (this. c. p1.x = x & this. c. p1.y = y) {return this. c. p1;} If (this. c. p2.x = x & this. c. p2.y = y) {return this. c. p2 ;}} return NULL;} public edge findedge (vpoint P1, vpoint P2) {If (this. a! = NULL) {If (this. A. p1 = p1 & this. A. P2 = P2) {return this. A ;}} if (this. B! = NULL) {If (this. B. p1 = p1 & this. B. P2 = P2) {return this. B ;}} if (this. C! = NULL) {If (this. C. p1 = p1 & this. C. P2 = P2) {return this. c ;}} return NULL ;}}

OK. Now, let's talk about how I created an ilist <trangle>, that is, generating a tin list.

At the beginning, we needed to solve the problem of "wood and wood". So I first set up an ilist <trangle> instance result, and then generated four vpoint objects, representing the four corners of a grid, then, five edge objects are generated, and two trangle objects are generated using five edges. Then, two trangle objects are added to the result object, and the result is searched for whether X is specified in the result, y's vpoint, and whether the P1 and P2 edge are specified in the search result. If yes, the new edge is formed (for vpoint) or trangle (for edge), if not, a new instance is created and then saved to the result through the trangle object. For more information, see trangle. findpoint method and trangle. the findedge method uses a large amount of data to query data using the LINQ method, resulting in a matrix of 45 × 27. It takes 00:00:04 to generate a tin. 7031250! Later, I improved the method by using a two-dimensional array to save vpoint object instances (vpoint [x, y]) and a four-dimensional array to save edge object instances (edge [p1x, p1y, p2x, p2y]). You can use the matrix sequence number to obtain an instance that may already exist. As a result, the performance is greatly improved, and the running time is only 00:00:00. 0156250.

For (INT x = 0; x <xcount-step; x + = step) {for (INT y = 0; y <ycount-step; y + = step) {var p1 = matrix [x, y]; var P2 = matrix [x + step, y]; var P3 = matrix [x + step, Y + step]; vaR P4 = matrix [x, y + step]; vpoint tmpp1, tmpp2, tmpp3, tmpp4; edge edge1, edge2, edge3, edge4, edge5; triangle triangle1 = New Triangle (), triangle2 = New Triangle (); tmpp1 = This. findorcreatenewpoint (tmpmatrix, X, Y, P1, zoomfactor); tmpp2 = This. findorcreatenewpoint (tmpmatrix, x + 1, Y, P2, zoomfactor); tmpp3 = This. findorcreatenewpoint (tmpmatrix, x + 1, Y + 1, P3, zoomfactor); tmpp4 = This. findorcreatenewpoint (tmpmatrix, X, Y + 1, P4, zoomfactor); edge1 = This. findorcreatenewedge (tmpedges, tmpmatrix, X, Y + 1, x + 1, Y + 1); edge2 = This. findorcreatenewedge (tmpedges, tmpmatrix, X, Y, X, Y + 1); edge3 = This. findorcreatenewedge (tmpedges, tmpmatrix, X, Y, x + 1, Y); edge4 = This. findorcreatenewedge (tmpedges, tmpmatrix, x + 1, Y, x + 1, Y + 1); edge5 = This. vertex (tmpedges, tmpmatrix, X, Y, x + 1, Y + 1); vertex = edge1; triangle1. B = edge2; triangle1.c = edge5; triangle2.a = edge3; triangle2. B = edge4; triangle2.c = edge5; result. add (triangle1); result. add (triangle2 );}}

Matrix is the raw data. In my project, it is the illumination point matrix. Step is used to skip the step to get a point when a triangle is generated from the raw data.

With a tin, we should track the contour.

Take a rest. Next we will talk about contour tracing...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.