为3D打印生成外部支持者网格 [英] Generating outside supporters into mesh for 3D printing

查看:295
本文介绍了为3D打印生成外部支持者网格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

/ 49458901/2521214>为3D打印生成支持者,因为这是一个有趣的问题,但缺乏重要的细节...这是 Q& A 的目的,目前我正在研究答案,但随时回答(我接受最好的答案)。

问题描述



确定这里有一些关于问题的基本信息:

<粗糙的我们需要添加尽可能少量的材料,并且仍然具有足够的强度来固定我们的网格而不弯曲。除此之外,我们需要削弱网格附近的支撑,以便在打印后很容易中断。



不要忘记形状和位置依赖于很多诸如材料和技术的使用,热流。

问题:



如何合并 3D 三角网格(边界表示如



此形状将开始在一些基准平面上( Z = 0 ),并且会上升,直到碰到网格。但是为了实现这个功能,支持必须在网格和它自身之间有一个小的 gap ,我们将在后面添加我们弱化的关节结构。


  • 支持模式

    这里有很多选项,所以我选择了最简单然而),那就是将支持物放置在支撑物之间具有恒定距离 grid 的统一网格中。

    so只需从底座平面上的每个网格位置向上投射光线,并检查与网格的交点即可。如果发现将交叉点下的支撑位置设置为 gap >


  • 联接



    这个想法是加入非常薄的支撑体,以小于45度的角度覆盖主支撑棱镜上方的支撑表面(所以​​ gap 应该足够大以覆盖 grid 这样的距离)。

    这里的主要问题是我们必须细分我们连接的三角形,所以我们遇到 STL 网格属性。为了解决连接问题(避免 STL 的孔或断开连接要求),我们可以使用不同的实体用于支撑,不同的用于我们的网格。这也可以让我们触摸表面而不需要重新三角化它们,这使得这项任务变得更容易。

    为了简单起见,我选择了四面体的形状,它很容易从三角形构造而成,目前在网格/支撑关节处存在弱点。


  • 因此,让我们进行一些测试 STL 网格并将其放置在我们的基准平面之上:



    和地点我们的主要支持:



    以及关节:







    这里 STL3D.h 的VCL / C ++代码:

      // ----------------------------- ---------------------------------------------- 
    // ---简单的STL 3D网格----------------------------------------- -----------
    // --------------------------------- ------------------------------------------
    #ifndef _STL3D_h
    #define _STL3D_h
    // -------------------------------------- -------------------------------------
    #ifdef ComctrlsHPP
    TProgressBar *进度= NULL; //加载进度条以获得真正的大STL文件
    #endif
    void _progress_init(int n);
    void _progress(int ix);
    void _progress_done();
    // -------------------------------------------- -------------------------------
    class STL3D // STL 3D网格
    {
    公开:
    双中心[3],尺寸[3],rmax; // bbox center,half size,max(size [])
    struct _fac
    {
    float p [3] [3]; //三角形顶点CCW顺序
    float n [3]; //三角形单元正常指出
    WORD attr;
    _fac(){}
    _fac(_fac& a){* this = a; }
    〜_fac(){}
    _fac * operator =(const _fac * a){* this = * a;返回这个; }
    // _ fac * operator =(const _fac& a){... copy ... return this; }
    void compute()//计算正常
    {
    float a [3],b [3];
    vectorf_sub(a,p [1],p [0]);
    vectorf_sub(b,p [2],p [1]);
    vectorf_mul(n,a,b);
    vectorf_one(n,n);
    }
    double intersect_ray(double * pos,double * dir)//返回-1或与三角形和单位射线相交的距离
    {
    double p0 [3],p1 [ 3],P2 [3]; //输入三角形顶点
    double e1 [3],e2 [3],pp [3],qq [3],rr [3]; // dir必须是单位向量!
    double t,u,v,det,idet;
    //获得分数
    vector_ld(p0,p [0] [0],p [0] [1],p [0] [2]);
    vector_ld(p1,p [1] [0],p [1] [1],p [1] [2]);
    vector_ld(p2,p [2] [0],p [2] [1],p [2] [2]);
    //计算射线三角形交点
    vector_sub(e1,p1,p0);
    vector_sub(e2,p2,p0);
    //计算平面法线向量
    vector_mul(pp,dir,e2);
    det = vector_mul(e1,pp);
    //如果(fabs(det)< 1e-8)返回-1.0,则Ray平行于平面
    ;
    idet = 1.0 / det;
    vector_sub(rr,pos,p0);
    u = vector_mul(rr,pp)* idet;如果((u <0.0)||(u> 1.0))返回-1.0,则
    ;
    vector_mul(qq,rr,e1);
    v = vector_mul(dir,qq)* idet;如果((v <0.0)||(u + v> 1.0))返回-1.0,则
    ;
    //距离
    t = vector_mul(e2,qq)* idet;
    if(t <0.0)t = -1.0;
    return t;
    }
    };
    列表< _fac> FAC; // faces

    STL3D(){reset(); }
    STL3D(STL3D& a){* this = a; }
    〜STL3D(){}
    STL3D * operator =(const STL3D * a){* this = * a;返回这个; }
    // STL3D * operator =(const STL3D& a){... copy ... return this; }

    void reset(){fac.num = 0;计算(); } //清除STL
    void draw(); //渲染STL网格(OpenGL)
    void draw_normals(float size); //渲染STL法线(OpenGL)
    void compute(); //计算bbox
    void compute_normals(); //从点重新计算法线
    void supports(reper& obj); //计算obj在基础平面上的支持z = 0
    void load(AnsiString name);
    void save(AnsiString name);
    };
    // -------------------------------------------- -------------------------------
    void STL3D :: draw()
    {
    _fac * f; int i,j; BYTE r,g,b;
    glBegin(GL_TRIANGLES); (f = fac.dat,i = 0; i {
    glNormal3fv(f-> n); (f-> attr< 32768)
    {
    r = f-> attr& 31;为r< = 3;
    g =(f-> attr> 5)& 31; G<< = 3;
    b =(f-> attr> 10)& 31; b将< = 3;
    glColor3ub(r,g,b); (j = 0; j <3; j ++)glVertex3fv(f-> p [j])的
    }
    ;
    }
    glEnd();
    }
    // --------------------------------------- ------------------------------------
    void STL3D :: draw_normals(float size)
    {
    _fac * f;
    int i; float a [3],b [3];
    glBegin(GL_LINES); (f = fac.dat,i = 0; i {
    vectorf_add(a,f-> p [0],f-指p [1]);
    vectorf_add(a,a,f-> p [2]);
    vectorf_mul(a,a,1.0 / 3.0);
    vectorf_mul(b,f-> n,size); glVertex3fv(一);
    vectorf_add(b,b,a); glVertex3fv(b)中;
    }
    glEnd();
    }
    // --------------------------------------- ------------------------------------
    void STL3D :: compute()
    {
    _fac * f;
    int i,j,k;
    double p0 [3],p1 [3];
    vector_ld(center,0.0,0.0,0.0);
    vector_ld(size,0.0,0.0,0.0);
    rmax = 0.0;
    if(fac.num == 0)return;对于(k = 0; k <3; k ++)p0 [k] = fac.dat [0] .p [0] [k];
    // bbox
    ; (k = 0; k <3; k ++)p1 [k] = fac.dat [0] .p [0] [k]的
    ;对于(k = 0; j <3; j ++)
    ,对于(f = fac.dat,i = 0; i< fac.num; i ++,f ++) 0; k <3; k ++)
    {
    if(p0 [k]> f-> p [j] [k])p0 [k] = f-> p [j] [K];如果(p1 [k] p [j] [k])p1 [k] = f-> p [j] [k]
    }
    vector_add(center,p0,p1); vector_mul(中心,中央,0.5);
    vector_sub(size,p1,p0); vector_mul(size,size,0.5);
    rmax = size [0];
    if(rmax< size [1])rmax = size [1];
    if(rmax< size [2])rmax = size [2]; (f = fac.dat,i = 0; i< fac.num; i ++,f ++)
    // attr修复
    if(f-> attr == 0)f - > ATTR = 32768;
    }
    // --------------------------------------- ------------------------------------
    void STL3D :: compute_normals()
    {
    _fac * f; int i; (f = fac.dat,i = 0; i compute()的

    }
    // --------------------------------------- ------------------------------------
    void STL3D :: supports(reper& obj )
    {
    _fac * f,ff;
    int i,j,k;
    double p [3],dp [3],x0,y0,h0,x1,y1,x2,y2,h1,t;
    //一些配置值首先
    const WORD attr0 = 31 <10; //支持attr应该不同于联合
    const WORD attr1 = 31 <5; //联合attr应该与mesh不同,支持
    const double grid0 = 8.0; //支持之间的距离
    const double grid1 = 2.0; //关节之间的距离
    const double gap = grid0 / tan(45.0 * deg); //主支撑和网格之间的距离(关节大小)
    const double ha = 1.0; // main support side size
    //不要乱用这些
    const double hx = ha * cos(60.0 * deg); //主要支持的一半大小x
    const double hy = 0.5 * ha * sin(60.0 * deg); // y
    主要支持的一半大小double double grid2 = 0.4 * hy; //关节之间的距离base
    const double ga = 2.0 * grid2 * grid1 / grid0; //主要支持边大小
    const double gx = hx * grid2 / grid0; //联合支持的一半大小x
    const double gy = hy * grid2 / grid0; //在y

    中的联合支持的一半大小//应用placement obj(可能会失去一些准确性)如果不使用矩阵
    for(f = fac.dat,i = 0 (k = 0; k <3; i {
    (j = 0; j <3; j ++)
    {
    ; k ++)p [k] = f-> p [j] [k]; // float-> double
    obj.l2g(p,p); (k = 0; k <3; k ++)f-> p [j] [k] = p [k]时的
    ;对于(k = 0; k <3; k ++)p [k] = f-> n [k]; // double-> float
    }
    ; // float-> double
    obj.l2g_dir(p,p); (k = 0; k <3; k ++)f-> n [k] = p [k]时的
    ; // double-> float
    } compute();

    //创建支持
    (x0 = center [0] -size [0] +(0.5 * grid0); x0 <= center [0] + size [0] - ( 0.5 * grid0); x0 + = grid0)
    (y0 = center [1] -size [1] +(0.5 * grid0); y0 <= center [1] + size [1] - (0.5 * grid0 ); y0 + = grid0)
    {
    //在Z +方向投射射线x0,y0,0检查网格相交以计算支撑高度h0
    h0 = center [2] + size [2] + 1E6;
    vector_ld(p,x0,y0,0.0);
    vector_ld(dp,0.0,0.0,+ 1.0); (f = fac.dat,i = 0; i {
    t = f-> intersect_ray(p,dp);如果((t> = 0.0)&(t ;
    }
    if(h0> center [2] + size [2] + 1e5)继续; //跳过非相交光线
    h0- = gap;如果(h0 <0.0)h0 = 0.0;
    //主支持棱镜
    ff.attr = attr0;
    //双方
    ff.attr = attr0;
    vectorf_ld(ff.p [0],x0-hx,y0-hy,0.0);
    vectorf_ld(ff.p [1],x0 + hx,y0-hy,0.0);
    vectorf_ld(ff.p [2],x0-hx,y0-hy,h0); ff.compute(); fac.add(FF);
    vectorf_ld(ff.p [0],x0 + hx,y0-hy,0.0);
    vectorf_ld(ff.p [1],x0 + hx,y0-hy,h0);
    vectorf_ld(ff.p [2],x0-hx,y0-hy,h0); ff.compute(); fac.add(FF);

    vectorf_ld(ff.p [0],x0-hx,y0-hy,h0);
    vectorf_ld(ff.p [1],x0,y0 + hy,0.0);
    vectorf_ld(ff.p [2],x0-hx,y0-hy,0.0); ff.compute(); fac.add(FF);
    vectorf_ld(ff.p [0],x0-hx,y0-hy,h0);
    vectorf_ld(ff.p [1],x0,y0 + hy,h0);
    vectorf_ld(ff.p [2],x0,y0 + hy,0.0); ff.compute(); fac.add(FF);

    vectorf_ld(ff.p [0],x0,y0 + hy,h0);
    vectorf_ld(ff.p [1],x0 + hx,y0-hy,0.0);
    vectorf_ld(ff.p [2],x0,y0 + hy,0.0); ff.compute(); fac.add(FF);
    vectorf_ld(ff.p [0],x0,y0 + hy,h0);
    vectorf_ld(ff.p [1],x0 + hx,y0-hy,h0);
    vectorf_ld(ff.p [2],x0 + hx,y0-hy,0.0); ff.compute(); fac.add(FF);
    //基三角形
    vectorf_ld(ff.p [0],x0,y0 + hy,0.0);
    vectorf_ld(ff.p [1],x0 + hx,y0-hy,0.0);
    vectorf_ld(ff.p [2],x0-hx,y0-hy,0.0); ff.compute(); fac.add(FF);
    vectorf_ld(ff.p [0],x0-hx,y0-hy,h0);
    vectorf_ld(ff.p [1],x0 + hx,y0-hy,h0);
    vectorf_ld(ff.p [2],x0,y0 + hy,h0); ff.compute(); fac.add(FF);对于(x1 = x0-(0.5 * grid0),x2 = x0-(0.5 * grid2); x1 <= x0 +(0.5 * grid0); x1 + = grid1时,b
    $ b //关节
    (y1 = y0-(0.5 * grid0),y2 = y0-(1.9 * grid2); y1 <= y0 +(0.5 * grid0); y1 + = grid1,y2 + = ga)$ x2 + = ga) b $ b {
    //在Z +方向投射线x1,y1,0以检查网格相交以计算接缝高度h1
    h1 = h0 + gap + 1e6;
    vector_ld(p,x1,y1,0.0);
    vector_ld(dp,0.0,0.0,+ 1.0); (f = fac.dat,i = 0; i {
    t = f-> intersect_ray(p,dp);如果((t> = 0.0)&(t ;
    }
    if(h1> h0 + gap + 1e5)继续; //跳过非相交光线
    //四面体关节
    ff.attr = attr1;
    //基三角形
    vectorf_ld(ff.p [0],x2,y2 + gy,h0);
    vectorf_ld(ff.p [1],x2 + gx,y2-gy,h0);
    vectorf_ld(ff.p [2],x2-gx,y2-gy,h0); ff.compute(); fac.add(FF);
    //边
    vectorf_ld(ff.p [0],x2 + gx,y2-gy,h0);
    vectorf_ld(ff.p [1],x2,y2 + gy,h0);
    vectorf_ld(ff.p [2],x1,y1,h1); ff.compute(); fac.add(FF);
    vectorf_ld(ff.p [0],x2,y2 + gy,h0);
    vectorf_ld(ff.p [1],x2-gx,y2-gy,h0);
    vectorf_ld(ff.p [2],x1,y1,h1); ff.compute(); fac.add(FF);
    vectorf_ld(ff.p [0],x2 + gx,y2 + gy,h0);
    vectorf_ld(ff.p [1],x2-gx,y2-gy,h0);
    vectorf_ld(ff.p [2],x1,y1,h1); ff.compute(); fac.add(FF);



    //反向放置obj(可能会失去一些准确性)如果不使用矩阵
    for(f = fac.dat,i = 0; i {
    for(j = 0; j <3; j ++)
    {
    for(k = 0; k < 3; k ++)p [k] = f-> p [j] [k]; // float-> double
    obj.g2l(p,p); (k = 0; k <3; k ++)f-> p [j] [k] = p [k]时的
    ;对于(k = 0; k <3; k ++)p [k] = f-> n [k]; // double-> float
    }
    ; // float-> double
    obj.g2l_dir(p,p); (k = 0; k <3; k ++)f-> n [k] = p [k]时的
    ; // double-> float
    } compute();
    }
    // --------------------------------------- ------------------------------------
    void STL3D :: load(AnsiString name)
    {
    int adr,siz,hnd;
    BYTE * dat;
    AnsiString lin,s;
    int i,j,l,n;
    _fac f;

    reset(); f.attr = 0;
    siz = 0;
    hnd = FileOpen(name,fmOpenRead);
    if(hnd <0)return;
    siz = FileSeek(hnd,0,2);
    FileSeek(hnd,0,0);
    dat = new BYTE [siz];
    if(dat == NULL){FileClose(hnd);返回; }
    FileRead(hnd,dat,siz);
    FileClose(hnd);

    adr = 0; S = txt_load_str(DAT,SIZ,ADR,TRUE);
    // ASCII
    if(s ==solid)
    {
    _progress_init(siz); int progress_cnt = 0;
    for(adr = 0; adr< siz;)
    {
    progress_cnt ++; if(progress_cnt> = 128){progress_cnt = 0; _progress(ADR); }
    lin = txt_load_lin(dat,siz,adr,true);
    for(i = 1,l = lin.Length(); i <= l;)
    {
    s = str_load_str(lin,i,true);
    if(s ==solid){name = str_load_str(lin,i,true);打破; }
    if(s ==endsolid)break;
    if(s ==facet)
    {
    j = 0;
    s = str_load_str(lin,i,true);
    f.n [0] = str2num(str_load_str(lin,i,true));
    f.n [1] = str2num(str_load_str(lin,i,true));
    f.n [2] = str2num(str_load_str(lin,i,true));

    if(s ==vertex)
    if(j <3)
    {
    fp [j] [0] = str2num(str_load_str(lin ,I,真));
    f.p [j] [1] = str2num(str_load_str(lin,i,true));
    f.p [j] [2] = str2num(str_load_str(lin,i,true));
    j ++;
    if(j == 3)fac.add(f);
    }
    break;
    }
    }
    }
    //二元
    其他{
    adr = 80;
    n =((DWORD *)(dat + adr))[0]; ADR + = 4;
    fac.allocate(n); fac.num = 0;
    _progress_init(n); int progress_cnt = 0; (i = 0; i< n; i ++)
    {
    if(adr + 50> siz)break; //错误
    progress_cnt ++; if(progress_cnt> = 128){progress_cnt = 0; _progress(ⅰ); }
    f.n [0] =((float *)(dat + adr))[0]; ADR + = 4;
    f.n [1] =((float *)(dat + adr))[0]; ADR + = 4;
    f.n [2] =((float *)(dat + adr))[0]; ADR + = 4; (j = 0; j <3; j ++)
    {
    f.p [j] [0] =((float *)(dat + adr))[0]; ADR + = 4;
    f.p [j] [1] =((float *)(dat + adr))[0]; ADR + = 4;
    f.p [j] [2] =((float *)(dat + adr))[0]; ADR + = 4;
    }
    f.attr =((WORD *)(dat + adr))[0]; ADR + = 2; //属性
    fac.add(f);
    }
    }
    _progress_done();
    delete [] dat;
    compute();
    }
    // --------------------------------------- ------------------------------------
    void STL3D :: save(AnsiString name)
    {
    //待办事项
    }
    // ---------------------------- -----------------------------------------------
    void _progress_init(int n)
    {
    #ifdef ComctrlsHPP
    if(progress == NULL)return;
    progress-> Position = 0;
    progress-> Max = n;
    progress-> Visible = true;
    #endif
    }
    // --------------------------------- ------------------------------------------
    void _progress(int ix)
    {
    #ifdef ComctrlsHPP
    if(progress == NULL)return;
    progress-> Position = ix;
    progress-> Update();
    #endif
    }
    // --------------------------------- ------------------------------------------
    void _progress_done()
    {
    #ifdef ComctrlsHPP
    if(progress == NULL)return;
    progress-> Visible = false;
    #endif
    }
    // --------------------------------- ------------------------------------------
    #endif
    // ---------------------------------------------- -----------------------------

    用法很简单:

      #includeSTL3D.h// STL mesh(this is重要的东西)
    STL3D网格; //点云和四面体网格

    mesh.load(space_invader_magnet.stl);
    mesh.supports(obj); // obj是持有4x4统一矩阵的对象,如果你已经放置了STL而不是不需要

    我使用了很多来自我的OpenGL引擎的东西,比如动态 List> 模板:


    列表与LT;双> xxx; double xxx [];

    xxx.add(5) ; 5 添加到列表的末尾

    xxx [7] 访问数组元素(安全)

    xxx.dat [7] 访问数组元素(不安全但快速直接访问)
    > xxx.num 是实际使用的数组大小

    xxx.reset()清除数组并设置 xxx.num = 0

    xxx.allocate(100)预分配空间为 100 项目



    或向量和矩阵运算( vectorf _ 使用 float * vector < double )一起工作这并不太重要。如果您需要数学计算,请参阅:




    • 在设计支撑时,请记住您应该符合正确的缠绕规则(CCW)和正常方向(向外)为打印过程...


      Prologue

      This is my attempt to re-ask the closed Generating supporters for 3D printing as it is interesting question but lacking important details ... This is intended as Q&A and currently I am working on the code for the answer but feel free to answer (I accept the best answer).

      Problem description

      OK here some basic info about the problem:

      As this is a huge problem I will focus on the generic mesh/support-pattern merging geometry problem.

      In a nutshell If we want to print any mesh we can do it only if it is connected to the starting plane up to angle of ~45 degrees (+/- for different printing technologies). So if we got parts that are not connected to this plane we need to create a bridge that will hold/connect it to it. Something like this (image taken from the page linked above):

      Of coarse we need to add as small amount of material possible and still has it strong enough to hold our mesh in place without bending. On top of all this we need to weaken the support near the mesh so it can be break off after printing easily.

      Do not forget that shape and placement is dependent on many things like material and technology used, heat flow.

      Question:

      To narrow this huge topic to answerable question let us focus solely on this problem:

      How to merge 3D triangulated mesh (boundary representation like STL) with predefined support pattern (like 3 side prism) connecting it from defined plane perpendicularly ?

      Using simple C++.

      解决方案

      OK lets start with the absolute basics.

      1. support shape

        You can use any shape to meet the specifics of used printing technology. The easiest to generate within STL is 3 side prism like shape which contains 2 triangular bases (top and bottom) and 3 sides all of which have 2 triangles. So 8 triangles total.

        This shape will start at some base plane (Z=0) and will go up until it hits the mesh. However to make this work the support must have a small gap between mesh and itself where we will add our weakened joint structure with mesh latter on.

      2. support pattern

        there are a lot of options here so I chose the simplest (not foul proof however) and that is to place the supports in a uniform grid with constant distance grid between the supports.

        so simply cast a ray from each grid position on the base plane in up direction and check for intersection with mesh. If found place the support at that position with height just gap below the intersection point.

      3. Joints

        The idea is to join fan of very thin supports in cone like shape connecting & covering the supported surface above main support prism with less than 45 deg angle (so the gap should be big enough to cover grid distance in such manner).

        The main problem here is that we must subdivide the triangles we are connecting to so we meet the STL mesh properties. To solve the connection problem (avoid holes or breaking connection requirements of the STL) we can use different solid for supports and different for our mesh. That will also allow us to touch surfaces without re-triangulating them making this a lot easier task.

        For simplicity I chose tetrahedron shape which is simple to construct from triangles and also present weakness at the mesh/support joint.

      So let us take some test STL mesh and place it above our base plane:

      and place our main supports:

      and also the joints:

      Here VCL/C++ code for this STL3D.h:

      //---------------------------------------------------------------------------
      //--- simple STL 3D mesh ----------------------------------------------------
      //---------------------------------------------------------------------------
      #ifndef _STL3D_h
      #define _STL3D_h
      //---------------------------------------------------------------------------
      #ifdef ComctrlsHPP
      TProgressBar *progress=NULL;        // loading progress bar for realy big STL files
      #endif
      void _progress_init(int n);
      void _progress     (int ix);
      void _progress_done();
      //---------------------------------------------------------------------------
      class STL3D                         // STL 3D mesh
          {                                                                      
      public:
          double center[3],size[3],rmax;  // bbox center,half sizes, max(size[])
          struct _fac
              {
              float p[3][3];              // triangle vertexes CCW order
              float n[3];                 // triangle unit normal pointing out
              WORD attr;
              _fac()  {}
              _fac(_fac& a)   { *this=a; }
              ~_fac() {}
              _fac* operator = (const _fac *a) { *this=*a; return this; }
              //_fac* operator = (const _fac &a) { ...copy... return this; }
              void compute()                                  // compute normal
                  {
                  float a[3],b[3];
                  vectorf_sub(a,p[1],p[0]);
                  vectorf_sub(b,p[2],p[1]);
                  vectorf_mul(n,a,b);
                  vectorf_one(n,n);
                  }
              double intersect_ray(double *pos,double *dir)   // return -1 or distance to triangle and unit ray intersection
                  {
                  double p0[3],p1[3],p2[3];                   // input triangle vertexes
                  double e1[3],e2[3],pp[3],qq[3],rr[3];       // dir must be unit vector !!!
                  double t,u,v,det,idet;
                  // get points
                  vector_ld(p0,p[0][0],p[0][1],p[0][2]);
                  vector_ld(p1,p[1][0],p[1][1],p[1][2]);
                  vector_ld(p2,p[2][0],p[2][1],p[2][2]);
                  //compute ray triangle intersection
                  vector_sub(e1,p1,p0);
                  vector_sub(e2,p2,p0);
                  // Calculate planes normal vector
                  vector_mul(pp,dir,e2);
                  det=vector_mul(e1,pp);
                  // Ray is parallel to plane
                  if (fabs(det)<1e-8) return -1.0;
                  idet=1.0/det;
                  vector_sub(rr,pos,p0);
                  u=vector_mul(rr,pp)*idet;
                  if ((u<0.0)||(u>1.0)) return -1.0;
                  vector_mul(qq,rr,e1);
                  v=vector_mul(dir,qq)*idet;
                  if ((v<0.0)||(u+v>1.0)) return -1.0;
                  // distance
                  t=vector_mul(e2,qq)*idet;
                  if (t<0.0) t=-1.0;
                  return t;
                  }
              };
          List<_fac> fac;                         // faces
      
          STL3D() { reset(); }
          STL3D(STL3D& a) { *this=a; }
          ~STL3D() {}
          STL3D* operator = (const STL3D *a) { *this=*a; return this; }
          //STL3D* operator = (const STL3D &a) { ...copy... return this; }
      
          void reset(){ fac.num=0; compute(); }   // clear STL
          void draw();                            // render STL mesh (OpenGL)
          void draw_normals(float size);          // render STL normals (OpenGL)
          void compute();                         // compute bbox
          void compute_normals();                 // recompute normals from points
          void supports(reper &obj);              // compute supports with obj placement above base plane z=0
          void load(AnsiString name);
          void save(AnsiString name);
          };
      //---------------------------------------------------------------------------
      void STL3D::draw()
          {
          _fac *f; int i,j; BYTE r,g,b;
          glBegin(GL_TRIANGLES);
          for (f=fac.dat,i=0;i<fac.num;i++,f++)
              {
              glNormal3fv(f->n);
              if (f->attr<32768)
                  {
                  r= f->attr     &31; r<<=3;
                  g=(f->attr>> 5)&31; g<<=3;
                  b=(f->attr>>10)&31; b<<=3;
                  glColor3ub(r,g,b);
                  }
              for (j=0;j<3;j++) glVertex3fv(f->p[j]);
              }
          glEnd();
          }
      //---------------------------------------------------------------------------
      void STL3D::draw_normals(float size)
          {
          _fac *f;
          int i; float a[3],b[3];
          glBegin(GL_LINES);
          for (f=fac.dat,i=0;i<fac.num;i++,f++)
              {
              vectorf_add(a,f->p[0],f->p[1]);
              vectorf_add(a,a      ,f->p[2]);
              vectorf_mul(a,a,1.0/3.0);
              vectorf_mul(b,f->n,size); glVertex3fv(a);
              vectorf_add(b,b,a);       glVertex3fv(b);
              }
          glEnd();
          }
      //---------------------------------------------------------------------------
      void STL3D::compute()
          {
          _fac *f;
          int i,j,k;
          double p0[3],p1[3];
          vector_ld(center,0.0,0.0,0.0);
          vector_ld(size,0.0,0.0,0.0);
          rmax=0.0;
          if (fac.num==0) return;
          // bbox
          for (k=0;k<3;k++) p0[k]=fac.dat[0].p[0][k];
          for (k=0;k<3;k++) p1[k]=fac.dat[0].p[0][k];
          for (f=fac.dat,i=0;i<fac.num;i++,f++)
           for (j=0;j<3;j++)
            for (k=0;k<3;k++)
              {
              if (p0[k]>f->p[j][k]) p0[k]=f->p[j][k];
              if (p1[k]<f->p[j][k]) p1[k]=f->p[j][k];
              }
          vector_add(center,p0,p1); vector_mul(center,center,0.5);
          vector_sub(size  ,p1,p0); vector_mul(size  ,size  ,0.5);
                            rmax=size[0];
          if (rmax<size[1]) rmax=size[1];
          if (rmax<size[2]) rmax=size[2];
          // attr repair
          for (f=fac.dat,i=0;i<fac.num;i++,f++)
           if (f->attr==0) f->attr=32768;
          }
      //---------------------------------------------------------------------------
      void STL3D::compute_normals()
          {
          _fac *f; int i;
          for (f=fac.dat,i=0;i<fac.num;i++,f++) f->compute();
          }
      //---------------------------------------------------------------------------
      void STL3D::supports(reper &obj)
          {
          _fac *f,ff;
          int i,j,k;
          double p[3],dp[3],x0,y0,h0,x1,y1,x2,y2,h1,t;
          // some config values first
          const WORD   attr0=31<<10;              // support attr should be different than joint
          const WORD   attr1=31<<5;               // joint attr should be different than mesh,support
          const double grid0=8.0;                 // distance between supports
          const double grid1=2.0;                 // distance between joints
          const double gap=grid0/tan(45.0*deg);// distance between main support and mesh (joint size)
          const double ha=1.0;                    // main support side size
          // do not mess with these
          const double hx=    ha*cos(60.0*deg);   // half size of main support in x
          const double hy=0.5*ha*sin(60.0*deg);   // half size of main support in y
          const double grid2=0.4*hy;              // distance between joints bases
          const double ga=2.0*grid2*grid1/grid0;  // main support side size
          const double gx=hx*grid2/grid0;         // half size of joint support in x
          const double gy=hy*grid2/grid0;         // half size of joint support in y
      
          // apply placement obj (may lose some accuracy) not needed if matrices are not used
          for (f=fac.dat,i=0;i<fac.num;i++,f++)
              {
              for (j=0;j<3;j++)
                  {
                  for (k=0;k<3;k++) p[k]=f->p[j][k];  // float->double
                  obj.l2g(p,p);
                  for (k=0;k<3;k++) f->p[j][k]=p[k];  // double->float
                  }
              for (k=0;k<3;k++) p[k]=f->n[k]; // float->double
              obj.l2g_dir(p,p);
              for (k=0;k<3;k++) f->n[k]=p[k]; // double->float
              } compute();
      
          // create supports
          for (x0=center[0]-size[0]+(0.5*grid0);x0<=center[0]+size[0]-(0.5*grid0);x0+=grid0)
           for (y0=center[1]-size[1]+(0.5*grid0);y0<=center[1]+size[1]-(0.5*grid0);y0+=grid0)
              {
              // cast ray x0,y0,0 in Z+ direction to check for mesh intersection to compute the support height h0
              h0=center[2]+size[2]+1e6;
              vector_ld(p,x0,y0,0.0);
              vector_ld(dp,0.0,0.0,+1.0);
              for (f=fac.dat,i=0;i<fac.num;i++,f++)
                  {
                  t=f->intersect_ray(p,dp);
                  if ((t>=0.0)&&(t<h0)) h0=t;
                  }
              if (h0>center[2]+size[2]+1e5) continue; // skip non intersected rays
              h0-=gap; if (h0<0.0) h0=0.0;
              // main suport prism
              ff.attr=attr0;
              // sides
              ff.attr=attr0;
              vectorf_ld(ff.p[0],x0-hx,y0-hy,0.0);
              vectorf_ld(ff.p[1],x0+hx,y0-hy,0.0);
              vectorf_ld(ff.p[2],x0-hx,y0-hy, h0); ff.compute(); fac.add(ff);
              vectorf_ld(ff.p[0],x0+hx,y0-hy,0.0);
              vectorf_ld(ff.p[1],x0+hx,y0-hy, h0);
              vectorf_ld(ff.p[2],x0-hx,y0-hy, h0); ff.compute(); fac.add(ff);
      
              vectorf_ld(ff.p[0],x0-hx,y0-hy, h0);
              vectorf_ld(ff.p[1],x0   ,y0+hy,0.0);
              vectorf_ld(ff.p[2],x0-hx,y0-hy,0.0); ff.compute(); fac.add(ff);
              vectorf_ld(ff.p[0],x0-hx,y0-hy, h0);
              vectorf_ld(ff.p[1],x0   ,y0+hy, h0);
              vectorf_ld(ff.p[2],x0   ,y0+hy,0.0); ff.compute(); fac.add(ff);
      
              vectorf_ld(ff.p[0],x0   ,y0+hy, h0);
              vectorf_ld(ff.p[1],x0+hx,y0-hy,0.0);
              vectorf_ld(ff.p[2],x0   ,y0+hy,0.0); ff.compute(); fac.add(ff);
              vectorf_ld(ff.p[0],x0   ,y0+hy, h0);
              vectorf_ld(ff.p[1],x0+hx,y0-hy, h0);
              vectorf_ld(ff.p[2],x0+hx,y0-hy,0.0); ff.compute(); fac.add(ff);
              // base triangles
              vectorf_ld(ff.p[0],x0   ,y0+hy,0.0);
              vectorf_ld(ff.p[1],x0+hx,y0-hy,0.0);
              vectorf_ld(ff.p[2],x0-hx,y0-hy,0.0); ff.compute(); fac.add(ff);
              vectorf_ld(ff.p[0],x0-hx,y0-hy, h0);
              vectorf_ld(ff.p[1],x0+hx,y0-hy, h0);
              vectorf_ld(ff.p[2],x0   ,y0+hy, h0); ff.compute(); fac.add(ff);
      
              // joints
              for (x1=x0-(0.5*grid0),x2=x0-(0.5*grid2);x1<=x0+(0.5*grid0);x1+=grid1,x2+=ga)
               for (y1=y0-(0.5*grid0),y2=y0-(1.9*grid2);y1<=y0+(0.5*grid0);y1+=grid1,y2+=ga)
                  {
                  // cast ray x1,y1,0 in Z+ direction to check for mesh intersection to compute the joint height h1
                  h1=h0+gap+1e6;
                  vector_ld(p,x1,y1,0.0);
                  vector_ld(dp,0.0,0.0,+1.0);
                  for (f=fac.dat,i=0;i<fac.num;i++,f++)
                      {
                      t=f->intersect_ray(p,dp);
                      if ((t>=0.0)&&(t<h1)) h1=t;
                      }
                  if (h1>h0+gap+1e5) continue; // skip non intersected rays
                  // tetrahedron joints
                  ff.attr=attr1;
                  // base triangle
                  vectorf_ld(ff.p[0],x2   ,y2+gy,h0);
                  vectorf_ld(ff.p[1],x2+gx,y2-gy,h0);
                  vectorf_ld(ff.p[2],x2-gx,y2-gy,h0); ff.compute(); fac.add(ff);
                  // sides
                  vectorf_ld(ff.p[0],x2+gx,y2-gy,h0);
                  vectorf_ld(ff.p[1],x2   ,y2+gy,h0);
                  vectorf_ld(ff.p[2],x1   ,y1   ,h1); ff.compute(); fac.add(ff);
                  vectorf_ld(ff.p[0],x2   ,y2+gy,h0);
                  vectorf_ld(ff.p[1],x2-gx,y2-gy,h0);
                  vectorf_ld(ff.p[2],x1   ,y1   ,h1); ff.compute(); fac.add(ff);
                  vectorf_ld(ff.p[0],x2+gx,y2+gy,h0);
                  vectorf_ld(ff.p[1],x2-gx,y2-gy,h0);
                  vectorf_ld(ff.p[2],x1   ,y1   ,h1); ff.compute(); fac.add(ff);
                  }
              }
      
          // reverse placement obj (may lose some accuracy) not needed if matrices are not used
          for (f=fac.dat,i=0;i<fac.num;i++,f++)
              {
              for (j=0;j<3;j++)
                  {
                  for (k=0;k<3;k++) p[k]=f->p[j][k];  // float->double
                  obj.g2l(p,p);
                  for (k=0;k<3;k++) f->p[j][k]=p[k];  // double->float
                  }
              for (k=0;k<3;k++) p[k]=f->n[k]; // float->double
              obj.g2l_dir(p,p);
              for (k=0;k<3;k++) f->n[k]=p[k]; // double->float
              } compute();
          }
      //---------------------------------------------------------------------------
      void STL3D::load(AnsiString name)
          {
          int   adr,siz,hnd;
          BYTE *dat;
          AnsiString lin,s;
          int i,j,l,n;
          _fac f;
      
          reset(); f.attr=0;
          siz=0;
          hnd=FileOpen(name,fmOpenRead);
          if (hnd<0) return;
          siz=FileSeek(hnd,0,2);
              FileSeek(hnd,0,0);
          dat=new BYTE[siz];
          if (dat==NULL) { FileClose(hnd); return; }
          FileRead(hnd,dat,siz);
          FileClose(hnd);
      
          adr=0; s=txt_load_str(dat,siz,adr,true);
          // ASCII
          if (s=="solid")
              {
              _progress_init(siz); int progress_cnt=0;
              for (adr=0;adr<siz;)
                  {
                  progress_cnt++; if (progress_cnt>=128) { progress_cnt=0; _progress(adr); }
                  lin=txt_load_lin(dat,siz,adr,true);
                  for (i=1,l=lin.Length();i<=l;)
                      {
                      s=str_load_str(lin,i,true);
                      if (s=="solid") { name=str_load_str(lin,i,true); break; }
                      if (s=="endsolid") break;
                      if (s=="facet")
                          {
                          j=0;
                          s=str_load_str(lin,i,true);
                          f.n[0]=str2num(str_load_str(lin,i,true));
                          f.n[1]=str2num(str_load_str(lin,i,true));
                          f.n[2]=str2num(str_load_str(lin,i,true));
                          }
                      if (s=="vertex")
                       if (j<3)
                          {
                          f.p[j][0]=str2num(str_load_str(lin,i,true));
                          f.p[j][1]=str2num(str_load_str(lin,i,true));
                          f.p[j][2]=str2num(str_load_str(lin,i,true));
                          j++;
                          if (j==3) fac.add(f);
                          }
                      break;
                      }
                  }
              }
          // binary
          else{
              adr=80;
              n=((DWORD*)(dat+adr))[0]; adr+=4;
              fac.allocate(n); fac.num=0;
              _progress_init(n); int progress_cnt=0;
              for (i=0;i<n;i++)
                  {
                  if (adr+50>siz) break;  // error
                  progress_cnt++; if (progress_cnt>=128) { progress_cnt=0; _progress(i); }
                  f.n[0]=((float*)(dat+adr))[0]; adr+=4;
                  f.n[1]=((float*)(dat+adr))[0]; adr+=4;
                  f.n[2]=((float*)(dat+adr))[0]; adr+=4;
                  for (j=0;j<3;j++)
                      {
                      f.p[j][0]=((float*)(dat+adr))[0]; adr+=4;
                      f.p[j][1]=((float*)(dat+adr))[0]; adr+=4;
                      f.p[j][2]=((float*)(dat+adr))[0]; adr+=4;
                      }
                  f.attr=((WORD*)(dat+adr))[0]; adr+=2;   // attributes
                  fac.add(f);
                  }
              }
          _progress_done();
          delete[] dat;
          compute();
          }
      //---------------------------------------------------------------------------
      void STL3D::save(AnsiString name)
          {
          // ToDo
          }
      //---------------------------------------------------------------------------
      void _progress_init(int n)
          {
          #ifdef ComctrlsHPP
          if (progress==NULL) return;
          progress->Position=0;
          progress->Max=n;
          progress->Visible=true;
          #endif
          }
      //---------------------------------------------------------------------------
      void _progress     (int ix)
          {
          #ifdef ComctrlsHPP
          if (progress==NULL) return;
          progress->Position=ix;
          progress->Update();
          #endif
          }
      //---------------------------------------------------------------------------
      void _progress_done()
          {
          #ifdef ComctrlsHPP
          if (progress==NULL) return;
          progress->Visible=false;
          #endif
          }
      //---------------------------------------------------------------------------
      #endif
      //---------------------------------------------------------------------------
      

      Usage is simple:

      #include "STL3D.h"                  // STL mesh (this is the important stuff)
      STL3D mesh;                         // point cloud and tetrahedronal mesh
      
      mesh.load("space_invader_magnet.stl");
      mesh.supports(obj); //  obj is object holding 4x4 uniform matrix of placement if you STL is already placed than it is not needed
      

      I used a lot of stuff from mine OpenGL engine like dynamic List<> template:


      List<double> xxx; is the same as double xxx[];
      xxx.add(5); adds 5 to end of the list
      xxx[7] access array element (safe)
      xxx.dat[7] access array element (unsafe but fast direct access)
      xxx.num is the actual used size of the array
      xxx.reset() clears the array and set xxx.num=0
      xxx.allocate(100) preallocate space for 100 items

      or vector and matrix math (vectorf_ works with float* and vector_ with double) which is not too important. If you need the math see:

      If the STL is already placed (no matrix) than no placement conversions nor the obj is needed at all. The code reflects the bullets above. I wanted to keep it as simple as I could so no optimizations are there yet.

      The gap and grid constants are hard-coded in the supports function and are not yet set to the valid values.

      [Notes]

      Now this barely cover only the very basic of the problem and there are a lot of edge cases left un-handled to keep this "short". The code itself does not check if triangles are above the 45 degree slope but that can be done with simple normal angle checking like:

      if (acos(dot(normal,(0.0,0.0,1.0))<45.0*deg) continue;
      

      There is the need to add also the supports between parts of mesh for example if your object has more layers than only the first layer will be supported from base plane. the rest must use the layer below itself ... and using weakened joint on both sides of support. That is similar to place the first layer of supports you just need to cast the ray in both directions ... or cast continuous ray going through the whole bbox and check for start/end surfaces by analyzing normal direction to ray (simple sign of dot product). For example this is mesh placement that would possibly need this (for some technologies):

      While designing the supports take in mind you should meet the proper winding rule (CCW) and normal direction (out) for the printing process ...

      这篇关于为3D打印生成外部支持者网格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