bool insertRectangles(tree_struct* t, rectangle2DList_struct* l) { listCell2D_struct*lc=l->first; bool rr=true; while(lc) { bool r=insertRectangle(t->root, &lc->data, t->width, t->height, 0, 0, area2D(lc->data)); NOGBA("r : %d",(int)r); if(r) { lc->data.real->lmPos.x=lc->data.position.x; lc->data.real->lmPos.y=lc->data.position.y; lc->data.real->rot=lc->data.rot; NOGBA("pos %p %d %d %d %d (%d)",lc->data.real,lc->data.real->lmPos.x,lc->data.real->lmPos.y,lc->data.size.x,lc->data.size.y,lc->data.rot); }else rr=false; lc=lc->next; } return rr; }
/* * return also the area for robustness verification */ double Intx2MeshOnSphere::setup_red_cell(EntityHandle red, int & nsRed){ // get coordinates of the red quad, to decide the gnomonic plane double cellArea =0; int num_nodes; ErrorCode rval = mb->get_connectivity(red, redConn, num_nodes); if (MB_SUCCESS != rval ) return 1; nsRed = num_nodes; // account for possible padded polygons while (redConn[nsRed-2]==redConn[nsRed-1] && nsRed>3) nsRed--; //CartVect coords[4]; rval = mb->get_coords(redConn, nsRed, &(redCoords[0][0])); if (MB_SUCCESS != rval) return 1; CartVect middle = redCoords[0]; for (int i=1; i<nsRed; i++) middle += redCoords[i]; middle = 1./nsRed * middle; decide_gnomonic_plane(middle, plane);// output the plane for (int j = 0; j < nsRed; j++) { // populate coords in the plane for intersection // they should be oriented correctly, positively int rc = gnomonic_projection(redCoords[j], R, plane, redCoords2D[2 * j], redCoords2D[2 * j + 1]); if (rc != 0) return 1; } for (int j=1; j<nsRed-1; j++) cellArea += area2D(&redCoords2D[0], &redCoords2D[2*j], &redCoords2D[2*j+2]); // take red coords in order and compute area in plane return cellArea; }
scalar GGIInterpolation<MasterPatch, SlavePatch>::polygonIntersection ( const List<point2D>& poly1, const List<point2D>& poly2 ) const { // Using pointers because clipping and subject may be swapped // by the algorithm. HJ, 24/Oct/2008 // The first polygon will be the clipping polygon const List<point2D>* clippingPolygon = &poly1; // Yhe second polygon will be the subject polygon; the one that // is going to be clipped const List<point2D>* subjectPolygon = &poly2; // Empty list so we can detect weird cases later List<point2D> clippedPolygon; scalar intersectionArea = 0.0; // First, let's get rid of the obvious: // 1: Neither polygons intersect one another // --> intersection area == 0.0 : that should not happen // 2: If both polygons completely overlap one another // ---> subjectPolygon is the intersection polygon // 3: If clippingPolygon totally enclosed subjectPolygon // ---> subjectPolygon is the intersecting polygon // 4: If subjectPolygon totally enclosed clippingPolygon // --> clippingPolygon is the intersecting polygon // 5: Otherwise, we have partial or full intersection // // For this, we first detect if the vertices of the subject polygon // are inside or outside of the clipping polygon // This is a quick intersection test... // Keep track of who is inside or outside List<bool> subjectVertexInside(subjectPolygon->size()); insideOutside statusInOut = isVertexInsidePolygon ( *clippingPolygon, *subjectPolygon, subjectVertexInside ); // We check right away if statusInOut == ALL_OUTSIDE // Sometimes, it is just that the clipping polygon is inside the // subject polygon instead So let's explore this situation, just // in case if (statusInOut == ALL_OUTSIDE) { // We need to check if subject is not completely or partially // enclosing clipping instead clippingPolygon = &poly2; subjectPolygon = &poly1; subjectVertexInside.setSize(subjectPolygon->size()); statusInOut = isVertexInsidePolygon ( *clippingPolygon, *subjectPolygon, subjectVertexInside ); } switch(statusInOut) { case ALL_INSIDE: { clippedPolygon = *subjectPolygon; break; } case ALL_OUTSIDE: case PARTIALLY_OVERLAPPING: default: { // Compute the intersection // If by any chance, we have reached a situation where the // intersection is really zero, it is because the quick // reject tests have missed something. The intersection // area will be 0.0, and the calling function should at // least check for this, and report loudly... clippedPolygon = clipPolygon2DSutherlandHodgman ( *clippingPolygon, *subjectPolygon );// For convex polygons #if 0 // This is the next candidate to code if the Sutherland // Hodgman algorithm encounters concave polygons... clippedPolygon = clipPolygon2DGreinerHormann ( *clippingPolygon, *subjectPolygon, subjectVertexInside ); // For arbitrary polygons #endif break; } } // Compute the area of clippedPolygon if we indeed do have a // clipped polygon; otherwise, the computed area stays at 0.0; if (clippedPolygon.size() > 2) { // We are only interested in the absolute value intersectionArea = mag(area2D(clippedPolygon)); } if (debug) { // Check against tolerances scalar clippingArea = area2D(*clippingPolygon); scalar subjectArea = area2D(*subjectPolygon); if ( mag(intersectionArea/clippingArea) < areaErrorTol_ || mag(intersectionArea/subjectArea) < areaErrorTol_ ) { WarningIn ( "GGIInterpolation<MasterPatch, SlavePatch>::" "polygonIntersection" ) << "Intersection might be wrong wrong: clipping side " << intersectionArea/clippingArea << " subject: " << intersectionArea/subjectArea << endl; } } return intersectionArea; }
/* the elements are convex for sure, then do a gnomonic projection of both, * compute intersection in the plane, then go back to the sphere for the points * */ int Intx2MeshOnSphere::computeIntersectionBetweenRedAndBlue(EntityHandle red, EntityHandle blue, double * P, int & nP, double & area, int markb[MAXEDGES], int markr[MAXEDGES], int & nsBlue, int & nsRed, bool check_boxes_first) { // the points will be at most 40; they will describe a convex patch, after the points will be ordered and // collapsed (eliminate doubles) // the area is not really required, except to see if it is greater than 0 // gnomonic projection // int plane = 0; // get coordinates of the red quad, to decide the gnomonic plane int num_nodes; ErrorCode rval = mb->get_connectivity(red, redConn, num_nodes); if (MB_SUCCESS != rval ) return 1; nsRed = num_nodes; //CartVect coords[4]; rval = mb->get_coords(redConn, num_nodes, &(redCoords[0][0])); if (MB_SUCCESS != rval) return 1; CartVect middle = redCoords[0]; for (int i=1; i<nsRed; i++) middle += redCoords[i]; middle = 1./nsRed * middle; decide_gnomonic_plane(middle, plane);// output the plane //CartVect bluecoords[4]; rval = mb->get_connectivity(blue, blueConn, num_nodes); if (MB_SUCCESS != rval ) return 1; nsBlue = num_nodes; rval = mb->get_coords(blueConn, nsBlue, &(blueCoords[0][0])); if (MB_SUCCESS != rval) return 1; if (dbg_1) { std::cout << "red " << mb->id_from_handle(red) << "\n"; for (int j = 0; j < nsRed; j++) { std::cout << redCoords[j] << "\n"; } std::cout << "blue " << mb->id_from_handle(blue) << "\n"; for (int j = 0; j < nsBlue; j++) { std::cout << blueCoords[j] << "\n"; } mb->list_entities(&red, 1); mb->list_entities(&blue, 1); std::cout << "middle " << middle << " plane:" << plane << "\n"; } area = 0.; nP = 0; // number of intersection points we are marking the boundary of blue! if (check_boxes_first) { // look at the boxes formed with vertices; if they are far away, return false early if (!GeomUtil::bounding_boxes_overlap(redCoords, nsRed, blueCoords, nsBlue, box_error)) return 0; // no error, but no intersection, decide early to get out } for (int j = 0; j < nsRed; j++) { // populate coords in the plane for intersection // they should be oriented correctly, positively int rc = gnomonic_projection(redCoords[j], R, plane, redCoords2D[2 * j], redCoords2D[2 * j + 1]); if (rc != 0) return 1; } for (int j=0; j<nsBlue; j++) { int rc = gnomonic_projection(blueCoords[j], R, plane, blueCoords2D[2 * j], blueCoords2D[2 * j + 1]); if (rc != 0) return 1; } if (dbg_1) { std::cout << "gnomonic plane: " << plane << "\n"; std::cout << " red blue\n"; for (int j = 0; j < nsRed; j++) { std::cout << redCoords2D[2 * j] << " " << redCoords2D[2 * j + 1] << "\n"; } for (int j = 0; j < nsBlue; j++) { std::cout << blueCoords2D[2 * j] << " " << blueCoords2D[2 * j + 1] << "\n"; } } int ret = EdgeIntersections2(blueCoords2D, nsBlue, redCoords2D, nsRed, markb, markr, P, nP); if (ret != 0) return 1; // some unforeseen error int side[MAXEDGES] = { 0 };// this refers to what side? blue or red? int extraPoints = borderPointsOfXinY2(blueCoords2D, nsBlue, redCoords2D, nsRed, &(P[2 * nP]), side); if (extraPoints >= 1) { for (int k = 0; k < nsBlue; k++) { if (side[k]) { // this means that vertex k of blue is inside convex red; mark edges k-1 and k in blue, // as being "intersected" by red; (even though they might not be intersected by other edges, // the fact that their apex is inside, is good enough) markb[k] = 1; markb[(k + nsBlue-1) % nsBlue] = 1; // it is the previous edge, actually, but instead of doing -1, it is // better to do modulo +3 (modulo 4) // null side b for next call side[k]=0; } } } nP += extraPoints; extraPoints = borderPointsOfXinY2(redCoords2D, nsRed, blueCoords2D, nsBlue, &(P[2 * nP]), side); if (extraPoints >= 1) { for (int k = 0; k < nsRed; k++) { if (side[k]) { // this is to mark that red edges k-1 and k are intersecting blue markr[k] = 1; markr[(k + nsRed-1) % nsRed] = 1; // it is the previous edge, actually, but instead of doing -1, it is // better to do modulo +3 (modulo 4) // null side b for next call } } } nP += extraPoints; // now sort and orient the points in P, such that they are forming a convex polygon // this will be the foundation of our new mesh // this works if the polygons are convex SortAndRemoveDoubles2(P, nP, epsilon_1); // nP should be at most 8 in the end ? // if there are more than 3 points, some area will be positive if (nP >= 3) { for (int k = 1; k < nP - 1; k++) area += area2D(P, &P[2 * k], &P[2 * k + 2]); } return 0; // no error }
// this method will also construct the triangles/polygons in the new mesh // if we accept planar polygons, we just save them // also, we could just create new vertices every time, and merge only in the end; // could be too expensive, and the tolerance for merging could be an // interesting topic int Intx2MeshOnSphere::findNodes(EntityHandle red, int nsRed, EntityHandle blue, int nsBlue, double * iP, int nP) { // first of all, check against red and blue vertices // if (dbg_1) { std::cout << "red, blue, nP, P " << mb->id_from_handle(red) << " " << mb->id_from_handle(blue) << " " << nP << "\n"; for (int n = 0; n < nP; n++) std::cout << " \t" << iP[2 * n] << "\t" << iP[2 * n + 1] << "\n"; } // get the edges for the red triangle; the extra points will be on those edges, saved as // lists (unordered) std::vector<EntityHandle> redEdges(nsRed);// int i = 0; for (i = 0; i < nsRed; i++) { EntityHandle v[2] = { redConn[i], redConn[(i + 1) % nsRed] }; std::vector<EntityHandle> adj_entities; ErrorCode rval = mb->get_adjacencies(v, 2, 1, false, adj_entities, Interface::INTERSECT); if (rval != MB_SUCCESS || adj_entities.size() < 1) return 0; // get out , big error redEdges[i] = adj_entities[0]; // should be only one edge between 2 nodes } // these will be in the new mesh, mbOut // some of them will be handles to the initial vertices from blue or red meshes (lagr or euler) EntityHandle * foundIds = new EntityHandle[nP]; for (i = 0; i < nP; i++) { double * pp = &iP[2 * i]; // iP+2*i // project the point back on the sphere CartVect pos; reverse_gnomonic_projection(pp[0], pp[1], R, plane, pos); int found = 0; // first, are they on vertices from red or blue? // priority is the red mesh (mb2?) int j = 0; EntityHandle outNode = (EntityHandle) 0; for (j = 0; j < nsRed && !found; j++) { //int node = redTri.v[j]; double d2 = dist2(pp, &redCoords2D[2 * j]); if (d2 < epsilon_1) { foundIds[i] = redConn[j]; // no new node found = 1; if (dbg_1) std::cout << " red node j:" << j << " id:" << mb->id_from_handle(redConn[j]) << " 2d coords:" << redCoords2D[2 * j] << " " << redCoords2D[2 * j + 1] << " d2: " << d2 << " \n"; } } for (j = 0; j < nsBlue && !found; j++) { //int node = blueTri.v[j]; double d2 = dist2(pp, &blueCoords2D[2 * j]); if (d2 < epsilon_1) { // suspect is blueConn[j] corresponding in mbOut foundIds[i] = blueConn[j]; // no new node found = 1; if (dbg_1) std::cout << " blue node " << j << " " << mb->id_from_handle(blueConn[j]) << " d2:" << d2 << " \n"; } } if (!found) { // find the edge it belongs, first, on the red element // for (j = 0; j < nsRed; j++) { int j1 = (j + 1) % nsRed; double area = area2D(&redCoords2D[2 * j], &redCoords2D[2 * j1], pp); if (dbg_1) std::cout << " edge " << j << ": " << mb->id_from_handle(redEdges[j]) << " " << redConn[j] << " " << redConn[j1] << " area : " << area << "\n"; if (fabs(area) < epsilon_1/2) { // found the edge; now find if there is a point in the list here //std::vector<EntityHandle> * expts = extraNodesMap[redEdges[j]]; int indx = -1; indx = RedEdges.index(redEdges[j]); std::vector<EntityHandle> * expts = extraNodesVec[indx]; // if the points pp is between extra points, then just give that id // if not, create a new point, (check the id) // get the coordinates of the extra points so far int nbExtraNodesSoFar = expts->size(); CartVect * coords1 = new CartVect[nbExtraNodesSoFar]; mb->get_coords(&(*expts)[0], nbExtraNodesSoFar, &(coords1[0][0])); //std::list<int>::iterator it; for (int k = 0; k < nbExtraNodesSoFar && !found; k++) { //int pnt = *it; double d2 = (pos - coords1[k]).length_squared(); if (d2 < epsilon_1) { found = 1; foundIds[i] = (*expts)[k]; if (dbg_1) std::cout << " found node:" << foundIds[i] << std::endl; } } if (!found) { // create a new point in 2d (at the intersection) //foundIds[i] = m_num2dPoints; //expts.push_back(m_num2dPoints); // need to create a new node in mbOut // this will be on the edge, and it will be added to the local list mb->create_vertex(pos.array(), outNode); (*expts).push_back(outNode); foundIds[i] = outNode; found = 1; if (dbg_1) std::cout << " new node: " << outNode << std::endl; } delete[] coords1; } } } if (!found) { std::cout << " red quad: "; for (int j1 = 0; j1 < nsRed; j1++) { std::cout << redCoords2D[2 * j1] << " " << redCoords2D[2 * j1 + 1] << "\n"; } std::cout << " a point pp is not on a red quad " << *pp << " " << pp[1] << " red quad " << mb->id_from_handle(red) << " \n"; delete[] foundIds; return 1; } } if (dbg_1) { std::cout << " candidate polygon: nP" << nP << " plane: " << plane << "\n"; for (int i1 = 0; i1 < nP; i1++) std::cout << iP[2 * i1] << " " << iP[2 * i1 + 1] << " " << foundIds[i1] << "\n"; } // first, find out if we have nodes collapsed; shrink them // we may have to reduce nP // it is possible that some nodes are collapsed after intersection only // nodes will always be in order (convex intersection) correct_polygon(foundIds, nP); // now we can build the triangles, from P array, with foundIds // we will put them in the out set if (nP >= 3) { EntityHandle polyNew; mb->create_element(MBPOLYGON, foundIds, nP, polyNew); mb->add_entities(outSet, &polyNew, 1); // tag it with the index ids from red and blue sets int id = rs1.index(blue); // index starts from 0 mb->tag_set_data(blueParentTag, &polyNew, 1, &id); id = rs2.index(red); mb->tag_set_data(redParentTag, &polyNew, 1, &id); static int count=0; count++; mb->tag_set_data(countTag, &polyNew, 1, &count); if (dbg_1) { std::cout << "Count: " << count << "\n"; std::cout << " polygon " << mb->id_from_handle(polyNew) << " nodes: " << nP << " :"; for (int i1 = 0; i1 < nP; i1++) std::cout << " " << mb->id_from_handle(foundIds[i1]); std::cout << " plane: " << plane << "\n"; std::vector<CartVect> posi(nP); mb->get_coords(foundIds, nP, &(posi[0][0])); for (int i1 = 0; i1 < nP; i1++) std::cout << foundIds[i1]<< " " << posi[i1] << "\n"; std::stringstream fff; fff << "file0" << count<< ".vtk"; mb->write_mesh(fff.str().c_str(), &outSet, 1); } } delete[] foundIds; foundIds = NULL; return 0; }
int ProjectShell::projectIn2D() { // considering the direction, classify each projected triangle as red or blue // the red ones are positive (inbound), blue ones are negative // first decide the other 2 vectors double vv[3]={0.,-1., 0.}; cross(m_dirX, m_direction, vv); double d1 = dist(m_dirX); if (d1<1.e-5)// consider another direction { vv[1]=0.; vv[2]=-1.; cross(m_dirX, m_direction, vv); d1 = dist(m_dirX); if (d1<1.e-5) { std::cerr << "cannot find a suitable direction; abort\n"; return 1; } } int k=0; for (k=0; k<3; k++) m_dirX[k]/=d1; cross(m_dirY, m_direction, m_dirX); // dirY must be already normalized, but why worry d1 = dist(m_dirY); if (d1==0.) { std::cerr<< " get out of here, it is hopeless\n"; return 1; } for (k=0; k<3; k++) m_dirY[k]/=d1; // now do the projection in 2d // we have 3 vectors, m_dirX, m_dirY, m_direction // for every point, A, the projection in xy plane will be just // xA = A . u; yA = A . v (dirX and dirY) // also, it is important to compute the normal // some triangles will be reverted and some may be projecting to a line // coordinates of the projected nodes on 2D // what could be a good estimate for total number of points in 2D? // we start with 2d capacity 3* m_numNodes m_2dcapacity = m_numNodes*3; m_num2dPoints = m_numNodes; // directly project 3d nodes in 2d, keep the ids m_xy = new double [3*m_2dcapacity]; // this array will be parallel with the original mesh // new nodes will appear after intersection computation // triangles are characterized by their orientation: negative, positive or 0 // the neighbors will be preserved // some edges will be collapsed, and also some triangles // in those cases, what will be the neighbors? // flag them with a high number () //m_finalNodes.resize(3*m_numNodes); // the actual size is n_numNodes first for ( k=0; k<m_numNodes; k++) { // double xx= dot( ps_nodes[k].xyz, m_dirX); // double yy= dot( ps_nodes[k].xyz, m_dirY); // _finalNodes[k].x = dot( ps_nodes[k].xyz, m_dirX); // _finalNodes[k].y = dot( ps_nodes[k].xyz, m_dirY); m_xy[3*k] = dot( ps_nodes[k].xyz, m_dirX); m_xy[3*k+1] = dot( ps_nodes[k].xyz, m_dirY); // m_finalNodes[k].x = m_xy[2*k]; // m_finalNodes[k].y = m_xy[2*k+1]; } for (k=0; k<m_2dcapacity; k++) m_xy[3*k+2] = 0;// the z ccordinate is always 0 !! // if any edges are collapsed, the corresponding triangles should be collapsed too // we will collapse the triangles first, then the edges // when a triangle is collapsed on an edge, it should break in 2 other triangles // we should really form another triangle array, in 2D // first, loop over edges and see which are eliminated; double *edgeLen2D=new double [m_numEdges]; for ( k=0; k<m_numEdges; k++) { int v0 = ps_edges[k].v[0]; int v1 = ps_edges[k].v[1]; edgeLen2D[k] = dist2(&m_xy[3*v0], &m_xy[3*v1]); } double *triArea = new double [m_numTriangles]; for ( k=0; k<m_numTriangles; k++) { const int * pV =&( ps_triangles[k].v[0]); triArea[k] = area2D( &m_xy[ 3*pV[0]], &m_xy[ 3*pV[1]], &m_xy[ 3*pV[2]]); } // if an edge is length 0, we must collapse the nodes, and 2 triangles // first construct a new 2d mesh // we will have to classify all triangles, edges // for each triangle we need to know its original triangle // first mark all triangles; then count positive, negative and zero area (some tolerance is needed) int numNeg = 0, numPos = 0, numZero = 0; // those that are negative will be reverted in the new array int * newTriId = new int [m_numTriangles]; for (k=0; k<m_numTriangles ; k++) { if (triArea[k] > 0) { //numPos++; newTriId[k] = numPos++; } else if (triArea[k] <0) { //numNeg ++; newTriId[k] = numNeg++; } else { numZero ++; newTriId[k] = -1;// receive no Id, as it will not be carried along } } // there are 2 groups: red (positive), blue (negative) // revert the negative ones, and decide the neighbors // red triangles are positive, blue are negative // the negative ones need to be reverted; revert the nodes, first, then edges // do we really need the edges? or just the neighboring triangles? // if a neighbor is the other sign or zero, will become boundary marker (large number, m_numTriangles+1) // // we need to find first 2 triangles (red and blue) that are intersecting // they will be the seeds m_redMesh = new PSTriangle2D [numPos] ; m_blueMesh = new PSTriangle2D [numNeg]; m_numPos = numPos; m_numNeg = numNeg; // do another loop, to really build the 2D mesh we start with // we may have potential starting triangles for the marching along, if the sign of one of the neighbors is // different for (k=0; k<m_numTriangles ; k++) { PS3DTriangle & orgTria = ps_triangles[k]; if (triArea[k] > 0) { //numPos++; PSTriangle2D & redTria= m_redMesh[newTriId[k]]; redTria.oldId = k ; // index redTria.area = triArea[k]; for (int j=0; j<3; j++) { // copy the edge information too redTria.e[j] = orgTria.e[j]; // qualify the neighbors // int t = orgTria.t[j]; redTria.v[j] = orgTria.v[j]; if (triArea[t]>0) { redTria.t[j] = newTriId[t];// will be the index in red mesh } else { redTria.t[j] = numPos; // marker for boundary } } } else if (triArea[k] <0) { //numNeg ++; PSTriangle2D & blueTria= m_blueMesh[newTriId[k]]; blueTria.oldId = k; blueTria.area =triArea[k]; // this is for debugging I think for (int j=0; j<3; j++) { // copy the edge information too blueTria.e[j] = orgTria.e[j]; // qualify the neighbors // int t = orgTria.t[j]; blueTria.v[j] = orgTria.v[j]; if (triArea[t]<0) { blueTria.t[j] = newTriId[t];// will be the index in red mesh } else { blueTria.t[j] = numNeg; // marker for boundary } } } else { // numZero ++; // newTriId[k] = -1;// receive no Id, as it will not be carried along // nothing to do for null triangles } } // revert the blue triangles, so they become positive oriented too for (k=0; k<numNeg; k++) { // PSTriangle2D & blueTri = m_blueMesh[k]; int tmp = blueTri.v[1]; blueTri.v[1] = blueTri.v[2]; blueTri.v[2] = tmp; // this is really stupid: // we should have switched triangle 1 and 3, not 2 and 3 // hard to catch tmp = blueTri.t[0]; blueTri.t[0] = blueTri.t[2]; blueTri.t[2] = tmp; // reverse the edges too tmp = blueTri.e[0]; blueTri.e[0] = -blueTri.e[2]; blueTri.e[1] = -blueTri.e[1]; blueTri.e[2] = -tmp; } // at this point, we have red triangles and blue triangles, and 2d nodes array // we will start creating new triangles, step by step, pointing to the nodes in _finalNodes m_numCurrentNodes = m_numNodes; if (dbg) { std::ofstream fout("dbg.m"); fout << "P=[ \n"; for (int i=0; i<m_numNodes; i++) { fout << m_xy[3*i] << " " << m_xy[3*i+1] << "\n"; } fout << "];\n "; fout << "Ta=[ \n"; for (int k=0; k<m_numPos; k++) { PSTriangle2D & redTri = m_redMesh[k]; for (int j=0; j<3; j++) fout << redTri.v[j]+1 << " " ; for (int jj=0; jj<3; jj++) { fout << redTri.t[jj]+1 << " " ; } fout << "\n"; } fout << "]; \n"; fout << "Tb=[ \n"; for (int kk=0; kk<m_numNeg; kk++) { PSTriangle2D & blueTri = m_blueMesh[kk]; for (int j=0; j<3; j++) fout << blueTri.v[j]+1 << " " ; for (int jj=0; jj<3; jj++) { fout << blueTri.t[jj]+1 << " " ; } fout << "\n"; } fout << "]; \n"; fout.close(); } delete [] edgeLen2D; delete [] triArea; delete [] newTriId; return 0; }
int ProjectShell::findNodes(int red, int blue, double * iP, int nP) { // first of all, check against red and blue vertices // if (dbg) { std::cout<< "red, blue, nP, P " << red << " " << blue << " " << nP <<"\n"; for (int n=0; n<nP; n++) std::cout << " \t" << iP[2*n] << "\t" << iP[2*n+1] << "\n"; } int * foundIds = new int [nP]; for (int i=0; i<nP; i++) { double * pp = &iP[2*i];// iP+2*i int found = 0; // first, are they on vertices from red or blue? PSTriangle2D & redTri = m_redMesh[red]; int j=0; for (j=0; j<3&& !found; j++) { int node = redTri.v[j]; double d2 = dist2( pp, m_xy+(3*node) ); if (dbg && i==0) std::cout<< " red node " << j << " " << node << " " << m_xy[3*node] << " " << m_xy[3*node+1] << " d2:" << d2 << " \n"; if (d2<epsilon) { foundIds[i] = node; // no new node found = 1; } } PSTriangle2D & blueTri = m_blueMesh[blue]; for (j=0; j<3 && !found; j++) { int node = blueTri.v[j]; double d2 = dist2( pp, m_xy+(3*node) ); if (dbg && i==0) std::cout<< " blu node " << j << " " << node << " " << m_xy[3*node] << " " << m_xy[3*node+1] << " d2:" << d2 << " \n"; if (d2<epsilon) { foundIds[i] = node; // no new node found = 1; } } if (!found) { // find the edge it belongs, first // for (j=0; j<3; j++) { int edge = redTri.e[j]; int ae = abs(edge); int v1 = ps_edges[ae-1].v[0]; int v2 = ps_edges[ae-1].v[1]; double area = area2D (&m_xy[3*v1], &m_xy[3*v2], pp); if (dbg) std::cout << " edge " << j << ": " << edge << " " << v1 << " " << v2 << " area : " << area << "\n"; if ( fabs(area) < epsilon*epsilon ) { // found the edge; now find if there is a point in the list here std::list<int> & expts = ps_edges[ae-1].extraNodes; // if the points pp is between extra points, then just give that id // if not, create a new point, (check the id) // std::list<int>::iterator it; for ( it = expts.begin(); it!=expts.end() && !found; it++) { int pnt = *it; double d2 = dist2(pp, &m_xy[3*pnt]); if (d2<epsilon) { found = 1; foundIds[i] = pnt; } } if (!found) { // create a new point in 2d (at the intersection) foundIds [i] = m_num2dPoints; expts.push_back(m_num2dPoints); if (m_2dcapacity < m_num2dPoints+1) { // exit, underestimate number of intersection points std::cout << " underestimate capacity for 2d array\n"; // double the capacity of m_xy array double * new_xy = new double [6* m_2dcapacity]; int jj=0; for (jj=0; jj<3*m_2dcapacity; jj++) { new_xy[jj] = m_xy[jj]; } for (jj=3*m_2dcapacity-1; jj<6*m_2dcapacity; jj+=3) new_xy[jj] = 0.; // make 0 the z coordinate m_2dcapacity *= 2; delete [] m_xy; m_xy = new_xy; } m_xy[3*m_num2dPoints] = pp[0]; m_xy[3*m_num2dPoints+1] = pp[1]; m_num2dPoints++; if (dbg) { std::cout<< " new 2d " << m_num2dPoints - 1 << " : " << pp[0] << " " << pp[1] << "on edge " << ae << "\n"; } found = 1; } } } } if (!found) { std::cout << " a point pp is not on a red triangle " << *pp << " " << pp[1] << " red triangle " << red << " \n"; exit (1); } } // now we can build the triangles, from P array, with foundIds if (nP>=3) { // what are the triangles FinalTriangle ftr; ftr.redTriangle = red; ftr.blueTriangle = blue; ftr.v[0] = foundIds[0]; for (int i=1; i<=nP-2; i++) { // triangle 0, i, i+1 ftr.v[1]=foundIds[i]; ftr.v[2] = foundIds[i+1]; m_finalMesh.push_back(ftr); if (dbg) { std::cout << " triangle " << ftr.v[0] << " " << ftr.v[1] << " " << ftr.v[2] << "\n"; } } } delete [] foundIds; foundIds = NULL; return 0; }
// this method computed intersection between 2 triangles: will output n points, area, affected sides int ProjectShell::computeIntersectionBetweenRedAndBlue(int red, int blue, double * P, int & nP, double & area, int mark[3]) { // the points will be at most 9; they will describe a convex patch, after the points will be ordered and // collapsed (eliminate doubles) // the area is not really required PSTriangle2D & redTri = m_redMesh[red]; PSTriangle2D & blueTri = m_blueMesh[blue]; double redTriangle[6];// column wise double blueTriangle[6]; for (int i=0; i<3; i++) { // node i, 2 coordinates for (int k=0; k<2; k++) { int node = redTri.v[i]; redTriangle[2*i+k] = m_xy[3*node+k]; node = blueTri.v[i]; blueTriangle[2*i+k] = m_xy[3*node+k]; } } /* Matlab source code: function [P,n,M]=Intersect(X,Y); % INTERSECT intersection of two triangles and mortar contribution % [P,n,M]=Intersect(X,Y); computes for the two given triangles X and % Y (point coordinates are stored column-wise, in counter clock % order) the points P where they intersect, in n the indices of % which neighbors of X are also intersecting with Y, and the local % mortar matrix M of contributions of the P1 elements X on the P1 % element Y. The numerical challenges are handled by including % points on the boundary and removing duplicates at the end. [P,n]=EdgeIntersections(X,Y); P1=PointsOfXInY(X,Y); if size(P1,2)>1 % if two or more interior points n=[1 1 1]; % the triangle is candidate for all end % neighbors P=[P P1]; P=[P PointsOfXInY(Y,X)]; P=SortAndRemoveDoubles(P); % sort counter clock wise M=zeros(3,3); if size(P,2)>0 for j=2:size(P,2)-1 % compute interface matrix M=M+MortarInt(P(:,[1 j j+1]),X,Y); end; patch(P(1,:),P(2,:),'m') % draw intersection for illustration % H=line([P(1,:) P(1,1)],[P(2,:),P(2,1)]); % set(H,'LineWidth',3,'Color','m'); pause(0) end; */ //we do not really need the mortar matrix //int n[3]={0, 0, 0};// no intersection of side red with blue //double area= 0.; // X corresponds to blue, Y to red nP=0; // number of intersection points int ret = EdgeIntersections(blueTriangle, redTriangle, mark, P, nP); if (ret!=0) exit(1);// some unforeseen error int extraPoints = borderPointsOfXinY(blueTriangle, redTriangle, &(P[2*nP])); if (extraPoints>1) { mark[0] = mark[1] = mark[2]=1; } nP+=extraPoints; extraPoints = borderPointsOfXinY(redTriangle, blueTriangle, &(P[2*nP])); nP+=extraPoints; // now sort and orient the points in P, such that they are forming a convex polygon // this will be the foundation of our new mesh // SortAndRemoveDoubles (P, nP); // nP should be at most 6 in the end // if there are more than 3 points, some area will be positive area = 0.; if (nP>=3) { for (int k=1; k<nP-1; k++) area += area2D(P, &P[2*k], &P[2*k+2]); } return 0; // no error }
forAll (masterPatch_, faceMi) { // First, we make sure that all the master faces points are // recomputed onto the 2D plane defined by the master faces // normals. // For triangles, this is useless, but for N-gons // with more than 3 points, this is essential. // The intersection between the master and slave faces will be // done in these 2D reference frames // A few basic information to keep close-by vector currentMasterFaceNormal = masterPatchNormals[faceMi]; vector currentMasterFaceCentre = masterPatch_[faceMi].centre(masterPatchPoints); scalarField facePolygonErrorProjection; // Project the master faces points onto the normal face plane to // form a flattened polygon masterFace2DPolygon[faceMi] = projectPointsOnPlane ( masterPatch_[faceMi].points(masterPatchPoints), currentMasterFaceCentre, currentMasterFaceNormal, facePolygonErrorProjection ); // Next we compute an orthonormal basis (u, v, w) aligned with // the face normal for doing the 3D to 2D projection. // // "w" is aligned on the face normal. We need to select a "u" // direction, it can be anything as long as it lays on the // projection plane. We chose to use the direction from the // master face center to the most distant projected master face // point on the plane. Finally, we get "v" by evaluating the // cross-product w^u = v. And we make sure that u, v, and w are // normalized. // // // u = vector from face center to most distant projected master face point. // / . // ^y / | . .w = normal to master face // | / | . . // | / | . . // | | | . // | | / . // | | / . // | | / . // ---------> x |/ . // / v = w^u // / // / // z // // orthoNormalBasis uvw = computeOrthonormalBasis ( currentMasterFaceCentre, currentMasterFaceNormal, masterFace2DPolygon[faceMi] ); // Recompute the master polygon into this orthoNormalBasis // We should only see a rotation along the normal of the face here List<point2D> masterPointsInUV; scalarField masterErrorProjectionAlongW; masterPointsInUV = projectPoints3Dto2D ( uvw, currentMasterFaceCentre, masterFace2DPolygon[faceMi], masterErrorProjectionAlongW // Should be at zero all the way ); // Compute the surface area of the polygon; // We need this for computing the weighting factors scalar surfaceAreaMasterPointsInUV = area2D(masterPointsInUV); // Check if polygon is CW.. Should not, it should be CCW; but // better and cheaper to check here if (surfaceAreaMasterPointsInUV < 0.0) { reverse(masterPointsInUV); surfaceAreaMasterPointsInUV = -surfaceAreaMasterPointsInUV; // Just generate a warning until we can verify this is a non issue InfoIn ( "void GGIInterpolation<MasterPatch, SlavePatch>::" "calcAddressing()" ) << "The master projected polygon was CW instead of CCW. " << "This is strange..." << endl; } // Next, project the candidate master neighbours faces points // onto the same plane using the new orthonormal basis const labelList& curCMN = candidateMasterNeighbors[faceMi]; forAll (curCMN, neighbI) { // For each points, compute the dot product with u,v,w. The // [u,v] component will gives us the 2D cordinates we are // looking for for doing the 2D intersection The w component // is basically the projection error normal to the projection // plane // NB: this polygon is most certainly CW w/r to the uvw // axis because of the way the normals are oriented on // each side of the GGI interface... We will switch the // polygon to CCW in due time... List<point2D> neighbPointsInUV; scalarField neighbErrorProjectionAlongW; // We use the xyz points directly, with a possible transformation pointField curSlaveFacePoints = slavePatch_[curCMN[neighbI]].points(slavePatch_.points()); if (doTransform()) { // Transform points to master plane if (forwardT_.size() == 1) { transform ( curSlaveFacePoints, forwardT_[0], curSlaveFacePoints ); } else { transform ( curSlaveFacePoints, forwardT_[curCMN[neighbI]], curSlaveFacePoints ); } } // Apply the translation offset in order to keep the // neighbErrorProjectionAlongW values to a minimum if (doSeparation()) { if (forwardSep_.size() == 1) { curSlaveFacePoints += forwardSep_[0]; } else { curSlaveFacePoints += forwardSep_[curCMN[neighbI]]; } } neighbPointsInUV = projectPoints3Dto2D ( uvw, currentMasterFaceCentre, curSlaveFacePoints, neighbErrorProjectionAlongW ); // We are now ready to filter out the "bad" neighbours. // For this, we will apply the Separating Axes Theorem // http://en.wikipedia.org/wiki/Separating_axis_theorem. // This will be the second and last quick reject test. // We will use the 2D projected points for both the master // patch and its neighbour candidates if ( detect2dPolygonsOverlap ( masterPointsInUV, neighbPointsInUV, sqrt(areaErrorTol_()) // distErrorTol ) ) { // We have an overlap between the master face and this // neighbor face. label faceMaster = faceMi; label faceSlave = curCMN[neighbI]; // Compute the surface area of the neighbour polygon; // We need this for computing the weighting factors scalar surfaceAreaNeighbPointsInUV = area2D(neighbPointsInUV); // Check for CW polygons. It most certainly is, and // the polygon intersection algorithms are expecting // to work with CCW point ordering for the polygons if (surfaceAreaNeighbPointsInUV < 0.0) { reverse(neighbPointsInUV); surfaceAreaNeighbPointsInUV = -surfaceAreaNeighbPointsInUV; } // We compute the intersection area using the // Sutherland-Hodgman algorithm. Of course, if the // intersection area is 0, that would constitute the last and // final reject test, but it would also be an indication that // our 2 previous rejection tests are a bit laxed... or that // maybe we are in presence of concave polygons.... scalar intersectionArea = polygonIntersection ( masterPointsInUV, neighbPointsInUV ); if (intersectionArea > VSMALL) // Or > areaErrorTol_ ??? { // We compute the GGI weights based on this // intersection area, and on the individual face // area on each side of the GGI. // Since all the intersection have been computed // in the projected UV space we need to compute // the weights using the surface area from the // faces projection as well. That way, we make // sure all our factors will sum up to 1.0. masterNeighbors[faceMaster].append(faceSlave); slaveNeighbors[faceSlave].append(faceMaster); masterNeighborsWeights[faceMaster].append ( intersectionArea/surfaceAreaMasterPointsInUV ); slaveNeighborsWeights[faceSlave].append ( intersectionArea/surfaceAreaNeighbPointsInUV ); } else { WarningIn ( "GGIInterpolation<MasterPatch, SlavePatch>::" "calcAddressing()" ) << "polygonIntersection is returning a " << "zero surface area between " << nl << " Master face: " << faceMi << " and Neighbour face: " << curCMN[neighbI] << " intersection area = " << intersectionArea << nl << "Please check the two quick-check algorithms for " << "GGIInterpolation. Something is missing." << endl; } } }
/* the elements are convex for sure, then do a gnomonic projection of both, * compute intersection in the plane, then go back to the sphere for the points * */ int IntxRllCssphere::computeIntersectionBetweenRedAndBlue(EntityHandle red, EntityHandle blue, double * P, int & nP, double & area, int markb[MAXEDGES], int markr[MAXEDGES], int & nsBlue, int & nsRed, bool check_boxes_first) { // the area will be used from now on, to see how well we fill the red cell with polygons // the points will be at most 40; they will describe a convex patch, after the points will be ordered and // collapsed (eliminate doubles) //CartVect bluecoords[4]; int num_nodes=0; ErrorCode rval = mb->get_connectivity(blue, blueConn, num_nodes); if (MB_SUCCESS != rval ) return 1; nsBlue = num_nodes; rval = mb->get_coords(blueConn, nsBlue, &(blueCoords[0][0])); if (MB_SUCCESS != rval) return 1; // determine the type of edge: const lat or not? // just look at the consecutive z coordinates for the edge for (int i=0; i<nsBlue; i++) { int nexti=(i+1)%nsBlue; if ( fabs(blueCoords[i][2]- blueCoords[nexti][2]) < 1.e-6 ) blueEdgeType[i]=1; else blueEdgeType[i]=0; } area = 0.; nP = 0; // number of intersection points we are marking the boundary of blue! if (check_boxes_first) { // look at the boxes formed with vertices; if they are far away, return false early // make sure the red is setup already setup_red_cell(red, nsRed); // we do not need area here if (!GeomUtil::bounding_boxes_overlap(redCoords, nsRed, blueCoords, nsBlue, box_error)) return 0; // no error, but no intersection, decide early to get out } if (dbg_1) { std::cout << "red " << mb->id_from_handle(red) << "\n"; for (int j = 0; j < nsRed; j++) { std::cout << redCoords[j] << "\n"; } std::cout << "blue " << mb->id_from_handle(blue) << "\n"; for (int j = 0; j < nsBlue; j++) { std::cout << blueCoords[j] << "\n"; } mb->list_entities(&red, 1); mb->list_entities(&blue, 1); } for (int j=0; j<nsBlue; j++) { int rc = gnomonic_projection(blueCoords[j], R, plane, blueCoords2D[2 * j], blueCoords2D[2 * j + 1]); if (rc != 0) return 1; } if (dbg_1) { std::cout << "gnomonic plane: " << plane << "\n"; std::cout << " red blue\n"; for (int j = 0; j < nsRed; j++) { std::cout << redCoords2D[2 * j] << " " << redCoords2D[2 * j + 1] << "\n"; } for (int j = 0; j < nsBlue; j++) { std::cout << blueCoords2D[2 * j] << " " << blueCoords2D[2 * j + 1] << "\n"; } } int ret = EdgeIntxRllCs(blueCoords2D, blueCoords, blueEdgeType, nsBlue, redCoords2D, redCoords, nsRed, markb, markr, plane, R, P, nP); if (ret != 0) return 1; // some unforeseen error int side[MAXEDGES] = { 0 };// this refers to what side? blue or red?// more tolerant here with epsilon_area int extraPoints = borderPointsOfXinY2(blueCoords2D, nsBlue, redCoords2D, nsRed, &(P[2 * nP]), side, 2*epsilon_area); if (extraPoints >= 1) { for (int k = 0; k < nsBlue; k++) { if (side[k]) { // this means that vertex k of blue is inside convex red; mark edges k-1 and k in blue, // as being "intersected" by red; (even though they might not be intersected by other edges, // the fact that their apex is inside, is good enough) markb[k] = 1; markb[(k + nsBlue-1) % nsBlue] = 1; // it is the previous edge, actually, but instead of doing -1, it is // better to do modulo +3 (modulo 4) // null side b for next call side[k]=0; } } } nP += extraPoints; extraPoints = borderPointsOfCSinRLL(redCoords, redCoords2D, nsRed, blueCoords, nsBlue, blueEdgeType, &(P[2 * nP]), side, 100*epsilon_area); // we need to compare with 0 a volume from 3 vector product; // lots of round off errors at stake if (extraPoints >= 1) { for (int k = 0; k < nsRed; k++) { if (side[k]) { // this is to mark that red edges k-1 and k are intersecting blue markr[k] = 1; markr[(k + nsRed-1) % nsRed] = 1; // it is the previous edge, actually, but instead of doing -1, it is // better to do modulo +3 (modulo 4) // null side b for next call } } } nP += extraPoints; // now sort and orient the points in P, such that they are forming a convex polygon // this will be the foundation of our new mesh // this works if the polygons are convex SortAndRemoveDoubles2(P, nP, epsilon_1); // nP should be at most 8 in the end ? // if there are more than 3 points, some area will be positive if (nP >= 3) { for (int k = 1; k < nP - 1; k++) area += area2D(P, &P[2 * k], &P[2 * k + 2]); } return 0; // no error }