star-enclosures-3d

Extract enclosures from 3D geometry
git clone git://git.meso-star.fr/star-enclosures-3d.git
Log | Files | Refs | README | LICENSE

commit 03851d9783bae8a8af2bde36cab66ea9863d59be
parent 0088efdaab3a8ded2b626fdabdeccb2cdddf6512
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue,  9 Apr 2024 15:45:35 +0200

Merge branch 'release_0.6'

Diffstat:
MREADME.md | 8++++++++
Mcmake/CMakeLists.txt | 7++++---
Msrc/senc3d.h | 11++++++++++-
Msrc/senc3d_scene_analyze.c | 770++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/senc3d_scene_analyze_c.h | 4++++
Asrc/test_senc3d_glazing.c | 1127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_senc3d_unspecified_medium.c | 41++++++++++++++++++++---------------------
Msrc/test_senc3d_utils.h | 4+++-
Msrc/test_senc3d_zero_distance.c | 749++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
9 files changed, 2466 insertions(+), 255 deletions(-)

diff --git a/README.md b/README.md @@ -39,6 +39,14 @@ variable the install directories of its dependencies. Release notes ------------- +### Version 0.6 + +- Major rework on the code that groups connex components to create enclosures. +- Add tests showing bugs at the grouping stage in previous release. +- Add debug code that allows to dump how connex components are grouped. +- Fix compilation warnings. +- Sets the required version of Star-3D to 0.9. + ### Version 0.5.5 - Fixes a crash linked to numerical accuracy that caused connex components diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -30,7 +30,7 @@ cmake_dependent_option(HUGE_ADDITIONAL_TESTS # Check dependencies ############################################################################### find_package(RCMake 0.4 REQUIRED) -find_package(Star3D 0.8 REQUIRED) +find_package(Star3D 0.9 REQUIRED) find_package(RSys 0.8.1 REQUIRED) find_package(OpenMP 2.0 REQUIRED) @@ -63,8 +63,8 @@ endif() # Configure and define targets ############################################################################### set(VERSION_MAJOR 0) -set(VERSION_MINOR 5) -set(VERSION_PATCH 5) +set(VERSION_MINOR 6) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SENC3D_FILES_SRC @@ -162,6 +162,7 @@ if(NOT NO_TEST) new_test(test_senc3d_some_triangles) new_test(test_senc3d_unspecified_medium) new_test(test_senc3d_zero_distance) + new_test(test_senc3d_glazing) target_link_libraries(test_senc3d_enclosure Star3D) rcmake_copy_runtime_libraries(test_senc3d_enclosure) diff --git a/src/senc3d.h b/src/senc3d.h @@ -141,7 +141,16 @@ enum senc3d_convention { /* Geometrical normals point toward the enclosure */ SENC3D_CONVENTION_NORMAL_INSIDE = BIT(2), /* Geometrical normals point to the opposite of the enclosure */ - SENC3D_CONVENTION_NORMAL_OUTSIDE = BIT(3) + SENC3D_CONVENTION_NORMAL_OUTSIDE = BIT(3), + + /* + * Additional bits used for debugging purposes + */ + + /* Dump identified connex components before grouping in STL files */ + SENC3D_DUMP_COMPONENTS_STL = BIT(4), + /* Extensive logs on grouping algorithm */ + SENC3D_LOG_COMPONENTS_INFORMATION = BIT(5) }; BEGIN_DECLS diff --git a/src/senc3d_scene_analyze.c b/src/senc3d_scene_analyze.c @@ -27,8 +27,10 @@ #include <rsys/mem_allocator.h> #include <rsys/hash_table.h> #include <rsys/dynamic_array.h> +#include <rsys/dynamic_array_uint.h> #include <rsys/dynamic_array_uchar.h> #include <rsys/clock_time.h> +#include <rsys/str.h> #include <star/s3d.h> @@ -38,7 +40,7 @@ #include <stdlib.h> #define CC_DESCRIPTOR_NULL__ {\ - 0, 0, NULL,\ + 0, 0, {{DBL_MAX,-DBL_MAX}, {DBL_MAX,-DBL_MAX}, {DBL_MAX,-DBL_MAX}}, NULL,\ 0, INT_MAX, VRTX_NULL__, 0,\ CC_ID_NONE, CC_GROUP_ROOT_NONE, ENCLOSURE_NULL__,\ { TRG_NULL__, 0}\ @@ -61,15 +63,28 @@ const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__; #define HTABLE_DATA char #include <rsys/hash_table.h> +/* A threshold for dot products: + * If ray.normal < threshold we suspect accuracy could be a problem */ +#define DOT_THRESHOLD 0.0001f + +struct filter_ctx0 { + component_id_t origin_component; + struct darray_triangle_comp* triangles_comp; +}; + struct filter_ctx1 { struct senc3d_scene* scn; struct s3d_scene_view* view; component_id_t origin_component; struct darray_triangle_comp* triangles_comp; struct darray_ptr_component_descriptor* components; - /* Result of hit */ + /* Tmp data used across filter calls */ double current_6volume; + float s; + /* Result of hit */ component_id_t hit_component; + float hit_dir[3], hit_dist; + struct s3d_primitive hit_prim; }; struct filter_ctx2 { @@ -79,6 +94,7 @@ struct filter_ctx2 { }; enum fctx_type { + FCTX0, FCTX1, FCTX2 }; @@ -86,6 +102,7 @@ enum fctx_type { struct filter_ctx { enum fctx_type type; union { + struct filter_ctx0 ctx0; struct filter_ctx1 ctx1; struct filter_ctx2 ctx2; } c; @@ -107,6 +124,76 @@ neighbour_cmp(const void* w1, const void* w2) return (a1 > a2) - (a1 < a2); } +/* Returns 1 if cc2 is inside cc1, 0 otherwise */ +static FINLINE int +is_component_inside + (struct cc_descriptor* cc1, + struct cc_descriptor* cc2, + struct filter_ctx1* ctx) +{ + int i; + side_id_t side; + const struct triangle_in* trg = NULL; + double pt[3] = { 0, 0, 0 }; + float org[3], dir[3] = { 0, 0, 1 }, rg[2] = { 0, FLT_MAX }; + struct filter_ctx ctx2; + struct s3d_hit hit = S3D_HIT_NULL; + const struct triangle_comp* + trg_comp = darray_triangle_comp_cdata_get(ctx->triangles_comp); + const struct triangle_in* + triangles = darray_triangle_in_cdata_get(&ctx->scn->triangles_in); + const union double3* vertices = darray_position_cdata_get(&ctx->scn->vertices); + ASSERT(cc1 && cc2 && ctx); + /* Volume must be compatible */ + if(fabs(cc2->_6volume) >= fabs(cc1->_6volume)) + return 0; + /* Bbox must be compatible */ + for(i = 0; i < 3; i++) { + if(cc2->bbox[i][0] < cc1->bbox[i][0] || cc2->bbox[i][1] > cc1->bbox[i][1]) + return 0; + } + /* Check if component cc2 is inside component cc1. + * We already know that bbox and volume allow cc2 to fit inside component + * ccc1, but it is not enough. + * The method is to cast a ray from cc2 and count the number of times it + * crosses component cc1; as components must not overlap, testing from a + * single point is OK, as long as the point is not on cc1 boundary (it is on + * cc2 boundary, though). */ + for(side = cc2->side_range.first; side <= cc2->side_range.last; side++) { + /* Find a triangle on cc2 boundary that is not on cc1 boundary (it exists, + * as the 2 components cannot share all their triangles) */ + trg_id_t t = TRGSIDE_2_TRG(side); + const component_id_t* candidate_comp = trg_comp[t].component; + if(candidate_comp[SENC3D_FRONT] != cc2->cc_id + && candidate_comp[SENC3D_BACK] != cc2->cc_id) + continue; + if(candidate_comp[SENC3D_FRONT] == cc1->cc_id + || candidate_comp[SENC3D_BACK] == cc1->cc_id) + continue; + /* This triangle is OK */ + trg = triangles + t; + break; + } + ASSERT(trg != NULL); + /* Any point on trg can do the trick: use the barycenter */ + FOR_EACH(i, 0, 3) { + vrtx_id_t v = trg->vertice_id[i]; + ASSERT(v < darray_position_size_get(&ctx->scn->vertices)); + d3_add(pt, pt, vertices[v].vec); + } + d3_divd(pt, pt, 3); + f3_set_d3(org, pt); + /* Trace a ray and count intersections with component c */ + ctx2.type = FCTX2; + ctx2.c.ctx2.triangles_comp = ctx->triangles_comp; + ctx2.c.ctx2.cpt = 0; + ctx2.c.ctx2.component = cc1->cc_id; + S3D(scene_view_trace_ray(ctx->view, org, dir, rg, &ctx2, &hit)); + /* cc2 is not inside cc1 if cpt is even */ + if(ctx2.c.ctx2.cpt % 2 == 0) return 0; + return 1; +} + static side_id_t get_side_not_in_connex_component (const side_id_t last_side, @@ -131,7 +218,11 @@ get_side_not_in_connex_component /* Here unsigned are required by s3d API */ static void -get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) { +get_scn_indices + (const unsigned itri, + unsigned ids[3], + void* ctx) +{ int i; const struct senc3d_scene* scene = ctx; const struct triangle_in* trg = @@ -145,7 +236,11 @@ get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) { /* Here unsigned are required by s3d API */ static void -get_scn_position(const unsigned ivert, float pos[3], void* ctx) { +get_scn_position + (const unsigned ivert, + float pos[3], + void* ctx) +{ const struct senc3d_scene* scene = ctx; const union double3* pt = darray_position_cdata_get(&scene->vertices) + ivert; @@ -162,212 +257,330 @@ self_hit_filter void* filter_data) { struct filter_ctx* fctx_ = ray_data; - struct filter_ctx1* fctx; - const struct triangle_comp* trg_comp; - const component_id_t* hit_comp; - float s = 0; - enum senc3d_side hit_side; - int i; - double org_z, mz = -INF; - const struct triangle_in* triangles; - const struct triangle_in* trg = NULL; - const union double3* vertices; - struct cc_descriptor* const* comp_descriptors; - - (void)ray_dir; (void)ray_range; (void)filter_data; - ASSERT(hit && fctx_); - - if(fctx_->type == FCTX2) { - /* The filter is used to count the hits on some component along - * an infinite ray */ - struct filter_ctx2* ctx2 = &fctx_->c.ctx2; - ASSERT(hit->prim.prim_id - < darray_triangle_comp_size_get(ctx2->triangles_comp)); - trg_comp = darray_triangle_comp_cdata_get(ctx2->triangles_comp); - hit_comp = trg_comp[hit->prim.prim_id].component; - if(hit_comp[SENC3D_FRONT] == ctx2->component - || hit_comp[SENC3D_BACK] == ctx2->component) - { - ctx2->cpt++; - } - return 1; /* Reject to continue counting */ - } - /* The filter is called from a point query on successive hits found from - * ray_org, that belongs to origin_component. It can keep or reject the hit. - * Hits are only submitted inside a certain radius from ray_org, that is - * decreased to the hit distance for every hit that is kept. - * At the end, the last kept hit (= the closest), determines a component to - * which origin_component is linked. At a later stage the algorithm process - * linked components to determine their relative inclusions. - * - * For each hit, the filter computes if the hit is on a component above - * origin_component (that is with >= Z). - * If the hit is distant (dist>0), we just keep the hit as a valid candidate, - * but things get more tricky when dist==0 (ray_org is a vertex where some - * other components are in contact with origin_component). - * In this case, one of the other components can include the origin_component - * (greater volume needed), or they can be disjoint, with (at least) ray_org - * as a common vertex (they can also partially intersect, but this is invalid - * and remains undetected by star enclosures). */ - ASSERT(fctx_->type == FCTX1); - fctx = &fctx_->c.ctx1; - comp_descriptors = darray_ptr_component_descriptor_cdata_get(fctx->components); - trg_comp = darray_triangle_comp_cdata_get(fctx->triangles_comp); - hit_comp = trg_comp[hit->prim.prim_id].component; - triangles = darray_triangle_in_cdata_get(&fctx->scn->triangles_in); - vertices = darray_position_cdata_get(&fctx->scn->vertices); - ASSERT(hit->prim.prim_id - < darray_triangle_comp_size_get(fctx->triangles_comp)); + (void)ray_org; (void)ray_range; (void)filter_data; + ASSERT(fctx_); ASSERT(hit->uv[0] == CLAMP(hit->uv[0], 0, 1)); ASSERT(hit->uv[1] == CLAMP(hit->uv[1], 0, 1)); - /* No self hit */ - if(hit_comp[SENC3D_FRONT] == fctx->origin_component - || hit_comp[SENC3D_BACK] == fctx->origin_component) - return 1; /* Reject */ - - if(hit->distance == 0) { - /* origin_component is in contact with some other components - * We will need further exploration to know if they should be considered */ - int n; - - /* If same component, process only once */ - FOR_EACH(n, 0, (hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK] ? 1 : 2)) { - const enum senc3d_side sides[2] = { SENC3D_FRONT, SENC3D_BACK }; - component_id_t c = hit_comp[sides[n]]; - side_id_t side; - double pt[3] = { 0, 0, 0 }; - float org[3], dir[3] = { 0, 0, 1 }, rg[2] = { 0, FLT_MAX }; - struct s3d_hit hit2 = S3D_HIT_NULL; - struct filter_ctx fctx2; - ASSERT(c < darray_ptr_component_descriptor_size_get(fctx->components)); - if(comp_descriptors[c]->is_outer_border) { - if(fabs(comp_descriptors[c]->_6volume) - <= fabs(comp_descriptors[fctx->origin_component]->_6volume)) - /* Component is not large enough to include origin_component */ - continue; - } else { - vrtx_id_t c_z_id = comp_descriptors[c]->max_z_vrtx_id; - vrtx_id_t o_z_id = comp_descriptors[fctx->origin_component]->max_z_vrtx_id; - ASSERT(c_z_id < darray_position_size_get(&fctx->scn->vertices)); - ASSERT(o_z_id < darray_position_size_get(&fctx->scn->vertices)); - if(vertices[c_z_id].pos.z <= vertices[o_z_id].pos.z) - /* Component is not above origin_component */ - continue; - } - /* Check if component c includes origin_component; as components cannot - * overlap, testing a single point is OK, as long as the point is not on - * c boundary (can be on origin_component boundary, though). - * As this case is supposed to be rare, we go for a basic algorithm */ - for(side = comp_descriptors[fctx->origin_component]->side_range.first; - side <= comp_descriptors[fctx->origin_component]->side_range.last; - side++) + switch (fctx_->type) { + default: FATAL("Invalid"); + + case FCTX2: { + /* The filter is used to count the hits on some component along an + * infinite ray */ + struct filter_ctx2* ctx2 = &fctx_->c.ctx2; + const struct triangle_comp* trg_comp; + const component_id_t* hit_comp; + ASSERT(hit->prim.prim_id + < darray_triangle_comp_size_get(ctx2->triangles_comp)); + trg_comp = darray_triangle_comp_cdata_get(ctx2->triangles_comp); + hit_comp = trg_comp[hit->prim.prim_id].component; + if(hit_comp[SENC3D_FRONT] == ctx2->component + || hit_comp[SENC3D_BACK] == ctx2->component) { - /* Find a triangle on origin_component boundary that is not on c - * boundary (the 2 components cannot share all their triangles) */ - trg_id_t t = TRGSIDE_2_TRG(side); - const component_id_t* candidate_comp = trg_comp[t].component; - if(candidate_comp[SENC3D_FRONT] != fctx->origin_component - && candidate_comp[SENC3D_BACK] != fctx->origin_component) - continue; - if(candidate_comp[SENC3D_FRONT] == c - || candidate_comp[SENC3D_BACK] == c) - continue; - /* This triangle is OK */ - trg = triangles + t; - break; + ctx2->cpt++; } - ASSERT(trg != NULL); - /* Any point on trg not on an edge can do the trick: use the barycenter */ - FOR_EACH(i, 0, 3) { - vrtx_id_t v = trg->vertice_id[i]; - ASSERT(v < darray_position_size_get(&fctx->scn->vertices)); - d3_add(pt, pt, vertices[v].vec); + return 1; /* Reject to continue counting */ + } + + case FCTX0: { + /* This filter is called from a closest point query from a point belonging + * to origin_component. The returned hit is used to determine the search + * radius for FCTX1 main computation. */ + struct filter_ctx0* ctx = &fctx_->c.ctx0; + const struct triangle_comp* + trg_comp = darray_triangle_comp_cdata_get(ctx->triangles_comp); + const component_id_t* + hit_comp = trg_comp[hit->prim.prim_id].component; + + ASSERT(hit->prim.prim_id + < darray_triangle_comp_size_get(ctx->triangles_comp)); + + if(hit_comp[SENC3D_FRONT] == ctx->origin_component + || hit_comp[SENC3D_BACK] == ctx->origin_component) + { + /* Self hit */ + return 1; /* Reject */ } - d3_divd(pt, pt, 3); - f3_set_d3(org, pt); - /* Trace a ray and count intersections with components of trg */ - fctx2.type = FCTX2; - fctx2.c.ctx2.triangles_comp = fctx->triangles_comp; - fctx2.c.ctx2.cpt = 0; - fctx2.c.ctx2.component = c; - S3D(scene_view_trace_ray(fctx->view, org, dir, rg, &fctx2, &hit2)); - ASSERT(S3D_HIT_NONE(&hit2)); /* The ray is supposed to go to infinity */ - /* origin_component is linked_to an outer component if cpt is odd, - * linked_to an inner component if cpt is even */ - if(comp_descriptors[c]->is_outer_border == (fctx2.c.ctx2.cpt % 2)) { - double v = fabs(comp_descriptors[c]->_6volume); - /* If origin_component is inside several components, the one we are - * looking for is the smallest one */ - if(v >= fctx->current_6volume) continue; - fctx->hit_component = fctx2.c.ctx2.component; - fctx->current_6volume = v; - /* Continue searching for a smaller component that includes - * origin_component */ + + if(hit->distance > 0 && ray_dir[2] <= 0) { + return 1; /* Not upward */ } + + return 0; /* Keep*/ } - return 1; /* Reject */ - } - /* Reject hits with < Z */ - ASSERT(hit->prim.prim_id < - darray_triangle_in_size_get(&fctx->scn->triangles_in)); - trg = triangles + hit->prim.prim_id; - /* Check if the hit is above ray_org (hit[2] > ray_org[2]) - * As we cannot rely on numerical accuracy when computing hit positions, - * we use the triangle vertices to check if some part of the hit triangle - * is above ray_org */ - FOR_EACH(i, 0, 3) { - vrtx_id_t v = trg->vertice_id[i]; - const union double3* p = vertices + v; - ASSERT(v < darray_position_size_get(&fctx->scn->vertices)); - if(i == 0 || mz < p->pos.z) mz = p->pos.z; - } - /* Don't use org[2] as, being float, it would lead to a float VS double - * comparison that causes accuracy problems. */ - org_z = vertices[comp_descriptors[fctx->origin_component]->max_z_vrtx_id].pos.z; - if(mz <= org_z) - return 1; /* Hit triangle is below ray_org: reject */ - - if(hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK]) { - /* Easy case and hit component is known */ - fctx->hit_component = hit_comp[SENC3D_FRONT]; - return 0; /* Keep */ - } + case FCTX1: { + /* This filter is called from a closest point query from a point belonging + * to origin_component. The returned hit is used to determine a component + * to which origin_component is linked. At a later stage the algorithm + * process linked components to determine their relative inclusions. + * + * This filter is called with a search distance that has been ajusted in + * FCTX0 filter. This distance must be left unchanged to ensure visiting + * all the surfaces at the determined distance: allways reject hits to + * avoid decreasing search distance. + * + * For each hit, the filter computes if the hit is on a component above + * origin_component (that is with >= Z). + * If the hit is distant (dist>0), we just keep the hit as a valid candidate, + * but things get more tricky when dist==0 (ray_org is a vertex where some + * other components can be in contact with origin_component). + * In this case, one of the other components can include the origin_component + * (greater volume needed), or they can be disjoint, with (at least) ray_org + * as a common vertex (they can also partially intersect, but this is invalid + * and remains undetected by star enclosures). */ + struct filter_ctx1* ctx = &fctx_->c.ctx1; + struct cc_descriptor* const* + comp_descriptors = darray_ptr_component_descriptor_cdata_get(ctx->components); + const struct triangle_comp* + trg_comp = darray_triangle_comp_cdata_get(ctx->triangles_comp); + const component_id_t* + hit_comp = trg_comp[hit->prim.prim_id].component; + const union double3* vertices = darray_position_cdata_get(&ctx->scn->vertices); + enum senc3d_side hit_side; + float s = 0, hit_normal[3], rdir[3]; + const int log_components = + ctx->scn->convention & SENC3D_LOG_COMPONENTS_INFORMATION; + + ASSERT(hit->prim.prim_id + < darray_triangle_comp_size_get(ctx->triangles_comp)); + + if(log_components) { + printf("Component #%u: investigating hit (d=%g, n= %g %g %g).\n", + ctx->origin_component, hit->distance, SPLIT3(hit->normal)); + } - /* Compute hit side by using the vertex with best accuracy */ - FOR_EACH(i, 0, 3) { - float tmps, tmp[3], dir[3]; - vrtx_id_t v = trg->vertice_id[i]; - const union double3* p = vertices + v; - ASSERT(v < darray_position_size_get(&fctx->scn->vertices)); - f3_sub(dir, f3_set_d3(tmp, p->vec), ray_org); - tmps = f3_dot(dir, hit->normal); - if(i == 0 || fabsf(s) < fabsf(tmps)) s = tmps; - } + if(hit->distance > ctx->hit_dist) { + /* No improvement */ + if(log_components) { + printf("Component #%u: further away => reject.\n", ctx->origin_component); + } + return 1; + } - /* We cannot know which side to consider if s==0. - * As hit distance > 0 and the 2 sides belong to 2 different components, - * another candidate must selected afterwards (can be at greater distance, - * disallowing to restrict the search distance here) */ - if(s == 0) { - fctx->hit_component = COMPONENT_NULL__; - return 1; /* Reject */ - } + if(hit_comp[SENC3D_FRONT] == ctx->origin_component + || hit_comp[SENC3D_BACK] == ctx->origin_component) + { + /* Self hit */ + if(log_components) { + printf("Component #%u: self hit => reject.\n", ctx->origin_component); + } + return 1; + } - /* Determine which side was hit */ - hit_side = - ((s < 0) /* Facing geometrical normal of hit */ - == ((fctx->scn->convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0)) - /* Warning: following Embree 2 convention for geometrical normals, - * the Star3D hit normal is left-handed while star-enclosures-3d uses - * right-handed convention */ - ? SENC3D_BACK : SENC3D_FRONT; + if(hit->distance > 0 && ray_dir[2] <= 0) { + /* Not upward */ + if(log_components) { + printf("Component #%u: not upward => reject.\n", ctx->origin_component); + } + return 1; + } - fctx->hit_component = hit_comp[hit_side]; + if(hit->distance == 0) { + /* origin_component is in contact with some other components + * We will need further exploration to know if they should be considered */ + int n; + + /* If same component, process only once */ + FOR_EACH(n, 0, (hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK] ? 1 : 2)) { + const enum senc3d_side sides[2] = { SENC3D_FRONT, SENC3D_BACK }; + component_id_t c = hit_comp[sides[n]]; + ASSERT(c < darray_ptr_component_descriptor_size_get(ctx->components)); + if(c == ctx->hit_component) { + /* Cannot change ctx->hit_component */ + if(log_components) { + printf("Component #%u: hit component #%u and already linked to it:" + " reject\n", ctx->origin_component, c); + } + continue; + } + if(comp_descriptors[c]->is_outer_border) { + double v; + /* The inner component we are trying to link can only be linked to + * an outer component if it is inside */ + if(log_components) { + printf("Component #%u: hit outer component #%u\n", + ctx->origin_component, c); + } + if(!is_component_inside(comp_descriptors[c], + comp_descriptors[ctx->origin_component], ctx)) + { + if(log_components) { + printf("Component #%u: not inside: reject\n", ctx->origin_component); + } + continue; + } + v = fabs(comp_descriptors[c]->_6volume); + /* If already linked to an inner component, prefer an outer one + * regardless of their respective volumes. + * If origin_component is inside several outer components, the one + * we are looking for is the smallest one (to manage outer component + * inside another outer component). */ + if((ctx->hit_component != COMPONENT_NULL__ + && !comp_descriptors[ctx->hit_component]->is_outer_border ) + || v < ctx->current_6volume) { + ctx->hit_component = c; + ctx->current_6volume = v; + ctx->hit_dist = 0; + ctx->hit_prim = hit->prim; + if(log_components) { + if(v < ctx->current_6volume) { + printf("Component #%u: currently the smaller one: keep component" + " #%u\n", ctx->origin_component, ctx->hit_component); + } else { + printf("Component #%u: change from inner to outer: keep component" + " #%u\n", ctx->origin_component, ctx->hit_component); + } + } + } else { + if(log_components) { + printf("Component #%u: not the smaller one: reject\n", + ctx->origin_component); + } + continue; + } + } else { + /* c is an inner component */ + vrtx_id_t c_z_id; + double org_z, v; + /* If we've already found a valid outer component, inner components + * should not be considered anymore */ + if(log_components) { + printf("Component #%u: hit inner component #%u\n", + ctx->origin_component, c); + } + if(ctx->hit_component != COMPONENT_NULL__ + && comp_descriptors[ctx->hit_component]->is_outer_border ) + { + if(log_components) { + printf("Component #%u: already in an outer component: reject\n", + ctx->origin_component); + } + continue; + } + /* The inner component we are trying to link can only be linked to + * another inner component if (at least partly) above it and not + * inside */ + c_z_id = comp_descriptors[c]->max_z_vrtx_id; + org_z = + vertices[comp_descriptors[ctx->origin_component]->max_z_vrtx_id].pos.z; + ASSERT(c_z_id < darray_position_size_get(&ctx->scn->vertices)); + ASSERT(vertices[c_z_id].pos.z >= org_z); + if(vertices[c_z_id].pos.z == org_z) { + if(log_components) { + printf("Component #%u: not (even in part) above: reject\n", + ctx->origin_component); + } + continue; /* Not above */ + } + if(is_component_inside(comp_descriptors[c], + comp_descriptors[ctx->origin_component], ctx)) + { + if(log_components) { + printf("Component #%u: not outside: reject\n", ctx->origin_component); + } + continue; /* Inside */ + } + v = fabs(comp_descriptors[c]->_6volume); + /* If origin_component is facing several inner components, the one + * we are looking for is the largest one (to manage inner component + * inside another inner component) */ + if(ctx->current_6volume == DBL_MAX || v > ctx->current_6volume) { + ctx->hit_component = c; + ctx->current_6volume = v; + ctx->hit_dist = 0; + ctx->hit_prim = hit->prim; + if(log_components) { + printf("Component #%u: currently the bigger one: keep component" + " #%u\n", ctx->origin_component, ctx->hit_component); + } + } else { + if(log_components) { + printf("Component #%u: not the bigger one: reject\n", + ctx->origin_component); + } + continue; + } + } + } + return 1; + } + + ASSERT(hit->distance > 0); + if(hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK]) { + /* Easy case and hit component is known */ + ctx->hit_component = hit_comp[SENC3D_FRONT]; + ctx->s = 1; + f3_set(ctx->hit_dir, ray_dir); + ctx->hit_dist = hit->distance; + ctx->hit_prim = hit->prim; + if(log_components) { + printf("Component #%u: 2 sides with same component: keep component" + " #%u\n", ctx->origin_component, ctx->hit_component); + } + return 1; + } + + /* Compute hit side */ + /* For s to be comparable, vectors must be normailzed */ + f3_normalize(hit_normal, hit->normal); + f3_normalize(rdir, ray_dir); + s = f3_dot(rdir, hit_normal); /* Can be NaN for tiny distances */ + if(isnan(s)) { + /* Try to fix it */ + f3_divf(rdir, ray_dir, hit->distance); + f3_normalize(rdir, rdir); + s = f3_dot(rdir, hit_normal); + ASSERT(!isnan(s)); + if(log_components) { + printf("Component #%u: had to fix s (was NaN)\n", ctx->origin_component); + } + } - return 0; /* Keep */ + if(ctx->hit_dist == hit->distance && fabsf(ctx->s) >= fabsf(s)) { + /* Same distance with no s improvement: keep the previous hit */ + if(log_components) { + printf("Component #%u: not improving s (%g VS %g): reject\n", + ctx->origin_component, s, ctx->s); + } + return 1; + } + + if(fabsf(s) < DOT_THRESHOLD) { + /* We cannot know for sure which side to consider */ + ctx->hit_component = COMPONENT_NULL__; + ctx->s = s; + f3_set(ctx->hit_dir, ray_dir); + ctx->hit_dist = hit->distance; + ctx->hit_prim = hit->prim; + if(log_components) { + printf("Component #%u: tiny s (%g): keep but don't know the component\n", + ctx->origin_component, s); + } + return 1; + } + /* Determine which side was hit */ + hit_side = + ((s < 0) /* Facing geometrical normal of hit */ + == ((ctx->scn->convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0)) + /* Warning: following Embree 2 convention for geometrical normals, + * the Star3D hit normal is left-handed while star-enclosures-3d uses + * right-handed convention */ + ? SENC3D_BACK : SENC3D_FRONT; + ctx->hit_component = hit_comp[hit_side]; + ctx->s = s; + f3_set(ctx->hit_dir, ray_dir); + ctx->hit_dist = hit->distance; + ctx->hit_prim = hit->prim; + if(log_components) { + printf("Component #%u: standard s (%g): keep component #%u\n", + ctx->origin_component, s, ctx->hit_component); + } + return 1; + } + } } static void @@ -425,7 +638,7 @@ extract_connex_components const struct side_range* media_use = darray_side_range_cdata_get(&scn->media_use); FOR_EACH(s, 0, 2) { - const side_id_t side = TRGIDxSIDE_2_TRGSIDE(t_, s); + const side_id_t side = TRGIDxSIDE_2_TRGSIDE(t_, (enum senc3d_side)s); medium_id_t medium = trg_in->medium[s]; m_idx = medium_id_2_medium_idx(medium); ASSERT(media_use[m_idx].first <= side && side @@ -636,8 +849,8 @@ extract_connex_components >= medium_id_2_medium_idx(medium)); cmp[side] = cc->cc_id; } - /* Compute component area and volume, and record information on the - * max_z side of the component to help find out if the component is + /* Compute component's bbox, area and volume, and record information on + * the max_z side of the component to help find out if the component is * inner or outer */ fst_nz = 1; max_nz = 0; @@ -656,10 +869,18 @@ extract_connex_components const double* v0 = vertices[trg_in->vertice_id[0]].vec; const double* v1 = vertices[trg_in->vertice_id[1]].vec; const double* v2 = vertices[trg_in->vertice_id[2]].vec; - int is_2sided = (trg_comp->component[SENC3D_FRONT] + int n, is_2sided = (trg_comp->component[SENC3D_FRONT] == trg_comp->component[SENC3D_BACK]); - /* Compute component area and volume */ + /* Compute component's bbox, area and volume */ + for(n = 0; n < 3; n++) { + cc->bbox[n][0] = MMIN(cc->bbox[n][0], v0[n]); + cc->bbox[n][0] = MMIN(cc->bbox[n][0], v1[n]); + cc->bbox[n][0] = MMIN(cc->bbox[n][0], v2[n]); + cc->bbox[n][1] = MMAX(cc->bbox[n][1], v0[n]); + cc->bbox[n][1] = MMAX(cc->bbox[n][1], v1[n]); + cc->bbox[n][1] = MMAX(cc->bbox[n][1], v2[n]); + } d3_sub(edge0, v1, v0); d3_sub(edge1, v2, v0); d3_cross(normal, edge0, edge1); @@ -893,8 +1114,10 @@ group_connex_components size_t tmp; component_id_t cc_count; int64_t ccc; - struct filter_ctx fctx; + struct filter_ctx ctx0, ctx1; float lower[3], upper[3]; + const int log_components = scn->convention & SENC3D_LOG_COMPONENTS_INFORMATION; + const int dump_components = scn->convention & SENC3D_DUMP_COMPONENTS_STL; ASSERT(scn && triangles_comp && connex_components && s3d_view && next_enclosure_id && res); @@ -908,20 +1131,80 @@ group_connex_components } if(*res != RES_OK) return; #endif - descriptors = darray_ptr_component_descriptor_data_get(connex_components); tmp = darray_ptr_component_descriptor_size_get(connex_components); ASSERT(tmp <= COMPONENT_MAX__); cc_count = (component_id_t)tmp; positions = darray_position_cdata_get(&scn->vertices); - fctx.type = FCTX1; - fctx.c.ctx1.scn = scn; - fctx.c.ctx1.view = s3d_view; - fctx.c.ctx1.triangles_comp = triangles_comp; - fctx.c.ctx1.components = connex_components; + + if(dump_components) { + /* Do it now before any other problem can occur (fingers crossed). + * Do it sequential and not optimized as it is debug code. + * Don't throw errors, just skip to the next component. */ + static unsigned scene_cpt = 0; + struct str name; + res_T tmp_res; + const struct triangle_comp* tc = + darray_triangle_comp_cdata_get(triangles_comp); + const struct triangle_in* tin = darray_triangle_in_cdata_get(&scn->triangles_in); + const int output_normal_in = + (scn->convention & SENC3D_CONVENTION_NORMAL_INSIDE) != 0; + str_init(scn->dev->allocator, &name); + printf("Dumping components for scene #%u.\n", scene_cpt); + for(ccc = 0; ccc < (int64_t)cc_count; ccc++) { + FILE* f; + trg_id_t t; + component_id_t c = (component_id_t)ccc; + tmp_res = str_printf(&name, "scn_%u_comp_%u.stl", scene_cpt, c); + if(tmp_res != RES_OK) continue; + f = fopen(str_cget(&name), "w"); + if(!f) continue; + fprintf(f, "solid %s\n", str_cget(&name)); + for(t = 0; t < scn->ntris; t++) { + const component_id_t cf_id = tc[t].component[SENC3D_FRONT]; + const component_id_t cb_id = tc[t].component[SENC3D_BACK]; + if(cf_id == c || cb_id == c) { + const vrtx_id_t* vertice_id = tin[t].vertice_id; + double n[3], e1[3], e2[3]; + const int input_normal_in = (cf_id == c); + const int revert_triangle = (input_normal_in != output_normal_in); + const vrtx_id_t i0 = vertice_id[0]; + const vrtx_id_t i1 = vertice_id[revert_triangle ? 2 : 1]; + const vrtx_id_t i2 = vertice_id[revert_triangle ? 1 : 2]; + /* This triangle is in component #c */ + if(cf_id == cb_id) { /* Both sides in component */ + /* Could add some log */ + } + d3_sub(e1, positions[i1].vec, positions[i0].vec); + d3_sub(e2, positions[i2].vec, positions[i0].vec); + d3_normalize(n, d3_cross(n, e1, e2)); + fprintf(f, " facet normal %16g %16g %16g\n", SPLIT3(n)); + fprintf(f, " outer loop\n"); + fprintf(f, " vertex %16g %16g %16g\n", SPLIT3(positions[i0].vec)); + fprintf(f, " vertex %16g %16g %16g\n", SPLIT3(positions[i1].vec)); + fprintf(f, " vertex %16g %16g %16g\n", SPLIT3(positions[i2].vec)); + fprintf(f, " endloop\n"); + fprintf(f, " endfacet\n"); + } + } + printf("Dumped component #%u in file %s.\n", c, str_cget(&name)); + fprintf(f, "endsolid %s\n", str_cget(&name)); + fclose(f); + } + str_release(&name); + scene_cpt++; + } + + + ctx0.type = FCTX0; + ctx0.c.ctx0.triangles_comp = triangles_comp; + ctx1.type = FCTX1; + ctx1.c.ctx1.scn = scn; + ctx1.c.ctx1.view = s3d_view; + ctx1.c.ctx1.triangles_comp = triangles_comp; + ctx1.c.ctx1.components = connex_components; *res = s3d_scene_view_get_aabb(s3d_view, lower, upper); if(*res != RES_OK) goto end; - /* Cast rays to find links between connex components */ #pragma omp for schedule(dynamic) for(ccc = 0; ccc < (int64_t)cc_count; ccc++) { res_T tmp_res = RES_OK; @@ -937,44 +1220,91 @@ group_connex_components ASSERT(cc->cc_group_root == CC_GROUP_ID_NONE); ASSERT(cc->max_z_vrtx_id < scn->nverts); - max_vrtx = positions[cc->max_z_vrtx_id].vec; if(cc->is_outer_border) { ATOMIC id; - /* No need to query closest point */ + /* No need to create a link from this CC: inner CC are doing the job */ cc->cc_group_root = cc->cc_id; /* New group with self as root */ id = ATOMIC_INCR(next_enclosure_id) - 1; ASSERT(id <= ENCLOSURE_MAX__); cc->enclosure_id = (enclosure_id_t)id; + if(log_components) { + printf("Component #%u: is outer, not processed\n", c); + } continue; } + /* First step is to determine the distance of the closest upward geometry */ + max_vrtx = positions[cc->max_z_vrtx_id].vec; f3_set_d3(origin, max_vrtx); - /* Self-hit data: self hit if hit this component "on the other side" */ - fctx.c.ctx1.origin_component = cc->cc_id; - fctx.c.ctx1.current_6volume = DBL_MAX; - fctx.c.ctx1.hit_component = COMPONENT_NULL__; /* Limit search radius. Only upwards moves (+Z) will be considered. * Use a radius allowing to reach the closest top vertex of scene's AABB */ FOR_EACH(i, 0, 2) { ASSERT(lower[i] <= origin[i] && origin[i] <= upper[i]); rrr[i] = MMIN(origin[i] - lower[i], upper[i] - origin[i]); } - ASSERT(lower[2] <= origin[2] && origin[2] <= upper[2]); rrr[2] = upper[2] - origin[2]; r = f3_len(rrr) + FLT_EPSILON; /* Ensure r > 0 */ - tmp_res = s3d_scene_view_closest_point(s3d_view, origin, r, &fctx, &hit); + ctx0.c.ctx0.origin_component = cc->cc_id; + tmp_res = s3d_scene_view_closest_point(s3d_view, origin, r, &ctx0, &hit); if(tmp_res != RES_OK) { *res = tmp_res; continue; } /* If no hit, the component is facing an infinite medium */ - if(fctx.c.ctx1.hit_component == COMPONENT_NULL__) { + if(S3D_HIT_NONE(&hit)) { + cc->cc_group_root = CC_GROUP_ROOT_INFINITE; + cc->enclosure_id = 0; + if(log_components) { + printf("Component #%u: is part of enclosure #0\n", c); + } + continue; + } + + /* Second step is to determine which component faces component #c */ + ctx1.c.ctx1.origin_component = cc->cc_id; + ctx1.c.ctx1.current_6volume = DBL_MAX; + ctx1.c.ctx1.hit_dist = FLT_MAX; + ctx1.c.ctx1.hit_component = COMPONENT_NULL__; + /* New search radius is hit.distance + some margin to cope with numerical + * issues (and r==0 is an error) */ + r = hit.distance * (1 + FLT_EPSILON) + FLT_EPSILON; + if(log_components) { + printf("Component #%u: starting search for components (R=%g) from %g %g %g\n", + c, r, SPLIT3(origin)); + } + /* Cast a sphere to find links between connex components */ + tmp_res = s3d_scene_view_closest_point(s3d_view, origin, r, &ctx1, &hit); + if(tmp_res != RES_OK) { + *res = tmp_res; + continue; + } + /* As FCTX1 filter rejects any hit, do not rely on hit but use result as + * stored in ctx1 */ + /* If no hit is accepted, the component is facing an infinite medium */ + if(ctx1.c.ctx1.hit_dist == FLT_MAX) { cc->cc_group_root = CC_GROUP_ROOT_INFINITE; cc->enclosure_id = 0; + if(log_components) { + printf("Component #%u: is part of enclosure #0\n", c); + } + continue; + } + else if(ctx1.c.ctx1.hit_component == COMPONENT_NULL__) { + /* The selected triangle was nearly parallel to the line of sight: + * FRONT/BACK discrimination was not reliable enough and should be done + * differently. */ + /* Could try something; now just report a failure */ + log_err(scn->dev, LIB_NAME": %s: %d: search failed.\n", FUNC_NAME, + __LINE__ ); + *res = RES_BAD_OP; + continue; } else { /* If hit, group this component */ - cc->cc_group_root = fctx.c.ctx1.hit_component; + cc->cc_group_root = ctx1.c.ctx1.hit_component; ASSERT(cc->cc_group_root < cc_count); + if(log_components) { + printf("Component #%u: linked to component #%u\n", c, cc->cc_group_root); + } } } /* Implicit barrier here */ @@ -1179,7 +1509,7 @@ collect_and_link_neighbours /* Compute rotation angle around common edge */ d3_sub(edge, vertices[v2].vec, vertices[v0].vec); d33_muld3(edge, basis, edge); - ASSERT(d3_len(edge) && (edge[0] || edge[1])); + ASSERT(d3_len(edge) != 0 && (edge[0] != 0 || edge[1] != 0)); neighbour_info->angle = atan2(edge[1], edge[0]); /* in ]-pi + pi]*/ if(is_reversed) d3(n.vec, +edge[1], -edge[0], 0); @@ -1501,7 +1831,7 @@ build_result /* Build side and vertex lists. */ OK2(darray_sides_enc_resize(&enc->sides, enc->side_count)); - /* Size is just a int */ + /* Size is just a hint */ OK2(darray_vrtx_id_reserve(&enc->vertices, (size_t)(enc->side_count * 0.6))); /* New vertex numbering scheme local to the enclosure */ diff --git a/src/senc3d_scene_analyze_c.h b/src/senc3d_scene_analyze_c.h @@ -17,6 +17,8 @@ #define SENC3D_SCNENE_ANALYZE_C_H #include "senc3d_internal_types.h" +#include "senc3d_side_range.h" +#include "senc3d_scene_c.h" #include "senc3d.h" #include <rsys/mem_allocator.h> @@ -47,6 +49,8 @@ struct cc_descriptor { double _2area; /* Six times the signed volume of the component */ double _6volume; + /* The component's bounding Box */ + double bbox[3][2]; /* Media used by this component */ uchar* media; unsigned media_count; diff --git a/src/test_senc3d_glazing.c b/src/test_senc3d_glazing.c @@ -0,0 +1,1127 @@ +/* Copyright (C) 2018-2020, 2023 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This test has been created using the sg3_geometry_dump_as_C_code feature + * of star-geometry. It uses output from test_sg3_cube_on_cube. */ + +#define _POSIX_C_SOURCE 200112L /* snprintf */ + +#include "senc3d.h" +#include "test_senc3d_utils.h" + +#include <rsys/double3.h> + +#include <stdio.h> + +#define glazing_UNSPECIFIED_PROPERTY 4294967295 + +static const unsigned +glazing_vertices_count = 223; + +static const unsigned +glazing_triangles_count = 398; + +static const double +glazing_vertices[223*3] = { + 82.6042, 60.329, 2.7625, + 83.9367, 60.4228, 2.51177, + 82.6042, 60.329, 1.24942, + 84.3672, 60.4531, 1.24942, + 84.3672, 60.4531, 4.27558, + 83.4786, 60.3906, 3.4916, + 82.6042, 60.329, 4.27558, + 86.1302, 60.5772, 4.27558, + 85.0127, 60.4986, 3.24271, + 85.1251, 60.5065, 2.219, + 86.1302, 60.5772, 1.24942, + 86.1302, 60.5772, 2.7625, + 86.1319, 60.5533, 1.24942, + 84.3689, 60.4292, 1.24942, + 82.6059, 60.3051, 1.24942, + 82.6059, 60.3051, 2.7625, + 82.6059, 60.3051, 4.27558, + 84.3689, 60.4292, 4.27558, + 86.1319, 60.5533, 4.27558, + 86.1319, 60.5533, 2.7625, + 84.7508, 60.4561, 2.59095, + 83.6545, 60.3789, 3.23353, + 83.611, 60.3758, 2.219, + 89.8033, 59.2472, 2.7625, + 89.1016, 59.2344, 1.24942, + 88.3998, 59.2215, 2.7625, + 89.1016, 59.2344, 4.27558, + 89.8033, 59.2472, 1.24942, + 88.3998, 59.2215, 1.24942, + 88.3998, 59.2215, 4.27558, + 89.8033, 59.2472, 4.27558, + 89.8038, 59.2232, 1.24942, + 89.102, 59.2104, 1.24942, + 88.4002, 59.1975, 1.24942, + 88.4002, 59.1975, 2.7625, + 88.4002, 59.1975, 4.27558, + 89.102, 59.2104, 4.27558, + 89.8038, 59.2232, 4.27558, + 89.8038, 59.2232, 2.7625, + 86.1302, 60.5772, 8.4875, + 84.7976, 60.4834, 8.73823, + 86.1302, 60.5772, 10.0006, + 84.3672, 60.4531, 10.0006, + 84.3672, 60.4531, 6.97442, + 85.2558, 60.5157, 7.7584, + 86.1302, 60.5772, 6.97442, + 82.6042, 60.329, 6.97442, + 83.7217, 60.4077, 8.00729, + 83.6093, 60.3998, 9.031, + 82.6042, 60.329, 10.0006, + 82.6042, 60.329, 8.4875, + 82.6059, 60.3051, 6.97442, + 84.3689, 60.4292, 6.97442, + 86.1319, 60.5533, 6.97442, + 82.6059, 60.3051, 8.4875, + 82.6059, 60.3051, 10.0006, + 84.3689, 60.4292, 10.0006, + 86.1319, 60.5533, 10.0006, + 86.1319, 60.5533, 8.4875, + 84.7993, 60.4595, 8.73823, + 85.2575, 60.4917, 7.7584, + 83.7234, 60.3837, 8.00729, + 83.611, 60.3758, 9.031, + 82.2266, 68.3242, 10.0006, + 82.2266, 68.3242, 6.97442, + 82.8171, 72.7595, 8.4875, + 81.636, 63.889, 8.4875, + 82.8171, 72.7595, 6.97442, + 81.636, 63.889, 6.97442, + 82.8171, 72.7595, 10.0006, + 81.636, 63.889, 10.0006, + 82.7933, 72.7627, 6.97442, + 82.2028, 68.3274, 6.97442, + 81.6123, 63.8921, 6.97442, + 82.7933, 72.7627, 8.4875, + 82.7933, 72.7627, 10.0006, + 82.2028, 68.3274, 10.0006, + 81.6123, 63.8921, 10.0006, + 81.6123, 63.8921, 8.4875, + 84.5273, 76.4272, 8.4875, + 85.6048, 76.4318, 8.93555, + 84.5273, 76.4272, 10.0006, + 87.4884, 76.44, 6.97442, + 86.3533, 76.4351, 8.11727, + 86.0078, 76.4336, 6.97442, + 87.4884, 76.44, 8.4875, + 86.0078, 76.4336, 10.0006, + 84.5273, 76.4272, 6.97442, + 85.3385, 76.4307, 7.80041, + 87.4884, 76.44, 10.0006, + 86.6106, 76.4362, 9.11589, + 87.4883, 76.464, 6.97442, + 86.0077, 76.4576, 6.97442, + 84.5271, 76.4512, 6.97442, + 87.4883, 76.464, 8.4875, + 87.4883, 76.464, 10.0006, + 86.0077, 76.4576, 10.0006, + 84.5271, 76.4512, 10.0006, + 84.5271, 76.4512, 8.4875, + 85.6047, 76.4558, 8.93555, + 86.3532, 76.4591, 8.11727, + 85.3384, 76.4547, 7.80041, + 86.6105, 76.4602, 9.11589, + 90.2861, 60.7753, 8.4875, + 90.3545, 59.7013, 8.4875, + 90.3203, 60.2383, 10.0006, + 90.3203, 60.2383, 6.97442, + 90.3545, 59.7013, 6.97442, + 90.2861, 60.7753, 6.97442, + 90.3545, 59.7013, 10.0006, + 90.2861, 60.7753, 10.0006, + 90.3785, 59.7028, 6.97442, + 90.3443, 60.2398, 6.97442, + 90.31, 60.7768, 6.97442, + 90.3785, 59.7028, 8.4875, + 90.3785, 59.7028, 10.0006, + 90.3443, 60.2398, 10.0006, + 90.31, 60.7768, 10.0006, + 90.31, 60.7768, 8.4875, + 84.5273, 76.4272, 2.7625, + 85.6048, 76.4318, 3.21055, + 84.5273, 76.4272, 4.27558, + 87.4884, 76.44, 1.24942, + 86.3533, 76.4351, 2.39227, + 86.0078, 76.4336, 1.24942, + 87.4884, 76.44, 2.7625, + 86.0078, 76.4336, 4.27558, + 84.5273, 76.4272, 1.24942, + 85.3385, 76.4307, 2.07541, + 87.4884, 76.44, 4.27558, + 86.6106, 76.4362, 3.39089, + 84.5271, 76.4512, 1.24942, + 86.0077, 76.4576, 1.24942, + 87.4883, 76.464, 1.24942, + 87.4883, 76.464, 2.7625, + 87.4883, 76.464, 4.27558, + 86.0077, 76.4576, 4.27558, + 84.5271, 76.4512, 4.27558, + 84.5271, 76.4512, 2.7625, + 86.4107, 76.4593, 3.21055, + 85.6622, 76.4561, 2.39227, + 86.677, 76.4605, 2.07541, + 85.405, 76.455, 3.39089, + 81.636, 63.889, 2.7625, + 82.2266, 68.3242, 1.24942, + 82.2266, 68.3242, 4.27558, + 82.8171, 72.7595, 2.7625, + 81.636, 63.889, 1.24942, + 82.8171, 72.7595, 1.24942, + 82.8171, 72.7595, 4.27558, + 81.636, 63.889, 4.27558, + 81.6123, 63.8921, 1.24942, + 82.2028, 68.3274, 1.24942, + 82.7933, 72.7627, 1.24942, + 82.7933, 72.7627, 2.7625, + 82.7933, 72.7627, 4.27558, + 82.2028, 68.3274, 4.27558, + 81.6123, 63.8921, 4.27558, + 81.6123, 63.8921, 2.7625, + 89.8033, 59.2472, 8.4875, + 88.3998, 59.2215, 8.4875, + 89.1016, 59.2344, 10.0006, + 89.1016, 59.2344, 6.97442, + 88.3998, 59.2215, 6.97442, + 89.8033, 59.2472, 6.97442, + 88.3998, 59.2215, 10.0006, + 89.8033, 59.2472, 10.0006, + 88.4002, 59.1975, 6.97442, + 89.102, 59.2104, 6.97442, + 89.8038, 59.2232, 6.97442, + 88.4002, 59.1975, 8.4875, + 88.4002, 59.1975, 10.0006, + 89.102, 59.2104, 10.0006, + 89.8038, 59.2232, 10.0006, + 89.8038, 59.2232, 8.4875, + 90.2861, 60.7753, 2.7625, + 90.3545, 59.7013, 2.7625, + 90.3203, 60.2383, 4.27558, + 90.3203, 60.2383, 1.24942, + 90.2861, 60.7753, 1.24942, + 90.3545, 59.7013, 1.24942, + 90.3545, 59.7013, 4.27558, + 90.2861, 60.7753, 4.27558, + 90.31, 60.7768, 1.24942, + 90.3443, 60.2398, 1.24942, + 90.3785, 59.7028, 1.24942, + 90.3785, 59.7028, 2.7625, + 90.3785, 59.7028, 4.27558, + 90.3443, 60.2398, 4.27558, + 90.31, 60.7768, 4.27558, + 90.31, 60.7768, 2.7625, + 89.0607, 73.002, 2.7625, + 89.4844, 68.832, 1.24942, + 89.4844, 68.832, 4.27558, + 89.908, 64.6621, 2.7625, + 89.0607, 73.002, 1.24942, + 89.908, 64.6621, 1.24942, + 89.908, 64.6621, 4.27558, + 89.0607, 73.002, 4.27558, + 89.0846, 73.0044, 1.24942, + 89.5083, 68.8345, 1.24942, + 89.9319, 64.6645, 1.24942, + 89.9319, 64.6645, 2.7625, + 89.9319, 64.6645, 4.27558, + 89.5083, 68.8345, 4.27558, + 89.0846, 73.0044, 4.27558, + 89.0846, 73.0044, 2.7625, + 89.0607, 73.002, 8.4875, + 89.4844, 68.832, 6.97442, + 89.4844, 68.832, 10.0006, + 89.908, 64.6621, 8.4875, + 89.908, 64.6621, 6.97442, + 89.0607, 73.002, 6.97442, + 89.908, 64.6621, 10.0006, + 89.0607, 73.002, 10.0006, + 89.9319, 64.6645, 6.97442, + 89.5083, 68.8345, 6.97442, + 89.0846, 73.0044, 6.97442, + 89.9319, 64.6645, 8.4875, + 89.9319, 64.6645, 10.0006, + 89.5083, 68.8345, 10.0006, + 89.0846, 73.0044, 10.0006, + 89.0846, 73.0044, 8.4875 +}; + +static const unsigned +glazing_triangles[398*3] = { + 0, 1, 2, + 2, 1, 3, + 4, 5, 6, + 7, 8, 4, + 3, 9, 10, + 11, 8, 7, + 1, 5, 8, + 8, 5, 4, + 6, 5, 0, + 10, 9, 11, + 1, 8, 9, + 3, 1, 9, + 0, 5, 1, + 9, 8, 11, + 3, 10, 12, + 13, 14, 2, + 3, 13, 2, + 3, 12, 13, + 0, 2, 14, + 15, 16, 6, + 0, 15, 6, + 0, 14, 15, + 4, 6, 16, + 17, 18, 7, + 4, 17, 7, + 4, 16, 17, + 11, 12, 10, + 19, 7, 18, + 11, 7, 19, + 11, 19, 12, + 17, 20, 18, + 19, 20, 12, + 12, 20, 13, + 16, 21, 17, + 13, 22, 14, + 15, 21, 16, + 17, 21, 20, + 14, 22, 15, + 20, 21, 22, + 13, 20, 22, + 22, 21, 15, + 18, 20, 19, + 23, 24, 25, + 23, 25, 26, + 23, 27, 24, + 24, 28, 25, + 25, 29, 26, + 26, 30, 23, + 24, 27, 31, + 32, 33, 28, + 24, 32, 28, + 24, 31, 32, + 25, 28, 33, + 34, 35, 29, + 25, 34, 29, + 25, 33, 34, + 26, 29, 35, + 36, 37, 30, + 26, 36, 30, + 26, 35, 36, + 23, 31, 27, + 38, 30, 37, + 23, 30, 38, + 23, 38, 31, + 34, 32, 38, + 36, 34, 38, + 32, 31, 38, + 34, 33, 32, + 36, 35, 34, + 38, 37, 36, + 39, 40, 41, + 41, 40, 42, + 43, 44, 45, + 46, 47, 43, + 42, 48, 49, + 50, 47, 46, + 40, 44, 47, + 47, 44, 43, + 45, 44, 39, + 49, 48, 50, + 40, 47, 48, + 42, 40, 48, + 39, 44, 40, + 48, 47, 50, + 43, 51, 46, + 52, 45, 53, + 43, 45, 52, + 43, 52, 51, + 50, 46, 51, + 54, 55, 49, + 50, 54, 49, + 50, 51, 54, + 56, 49, 55, + 42, 49, 56, + 42, 57, 41, + 42, 56, 57, + 39, 53, 45, + 58, 41, 57, + 41, 58, 39, + 39, 58, 53, + 57, 59, 58, + 56, 59, 57, + 53, 60, 52, + 52, 61, 51, + 55, 62, 56, + 51, 61, 54, + 61, 60, 59, + 52, 60, 61, + 58, 60, 53, + 54, 62, 55, + 62, 61, 59, + 62, 59, 56, + 59, 60, 58, + 54, 61, 62, + 63, 64, 65, + 66, 64, 63, + 64, 67, 65, + 66, 68, 64, + 65, 69, 63, + 63, 70, 66, + 64, 71, 67, + 72, 68, 73, + 64, 68, 72, + 64, 72, 71, + 65, 67, 71, + 74, 75, 69, + 65, 74, 69, + 65, 71, 74, + 76, 69, 75, + 63, 69, 76, + 63, 77, 70, + 63, 76, 77, + 66, 73, 68, + 78, 70, 77, + 70, 78, 66, + 66, 78, 73, + 74, 72, 76, + 76, 72, 78, + 74, 71, 72, + 72, 73, 78, + 76, 75, 74, + 78, 77, 76, + 79, 80, 81, + 82, 83, 84, + 85, 83, 82, + 81, 80, 86, + 87, 88, 79, + 89, 90, 85, + 84, 88, 87, + 86, 90, 89, + 79, 88, 80, + 90, 83, 85, + 80, 88, 83, + 83, 88, 84, + 90, 80, 83, + 86, 80, 90, + 84, 91, 82, + 92, 87, 93, + 84, 87, 92, + 84, 92, 91, + 85, 82, 91, + 94, 95, 89, + 85, 94, 89, + 85, 91, 94, + 96, 89, 95, + 86, 89, 96, + 86, 97, 81, + 86, 96, 97, + 79, 93, 87, + 98, 81, 97, + 81, 98, 79, + 79, 98, 93, + 97, 99, 98, + 92, 100, 91, + 91, 100, 94, + 96, 99, 97, + 98, 101, 93, + 94, 102, 95, + 93, 101, 92, + 95, 102, 96, + 99, 101, 98, + 94, 100, 102, + 100, 101, 99, + 92, 101, 100, + 100, 99, 102, + 102, 99, 96, + 103, 104, 105, + 103, 106, 104, + 106, 107, 104, + 103, 108, 106, + 104, 109, 105, + 105, 110, 103, + 106, 111, 107, + 112, 108, 113, + 106, 108, 112, + 106, 112, 111, + 104, 107, 111, + 114, 115, 109, + 104, 114, 109, + 104, 111, 114, + 116, 109, 115, + 105, 109, 116, + 105, 117, 110, + 105, 116, 117, + 103, 113, 108, + 118, 110, 117, + 110, 118, 103, + 103, 118, 113, + 114, 112, 118, + 116, 114, 118, + 114, 111, 112, + 112, 113, 118, + 116, 115, 114, + 118, 117, 116, + 119, 120, 121, + 122, 123, 124, + 125, 123, 122, + 121, 120, 126, + 127, 128, 119, + 129, 130, 125, + 124, 128, 127, + 126, 130, 129, + 119, 128, 120, + 130, 123, 125, + 120, 128, 123, + 123, 128, 124, + 130, 120, 123, + 126, 120, 130, + 124, 127, 131, + 132, 133, 122, + 124, 132, 122, + 124, 131, 132, + 125, 122, 133, + 134, 135, 129, + 125, 134, 129, + 125, 133, 134, + 126, 129, 135, + 136, 137, 121, + 126, 136, 121, + 126, 135, 136, + 119, 131, 127, + 138, 121, 137, + 119, 121, 138, + 119, 138, 131, + 134, 139, 135, + 131, 140, 132, + 138, 140, 131, + 135, 139, 136, + 133, 141, 134, + 137, 142, 138, + 132, 141, 133, + 136, 142, 137, + 134, 141, 139, + 142, 140, 138, + 139, 141, 140, + 140, 141, 132, + 142, 139, 140, + 136, 139, 142, + 143, 144, 145, + 145, 144, 146, + 143, 147, 144, + 144, 148, 146, + 146, 149, 145, + 145, 150, 143, + 144, 147, 151, + 152, 153, 148, + 144, 152, 148, + 144, 151, 152, + 146, 148, 153, + 154, 155, 149, + 146, 154, 149, + 146, 153, 154, + 145, 149, 155, + 156, 157, 150, + 145, 156, 150, + 145, 155, 156, + 143, 151, 147, + 158, 150, 157, + 143, 150, 158, + 143, 158, 151, + 156, 152, 158, + 154, 152, 156, + 152, 151, 158, + 154, 153, 152, + 156, 155, 154, + 158, 157, 156, + 159, 160, 161, + 159, 162, 160, + 162, 163, 160, + 159, 164, 162, + 160, 165, 161, + 161, 166, 159, + 162, 167, 163, + 168, 164, 169, + 162, 164, 168, + 162, 168, 167, + 160, 163, 167, + 170, 171, 165, + 160, 170, 165, + 160, 167, 170, + 172, 165, 171, + 161, 165, 172, + 161, 173, 166, + 161, 172, 173, + 159, 169, 164, + 174, 166, 173, + 166, 174, 159, + 159, 174, 169, + 172, 170, 174, + 170, 168, 174, + 170, 167, 168, + 168, 169, 174, + 172, 171, 170, + 174, 173, 172, + 175, 176, 177, + 175, 178, 176, + 175, 179, 178, + 178, 180, 176, + 176, 181, 177, + 177, 182, 175, + 178, 179, 183, + 184, 185, 180, + 178, 184, 180, + 178, 183, 184, + 176, 180, 185, + 186, 187, 181, + 176, 186, 181, + 176, 185, 186, + 177, 181, 187, + 188, 189, 182, + 177, 188, 182, + 177, 187, 188, + 175, 183, 179, + 190, 182, 189, + 175, 182, 190, + 175, 190, 183, + 188, 186, 190, + 186, 184, 190, + 184, 183, 190, + 186, 185, 184, + 188, 187, 186, + 190, 189, 188, + 191, 192, 193, + 193, 192, 194, + 191, 195, 192, + 192, 196, 194, + 194, 197, 193, + 193, 198, 191, + 192, 195, 199, + 200, 201, 196, + 192, 200, 196, + 192, 199, 200, + 194, 196, 201, + 202, 203, 197, + 194, 202, 197, + 194, 201, 202, + 193, 197, 203, + 204, 205, 198, + 193, 204, 198, + 193, 203, 204, + 191, 199, 195, + 206, 198, 205, + 191, 198, 206, + 191, 206, 199, + 204, 200, 206, + 202, 200, 204, + 200, 199, 206, + 202, 201, 200, + 204, 203, 202, + 206, 205, 204, + 207, 208, 209, + 209, 208, 210, + 208, 211, 210, + 207, 212, 208, + 210, 213, 209, + 209, 214, 207, + 208, 215, 211, + 216, 212, 217, + 208, 212, 216, + 208, 216, 215, + 210, 211, 215, + 218, 219, 213, + 210, 218, 213, + 210, 215, 218, + 220, 213, 219, + 209, 213, 220, + 209, 221, 214, + 209, 220, 221, + 207, 217, 212, + 222, 214, 221, + 214, 222, 207, + 207, 222, 217, + 220, 216, 222, + 218, 216, 220, + 218, 215, 216, + 216, 217, 222, + 220, 219, 218, + 222, 221, 220 +}; + +static const unsigned +glazing_properties[398*3] = { + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY, + 0, glazing_UNSPECIFIED_PROPERTY, glazing_UNSPECIFIED_PROPERTY +}; + + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct senc3d_device* dev = NULL; + struct senc3d_scene* scn = NULL; + struct context ctx = CONTEXT_NULL__; + unsigned ecount, tcount, e; + /* Triangle counts and their numbers of occurence */ + const unsigned possible_trg_counts[] = { 28, 44, 398, 42 }; + int possible_cpt[] = { 8, 3, 1, 1 }; + const size_t sz = sizeof(possible_trg_counts)/sizeof(*possible_trg_counts); + size_t i; + (void)argc, (void)argv; + ASSERT(sz == sizeof(possible_cpt)/sizeof(*possible_cpt)); + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev)); + + /* Degenerated triangle: duplicated vertex */ + ctx.positions = glazing_vertices; + ctx.indices = glazing_triangles; + ctx.properties = glazing_properties; + OK(senc3d_scene_create(dev, + SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE, + glazing_triangles_count, get_indices, get_media_from_properties, + glazing_vertices_count, get_position, &ctx, &scn)); + + OK(senc3d_scene_get_triangles_count(scn, &tcount)); + CHK(tcount == glazing_triangles_count); + OK(senc3d_scene_get_enclosure_count(scn, &ecount)); + CHK(ecount == 13); + for(e = 0; e < ecount; e++) { + struct senc3d_enclosure_header header; + struct senc3d_enclosure* enc; + int found = 0; + OK(senc3d_scene_get_enclosure(scn, e, &enc)); + OK(senc3d_enclosure_get_header(enc, &header)); + for(i = 0; i < sz; i++) { + if(possible_trg_counts[i] == header.unique_primitives_count) { + possible_cpt[i]--; + found = 1; + break; + } + } + CHK(found); + OK(senc3d_enclosure_ref_put(enc)); + } + for(i = 0; i < sz; i++) { + CHK(possible_cpt[i] == 0); + } + + OK(senc3d_scene_ref_put(scn)); + OK(senc3d_device_ref_put(dev)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_senc3d_unspecified_medium.c b/src/test_senc3d_unspecified_medium.c @@ -19,12 +19,11 @@ * geometry by program. */ #include "senc3d.h" -#include "senc3d_sXd_helper.h" #include "test_senc3d_utils.h" #include <rsys/double3.h> -#define SG3_UNSPECIFED_PROPERTY UINT_MAX +#define SG3D_UNSPECIFIED_PROPERTY UINT_MAX /* Dump of star-geometry 'front_unspecified'. */ static const unsigned front_unspecified_vertices_count = 8; @@ -57,18 +56,18 @@ static const unsigned front_unspecified_triangles[36] = }; static const unsigned front_unspecified_properties[36] = { - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY }; /* Dump of star-geometry 'front_half_unspecified'. */ static const unsigned front_half_unspecified_vertices_count = 8; @@ -101,17 +100,17 @@ static const unsigned front_half_unspecified_triangles[36] = }; static const unsigned front_half_unspecified_properties[36] = { - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, 0, 1, 0, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, 0, 1, 0, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, 0, 1, 0, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, 0, 1, 0, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, 0, 1, 0, - SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY, + SG3D_UNSPECIFIED_PROPERTY, 1, SG3D_UNSPECIFIED_PROPERTY, 0, 1, 0 }; /* Dump of star-geometry 'all_defined'. */ @@ -159,7 +158,7 @@ static const unsigned all_defined_properties[36] = 0, 1, 0 }; -#undef SG3_UNSPECIFED_PROPERTY +#undef SG3D_UNSPECIFIED_PROPERTY static void test(const int convention) diff --git a/src/test_senc3d_utils.h b/src/test_senc3d_utils.h @@ -22,6 +22,8 @@ #include <stdio.h> +#include <star/senc3d.h> + #define OK(Expr) CHK((Expr) == RES_OK) #define BA(Expr) CHK((Expr) == RES_BAD_ARG) #define BO(Expr) CHK((Expr) == RES_BAD_OP) @@ -113,7 +115,7 @@ static INLINE void get_position(const unsigned ivert, double pos[3], void* context) { const struct context* ctx = context; - ASSERT(pos && ctx && ctx->scale); + ASSERT(pos && ctx && ctx->scale != 0); pos[0] = ctx->positions[ivert * 3 + 0] * ctx->scale + ctx->offset[0]; pos[1] = ctx->positions[ivert * 3 + 1] * ctx->scale + ctx->offset[1]; pos[2] = ctx->positions[ivert * 3 + 2] * ctx->scale + ctx->offset[2]; diff --git a/src/test_senc3d_zero_distance.c b/src/test_senc3d_zero_distance.c @@ -145,6 +145,270 @@ zero_1_properties[36][3] = { { 1, 0, zero_1_UNSPECIFIED_PROPERTY } }; +/* zero_1d is similar as zero_1, with geometry duplicated in mirror along Z axis */ +static const unsigned +zero_1d_vertices_count = 44; + +static const unsigned +zero_1d_triangles_count = 72; + +static const double +zero_1d_vertices[44][3] = { + { 10, 10, -11 }, + { 10, 0, -11 }, + { 0, 10, -11 }, + { 0, 0, -11 }, + { 0, 10, -1 }, + { 0, 0, -1 }, + { 10, 0, -1 }, + { 9, 9, 0 }, + { 8, 9, -10 }, + { 4, 7, -10 }, + { 1, 9, -10 }, + { 1, 2, -10 }, + { 1, 9, -2 }, + { 1, 2, -2 }, + { 4, 7, -2 }, + { 7, 5, -10 }, + { 9, 8, -10 }, + { 9, 1, -10 }, + { 2, 1, -10 }, + { 2, 1, -2 }, + { 9, 1, -2 }, + { 7, 4, -2 }, + { 10, 10, 11 }, + { 10, 0, 11 }, + { 0, 10, 11 }, + { 0, 0, 11 }, + { 0, 10, 1 }, + { 0, 0, 1 }, + { 10, 0, 1 }, + { 9, 9, 0.1 }, /* Vertex #29 == vertex #7 => keep a dummy placeholder here and use #7 instead in triangles */ + { 8, 9, 10 }, + { 4, 7, 10 }, + { 1, 9, 10 }, + { 1, 2, 10 }, + { 1, 9, 2 }, + { 1, 2, 2 }, + { 4, 7, 2 }, + { 7, 5, 10 }, + { 9, 8, 10 }, + { 9, 1, 10 }, + { 2, 1, 10 }, + { 2, 1, 2 }, + { 9, 1, 2 }, + { 7, 4, 2 } +}; + +static const unsigned +zero_1d_triangles[72][3] = { + { 0, 1, 2 }, + { 1, 3, 2 }, + { 4, 5, 6 }, + { 7, 4, 6 }, + { 2, 3, 4 }, + { 3, 5, 4 }, + { 6, 1, 7 }, + { 1, 0, 7 }, + { 0, 2, 4 }, + { 7, 0, 4 }, + { 5, 3, 1 }, + { 6, 5, 1 }, + { 8, 9, 10 }, + { 9, 11, 10 }, + { 12, 13, 14 }, + { 7, 12, 14 }, + { 10, 11, 12 }, + { 11, 13, 12 }, + { 14, 9, 7 }, + { 9, 8, 7 }, + { 8, 10, 12 }, + { 7, 8, 12 }, + { 13, 11, 9 }, + { 14, 13, 9 }, + { 15, 16, 17 }, + { 18, 15, 17 }, + { 19, 20, 21 }, + { 20, 7, 21 }, + { 18, 17, 20 }, + { 19, 18, 20 }, + { 15, 21, 7 }, + { 16, 15, 7 }, + { 17, 16, 20 }, + { 16, 7, 20 }, + { 18, 19, 15 }, + { 19, 21, 15 }, + { 22, 23, 24 }, + { 23, 25, 24 }, + { 26, 27, 28 }, + { 7, 26, 28 }, + { 24, 25, 26 }, + { 25, 27, 26 }, + { 28, 23, 7 }, + { 23, 22, 7 }, + { 22, 24, 26 }, + { 7, 22, 26 }, + { 27, 25, 23 }, + { 28, 27, 23 }, + { 30, 31, 32 }, + { 31, 33, 32 }, + { 34, 35, 36 }, + { 7, 34, 36 }, + { 32, 33, 34 }, + { 33, 35, 34 }, + { 36, 31, 7 }, + { 31, 30, 7 }, + { 30, 32, 34 }, + { 7, 30, 34 }, + { 35, 33, 31 }, + { 36, 35, 31 }, + { 37, 38, 39 }, + { 40, 37, 39 }, + { 41, 42, 43 }, + { 42, 7, 43 }, + { 40, 39, 42 }, + { 41, 40, 42 }, + { 37, 43, 7 }, + { 38, 37, 7 }, + { 39, 38, 42 }, + { 38, 7, 42 }, + { 40, 41, 37 }, + { 41, 43, 37 } +}; + +static const unsigned +zero_1d_properties[72][3] = { + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 0, zero_1_UNSPECIFIED_PROPERTY, 2 }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_1_UNSPECIFIED_PROPERTY }, + + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { zero_1_UNSPECIFIED_PROPERTY, 0, 2 }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_1_UNSPECIFIED_PROPERTY } +}; + +/* zero_1D is similar as zero_1d, with a tiny distance between mirrored + * geometries */ +static const double +zero_1D_vertices[44][3] = { + { 10, 10, -11 }, + { 10, 0, -11 }, + { 0, 10, -11 }, + { 0, 0, -11 }, + { 0, 10, -1 }, + { 0, 0, -1 }, + { 10, 0, -1 }, + { 9, 9, 0 }, + { 8, 9, -10 }, + { 4, 7, -10 }, + { 1, 9, -10 }, + { 1, 2, -10 }, + { 1, 9, -2 }, + { 1, 2, -2 }, + { 4, 7, -2 }, + { 7, 5, -10 }, + { 9, 8, -10 }, + { 9, 1, -10 }, + { 2, 1, -10 }, + { 2, 1, -2 }, + { 9, 1, -2 }, + { 7, 4, -2 }, + { 10, 10, 11 }, + { 10, 0, 11 }, + { 0, 10, 11 }, + { 0, 0, 11 }, + { 0, 10, 1 }, + { 0, 0, 1 }, + { 10, 0, 1 }, + { 9, 9, 1e-30 }, + { 8, 9, 10 }, + { 4, 7, 10 }, + { 1, 9, 10 }, + { 1, 2, 10 }, + { 1, 9, 2 }, + { 1, 2, 2 }, + { 4, 7, 2 }, + { 7, 5, 10 }, + { 9, 8, 10 }, + { 9, 1, 10 }, + { 2, 1, 10 }, + { 2, 1, 2 }, + { 9, 1, 2 }, + { 7, 4, 2 } +}; + +#define zero_1D_triangles zero_1d_triangles + +#define zero_1D_properties zero_1d_properties +static unsigned zero_1D_triangles_count = zero_1d_triangles_count; +static unsigned zero_1D_vertices_count = zero_1d_vertices_count; + /* zero_2 geometry is made of 5 nested distorded cubes of decreasing sizes, that * all join at a single vertex V (the highest vertex in the model). Distance between * the 10 components (inside and outside of each shape) is zero. */ @@ -324,6 +588,422 @@ zero_2_properties[60][3] = { { 4, 3, zero_2_UNSPECIFIED_PROPERTY } }; +/* zero_2d is similar as zero_2, with geometry duplicated in mirror along Z axis */ +static const unsigned +zero_2d_vertices_count = 72; + +static const unsigned +zero_2d_triangles_count = 120; + +static const double +zero_2d_vertices[72][3] = { + { 0, 10, -11 }, + { 0, 0, -11 }, + { 0, 10, -1 }, + { 0, 0, -1 }, + { 10, 0, -1 }, + { 10, 0, -11 }, + { 9, 9, 0 }, + { 10, 10, -11 }, + { 1, 9, -10 }, + { 1, 1, -10 }, + { 1, 9, -2 }, + { 1, 1, -2 }, + { 9, 1, -2 }, + { 9, 1, -10 }, + { 9, 9, -10 }, + { 2, 8, -9 }, + { 2, 2, -9 }, + { 2, 8, -3 }, + { 2, 2, -3 }, + { 8, 2, -3 }, + { 8, 2, -9 }, + { 8, 8, -9 }, + { 3, 7, -8 }, + { 3, 3, -8 }, + { 3, 7, -4 }, + { 3, 3, -4 }, + { 7, 3, -4 }, + { 7, 3, -8 }, + { 7, 7, -8 }, + { 4, 6, -7 }, + { 4, 4, -7 }, + { 4, 6, -5 }, + { 4, 4, -5 }, + { 6, 4, -5 }, + { 6, 4, -7 }, + { 6, 6, -7 }, + { 0, 10, 11 }, + { 0, 0, 11 }, + { 0, 10, 1 }, + { 0, 0, 1 }, + { 10, 0, 1 }, + { 10, 0, 11 }, + { 9, 9, 0.1 }, /* Vertex #42 == vertex #6 => keep a dummy placeholder here and use #6 instead in triangles */ + { 10, 10, 11 }, + { 1, 9, 10 }, + { 1, 1, 10 }, + { 1, 9, 2 }, + { 1, 1, 2 }, + { 9, 1, 2 }, + { 9, 1, 10 }, + { 9, 9, 10 }, + { 2, 8, 9 }, + { 2, 2, 9 }, + { 2, 8, 3 }, + { 2, 2, 3 }, + { 8, 2, 3 }, + { 8, 2, 9 }, + { 8, 8, 9 }, + { 3, 7, 8 }, + { 3, 3, 8 }, + { 3, 7, 4 }, + { 3, 3, 4 }, + { 7, 3, 4 }, + { 7, 3, 8 }, + { 7, 7, 8 }, + { 4, 6, 7 }, + { 4, 4, 7 }, + { 4, 6, 5 }, + { 4, 4, 5 }, + { 6, 4, 5 }, + { 6, 4, 7 }, + { 6, 6, 7 } +}; + +static const unsigned +zero_2d_triangles[120][3] = { + { 0, 1, 2 }, + { 1, 3, 2 }, + { 4, 5, 6 }, + { 5, 7, 6 }, + { 2, 3, 4 }, + { 6, 2, 4 }, + { 5, 1, 0 }, + { 7, 5, 0 }, + { 3, 1, 5 }, + { 4, 3, 5 }, + { 7, 0, 2 }, + { 6, 7, 2 }, + { 8, 9, 10 }, + { 9, 11, 10 }, + { 12, 13, 6 }, + { 13, 14, 6 }, + { 10, 11, 12 }, + { 6, 10, 12 }, + { 13, 9, 8 }, + { 14, 13, 8 }, + { 11, 9, 13 }, + { 12, 11, 13 }, + { 14, 8, 10 }, + { 6, 14, 10 }, + { 15, 16, 17 }, + { 16, 18, 17 }, + { 19, 20, 6 }, + { 20, 21, 6 }, + { 17, 18, 19 }, + { 6, 17, 19 }, + { 20, 16, 15 }, + { 21, 20, 15 }, + { 18, 16, 20 }, + { 19, 18, 20 }, + { 21, 15, 17 }, + { 6, 21, 17 }, + { 22, 23, 24 }, + { 23, 25, 24 }, + { 26, 27, 6 }, + { 27, 28, 6 }, + { 24, 25, 26 }, + { 6, 24, 26 }, + { 27, 23, 22 }, + { 28, 27, 22 }, + { 25, 23, 27 }, + { 26, 25, 27 }, + { 28, 22, 24 }, + { 6, 28, 24 }, + { 29, 30, 31 }, + { 30, 32, 31 }, + { 33, 34, 6 }, + { 34, 35, 6 }, + { 31, 32, 33 }, + { 6, 31, 33 }, + { 34, 30, 29 }, + { 35, 34, 29 }, + { 32, 30, 34 }, + { 33, 32, 34 }, + { 35, 29, 31 }, + { 6, 35, 31 }, + { 36, 37, 38 }, + { 37, 39, 38 }, + { 40, 41, 6 }, + { 41, 43, 6 }, + { 38, 39, 40 }, + { 6, 38, 40 }, + { 41, 37, 36 }, + { 43, 41, 36 }, + { 39, 37, 41 }, + { 40, 39, 41 }, + { 43, 36, 38 }, + { 6, 43, 38 }, + { 44, 45, 46 }, + { 45, 47, 46 }, + { 48, 49, 6 }, + { 49, 50, 6 }, + { 46, 47, 48 }, + { 6, 46, 48 }, + { 49, 45, 44 }, + { 50, 49, 44 }, + { 47, 45, 49 }, + { 48, 47, 49 }, + { 50, 44, 46 }, + { 6, 50, 46 }, + { 51, 52, 53 }, + { 52, 54, 53 }, + { 55, 56, 6 }, + { 56, 57, 6 }, + { 53, 54, 55 }, + { 6, 53, 55 }, + { 56, 52, 51 }, + { 57, 56, 51 }, + { 54, 52, 56 }, + { 55, 54, 56 }, + { 57, 51, 53 }, + { 6, 57, 53 }, + { 58, 59, 60 }, + { 59, 61, 60 }, + { 62, 63, 6 }, + { 63, 64, 6 }, + { 60, 61, 62 }, + { 6, 60, 62 }, + { 63, 59, 58 }, + { 64, 63, 58 }, + { 61, 59, 63 }, + { 62, 61, 63 }, + { 64, 58, 60 }, + { 6, 64, 60 }, + { 65, 66, 67 }, + { 66, 68, 67 }, + { 69, 70, 6 }, + { 70, 71, 6 }, + { 67, 68, 69 }, + { 6, 67, 69 }, + { 70, 66, 65 }, + { 71, 70, 65 }, + { 68, 66, 70 }, + { 69, 68, 70 }, + { 71, 65, 67 }, + { 6, 71, 67 } +}; + +static const unsigned +zero_2d_properties[120][3] = { + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { zero_2_UNSPECIFIED_PROPERTY, 0, 5 }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 0, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 4, zero_2_UNSPECIFIED_PROPERTY } +}; + +/* zero_2D is similar as zero_2d, with a tiny distance between mirrored + * geometries */ +static const double +zero_2D_vertices[72][3] = { + { 0, 10, -11 }, + { 0, 0, -11 }, + { 0, 10, -1 }, + { 0, 0, -1 }, + { 10, 0, -1 }, + { 10, 0, -11 }, + { 9, 9, 0 }, + { 10, 10, -11 }, + { 1, 9, -10 }, + { 1, 1, -10 }, + { 1, 9, -2 }, + { 1, 1, -2 }, + { 9, 1, -2 }, + { 9, 1, -10 }, + { 9, 9, -10 }, + { 2, 8, -9 }, + { 2, 2, -9 }, + { 2, 8, -3 }, + { 2, 2, -3 }, + { 8, 2, -3 }, + { 8, 2, -9 }, + { 8, 8, -9 }, + { 3, 7, -8 }, + { 3, 3, -8 }, + { 3, 7, -4 }, + { 3, 3, -4 }, + { 7, 3, -4 }, + { 7, 3, -8 }, + { 7, 7, -8 }, + { 4, 6, -7 }, + { 4, 4, -7 }, + { 4, 6, -5 }, + { 4, 4, -5 }, + { 6, 4, -5 }, + { 6, 4, -7 }, + { 6, 6, -7 }, + { 0, 10, 11 }, + { 0, 0, 11 }, + { 0, 10, 1 }, + { 0, 0, 1 }, + { 10, 0, 1 }, + { 10, 0, 11 }, + { 9, 9, 1e-30 }, + { 10, 10, 11 }, + { 1, 9, 10 }, + { 1, 1, 10 }, + { 1, 9, 2 }, + { 1, 1, 2 }, + { 9, 1, 2 }, + { 9, 1, 10 }, + { 9, 9, 10 }, + { 2, 8, 9 }, + { 2, 2, 9 }, + { 2, 8, 3 }, + { 2, 2, 3 }, + { 8, 2, 3 }, + { 8, 2, 9 }, + { 8, 8, 9 }, + { 3, 7, 8 }, + { 3, 3, 8 }, + { 3, 7, 4 }, + { 3, 3, 4 }, + { 7, 3, 4 }, + { 7, 3, 8 }, + { 7, 7, 8 }, + { 4, 6, 7 }, + { 4, 4, 7 }, + { 4, 6, 5 }, + { 4, 4, 5 }, + { 6, 4, 5 }, + { 6, 4, 7 }, + { 6, 6, 7 } +}; + +#define zero_2D_triangles zero_2d_triangles + +#define zero_2D_properties zero_2d_properties +static unsigned zero_2D_triangles_count = zero_2d_triangles_count; +static unsigned zero_2D_vertices_count = zero_2d_vertices_count; + + /* Enclosures' order is consistent accross runs as they are sorted by triangle * sides, thus allowing to expect a given order */ struct expected { @@ -356,12 +1036,10 @@ test ctx.indices = indices; ctx.properties = properties; - if(n == 1) { - /* Same model with symmetry / origin - * (need to reverse vertices' order to keep same inside/outside) */ - ctx.scale = -1; - ctx.reverse_vrtx = 1; - } + /* If n==1, same model with symmetry / origin + * (need to reverse vertices' order to keep same inside/outside) */ + ctx.scale = (n == 1) ? -1 : +1; + ctx.reverse_vrtx = (n == 1) ? 1 : 0; OK(senc3d_scene_create(dev, SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE, @@ -390,7 +1068,7 @@ test CHK(eq_eps(header.volume, expected->volume[e], 0.01)); OK(senc3d_enclosure_ref_put(enclosure)); #ifdef DUMP_ENCLOSURES - snprintf(name, sizeof(name), "test_cube_on_cube_%u.obj", e); + snprintf(name, sizeof(name), "test_zero_distance_%u.obj", e); dump_enclosure(scn, e, name); #endif } @@ -425,6 +1103,29 @@ main(int argc, char** argv) (unsigned *)zero_1_properties, zero_1_triangles_count, zero_1_vertices_count, &expected); + expected.enclosure_count = 7; + expected.medium[0] = SENC3D_UNSPECIFIED_MEDIUM; + expected.volume[0] = -1933.33; + expected.medium[1] = 0; + expected.volume[1] = 647.33; + expected.medium[2] = 1; + expected.volume[2] = 150; + expected.medium[3] = 1; + expected.volume[3] = 169.33; + expected.medium[4] = 0; + expected.volume[4] = 647.33; + expected.medium[5] = 1; + expected.volume[5] = 150; + expected.medium[6] = 1; + expected.volume[6] = 169.33; + test((double *)zero_1d_vertices, (unsigned*)zero_1d_triangles, + (unsigned *)zero_1d_properties, zero_1d_triangles_count, + zero_1d_vertices_count, &expected); + + test((double *)zero_1D_vertices, (unsigned*)zero_1D_triangles, + (unsigned *)zero_1D_properties, zero_1D_triangles_count, + zero_1D_vertices_count, &expected); + expected.enclosure_count = 6; expected.medium[0] = SENC3D_UNSPECIFIED_MEDIUM; expected.volume[0] = -966.67; @@ -442,5 +1143,36 @@ main(int argc, char** argv) (unsigned*)zero_2_properties, zero_2_triangles_count, zero_2_vertices_count, &expected); + expected.enclosure_count = 11; + expected.medium[0] = SENC3D_UNSPECIFIED_MEDIUM; + expected.volume[0] = -1933.33; + expected.medium[1] = 0; + expected.volume[1] = 433.33; + expected.medium[2] = 1; + expected.volume[2] = 281.33; + expected.medium[3] = 2; + expected.volume[3] = 161.33; + expected.medium[4] = 3; + expected.volume[4] = 73.33; + expected.medium[5] = 4; + expected.volume[5] = 17.33; + expected.medium[6] = 0; + expected.volume[6] = 433.33; + expected.medium[7] = 1; + expected.volume[7] = 281.33; + expected.medium[8] = 2; + expected.volume[8] = 161.33; + expected.medium[9] = 3; + expected.volume[9] = 73.33; + expected.medium[10] = 4; + expected.volume[10] = 17.33; + test((double*)zero_2d_vertices, (unsigned*)zero_2d_triangles, + (unsigned*)zero_2d_properties, zero_2d_triangles_count, + zero_2d_vertices_count, &expected); + + test((double*)zero_2D_vertices, (unsigned*)zero_2D_triangles, + (unsigned*)zero_2D_properties, zero_2D_triangles_count, + zero_2d_vertices_count, &expected); + return 0; -} -\ No newline at end of file +}