Example #1
0
static tb_void_t gb_demo_utils_mesh_tetrahedron()
{
    // trace
    tb_trace_i("==========================================================================");

    // init mesh
    gb_mesh_ref_t mesh = gb_mesh_init(tb_element_str(tb_true), tb_element_str(tb_true), tb_element_str(tb_true));
    if (mesh)
    {
        // init listener
        gb_mesh_listener_set(mesh, gb_demo_utils_mesh_listener, mesh);
        gb_mesh_listener_event_add(mesh, GB_MESH_EVENT_FACE_MERGE | GB_MESH_EVENT_FACE_SPLIT | GB_MESH_EVENT_EDGE_MERGE | GB_MESH_EVENT_EDGE_SPLIT);

        // make a clockwise self-loop edge
        gb_mesh_edge_ref_t edge0 = gb_mesh_edge_make_loop(mesh, tb_false);
        if (edge0)
        {
            /* make a tetrahedron
             *
             *                     e1
             *           v0 --------------> v1-----------------
             *            | .         rface |                  |
             *         e0 |        .        | e2     lface     |
             *            | face1     e5 .  |                  | e4
             *           v3 <-------------- v2                 | 
             *            |        e3                          | 
             *            |                                    |   face0
             *             <-----------------------------------
             *
             */
            gb_mesh_edge_ref_t edge1 = gb_mesh_edge_insert(mesh, edge0, edge0);
            gb_mesh_edge_ref_t edge2 = gb_mesh_edge_insert(mesh, edge1, edge0);
            gb_mesh_edge_ref_t edge3 = gb_mesh_edge_insert(mesh, edge2, edge0);

            // save face name
            gb_mesh_face_data_set(mesh, gb_mesh_edge_lface(edge0), "lface");
            gb_mesh_face_data_set(mesh, gb_mesh_edge_rface(edge0), "rface");

            gb_mesh_edge_ref_t edge4 = gb_mesh_edge_connect(mesh, edge1, edge0);
            gb_mesh_edge_ref_t edge5 = gb_mesh_edge_connect(mesh, gb_mesh_edge_sym(edge3), gb_mesh_edge_sym(edge0));

            // save face name
            gb_mesh_face_data_set(mesh, gb_mesh_edge_lface(edge4), "face0");
            gb_mesh_face_data_set(mesh, gb_mesh_edge_lface(edge5), "face1");

            // save edge name
            gb_mesh_edge_data_set(mesh, edge0, "e0");
            gb_mesh_edge_data_set(mesh, edge1, "e1");
            gb_mesh_edge_data_set(mesh, edge2, "e2");
            gb_mesh_edge_data_set(mesh, edge3, "e3");
            gb_mesh_edge_data_set(mesh, edge4, "e4");
            gb_mesh_edge_data_set(mesh, edge5, "e5");

            // save vertex name
            gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge0), "v0");
            gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge1), "v1");
            gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge2), "v2");
            gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge3), "v3");

#ifdef __gb_debug__
            // trace
            tb_trace_i("");
            tb_trace_i("tetrahedron: make");

            // check mesh
            gb_mesh_check(mesh);
        
            // dump mesh
            gb_mesh_dump(mesh);
#endif

            // delete two
            gb_mesh_edge_delete(mesh, edge4);
            gb_mesh_edge_delete(mesh, edge5);

#ifdef __gb_debug__
            // trace
            tb_trace_i("");
            tb_trace_i("tetrahedron: kill");

            // check mesh
            gb_mesh_check(mesh);
        
            // dump mesh
            gb_mesh_dump(mesh);
