city_generator2

Generated conformal 3D meshes representing a city
git clone git://git.meso-star.fr/city_generator2.git
Log | Files | Refs | README | LICENSE

commit 26d5fae0ce66c4f870b0cc409e13e481ad717e0d
Author: Benjamin Piaud <benjamin.piaud@meso-star.com>
Date:   Tue,  2 Aug 2022 17:50:51 +0200

First commit

Diffstat:
Asrc/building.c | 532+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/building.h | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/city.c | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/city.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ground.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ground.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Asrc/polygon.c | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/polygon.h | 25+++++++++++++++++++++++++
9 files changed, 1299 insertions(+), 0 deletions(-)

diff --git a/src/building.c b/src/building.c @@ -0,0 +1,532 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 |Meso|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/>. */ + +#include <rsys/str.h> + +#include "building.h" + +#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0 + + +static res_T +build_slab +(const struct pg_polygon* pg, + struct building* b) +{ + res_T res = RES_OK; + size_t id; + enum model model; + double e; + struct data_model0* data; + struct data_cad_model0* data_cad; + struct scad_geometry* footprint; + double d[3] = {0, 0, 0}; + struct str name; + + id = b->id; + model = b->model; + data = (struct data_model0*)b->data; + data_cad = (struct data_cad_model0*)b->data_cad; + e = data->slab; + + str_init(NULL, &name); + ERR(str_set(&name, "building_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)id)); + ERR(str_append(&name, "_model_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)model)); + ERR(str_append(&name, "_slab")); + + ERR(scad_scene_add_polygon + (b->scene, + NULL, /* Can be NULL */ + pg->x, + pg->y, + 0, + pg->n, /* size of x and y arrays */ + &footprint)); + + d[2] = e; + ERR(scad_geometry_extrude + (footprint, + str_cget(&name), + d, + &data_cad->slab)); + +exit: + return res; +error: + goto exit; +} + +static res_T +build_roof(const struct scad_geometry* slab, struct building* b) +{ + res_T res = RES_OK; + size_t id; + enum model model; + double height; + double e; + double d[3] = {0, 0, 0}; + struct data_model0* data; + struct data_cad_model0* data_cad; + struct str name; + + id = b->id; + model = b->model; + height = b->height; + data = (struct data_model0*)b->data; + data_cad = (struct data_cad_model0*)b->data_cad; + e = data->slab; + + str_init(NULL, &name); + ERR(str_set(&name, "building_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)id)); + ERR(str_append(&name, "_model_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)model)); + ERR(str_append(&name, "_roof")); + + ERR(scad_geometry_copy(slab, str_cget(&name), &data_cad->roof)); + d[2] = height - e ; + ERR(scad_geometry_translate(data_cad->roof, d)); + +exit: + return res; +error: + goto exit; +} + +static res_T +build_wall + (const struct pg_polygon* pg, + const struct pg_polygon* pg_int, + struct building* b) +{ + res_T res = RES_OK; + size_t id; + enum model model; + double height; + struct data_cad_model0* data_cad; + struct scad_geometry* polygon; + struct scad_geometry* polygon_int; + struct scad_geometry* footprint; + double d[3] = {0, 0, 0}; + struct str name; + + id = b->id; + model = b->model; + height = b->height; + data_cad = (struct data_cad_model0*)b->data_cad; + + str_init(NULL, &name); + ERR(str_set(&name, "building_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)id)); + ERR(str_append(&name, "_model_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)model)); + ERR(str_append(&name, "_wall")); + + ERR(scad_scene_add_polygon + (b->scene, + NULL, + pg->x, + pg->y, + 0, + pg->n, + &polygon)); + + ERR(scad_scene_add_polygon + (b->scene, + NULL, + pg_int->x, + pg_int->y, + 0, + pg_int->n, + &polygon_int)); + + + ERR(scad_scene_cut_geometries + (b->scene, + NULL, + polygon, + polygon_int, + &footprint, + 0)); + + d[2] = height; + ERR(scad_geometry_extrude + (footprint, + str_cget(&name), + d, + &data_cad->wall)); + +exit: + return res; +error: + goto exit; +} + +static res_T +build_cavity(const struct pg_polygon* pg, struct building* b) +{ + res_T res = RES_OK; + size_t id; + enum model model; + double e, height; + struct data_model0* data; + struct data_cad_model0* data_cad; + double d[3] = {0, 0, 0}; + struct scad_geometry* polygon; + struct str name; + + id = b->id; + model = b->model; + height = b->height; + data = (struct data_model0*)b->data; + data_cad = (struct data_cad_model0*)b->data_cad; + e = data->slab; + + str_init(NULL, &name); + ERR(str_set(&name, "building_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)id)); + ERR(str_append(&name, "_model_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)model)); + ERR(str_append(&name, "_cavity")); + + ERR(scad_scene_add_polygon + (b->scene, + NULL, /* Can be NULL */ + pg->x, + pg->y, + e, + pg->n, /* size of x and y arrays */ + &polygon)); + + d[2] = height - e; + ERR(scad_geometry_extrude + (polygon, + str_cget(&name), + d, + &data_cad->cavity)); + +exit: + return res; +error: + goto exit; +} + +static res_T +build_connection(struct building* b) +{ + res_T res = RES_OK; + size_t id; + enum model model; + struct data_cad_model0* data_cad; + struct str slab_name, wall_name, roof_name; + + id = b->id; + model = b->model; + data_cad = (struct data_cad_model0*)b->data_cad; + + data_cad->connection = malloc(3 * sizeof(struct scad_geometry*)); + data_cad->n_connection = 3; + + /* cavity/slab connection */ + str_init(NULL, &slab_name); + ERR(str_set(&slab_name, "building_")); + ERR(str_append_printf(&slab_name, "%lu", (unsigned long)id)); + ERR(str_append(&slab_name, "_model_")); + ERR(str_append_printf(&slab_name, "%lu", (unsigned long)model)); + ERR(str_append(&slab_name, "_C_cavity_slab")); + + ERR(scad_scene_geometries_common_boundaries + (b->scene, + str_cget(&slab_name), + data_cad->cavity, + data_cad->slab, + &data_cad->connection[0], + 0)); + + /* cavity/wall connection */ + str_init(NULL, &wall_name); + ERR(str_set(&wall_name, "building_")); + ERR(str_append_printf(&wall_name, "%lu", (unsigned long)id)); + ERR(str_append(&wall_name, "_model_")); + ERR(str_append_printf(&wall_name, "%lu", (unsigned long)model)); + ERR(str_append(&wall_name, "_C_cavity_wall")); + + ERR(scad_scene_geometries_common_boundaries + (b->scene, + str_cget(&wall_name), + data_cad->cavity, + data_cad->wall, + &data_cad->connection[1], + 0)); + + /* cavity/roof connection */ + str_init(NULL, &roof_name); + ERR(str_set(&roof_name, "building_")); + ERR(str_append_printf(&roof_name, "%lu", (unsigned long)id)); + ERR(str_append(&roof_name, "_model_")); + ERR(str_append_printf(&roof_name, "%lu", (unsigned long)model)); + ERR(str_append(&roof_name, "_C_cavity_roof")); + + ERR(scad_scene_geometries_common_boundaries + (b->scene, + str_cget(&roof_name), + data_cad->cavity, + data_cad->roof, + &data_cad->connection[2], + 0)); + +exit: + return res; +error: + goto exit; +} + +static res_T +build_boundary(struct building* b) +{ + res_T res = RES_OK; + size_t id; + enum model model; + struct data_cad_model0* data_cad; + struct scad_geometry** list; + struct str name; + + id = b->id; + model = b->model; + data_cad = (struct data_cad_model0*)b->data_cad; + + list = malloc(4 * sizeof(struct scad_geometry*)); + list[0] = data_cad->slab; + list[1] = data_cad->wall; + list[2] = data_cad->roof; + list[3] = data_cad->cavity; + + str_init(NULL, &name); + ERR(str_set(&name, "building_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)id)); + ERR(str_append(&name, "_model_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)model)); + ERR(str_append(&name, "_boundary")); + + ERR(scad_scene_create_group + (b->scene, + str_cget(&name), + 3, + list, + 4, + &data_cad->boundary)); + +exit: + if (list) free(list); + return res; +error: + goto exit; +} + +res_T +build_cad_model0 +(struct scad_device* dev, + struct building* building) +{ + res_T res = RES_OK; + double height = building->height; + struct pg_polygon pg = building->pg[0]; + struct pg_polygon pg_int, pg_ext; + struct data_model0* data = (struct data_model0 *)building->data; + struct data_cad_model0* data_cad; + double e_wall; + + if (!building || !dev) { + res = RES_BAD_ARG; + goto error; + } + + if (height <= 0 || data->wall <= 0 || data->slab <= 0) { + res = RES_BAD_ARG; + goto error; + } + + data_cad = malloc(sizeof(struct data_cad_model0)); + building->data_cad = (struct data_cad_model0*)data_cad; + + ERR(scad_scene_create(dev, &building->scene)); + + e_wall = data->wall; + ERR(pg_offset(&pg, e_wall, &pg_int, &pg_ext)); + + /* build slab with pg_int */ + ERR(build_slab(&pg_int, building)); + + /* roof is a translated copy of slab */ + ERR(build_roof(data_cad->slab, building)); + + /* build wall with pg and pg_int */ + ERR(build_wall(&pg, &pg_int, building)); + + /* build cavity */ + ERR(build_cavity(&pg_int, building)); + + ERR(scad_scene_conformal_mesh(building->scene)); + + /* build connection cavity/slab */ + ERR(build_connection(building)); + + /* build boundary */ + ERR(build_boundary(building)); + +exit: + pg_release(&pg_int); + pg_release(&pg_ext); + return res; +error: + goto exit; +} + +res_T +build_footprint_model0 +(struct scad_scene* scene, + struct building* building, + struct scad_geometry** footprint) +{ + res_T res = RES_OK; + struct pg_polygon pg = building->pg[0]; + struct pg_polygon pg_int, pg_ext; + struct data_model0* data = (struct data_model0 *)building->data; + double e_wall; + struct scad_geometry* geom[2]; + struct scad_geometry* polygon; + enum model model = building->model; + size_t id = building->id; + struct str name; + + e_wall = data->wall; + ERR(pg_offset(&pg, e_wall, &pg_int, &pg_ext)); + + ERR(scad_scene_add_polygon + (scene, + NULL, + pg.x, + pg.y, + 0, + pg.n, + &polygon)); + + ERR(scad_scene_add_polygon + (scene, + NULL, + pg_int.x, + pg_int.y, + 0, + pg_int.n, + &geom[0])); + + + ERR(scad_scene_cut_geometries + (scene, + NULL, + polygon, + geom[0], + &geom[1], + 0)); + + str_init(NULL, &name); + ERR(str_set(&name, "building_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)id)); + ERR(str_append(&name, "_model_")); + ERR(str_append_printf(&name, "%lu", (unsigned long)model)); + ERR(str_append(&name, "_footprint")); + + ERR(scad_scene_create_group + (scene, + str_cget(&name), + 3, + geom, + 2, + footprint)); + +exit: + pg_release(&pg_int); + pg_release(&pg_ext); + return res; +error: + goto exit; +} + +res_T +export_stl_model0 +(const struct building* building) +{ + res_T res = RES_OK; + struct data_cad_model0* data_cad = (struct data_cad_model0 *)building->data_cad; + size_t i; + + /* slab export */ + ERR(scad_stl_export(data_cad->slab, NULL, 0)); + + /* roof export */ + ERR(scad_stl_export(data_cad->roof, NULL, 0)); + + /* wall export */ + ERR(scad_stl_export(data_cad->wall, NULL, 0)); + + /* cavity export */ + ERR(scad_stl_export(data_cad->cavity, NULL, 0)); + + /* connection export */ + for (i=0; i<data_cad->n_connection; ++i) { + ERR(scad_stl_export(data_cad->connection[i], NULL, 0)); + } + + /* boundary export */ + ERR(scad_stl_export(data_cad->boundary, NULL, 0)); + + /* footprint export */ + /*ERR(scad_stl_export(building->footprint, NULL, 0)); */ + +exit: + return res; +error: + goto exit; +} + +res_T +release_model0 +(struct building* building) +{ + res_T res = RES_OK; + size_t i; + + struct data_model0* data = (struct data_model0 *)building->data; + struct data_cad_model0* data_cad = (struct data_cad_model0 *)building->data_cad; + + ERR(scad_scene_ref_put(building->scene)); + + for (i=0; i<building->polygon_count; ++i) { + pg_release(&building->pg[i]); + } + if (building->pg) free(building->pg); + + if (data_cad->connection) free(data_cad->connection); + if (data) free(data); + if (data_cad) free(data_cad); + +exit: + return res; +error: + goto exit; +} diff --git a/src/building.h b/src/building.h @@ -0,0 +1,93 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 |Meso|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/>. */ + +#include <rsys/rsys.h> +#include <star/scad.h> + +#include "polygon.h" + +#ifndef BUILDING_H +#define BUILDING_H + +enum model { + MODEL0, + MODEL_COUNT_ +}; + +struct building { + /* generic building data */ + size_t id; + enum model model; + double height; + struct pg_polygon* pg; /* list of polygons. First is external footprint. + * Others describe internal holes*/ + size_t polygon_count; /* number of polygon */ + + /* each building has his own scene */ + struct scad_scene* scene; + /* footprint for ground scene */ + struct scad_geometry* footprint; + + /* specific data depending model */ + void* data; + void* data_cad; + + /* functors depending model */ + res_T (*build_cad)(struct scad_device* dev, struct building* building); + res_T (*build_footprint) + (struct scad_scene* scene, + struct building* building, + struct scad_geometry** footprint); + res_T (*export_stl)(const struct building* building); + res_T (*release)(struct building* building); +}; + +/* specific data for model 0 */ +struct data_model0 { + double wall; /* wall thickness */ + double slab; /* slab thickness */ +}; + +struct data_cad_model0 { + struct scad_geometry* wall; + struct scad_geometry* roof; + struct scad_geometry* slab; + struct scad_geometry* cavity; + struct scad_geometry* boundary; + struct scad_geometry** connection; + size_t n_connection; +}; + +res_T +build_cad_model0 +(struct scad_device* dev, + struct building* building); + +res_T +build_footprint_model0 +(struct scad_scene* scene, + struct building* building, + struct scad_geometry** footprint); + +res_T +export_stl_model0 +(const struct building* building); + +res_T +release_model0 +(struct building* building); + +#endif /* BUILDING_H */ diff --git a/src/city.c b/src/city.c @@ -0,0 +1,180 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 |Meso|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/>. */ + +#include "city.h" + +res_T +city_init(struct city* city) +{ + res_T res = RES_OK; + struct building* building = NULL; + struct data_model0 data0, data1; + /*struct ground ground;*/ + +#define NBUILD 2 + building = malloc(NBUILD * sizeof(struct building)); + + building[0].id = 0; + building[0].model = MODEL0; + building[0].height = 3; + building[0].polygon_count = 1; + building[0].pg = malloc(building[0].polygon_count * sizeof(struct pg_polygon)); + ERR(pg_init(&building[0].pg[0], 4)); + building[0].pg[0].x[0] = 0; building[0].pg[0].y[0] = 0; + building[0].pg[0].x[1] = 0; building[0].pg[0].y[1] = 10; + building[0].pg[0].x[2] = 10; building[0].pg[0].y[2] = 10; + building[0].pg[0].x[3] = 10; building[0].pg[0].y[3] = 0; + building[0].data = malloc(sizeof(struct data_model0)); + data0.wall = 0.2; + data0.slab = 0.3; + *(struct data_model0*)(building[0].data) = data0; + building[0].build_cad = &build_cad_model0; + building[0].export_stl = &export_stl_model0; + building[0].release = &release_model0; + building[0].build_footprint = &build_footprint_model0; + + building[1].id = 1; + building[1].model = MODEL0; + building[1].height = 3.5; + building[1].polygon_count = 1; + building[1].pg = malloc(building[1].polygon_count * sizeof(struct pg_polygon)); + ERR(pg_init(&building[1].pg[0], 3)); + building[1].pg[0].x[0] = 20; building[1].pg[0].y[0] = 0; + building[1].pg[0].x[1] = 25; building[1].pg[0].y[1] = 10; + building[1].pg[0].x[2] = 30; building[1].pg[0].y[2] = 1; + building[1].data = malloc(sizeof(struct data_model0)); + data1.wall = 0.15; + data1.slab = 0.1; + *(struct data_model0*)(building[1].data) = data1; + building[1].build_cad = &build_cad_model0; + building[1].export_stl = &export_stl_model0; + building[1].release = &release_model0; + building[1].build_footprint = &build_footprint_model0; + + city->n = NBUILD; + city->building = building; + + city->ground.extent[0] = -100; + city->ground.extent[1] = 100; + city->ground.extent[2] = -100; + city->ground.extent[3] = 100; + city->ground.depth = 3; + + ERR(scad_device_create(NULL, NULL, 1, &city->scad_device)); + +exit: + return res; + +error: + if (building[0].pg) free(building[0].pg); + if (building[1].pg) free(building[1].pg); + if (building) free(building); + goto exit; +} + +res_T +city_release(struct city* city) +{ + res_T res = RES_OK; + size_t i,n; + + /* iterate on building */ + n = city->n; + for (i=0; i<n; ++i) { + ERR(city->building[i].release(&city->building[i])); + } + + ERR(ground_release(&city->ground)); + + if (city->scad_device) scad_device_ref_put(city->scad_device); + if (city->building) free(city->building); + +exit: + return res; +error: + goto exit; +} + +res_T +city_cad_build(struct city* city) +{ + res_T res = RES_OK; + size_t i,n; + + /* iterate on building */ + n = city->n; + for (i=0; i<n; ++i) { + /* create building */ + ERR(city->building[i].build_cad(city->scad_device, &city->building[i])); + } + +exit: + return res; +error: + goto exit; +} + +res_T +city_ground_build(struct city* city) +{ + res_T res = RES_OK; + size_t i,n; + + ERR(scad_scene_create(city->scad_device, &city->ground.scene)); + + /* iterate on building */ + n = city->n; + city->ground.n = n; + city->ground.footprint = malloc(n * sizeof(struct scad_geometry*)); + + for (i=0; i<n; ++i) { + /* create building footprint */ + ERR(city->building[i].build_footprint + (city->ground.scene, + &city->building[i], + &city->ground.footprint[i])); + } + + ERR(ground_build_cad(&city->ground)); + + +exit: + return res; +error: + goto exit; +} + + +res_T +city_export_stl(const struct city* city) +{ + res_T res = RES_OK; + size_t i,n; + + /* iterate on building */ + n = city->n; + for (i=0; i<n; ++i) { + ERR(city->building[i].export_stl(&city->building[i])); + } + + /* ground */ + ERR(ground_export_stl(&city->ground)); + +exit: + return res; +error: + goto exit; +} diff --git a/src/city.h b/src/city.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 |Meso|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/>. */ +#include <star/scad.h> + +#include "building.h" +#include "ground.h" + + +#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0 + +#ifndef CITY_H +#define CITY_H + +struct city { + struct scad_device* scad_device; + struct building* building; /* list of buildings */ + size_t n; + struct ground ground; +}; + +res_T +city_init(struct city* city); + +res_T +city_cad_build(struct city* city); + +res_T +city_ground_build(struct city* city); + +res_T +city_export_stl(const struct city* city); + +res_T +city_release(struct city* city); +#endif /*CITY_H*/ diff --git a/src/ground.c b/src/ground.c @@ -0,0 +1,107 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 |Meso|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/>. */ + +#include <rsys/str.h> + +#include "ground.h" + +#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0 + + +res_T +ground_build_cad +( struct ground* ground) +{ + res_T res = RES_OK; + size_t i; + double origin[3]; + double extent[3]; + struct str name; + + if (!ground) { + res = RES_BAD_ARG; + goto error; + } + + origin[0] = ground->extent[0]; + origin[1] = ground->extent[2]; + origin[2] = -ground->depth; + + extent[0] = ground->extent[1] - ground->extent[0]; + extent[1] = ground->extent[3] - ground->extent[2]; + extent[2] = ground->depth; + + if (origin[2] > 0 || extent[0] < 0 || extent[1] < 0 || extent[2] < 0 ) { + res = RES_BAD_ARG; + goto error; + } + + str_init(NULL, &name); + ERR(str_set(&name, "ground")); + + ERR(scad_scene_add_box + (ground->scene, + str_cget(&name), + origin, + extent, + &ground->geometry)); + + for (i=0; i<ground->n; ++i) { + ERR(scad_scene_geometries_fragment + (ground->scene, + NULL, + ground->geometry, + ground->footprint[i], + &ground->geometry, + 0)); + } + + ERR(scad_scene_conformal_mesh(ground->scene)); + +exit: + return res; +error: + goto exit; +} + + +res_T +ground_export_stl(const struct ground* ground) +{ + res_T res = RES_OK; + + ERR(scad_stl_export(ground->geometry, "ground", 0)); + +exit: + return res; +error: + goto exit; +} + + +res_T +ground_release(struct ground* ground) +{ + res_T res = RES_OK; + + if (ground->scene) {ERR(scad_scene_ref_get(ground->scene));} + if (ground->footprint) free(ground->footprint); + +exit: + return res; +error: + goto exit; +} diff --git a/src/ground.h b/src/ground.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 |Meso|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/>. */ + +#include <rsys/rsys.h> +#include <star/scad.h> + +#include "polygon.h" + +#ifndef GROUND_H +#define GROUND_H + +struct ground { + /* generic building data */ + double extent[4]; /* [xmin, xmax, ymin, ymax */ + double depth; + + /* cad representation */ + struct scad_scene* scene; + struct scad_geometry* geometry; + struct scad_geometry** footprint; /* list of building footprint */ + size_t n; /* number of footprint */ +}; + + +res_T +ground_build_cad +(struct ground* ground); + +res_T +ground_export_stl(const struct ground* ground); + +res_T +ground_release(struct ground* ground); + +#endif /* GROUND */ diff --git a/src/main.c b/src/main.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 |Meso|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/>. */ + + + +#include <rsys/rsys.h> +#include <star/scad.h> + +#include "city.h" + +int main +(int argc, char** argv) +{ + int err = EXIT_SUCCESS; + res_T res = RES_OK; + struct city city; + + (void)argc; (void)argv; + + + ERR(city_init(&city)); + ERR(city_cad_build(&city)); + ERR(city_ground_build(&city)); + ERR(city_export_stl(&city)); + ERR(city_release(&city)); + +exit: + return err; +error: + err = EXIT_FAILURE; + printf("ERROR\n"); + goto exit; +} diff --git a/src/polygon.c b/src/polygon.c @@ -0,0 +1,220 @@ +#include "polygon.h" +#include <rsys/double3.h> +#include <rsys/double2.h> + + +static +res_T +set_polygon(const double* x, const double* y, const size_t n, struct pg_polygon* pg) +{ + res_T res = RES_OK; + size_t i; + + res = pg_init(pg, n); + + for (i=0; i<n; ++i) { + pg->x[i] = x[i]; + pg->y[i] = y[i]; + } + + return res; +} + + +/******************************************************************************/ + +res_T +pg_init(struct pg_polygon* pg, const size_t n) +{ + res_T res = RES_OK; + + if (!pg || n < 3) { + res = RES_BAD_ARG; + goto error; + } + + pg->x = malloc(n * sizeof(double)); + pg->y = malloc(n * sizeof(double)); + pg->n = n; + +exit: + return res; +error: + goto exit; +} + +res_T +pg_release(struct pg_polygon* pg) +{ + res_T res = RES_OK; + + if (!pg) { + res = RES_BAD_ARG; + goto error; + } + + if (pg->x) free(pg->x); + if (pg->y) free(pg->y); + +exit: + return res; +error: + goto exit; +} + +res_T +pg_offset +(const struct pg_polygon* pg, const double delta, + struct pg_polygon* pg_int, + struct pg_polygon* pg_ext) +{ + res_T res = RES_OK; + size_t i, sz; + double* x1 = NULL; + double* y1 = NULL; + double* x2 = NULL; + double* y2 = NULL; + double len1, len2; + + if (!pg || delta <= 0) { + res = RES_BAD_ARG; + goto error; + } + + sz = pg->n; + + x1 = malloc(sz * sizeof(double)); + y1 = malloc(sz * sizeof(double)); + x2 = malloc(sz * sizeof(double)); + y2 = malloc(sz * sizeof(double)); + + /*iterate on vertices*/ + for (i = 0; i < sz; ++i) { + size_t i_prev, i_next; + double pt[3]; + double pt_displace1[3]; + double pt_displace2[3]; + double pt_prev[3]; + double pt_next[3]; + double u[3]; + double v[3]; + double d[3]; + double u_x_d[3]; + double u_x_v[3]; + double l; + + i_prev = i - 1; + i_next = i + 1; + if (i==0) i_prev = sz - 1; + if (i==(sz-1)) i_next = 0; + + pt[0] = pg->x[i]; + pt[1] = pg->y[i]; + pt[2] = 0; + + pt_prev[0] = pg->x[i_prev]; + pt_prev[1] = pg->y[i_prev]; + pt_prev[2] = 0; + + pt_next[0] = pg->x[i_next]; + pt_next[1] = pg->y[i_next]; + pt_next[2] = 0; + + /*u is unit vector from pt to pt_prev*/ + d3_sub(u, pt_prev, pt); + d3_normalize(u, u); + /*v is unit vector from pt to pt_next*/ + d3_sub(v, pt_next, pt); + d3_normalize(v, v); + + /*displacement direction along the (u,v) bisector*/ + d3_add(d, u, v); + d3_normalize(d, d); + + /*displacement lenght*/ + d3_cross(u_x_d ,u, d); + l = delta/d3_len(u_x_d); + /*printf("l %g\n", l);*/ + + d3_muld(d, d, l); + d3_add(pt_displace1, pt, d); + + d3_muld(d, d, -1); + d3_add(pt_displace2, pt, d); + + /* order pt_displace by side*/ + d3_sub(u, pt_displace1, pt_prev); + d3_sub(v, pt, pt_prev); + d3_cross(u_x_v ,u, v); + if (u_x_v[2] > 0) { + x1[i] = pt_displace1[0]; + y1[i] = pt_displace1[1]; + x2[i] = pt_displace2[0]; + y2[i] = pt_displace2[1]; + } else { + x1[i] = pt_displace2[0]; + y1[i] = pt_displace2[1]; + x2[i] = pt_displace1[0]; + y2[i] = pt_displace1[1]; + } + } + + + len1 = 0; + len2 = 0; + for (i=0; i<sz; ++i) { + double pt1[2]; + double pt2[2]; + double pt1_next[2]; + double pt2_next[2]; + double u1[2], u2[2]; + double l1 = 0; + double l2 = 0; + + pt1[0] = x1[i]; + pt1[1] = y1[i]; + pt2[0] = x2[i]; + pt2[1] = y2[i]; + + if (i == sz-1) { + pt1_next[0] = x1[0]; + pt1_next[1] = y1[0]; + pt2_next[0] = x2[0]; + pt2_next[1] = y2[0]; + } else { + pt1_next[0] = x1[i+1]; + pt1_next[1] = y1[i+1]; + pt2_next[0] = x2[i+1]; + pt2_next[1] = y2[i+1]; + } + + d2_sub(u1, pt1_next, pt1); + l1 = d2_len(u1); + len1 += l1; + + d2_sub(u2, pt2_next, pt2); + l2 = d2_len(u2); + len2 += l2; + } + + if (len1 < len2) { + res = set_polygon(x1, y1, sz, pg_int); + res = set_polygon(x2, y2, sz, pg_ext); + } else { + res = set_polygon(x1, y1, sz, pg_ext); + res = set_polygon(x2, y2, sz, pg_int); + } + +exit: + if (x1) free(x1); + if (y1) free(y1); + if (x2) free(x2); + if (y2) free(y2); + return res; + +error: + if (pg_int->x || pg_int->y) pg_release(pg_int); + if (pg_ext->x || pg_ext->y) pg_release(pg_ext); + goto exit; + +} diff --git a/src/polygon.h b/src/polygon.h @@ -0,0 +1,25 @@ +#include <rsys/rsys.h> + +#ifndef POLYGON_H +#define POLYGON_H + +struct pg_polygon +{ + double* x; + double* y; + size_t n; +}; + +res_T +pg_init(struct pg_polygon* pg, const size_t n); + +res_T +pg_release(struct pg_polygon* pg); + +res_T +pg_offset +(const struct pg_polygon* pg, const double delta, + struct pg_polygon* pg_int, + struct pg_polygon* pg_ext); + +#endif /* POLYGON_H */