Beispiel #1
0
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;
}
Beispiel #2
0
/*
 * 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;
}
Beispiel #6
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; 
}
Beispiel #7
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;
}
Beispiel #8
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;
                }
            }
        }
Beispiel #10
0
/* 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
}