+ // not reduced side elements (if any)
+ for (; j < curr_base_len; j++) {
+ // f (i + 1, j + 1)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + 1));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + 1 == curr_base_len) { // right
+ Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ //double norm_par = double(next_base_len - 1)/double(nb_next - 1);
+ //u = uv_el[i].u + du * norm_par;
+ //v = uv_el[i].v + dv * norm_par;
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ //u = uv_el[i].u + du*npb.Value(curr_base.Value(j + 1));
+ //v = uv_el[i].v + dv*npb.Value(curr_base.Value(j + 1));
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+
+ curr_base_len = next_base_len;
+ curr_base = next_base;
+ curr_par_u = next_par_u;
+ curr_par_v = next_par_v;
+ next_base_len = 0;
+ }
+ } // end "tree" simple reduce "42"
+ else if (is_tree_31) {
+ // "tree" simple reduce "31": 1->3->9->27->...
+ //
+ // .-----------------------------------------------------. nr
+ // | \ / |
+ // | .-----------------. |
+ // | | | |
+ // .-----------------.-----------------.-----------------.
+ // | \ / | \ / | \ / |
+ // | .-----. | .-----. | .-----. | i
+ // | | | | | | | | | |
+ // .-----.-----.-----.-----.-----.-----.-----.-----.-----.
+ // |\ /|\ /|\ /|\ /|\ /|\ /|\ /|\ /|\ /|
+ // | .-. | .-. | .-. | .-. | .-. | .-. | .-. | .-. | .-. |
+ // | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+ // .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. 1
+ // 1 j nb
+
+ for (i = 1; i < nr; i++) { // layer by layer
+ // left
+ NodesBRD.SetValue(1, i+1, uv_el[i].node);
+ next_base.SetValue(++next_base_len, 1);
+ // right
+ NodesBRD.SetValue(nb, i+1, uv_er[i].node);
+
+ next_par_u.SetValue(next_base_len, uv_el[i].u);
+ next_par_v.SetValue(next_base_len, uv_el[i].v);
+
+ // to stop reducing, if number of nodes reaches nt
+ int delta = curr_base_len - nt;
+
+ // to calculate normalized parameter, we must know number of points in next layer
+ int nb_three = (curr_base_len - 1) / 3;
+ int nb_next = nb_three + (curr_base_len - nb_three*3);
+ if (nb_next < nt) nb_next = nt;
+
+ for (j = 1; j + 3 <= curr_base_len && delta > 0; j += 3, delta -= 2) {
+ // add one "H": nodes b,c,e and faces 1,2,4,5
+ //
+ // .---------b i + 1
+ // |\ 5 /|
+ // | \ / |
+ // | c---e |
+ // |1 |2 |4 |
+ // | | | |
+ // .--.---.--. i
+ //
+ // j j+1 j+2 j+3
+
+ double u,v;
+
+ // b (i + 1, j + 3)
+ const SMDS_MeshNode* Nb;
+ next_base_len++;
+ next_base.SetValue(next_base_len, curr_base.Value(j + 3));
+ if (i + 1 == nr) { // top
+ Nb = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + 3 == curr_base_len) { // right
+ Nb = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nb1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nb1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb1);
+ Nb = Nb1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+
+ // c and e
+ double u1 = (curr_par_u.Value(j) + next_par_u.Value(next_base_len - 1)) / 2.0;
+ double u2 = (curr_par_u.Value(j + 3) + next_par_u.Value(next_base_len)) / 2.0;
+ double u3 = (u2 - u1) / 3.0;
+
+ double v1 = (curr_par_v.Value(j) + next_par_v.Value(next_base_len - 1)) / 2.0;
+ double v2 = (curr_par_v.Value(j + 3) + next_par_v.Value(next_base_len)) / 2.0;
+ double v3 = (v2 - v1) / 3.0;
+
+ // c
+ u = u1 + u3;
+ v = v1 + v3;
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nc = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nc, geomFaceID, u, v);
+
+ // e
+ u = u1 + u3 + u3;
+ v = v1 + v3 + v3;
+ P = S->Value(u,v);
+ SMDS_MeshNode* Ne = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Ne, geomFaceID, u, v);
+
+ // Faces
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 0), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ Nc,
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+
+ SMDS_MeshFace* F2 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(curr_base.Value(j + 2), i),
+ Ne, Nc);
+ if (F2) meshDS->SetMeshElementOnShape(F2, geomFaceID);
+
+ SMDS_MeshFace* F4 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 2), i),
+ NodesBRD.Value(curr_base.Value(j + 3), i),
+ Nb, Ne);
+ if (F4) meshDS->SetMeshElementOnShape(F4, geomFaceID);
+
+ SMDS_MeshFace* F5 = myHelper->AddFace(Nc, Ne, Nb,
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F5) meshDS->SetMeshElementOnShape(F5, geomFaceID);
+ }
+
+ // not reduced side elements (if any)
+ for (; j < curr_base_len; j++) {
+ // f (i + 1, j + 1)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + 1));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + 1 == curr_base_len) { // right
+ Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+
+ curr_base_len = next_base_len;
+ curr_base = next_base;
+ curr_par_u = next_par_u;
+ curr_par_v = next_par_v;
+ next_base_len = 0;
+ }
+ } // end "tree" simple reduce "31"
+ else if (is_lin_42) {
+ // "linear" simple reduce "42": 4->8->12->16
+ //
+ // .---------------.---------------.---------------.---------------. nr
+ // | \ | / | \ | / |
+ // | \ .-------.-------. / | \ .-------.-------. / |
+ // | | | | | | | | |
+ // .-------.-------.-------.-------.-------.-------.-------.-------.
+ // | / \ | / \ | / \ | / \ |
+ // | / \.----.----./ \ | / \.----.----./ \ | i
+ // | / | | | \ | / | | | \ |
+ // .-----.----.----.----.----.-----.-----.----.----.----.----.-----.
+ // | / / \ | / \ \ | / / \ | / \ \ |
+ // | / / .-.-. \ \ | / / .-.-. \ \ |
+ // | / / / | \ \ \ | / / / | \ \ \ |
+ // .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. 1
+ // 1 j nb
+
+ // nt = 5, nb = 7, nr = 4
+ //int delta_all = 2;
+ //int delta_one_col = 6;
+ //int nb_col = 0;
+ //int remainder = 2;
+ //if (remainder > 0) nb_col++;
+ //nb_col = 1;
+ //int free_left = 1;
+ //free_left += 2;
+ //int free_middle = 4;
+
+ int delta_all = nb - nt;
+ int delta_one_col = (nr - 1) * 2;
+ int nb_col = delta_all / delta_one_col;
+ int remainder = delta_all - nb_col * delta_one_col;
+ if (remainder > 0) {
+ nb_col++;
+ }
+ int free_left = ((nt - 1) - nb_col * 2) / 2;
+ free_left += nr - 2;
+ int free_middle = (nr - 2) * 2;
+ if (remainder > 0 && nb_col == 1) {
+ int nb_rows_short_col = remainder / 2;
+ int nb_rows_thrown = (nr - 1) - nb_rows_short_col;
+ free_left -= nb_rows_thrown;
+ }
+
+ // nt = 5, nb = 17, nr = 4
+ //int delta_all = 12;
+ //int delta_one_col = 6;
+ //int nb_col = 2;
+ //int remainder = 0;
+ //int free_left = 2;
+ //int free_middle = 4;
+
+ for (i = 1; i < nr; i++, free_middle -= 2, free_left -= 1) { // layer by layer
+ // left
+ NodesBRD.SetValue(1, i+1, uv_el[i].node);
+ next_base.SetValue(++next_base_len, 1);
+ // right
+ NodesBRD.SetValue(nb, i+1, uv_er[i].node);
+
+ // left
+ next_par_u.SetValue(next_base_len, uv_el[i].u);
+ next_par_v.SetValue(next_base_len, uv_el[i].v);
+
+ // to calculate normalized parameter, we must know number of points in next layer
+ int nb_next = curr_base_len - nb_col * 2;
+ if (remainder > 0 && i > remainder / 2)
+ // take into account short "column"
+ nb_next += 2;
+ if (nb_next < nt) nb_next = nt;
+
+ // not reduced left elements
+ for (j = 1; j <= free_left; j++) {
+ // f (i + 1, j + 1)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + 1));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+
+ for (int icol = 1; icol <= nb_col; icol++) {
+
+ if (remainder > 0 && icol == nb_col && i > remainder / 2)
+ // stop short "column"
+ break;
+
+ // add one "HH": nodes a,b,c,d,e and faces 1,2,3,4,5,6
+ //
+ // .-----a-----b i + 1
+ // |\ 5 | 6 /|
+ // | \ | / |
+ // | c--d--e |
+ // |1 |2 |3 |4 |
+ // | | | | |
+ // .--.--.--.--. i
+ //
+ // j j+2 j+4
+
+ double u,v;
+
+ // a (i + 1, j + 2)
+ const SMDS_MeshNode* Na;
+ next_base_len++;
+ next_base.SetValue(next_base_len, curr_base.Value(j + 2));
+ if (i + 1 == nr) { // top
+ Na = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Na);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Na1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Na1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Na1);
+ Na = Na1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+
+ // b (i + 1, j + 4)
+ const SMDS_MeshNode* Nb;
+ next_base_len++;
+ next_base.SetValue(next_base_len, curr_base.Value(j + 4));
+ if (i + 1 == nr) { // top
+ Nb = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + 4 == curr_base_len) { // right
+ Nb = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nb1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nb1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb1);
+ Nb = Nb1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+
+ // c
+ u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len - 2)) / 2.0;
+ v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len - 2)) / 2.0;
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nc = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nc, geomFaceID, u, v);
+
+ // d
+ u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len - 1)) / 2.0;
+ v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len - 1)) / 2.0;
+ P = S->Value(u,v);
+ SMDS_MeshNode* Nd = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nd, geomFaceID, u, v);
+
+ // e
+ u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len)) / 2.0;
+ v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len)) / 2.0;
+ P = S->Value(u,v);
+ SMDS_MeshNode* Ne = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Ne, geomFaceID, u, v);
+
+ // Faces
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 0), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ Nc,
+ NodesBRD.Value(next_base.Value(next_base_len - 2), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+
+ SMDS_MeshFace* F2 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(curr_base.Value(j + 2), i),
+ Nd, Nc);
+ if (F2) meshDS->SetMeshElementOnShape(F2, geomFaceID);
+
+ SMDS_MeshFace* F3 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 2), i),
+ NodesBRD.Value(curr_base.Value(j + 3), i),
+ Ne, Nd);
+ if (F3) meshDS->SetMeshElementOnShape(F3, geomFaceID);
+
+ SMDS_MeshFace* F4 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 3), i),
+ NodesBRD.Value(curr_base.Value(j + 4), i),
+ Nb, Ne);
+ if (F4) meshDS->SetMeshElementOnShape(F4, geomFaceID);
+
+ SMDS_MeshFace* F5 = myHelper->AddFace(Nc, Nd, Na,
+ NodesBRD.Value(next_base.Value(next_base_len - 2), i + 1));
+ if (F5) meshDS->SetMeshElementOnShape(F5, geomFaceID);
+
+ SMDS_MeshFace* F6 = myHelper->AddFace(Nd, Ne, Nb, Na);
+ if (F6) meshDS->SetMeshElementOnShape(F6, geomFaceID);
+
+ j += 4;
+
+ // not reduced middle elements
+ if (icol < nb_col) {
+ if (remainder > 0 && icol == nb_col - 1 && i > remainder / 2)
+ // pass middle elements before stopped short "column"
+ break;
+
+ int free_add = free_middle;
+ if (remainder > 0 && icol == nb_col - 1)
+ // next "column" is short
+ free_add -= (nr - 1) - (remainder / 2);
+
+ for (int imiddle = 1; imiddle <= free_add; imiddle++) {
+ // f (i + 1, j + imiddle)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + imiddle));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + imiddle == curr_base_len) { // right
+ Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j - 1 + imiddle), i),
+ NodesBRD.Value(curr_base.Value(j + imiddle), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+ j += free_add;
+ }
+ }
+
+ // not reduced right elements
+ for (; j < curr_base_len; j++) {
+ // f (i + 1, j + 1)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + 1));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + 1 == curr_base_len) { // right
+ Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+
+ curr_base_len = next_base_len;
+ curr_base = next_base;
+ curr_par_u = next_par_u;
+ curr_par_v = next_par_v;
+ next_base_len = 0;
+ }
+ } // end "linear" simple reduce "42"
+ else if (is_lin_31) {
+ // "linear" simple reduce "31": 2->6->10->14
+ //
+ // .-----------------------------.-----------------------------. nr
+ // | \ / | \ / |
+ // | .---------. | .---------. |
+ // | | | | | | |
+ // .---------.---------.---------.---------.---------.---------.
+ // | / \ / \ | / \ / \ |
+ // | / .-----. \ | / .-----. \ | i
+ // | / | | \ | / | | \ |
+ // .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
+ // | / / \ / \ \ | / / \ / \ \ |
+ // | / / .-. \ \ | / / .-. \ \ |
+ // | / / / \ \ \ | / / / \ \ \ |
+ // .--.----.---.-----.---.-----.-.--.----.---.-----.---.-----.-. 1
+ // 1 j nb
+
+ int delta_all = nb - nt;
+ int delta_one_col = (nr - 1) * 2;
+ int nb_col = delta_all / delta_one_col;
+ int remainder = delta_all - nb_col * delta_one_col;
+ if (remainder > 0) {
+ nb_col++;
+ }
+ int free_left = ((nt - 1) - nb_col) / 2;
+ free_left += nr - 2;
+ int free_middle = (nr - 2) * 2;
+ if (remainder > 0 && nb_col == 1) {
+ int nb_rows_short_col = remainder / 2;
+ int nb_rows_thrown = (nr - 1) - nb_rows_short_col;
+ free_left -= nb_rows_thrown;
+ }
+
+ for (i = 1; i < nr; i++, free_middle -= 2, free_left -= 1) { // layer by layer
+ // left
+ NodesBRD.SetValue(1, i+1, uv_el[i].node);
+ next_base.SetValue(++next_base_len, 1);
+ // right
+ NodesBRD.SetValue(nb, i+1, uv_er[i].node);
+
+ // left
+ next_par_u.SetValue(next_base_len, uv_el[i].u);
+ next_par_v.SetValue(next_base_len, uv_el[i].v);
+
+ // to calculate normalized parameter, we must know number of points in next layer
+ int nb_next = curr_base_len - nb_col * 2;
+ if (remainder > 0 && i > remainder / 2)
+ // take into account short "column"
+ nb_next += 2;
+ if (nb_next < nt) nb_next = nt;
+
+ // not reduced left elements
+ for (j = 1; j <= free_left; j++) {
+ // f (i + 1, j + 1)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + 1));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+
+ for (int icol = 1; icol <= nb_col; icol++) {
+
+ if (remainder > 0 && icol == nb_col && i > remainder / 2)
+ // stop short "column"
+ break;
+
+ // add one "H": nodes b,c,e and faces 1,2,4,5
+ //
+ // .---------b i + 1
+ // |\ 5 /|
+ // | \ / |
+ // | c---e |
+ // |1 |2 |4 |
+ // | | | |
+ // .--.---.--. i
+ //
+ // j j+1 j+2 j+3
+
+ double u,v;
+
+ // b (i + 1, j + 3)
+ const SMDS_MeshNode* Nb;
+ next_base_len++;
+ next_base.SetValue(next_base_len, curr_base.Value(j + 3));
+ if (i + 1 == nr) { // top
+ Nb = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + 3 == curr_base_len) { // right
+ Nb = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nb1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nb1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb1);
+ Nb = Nb1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+
+ // c and d
+ double u1 = (curr_par_u.Value(j) + next_par_u.Value(next_base_len - 1)) / 2.0;
+ double u2 = (curr_par_u.Value(j + 3) + next_par_u.Value(next_base_len)) / 2.0;
+ double u3 = (u2 - u1) / 3.0;
+
+ double v1 = (curr_par_v.Value(j) + next_par_v.Value(next_base_len - 1)) / 2.0;
+ double v2 = (curr_par_v.Value(j + 3) + next_par_v.Value(next_base_len)) / 2.0;
+ double v3 = (v2 - v1) / 3.0;
+
+ // c
+ u = u1 + u3;
+ v = v1 + v3;
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nc = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nc, geomFaceID, u, v);
+
+ // e
+ u = u1 + u3 + u3;
+ v = v1 + v3 + v3;
+ P = S->Value(u,v);
+ SMDS_MeshNode* Ne = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Ne, geomFaceID, u, v);
+
+ // Faces
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 0), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ Nc,
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+
+ SMDS_MeshFace* F2 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(curr_base.Value(j + 2), i),
+ Ne, Nc);
+ if (F2) meshDS->SetMeshElementOnShape(F2, geomFaceID);
+
+ SMDS_MeshFace* F4 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j + 2), i),
+ NodesBRD.Value(curr_base.Value(j + 3), i),
+ Nb, Ne);
+ if (F4) meshDS->SetMeshElementOnShape(F4, geomFaceID);
+
+ SMDS_MeshFace* F5 = myHelper->AddFace(Nc, Ne, Nb,
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F5) meshDS->SetMeshElementOnShape(F5, geomFaceID);
+
+ j += 3;
+
+ // not reduced middle elements
+ if (icol < nb_col) {
+ if (remainder > 0 && icol == nb_col - 1 && i > remainder / 2)
+ // pass middle elements before stopped short "column"
+ break;
+
+ int free_add = free_middle;
+ if (remainder > 0 && icol == nb_col - 1)
+ // next "column" is short
+ free_add -= (nr - 1) - (remainder / 2);
+
+ for (int imiddle = 1; imiddle <= free_add; imiddle++) {
+ // f (i + 1, j + imiddle)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + imiddle));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + imiddle == curr_base_len) { // right
+ Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j - 1 + imiddle), i),
+ NodesBRD.Value(curr_base.Value(j + imiddle), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+ j += free_add;
+ }
+ }
+
+ // not reduced right elements
+ for (; j < curr_base_len; j++) {
+ // f (i + 1, j + 1)
+ const SMDS_MeshNode* Nf;
+ double u,v;
+ next_base.SetValue(++next_base_len, curr_base.Value(j + 1));
+ if (i + 1 == nr) { // top
+ Nf = uv_et[next_base_len - 1].node;
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf);
+ u = uv_et[next_base_len - 1].u;
+ v = uv_et[next_base_len - 1].v;
+ }
+ else if (j + 1 == curr_base_len) { // right
+ Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1);
+ u = uv_er[i].u;
+ v = uv_er[i].v;
+ }
+ else {
+ {
+ double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1;
+ int nearest_node_j = (int)rel;
+ rel -= nearest_node_j;
+ int ij = (i + 1 - 1) * nt + (nearest_node_j - 1);
+ double u1 = quad->uv_grid[ij].u;
+ double v1 = quad->uv_grid[ij].v;
+ double u2 = quad->uv_grid[ij + 1].u;
+ double v2 = quad->uv_grid[ij + 1].v;
+ double duj = (u2 - u1) * rel;
+ double dvj = (v2 - v1) * rel;
+ u = u1 + duj;
+ v = v1 + dvj;
+ }
+ gp_Pnt P = S->Value(u,v);
+ SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v);
+ NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1);
+ Nf = Nf1;
+ }
+ next_par_u.SetValue(next_base_len, u);
+ next_par_v.SetValue(next_base_len, v);
+ SMDS_MeshFace* F1 = myHelper->AddFace(NodesBRD.Value(curr_base.Value(j), i),
+ NodesBRD.Value(curr_base.Value(j + 1), i),
+ NodesBRD.Value(next_base.Value(next_base_len), i + 1),
+ NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1));
+ if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID);
+ }
+
+ curr_base_len = next_base_len;
+ curr_base = next_base;
+ curr_par_u = next_par_u;
+ curr_par_v = next_par_v;
+ next_base_len = 0;
+ }
+ } // end "linear" simple reduce "31"
+ else {
+ }
+ } // end Simple Reduce implementation
+
+ bool isOk = true;
+ return isOk;
+}
+
+//================================================================================
+namespace // data for smoothing
+{
+ struct TSmoothNode;
+ // --------------------------------------------------------------------------------
+ /*!
+ * \brief Structure used to check validity of node position after smoothing.
+ * It holds two nodes connected to a smoothed node and belonging to
+ * one mesh face
+ */
+ struct TTriangle