Author Topic: Best practice for union of several solids with overlapp  (Read 152 times)

matthest

  • Newbie
  • *
  • Posts: 3
    • View Profile
Hi. Wondering if there is some sort of best practice for adding several solids on top of each other.

I have an example with three solids made out of sinusoidal functions called circle_bottom(), circle_middle(), and circle_top().
Having added them in a sum "return circle_bottom()+ circle_top()" works, but "return circle_bottom()+ circle_top() + circle_middle();" removes the first two solids.

I get some warnings etc, but I am nut sure how to debug:
Code: [Select]
Warning: Polyhedron is not water-tight, it has 8 edges, 8 with wrong use count, 8 with use-count==1
https://imgur.com/LPWtILJ
https://imgur.com/X36oa4V

Code: [Select]
// AngelCAD sample: vase_with_handle.as
// This example demonstrates use of sweep
#include "circlemaker.h"



shape@ main_shape()
{
   // scale down for web visualisation
   return circle_bottom()+ circle_top() + circle_middle();
}

void main()
{
   shape@ obj = main_shape();
   obj.write_xcsg(GetInputFullPath(),secant_tolerance:-1.0);
}


Code: [Select]
solid@ circle_middle()
{
   
   shape2d@ prof = circle(r:2);
   pos3d@[] p;
   vec3d@[] v;
   double dt = 10.0;
   double ds = 2*PI/40;
   double alpha = 0;
   
   double x_; // new x value after movement
   double z_; // new z value after movement
   
   for(uint i=0; i<21; i++) {
      double x= 40*sin(i*ds);
      double y = 40*cos(i*ds);
      double z = 40*(-cos(2*PI*x/(40*4)));
     
      double hypotenus =x;
      if(x != 0){
         alpha = atan(z/x);
         print("x="+x);
         print("\n");
         print("z="+z);
         print("\n");
         x_ = hypotenus*cos(alpha);
         z_ = hypotenus*sin(alpha);
         print("x' = "+x_);
         print("\n");
         print("z' = "+z_);
         print("\n");
         print("alpha="+alpha/(2*PI)*360+" degrees");
         print("\n\r");

      }
      else{
         alpha = 0;
         print("x="+x);
         print("\n");
         print("z="+z);
         print("\n");
         x_ = hypotenus*cos(alpha);
         z_ = hypotenus*sin(alpha);
         print("x' = "+x_);
         print("\n");
         print("z' = "+z_);
         print("\n");
         print("alpha="+alpha/(2*PI)*360+" degrees");
         print("\n\r");
      }
     
     
      p.push_back(
         pos3d(x_, y, z_)
         ); // straight line
      v.push_back(vec3d(1,0,0));   // sine curve radius
   }

   spline_path@ path = spline_path(p,v);
   return sweep(prof,path);
}

solid@ circle_top()
{
   
   shape2d@ prof = circle(r:2);
   pos3d@[] p;
   vec3d@[] v;
   double dt = 10.0;
   double ds = 2*PI/40;
   double alpha = 0;
   double x_; // new x value after movement
   double z_; // new z value after movement
   
   for(uint i=0; i<21; i++) {
      double x= 40*sin(i*ds);

      double y = 40*cos(i*ds);
      double z = 40+40*(-cos(2*PI*x/(40*4)));
      double hypotenus =x;
      if(x != 0){
         alpha = atan(z/x);
         print("x="+x);
         print("\n");
         print("z="+z);
         print("\n");
         x_ = hypotenus*cos(alpha);
         z_ = hypotenus*sin(alpha);
         print("x' = "+x_);
         print("\n");
         print("z' = "+z_);
         print("\n");
         print("alpha="+alpha/(2*PI)*360+" degrees");
         print("\n\r");

      }
      else{
         alpha = 0;
         print("x="+x);
         print("\n");
         print("z="+z);
         print("\n");
         x_ = hypotenus*cos(alpha);
         z_ = hypotenus*sin(alpha);
         print("x' = "+x_);
         print("\n");
         print("z' = "+z_);
         print("\n");
         print("alpha="+alpha/(2*PI)*360+" degrees");
         print("\n\r");
      }
     
     
      p.push_back(
         pos3d(x_, y, z_)
         ); // straight line
      v.push_back(vec3d(1,0,0));   // sine curve radius
   }

   spline_path@ path = spline_path(p,v);
   return sweep(prof,path);
}


solid@ circle_bottom()
{
   shape2d@ prof = circle(r:2);
   pos3d@[] p;
   vec3d@[] v;
   double dt = 10.0;
   double ds = 2*PI/40;
   
   for(uint i=0; i<21; i++) {
      p.push_back(pos3d(40*sin(i*ds),40*cos(i*ds),0)); // straight line
      v.push_back(vec3d(1,0,0));   // sine curve radius
   }

   spline_path@ path = spline_path(p,v);
   return sweep(prof,path);
}

Carsten Arnholm

  • Administrator
  • Newbie
  • *****
  • Posts: 44
    • View Profile
Re: Best practice for union of several solids with overlapp
« Reply #1 on: 2020-06-07, 16:51:16 »
Hello, interesting example. Is this for some real life modelling, or just "random testing"? I will need a bit of time to study it before coming back with more specific answers, please allow for that.

In general, the polyhedron warning can be a real issue or sometimes kind of false alarm. A polyhedron with 8 edges, all with use count 1 sounds like a couple of loose faces, so possibly a real issue.

In general, you want solids to slightly overlap each other, i.e. not "exact" face/face intersections as that can be ambiguous. This sort of thing can sometimes be a little tricky to get right.  As noted, I will try your code later.

matthest

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Best practice for union of several solids with overlapp
« Reply #2 on: 2020-06-07, 17:18:33 »
Hi Carsten. the result is not going to look like this, but it is interesting for an analysis I have in modeling of an optical cable.
Optical cables have loss when being bent to much and I will use this to find best case e.g bend radius on optical cables.

I have time to wait, and I think the answer you come up with would be very interesting for other solids, as well as for debugging issues later.
Thanks for your effort

Carsten Arnholm

  • Administrator
  • Newbie
  • *****
  • Posts: 44
    • View Profile
Re: Best practice for union of several solids with overlapp
« Reply #3 on: 2020-06-08, 08:31:41 »
Hi, after a quick review I think the problem is trying to union tubular shapes with same radius, but not identical mesh representations at the ends where the circular shapes meet. This sometimes works, sometimes not. For example, this kind of works

Code: [Select]
shape@ main_shape()
{
   // scale down for web visualisation
   return circle_bottom()+ mirror(1,0,0)*circle_top();
}

See attached image.

But the result is not perfect because the intersection between the two shapes edges don't line up at the ends. All the boolean operations are mesh based, so everything is discretized into meshes with triangular faces and straight edges. For circular cross sections like in this case you may end up with different discretizations that don't always result in a useful result after a boolean operation. In this case you get the "Warning: Polyhedron is not water-tight" message for this reason. If you don't do the mirror the problem is more severe (because tubes with same radus/different discretization meet "everywhere") and you might end up with losing parts as you saw.

One possible remedy is to create a "junction cylinder" with slightly larger radius so that the other shapes meet a flat surface, causing fewer problems with non-aligning edges. Perhaps this is acceptable for your use, perhaps not.

In essence I think this is what you are seeing.