#endif

            // remove all
            gb_mesh_edge_remove(mesh, edge2);
            gb_mesh_edge_remove(mesh, edge3);
            gb_mesh_edge_remove(mesh, edge0);
            gb_mesh_edge_remove(mesh, edge1);

            // check
            tb_assert_abort(gb_mesh_is_empty(mesh));
        }
    
        // exit mesh
        gb_mesh_exit(mesh);
    }
}
Example #2
0
File: mesh.c Project: waruqi/gbox
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_bool_t gb_tessellator_mesh_make(gb_tessellator_impl_t* impl, gb_polygon_ref_t polygon)
{
    // check
    tb_assert(impl && polygon);

    // the points
    gb_point_ref_t      points = polygon->points;
    tb_uint16_t const*  counts = polygon->counts;
    tb_assert_and_check_return_val(points && counts, tb_false);

    // not exists mesh?
    if (!impl->mesh) 
    {
        // init func
        tb_element_t edge_element    = tb_element_mem(sizeof(gb_tessellator_edge_t), tb_null, tb_null);
        tb_element_t face_element    = tb_element_mem(sizeof(gb_tessellator_face_t), tb_null, tb_null);
        tb_element_t vertex_element  = tb_element_mem(sizeof(gb_tessellator_vertex_t), tb_null, tb_null);

#ifdef __gb_debug__
        // init func cstr for gb_mesh_dump
        edge_element.cstr      = gb_tessellator_edge_cstr;
        face_element.cstr      = gb_tessellator_face_cstr;
        vertex_element.cstr    = gb_tessellator_vertex_cstr;
#endif

        // init mesh
        impl->mesh = gb_mesh_init(edge_element, face_element, vertex_element);

        /* init the order
         *
         * the new edges/faces/vertice will be inserted to the head of list
         */
        gb_mesh_edge_order_set(impl->mesh,      GB_MESH_ORDER_INSERT_HEAD);
        gb_mesh_face_order_set(impl->mesh,      GB_MESH_ORDER_INSERT_HEAD);
        gb_mesh_vertex_order_set(impl->mesh,    GB_MESH_ORDER_INSERT_HEAD);

        // init listener
        gb_mesh_listener_set(impl->mesh, gb_tessellator_listener, impl->mesh);
        gb_mesh_listener_event_add(impl->mesh, GB_MESH_EVENT_FACE_SPLIT | GB_MESH_EVENT_EDGE_SPLIT);
    }

    // check
    gb_mesh_ref_t mesh = impl->mesh;
    tb_assert_and_check_return_val(mesh, tb_false);

    // clear mesh first
    gb_mesh_clear(mesh);

    // done
    gb_point_ref_t      point       = tb_null;
    tb_uint16_t         count       = *counts++;
    tb_size_t           index       = 0;
    gb_mesh_edge_ref_t  edge        = tb_null;
    gb_mesh_edge_ref_t  edge_first  = tb_null;
    while (index < count)
    {
        // the point
        point = points++;

        // first point?
        if (!index) 
        {
            // must be closed contour
            tb_assertf(gb_point_eq(point, point + count - 1), "this contour(%lu: %{point} => %{point}) is not closed!", count, point, point + count - 1);
            
            // clear the edge
            edge = tb_null;

            // clear the first edge
            edge_first = tb_null;

            // trace
            tb_trace_d("move_to: %{point}", point);
        }
        // closed?
        else if (index + 1 == count)
        {
            // trace
            tb_trace_d("closed: %{point}", point);

            // connect an edge to the first edge
            edge = gb_mesh_edge_connect(mesh, edge, edge_first);

            // init edge.faces.inside
            gb_tessellator_face_inside_set(gb_mesh_edge_lface(edge), 0);
            gb_tessellator_face_inside_set(gb_mesh_edge_rface(edge), 0);
        }
        else 
        {
            // trace
            tb_trace_d("line_to: %{point}", point);

            // exists the first edge?
            if (edge_first)
            {
                // append an edge
                edge = gb_mesh_edge_append(mesh, edge);
            }
            else
            {
                // make a new non-loop edge
                edge = gb_mesh_edge_make(mesh);

                // save the first edge
                edge_first = edge;
            }
        }

        // has new edge?
        if (edge)
        {
            // init edge.winding
            gb_tessellator_edge_winding_set(edge, 1);
            gb_tessellator_edge_winding_set(gb_mesh_edge_sym(edge), -1);

            // init edge.region
            gb_tessellator_edge_region_set(edge, tb_null);
            gb_tessellator_edge_region_set(gb_mesh_edge_sym(edge), tb_null);

            // init edge.dst
            gb_tessellator_vertex_point_set(gb_mesh_edge_dst(edge), point);
        }

        // next point
        index++;

        // next polygon
        if (index == count) 
        {
            // next
            count = *counts++;
            index = 0;
        }
    }

#ifdef __gb_debug__
    // check mesh
    gb_mesh_check(mesh);
#endif

    // ok?
    return !gb_mesh_is_empty(mesh);
}
Example #3
0
/* make triangulation region 
 *
 * TODO need optimization, maybe generate some degenerated triangles
 *
 * the region of this face must be horizontal monotone and counter-clockwise loop
 *                      
 * before:
 *
 *                  ccw
 *             <------------
 *            |             |
 *         
 *                   1                
 *                 .   .    right
 *      left     .       2
 *             .       .
 *           .       .  
 *         3        4
 *          .        .
 *           .        .
 *            5        .
 *           .          .  
 *          .            .
 *         .              .
 *        6                .    
 *         .                .
 *          .               7
 *           .             .
 *            8          . 
 *            .        9
 *            .        .
 *           10        11
 *             .      .
 *                .  .  
 *                 12
 *                      
 *     |                        |
 *     |                        |
 *    \ /                      \ /
 *
 *
 * after:
 *                   1                
 *                 .   .    R2
 *      L1       .     . 2
 *             .   .L4 .
 *           . .     .  R3
 *         3 . . R6 4
 *          .      . .
 *        L5 .  .L8   .
 *            5        .
 *           .   .      . R7 
 *       L9 .     R11    .
 *         .         .    .
 *        6  .  R12        .    
 *         .        .     . .
 *      L10 .             . 7
 *           .   L14 .     .
 *            8 .        . R13
 *            .  R16 . 9
 *        L15 .        .
 *           10  L18 . 11
 *              .     .
 *           L19  .  .  R17
 *                 12
 *
 */
