major update for tin.h
This commit is contained in:
parent
760db80652
commit
f5e1e808e1
12
demo.cpp
12
demo.cpp
@ -15,9 +15,19 @@ int main(int argc, char const *argv[])
|
||||
}
|
||||
infile.close();
|
||||
|
||||
std::vector<double> err_records;
|
||||
std::vector<vertex2dc*> tin_vert;
|
||||
std::vector<triangle*> tin_ele;
|
||||
dem2tin(topo, 0, 1000, 0, 1000, 10, 10, tin_vert, tin_ele, 1.0);
|
||||
dem2tin(topo, 0, 1000, 0, 1000, 10, 10, tin_vert, tin_ele, 1.0, &err_records);
|
||||
|
||||
// Write a log file
|
||||
std::ofstream logfile("topo_TIN.log");
|
||||
logfile << "# Insertion Maxi-Error\n";
|
||||
for (int i = 0; i < err_records.size(); ++i)
|
||||
{
|
||||
logfile << i+1 << " " << err_records[i] << std::endl;
|
||||
}
|
||||
logfile.close();
|
||||
|
||||
// Write a Gmsh's .msh file
|
||||
std::ofstream outfile("topo_TIN.msh");
|
||||
|
180
tin.h
180
tin.h
@ -1,10 +1,10 @@
|
||||
/**
|
||||
* @defgroup TIN
|
||||
*
|
||||
* @brief Generation of a Triangular Irregular Network (TIN) from a dense DEM grid
|
||||
* @brief Generation of a Triangular Irregular Network (TIN) from a dense DEM grid.
|
||||
*
|
||||
* @author Yi Zhang
|
||||
* @date 2021-09-15
|
||||
* @date 2021-09-16
|
||||
*/
|
||||
|
||||
#ifndef _TIN_DELAUNAY_H
|
||||
@ -108,7 +108,7 @@ struct triangle
|
||||
l2x = inx - vert[i]->x;
|
||||
l2y = iny - vert[i]->y;
|
||||
|
||||
if ((l1x*l2y - l1y*l2x) < 0)
|
||||
if ((l1x*l2y - l1y*l2x) < 0) // This condition includes points on the triangle's edge
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -126,6 +126,25 @@ struct triangle
|
||||
};
|
||||
// End triangle definition
|
||||
|
||||
// Start DEM definition
|
||||
struct dem_point
|
||||
{
|
||||
double x, y; // position of the DEM location
|
||||
double elev; // elevation at the DEM location
|
||||
triangle *host; // host triangle of the DEM location
|
||||
std::vector<triangle*> circum_host; // triangles which circumcircles include the location
|
||||
|
||||
dem_point() : x(NAN), y(NAN), elev(NAN), host(nullptr) {}
|
||||
dem_point(double inx, double iny, double inelev) {set(inx, iny, inelev);}
|
||||
void set(double inx, double iny, double inelev)
|
||||
{
|
||||
x = inx; y = iny; elev = inelev; host = nullptr;
|
||||
circum_host.clear();
|
||||
return;
|
||||
}
|
||||
};
|
||||
// End DEM definition
|
||||
|
||||
/**
|
||||
* @brief Generate the TIN from the DEM grid
|
||||
*
|
||||
@ -138,13 +157,16 @@ struct triangle
|
||||
* @param[in] dy Data spacing of the DEM grid on the y-axis
|
||||
* @param out_verts The output vector of vertex's pointers. The user need to destroy the memories allocated by the function before destroy the vector
|
||||
* @param out_tris The output vector of triangle's pointers. The user need to destroy the memories allocated by the function before destroy the vector
|
||||
* @param[in] maxi_err Threshold to quit the algorithm. The default is 1e-2
|
||||
* @param[in] maxi_err Threshold to quit the algorithm. The default is 1e-0
|
||||
* @param[in] err_records If this pointer is not NULL, record maximal error values after each insertion of vertex.
|
||||
*/
|
||||
void dem2tin(const std::vector<double> &dem, double xmin, double xmax, double ymin, double ymax,
|
||||
double dx, double dy, std::vector<vertex2dc*> &out_verts, std::vector<triangle*> &out_tris, double maxi_err = 1e-2)
|
||||
double dx, double dy, std::vector<vertex2dc*> &out_verts, std::vector<triangle*> &out_tris,
|
||||
double maxi_err = 1e-0, std::vector<double> *err_records = nullptr)
|
||||
{
|
||||
if (!out_verts.empty()) out_verts.clear();
|
||||
if (!out_tris.empty()) out_tris.clear();
|
||||
if (err_records != nullptr && !err_records->empty()) err_records->clear();
|
||||
|
||||
if (dx <= 0.0 || dy <= 0.0 || maxi_err <= 0.0) return;
|
||||
if (xmin >= xmax || ymin >= ymax || (xmin + dx) > xmax || (ymin + dy) > ymax) return;
|
||||
@ -154,22 +176,37 @@ void dem2tin(const std::vector<double> &dem, double xmin, double xmax, double ym
|
||||
|
||||
if (dem.size() != xnum*ynum) return;
|
||||
|
||||
// Prepare the DEM points
|
||||
std::vector<dem_point> dem_grid(xnum*ynum);
|
||||
std::vector<dem_point>::iterator d_iter;
|
||||
for (int i = 0; i < ynum; ++i)
|
||||
{
|
||||
for (int j = 0; j < xnum; ++j)
|
||||
{
|
||||
dem_grid[j + i*xnum].set(xmin + dx*j, ymin + dy*i, dem[j + i*xnum]);
|
||||
}
|
||||
}
|
||||
|
||||
vertex2dc *tmp_vert = nullptr;
|
||||
|
||||
tmp_vert = new vertex2dc(xmin, ymin, dem[0], out_verts.size()); // lower left corner
|
||||
tmp_vert = new vertex2dc(xmin, ymin, dem_grid[0].elev, out_verts.size()); // lower left corner
|
||||
out_verts.push_back(tmp_vert);
|
||||
d_iter = dem_grid.begin(); dem_grid.erase(d_iter);
|
||||
|
||||
tmp_vert = new vertex2dc(xmax, ymin, dem[xnum-1], out_verts.size()); // lower right corner
|
||||
tmp_vert = new vertex2dc(xmax, ymin, dem_grid[xnum-2].elev, out_verts.size()); // lower right corner. Note the first location is already erased
|
||||
out_verts.push_back(tmp_vert);
|
||||
d_iter = dem_grid.begin() + (xnum - 2); dem_grid.erase(d_iter);
|
||||
|
||||
tmp_vert = new vertex2dc(xmax, ymax, dem[xnum*ynum-1], out_verts.size()); // upper right corner
|
||||
tmp_vert = new vertex2dc(xmax, ymax, dem_grid[xnum*ynum-3].elev, out_verts.size()); // upper right corner. Note the first two locations are already erased
|
||||
out_verts.push_back(tmp_vert);
|
||||
d_iter = dem_grid.begin() + (xnum*ynum - 3); dem_grid.erase(d_iter);
|
||||
|
||||
tmp_vert = new vertex2dc(xmin, ymax, dem[xnum*(ynum-1)], out_verts.size()); // upper left corner
|
||||
tmp_vert = new vertex2dc(xmin, ymax, dem_grid[xnum*(ynum-1) - 2].elev, out_verts.size()); // upper left corner. Note the first two locations are already erased
|
||||
out_verts.push_back(tmp_vert);
|
||||
d_iter = dem_grid.begin() + (xnum*(ynum-1) - 2); dem_grid.erase(d_iter);
|
||||
|
||||
triangle *tmp_tri = nullptr;
|
||||
std::vector<triangle*> cnst_tri;
|
||||
std::vector<triangle*> cnst_tri, new_tri;
|
||||
std::vector<triangle*>::iterator t_iter;
|
||||
|
||||
if (!is_collinear(out_verts[0], out_verts[1], out_verts[2])) // Do not create triangle if the vertexes are collinear
|
||||
@ -184,12 +221,39 @@ void dem2tin(const std::vector<double> &dem, double xmin, double xmax, double ym
|
||||
out_tris.push_back(tmp_tri);
|
||||
}
|
||||
|
||||
// Find host triangle for all DEM locations
|
||||
for (int i = 0; i < dem_grid.size(); ++i)
|
||||
{
|
||||
for (int t = 0; t < out_tris.size(); ++t)
|
||||
{
|
||||
if (out_tris[t]->bound_location(dem_grid[i].x, dem_grid[i].y))
|
||||
{
|
||||
dem_grid[i].host = out_tris[t];
|
||||
break; // already found, no need to search more
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find circum_host triangles for all DEM locations
|
||||
double dist;
|
||||
for (int i = 0; i < dem_grid.size(); ++i)
|
||||
{
|
||||
for (int t = 0; t < out_tris.size(); ++t)
|
||||
{
|
||||
dist = (out_tris[t]->cx - dem_grid[i].x) * (out_tris[t]->cx - dem_grid[i].x)
|
||||
+ (out_tris[t]->cy - dem_grid[i].y) * (out_tris[t]->cy - dem_grid[i].y);
|
||||
if ((dist - out_tris[t]->cr) <= ZERO) // Points on the circumcircle are also included
|
||||
{
|
||||
dem_grid[i].circum_host.push_back(out_tris[t]);
|
||||
// no beak here. There might be more than one triangle's circumcircle includes the DEM location
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int now_maxi_id;
|
||||
double now_x, now_y, now_err;
|
||||
double now_maxi_err;
|
||||
double now_err, now_maxi_err;
|
||||
|
||||
bool removed;
|
||||
double dist;
|
||||
edge tmp_edge;
|
||||
std::vector<edge> cnst_edge;
|
||||
std::vector<edge>::iterator e_iter;
|
||||
@ -197,47 +261,51 @@ void dem2tin(const std::vector<double> &dem, double xmin, double xmax, double ym
|
||||
do // quit til the threshold is meet
|
||||
{
|
||||
// loop all DEM data to find the location with maximal error
|
||||
// this part is very time consuming. We will fix it later
|
||||
now_maxi_err = -1.0;
|
||||
for (int i = 0; i < xnum*ynum; ++i)
|
||||
for (int i = 0; i < dem_grid.size(); ++i)
|
||||
{
|
||||
now_x = (i%xnum)*dx + xmin;
|
||||
now_y = (i/xnum)*dy + ymin;
|
||||
for (int e = 0; e < out_tris.size(); ++e)
|
||||
{
|
||||
if (out_tris[e]->bound_location(now_x, now_y))
|
||||
{
|
||||
now_err = fabs(out_tris[e]->interpolate(now_x, now_y) - dem[i]);
|
||||
now_err = fabs(dem_grid[i].host->interpolate(dem_grid[i].x, dem_grid[i].y) - dem_grid[i].elev);
|
||||
if (now_err > now_maxi_err)
|
||||
{
|
||||
now_maxi_err = now_err;
|
||||
now_maxi_id = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err_records != nullptr)
|
||||
{
|
||||
err_records->push_back(now_maxi_err);
|
||||
}
|
||||
|
||||
// create a new vertex
|
||||
now_x = (now_maxi_id%xnum)*dx + xmin;
|
||||
now_y = (now_maxi_id/xnum)*dy + ymin;
|
||||
tmp_vert = new vertex2dc(now_x, now_y, dem[now_maxi_id], out_verts.size());
|
||||
tmp_vert = new vertex2dc(dem_grid[now_maxi_id].x, dem_grid[now_maxi_id].y, dem_grid[now_maxi_id].elev, out_verts.size());
|
||||
out_verts.push_back(tmp_vert);
|
||||
|
||||
// determine triangles that include the point and add the triangle to the cnst_tri and remove it from out_tris
|
||||
// this is also a part that could take a lot of time if we are working with a large amount of points. We will fix it later
|
||||
// Move triangles which circumcircles include the new vertex to the cnst_tri and remove it from out_tris
|
||||
cnst_tri.clear();
|
||||
for (int i = 0; i < dem_grid[now_maxi_id].circum_host.size(); ++i)
|
||||
{
|
||||
cnst_tri.push_back(dem_grid[now_maxi_id].circum_host[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < cnst_tri.size(); ++i)
|
||||
{
|
||||
for (t_iter = out_tris.begin(); t_iter != out_tris.end(); )
|
||||
{
|
||||
tmp_tri = *t_iter;
|
||||
dist = (tmp_tri->cx - now_x) * (tmp_tri->cx - now_x) + (tmp_tri->cy - now_y) * (tmp_tri->cy - now_y);
|
||||
if ((dist - tmp_tri->cr) <= ZERO) // Points on the circumcircle are also included
|
||||
if (cnst_tri[i] == tmp_tri)
|
||||
{
|
||||
t_iter = out_tris.erase(t_iter);
|
||||
cnst_tri.push_back(tmp_tri);
|
||||
break; // no need to search more
|
||||
}
|
||||
else t_iter++;
|
||||
}
|
||||
}
|
||||
|
||||
// clear host and circumcircle triangles for the used DEM location
|
||||
dem_grid[now_maxi_id].host = nullptr;
|
||||
dem_grid[now_maxi_id].circum_host.clear();
|
||||
d_iter = dem_grid.begin() + now_maxi_id; dem_grid.erase(d_iter);
|
||||
|
||||
// loop to remove duplicate edges
|
||||
cnst_edge.clear();
|
||||
@ -267,12 +335,59 @@ void dem2tin(const std::vector<double> &dem, double xmin, double xmax, double ym
|
||||
}
|
||||
|
||||
// construct new triangles and add to out_tris
|
||||
new_tri.clear();
|
||||
for (int c = 0; c < cnst_edge.size(); ++c)
|
||||
{
|
||||
if (!is_collinear(cnst_edge[c].vert[0], cnst_edge[c].vert[1], tmp_vert)) // Do not create triangle if the vertexes are collinear
|
||||
{
|
||||
tmp_tri = new triangle(cnst_edge[c].vert[0], cnst_edge[c].vert[1], tmp_vert); // order the vertex anti-clock wise
|
||||
out_tris.push_back(tmp_tri);
|
||||
new_tri.push_back(tmp_tri);
|
||||
}
|
||||
}
|
||||
|
||||
// purge circumcircle triangles for all DEM data
|
||||
for (int c = 0; c < cnst_tri.size(); ++c)
|
||||
{
|
||||
for (int i = 0; i < dem_grid.size(); ++i)
|
||||
{
|
||||
for (t_iter = dem_grid[i].circum_host.begin(); t_iter != dem_grid[i].circum_host.end(); )
|
||||
{
|
||||
if (cnst_tri[c] == *t_iter)
|
||||
{
|
||||
t_iter = dem_grid[i].circum_host.erase(t_iter);
|
||||
break; // no need to search more
|
||||
}
|
||||
else t_iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop all DEM data to update host and circumcircle triangles
|
||||
for (int i = 0; i < dem_grid.size(); ++i)
|
||||
{
|
||||
for (int n = 0; n < new_tri.size(); ++n) // search in newly created triangles to find new host
|
||||
{
|
||||
if (new_tri[n]->bound_location(dem_grid[i].x, dem_grid[i].y))
|
||||
{
|
||||
dem_grid[i].host = new_tri[n];
|
||||
break; // already found, no need to search more
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find circum_host triangles for all DEM locations
|
||||
for (int i = 0; i < dem_grid.size(); ++i)
|
||||
{
|
||||
for (int n = 0; n < new_tri.size(); ++n) // search in newly created triangles to find new circumcircle triangles
|
||||
{
|
||||
dist = (new_tri[n]->cx - dem_grid[i].x) * (new_tri[n]->cx - dem_grid[i].x)
|
||||
+ (new_tri[n]->cy - dem_grid[i].y) * (new_tri[n]->cy - dem_grid[i].y);
|
||||
if ((dist - new_tri[n]->cr) <= ZERO) // Points on the circumcircle are also included
|
||||
{
|
||||
dem_grid[i].circum_host.push_back(new_tri[n]);
|
||||
// no beak here. There might be more than one triangle's circumcircle includes the DEM location
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,6 +397,7 @@ void dem2tin(const std::vector<double> &dem, double xmin, double xmax, double ym
|
||||
tmp_tri = cnst_tri[c];
|
||||
delete tmp_tri; tmp_tri = nullptr;
|
||||
}
|
||||
|
||||
} while (now_maxi_err >= maxi_err);
|
||||
|
||||
return;
|
||||
|
2343
topo_TIN.log
Normal file
2343
topo_TIN.log
Normal file
File diff suppressed because it is too large
Load Diff
40
topo_TIN.msh
40
topo_TIN.msh
@ -2339,9 +2339,9 @@ $Nodes
|
||||
2334 850 360 40.4211
|
||||
2335 830 360 45.5722
|
||||
2336 340 630 112.757
|
||||
2337 300 190 15.6154
|
||||
2338 350 260 26.3352
|
||||
2339 340 260 24.4764
|
||||
2337 350 260 26.3352
|
||||
2338 340 260 24.4764
|
||||
2339 300 190 15.6154
|
||||
2340 540 1000 1.93313
|
||||
2341 480 1000 2.29036
|
||||
2342 440 920 15.8236
|
||||
@ -6944,20 +6944,20 @@ $Elements
|
||||
4590 2 0 2253 342 2336
|
||||
4591 2 0 336 2011 2336
|
||||
4592 2 0 2011 2253 2336
|
||||
4593 2 0 1175 61 2337
|
||||
4594 2 0 1575 1175 2337
|
||||
4595 2 0 2251 1575 2337
|
||||
4596 2 0 61 1930 2337
|
||||
4597 2 0 1930 1749 2337
|
||||
4598 2 0 1749 2251 2337
|
||||
4599 2 0 441 1735 2338
|
||||
4600 2 0 2103 441 2338
|
||||
4601 2 0 1735 1641 2338
|
||||
4602 2 0 1641 2266 2339
|
||||
4603 2 0 2338 1641 2339
|
||||
4604 2 0 2101 2103 2339
|
||||
4605 2 0 2103 2338 2339
|
||||
4606 2 0 2266 2101 2339
|
||||
4593 2 0 441 1735 2337
|
||||
4594 2 0 2103 441 2337
|
||||
4595 2 0 1735 1641 2337
|
||||
4596 2 0 1641 2266 2338
|
||||
4597 2 0 2337 1641 2338
|
||||
4598 2 0 2101 2103 2338
|
||||
4599 2 0 2103 2337 2338
|
||||
4600 2 0 2266 2101 2338
|
||||
4601 2 0 1175 61 2339
|
||||
4602 2 0 1575 1175 2339
|
||||
4603 2 0 2251 1575 2339
|
||||
4604 2 0 61 1930 2339
|
||||
4605 2 0 1930 1749 2339
|
||||
4606 2 0 1749 2251 2339
|
||||
4607 2 0 1728 100 2340
|
||||
4608 2 0 1866 1728 2340
|
||||
4609 2 0 1986 2030 2341
|
||||
@ -9335,9 +9335,9 @@ $NodeData
|
||||
2334 40.4211
|
||||
2335 45.5722
|
||||
2336 112.757
|
||||
2337 15.6154
|
||||
2338 26.3352
|
||||
2339 24.4764
|
||||
2337 26.3352
|
||||
2338 24.4764
|
||||
2339 15.6154
|
||||
2340 1.93313
|
||||
2341 2.29036
|
||||
2342 15.8236
|
||||
|
Loading…
Reference in New Issue
Block a user