static tb_void_t gb_tessellator_triangulation_make_face(gb_tessellator_impl_t* impl, gb_mesh_face_ref_t face)
{
    // check
    tb_assert_abort(impl && face);

    // the mesh
    gb_mesh_ref_t mesh = impl->mesh;
    tb_assert_abort(mesh);

    // the face edge
    gb_mesh_edge_ref_t edge = gb_mesh_face_edge(face);

    // must be triangle region at least
    tb_assert_abort(edge && gb_mesh_edge_lnext(edge) != edge && gb_mesh_edge_lnext(gb_mesh_edge_lnext(edge)) != edge);

    /* get the uppermost left edge
     *
     * @note the face edge has been optimizated when we made monotone polygon.
     *
     *          . 
     * left   .   .  right
     *      .       .
     *       .        .
     *        .       .
     *         .      .
     */
    gb_mesh_edge_ref_t left = edge;
    while (gb_tessellator_edge_go_down_(left)) left = gb_mesh_edge_lprev(left);
    while (gb_tessellator_edge_go_up_(left)) left = gb_mesh_edge_lnext(left);

    // get the uppermost right edge
    gb_mesh_edge_ref_t right = gb_mesh_edge_lprev(left);

    // done
    while (gb_mesh_edge_lnext(left) != right) 
    {
        /* the right edge is too lower? done some left edges
         *
         *          .
         * left   .   . right 
         *  dst .       .
         *       .        . org
         *        .       . 
         *         .      .
         */
        if (gb_tessellator_vertex_in_top_or_horizontal_(gb_mesh_edge_dst(left), gb_mesh_edge_org(right))) 
        {
            /* done some left edges
             *
             * go up? connect it
             *
             *     .
             *     .    .
             *     .        .
             *     .            .
             *  L  .   L1   .    .
             *     .     .        .
             *     .  .            .
             *     .  .  .  .  . .  .
             *             L2     .
             *                  . R
             *                .
             *
             *
             * on left? connect it
             *
             * TODO: will generate some degenerated triangles
             *
             *             .
             *           . .
             * on left?. . .
             *       .     .
             *     .    .  .
             *     .       .
             *   L .  .    . R
             *     ..      .
             *     .       .
             *    .        .
             *   .         .
             *             .
             *             .
             */
            while ( gb_mesh_edge_lnext(right) != left
                &&  (   gb_tessellator_edge_go_up_(gb_mesh_edge_lprev(left))
                    ||  gb_tessellator_vertex_on_edge_or_left_( gb_mesh_edge_org(left)
                                                            ,   gb_mesh_edge_org(gb_mesh_edge_lprev(left))
                                                            ,   gb_mesh_edge_dst(left))))
            {
                // connect it
                edge = gb_mesh_edge_connect(mesh, left, gb_mesh_edge_lprev(left));
                tb_assert_abort_and_check_return(edge);

                // update the left edge
                left = gb_mesh_edge_sym(edge);
            }

            // the next left edge
            left = gb_mesh_edge_lnext(left);
        } 
        /* the left edge is too lower? done some right edges
         *
         *           .
         *   left  .   . right  
         *       .       . org
         * dst .        .
         *     .       .  
         *     .      .
         */
        else
        {
            /* done some right edges
             * 
             * go down? connect it
             *
             *                      .
             *                 .    .
             *             .        .
             *         .            . R
             *        .   .   R1    .
             *       .       .      .
             *      .  R2       .   .
             *     . . . . . . . .  .
             *       . 
             *      L  .
             *           .
             *
             * on right? connect it
             *
             * TODO: will generate some degenerated triangles
             *
             *     . 
             *     .  .
             *     .  .  . 
             *     .   .   .
             *     .    .    . on right?
             *     .     .   .
             *   L .      .  . R
             *     .       . .
             *     .         .
             *     .           . 
             *     .             .
             *     .            
             *     .
             */
            while ( gb_mesh_edge_lnext(right) != left
                &&  (   gb_tessellator_edge_go_down_(gb_mesh_edge_lnext(right))
                    ||  gb_tessellator_vertex_on_edge_or_right_(gb_mesh_edge_dst(right)
                                                            , gb_mesh_edge_dst(gb_mesh_edge_lnext(right))
                                                            , gb_mesh_edge_org(right))))
            {
                // connect it
                edge = gb_mesh_edge_connect(mesh, gb_mesh_edge_lnext(right), right);
                tb_assert_abort_and_check_return(edge);

                // update the right edge
                right = gb_mesh_edge_sym(edge);
            }

            // the next right edge
            right = gb_mesh_edge_lprev(right);
        }
    }
    
    // the last region must be triangle at least
    tb_assert_abort(gb_mesh_edge_lnext(right) != left);

    /* tessellate the remaining region
     *
     *     . . . . 
     *   .        .
     * .           .
     *    .         .
     * left  .    . right
     *          .
     *
     */
    while (gb_mesh_edge_lnext(gb_mesh_edge_lnext(right)) != left) 
    {
        // connect it
        edge = gb_mesh_edge_connect(mesh, gb_mesh_edge_lnext(right), right);
        tb_assert_abort_and_check_return(edge);

        // the next edge
        right = gb_mesh_edge_sym(edge);
    }
}