Qasari: La conception paramétrique et procédurale en natif

Feature très importante de Qasari, en natif le logiciel tourne en conception paramétrique et procédurale, ou tout tourne en liant la notion de nanite qui est un modèle architectural d'organe. Je propose des pistes pour demarrer la programmation et d'aide pour comprendre un peu le code via chatGPT et comment facilement intégrer. Tous ça sont des petites notions pour s'habituer à manipuler des idées essentiels que l'on doit garder à l'esprit quand on fait le logiciel car on revient toujours sur les mêmes problématiques à gérer. Au départ on commence avec des choses simples, d'ou que Qasari fonctionne comme AutoCAD en 2D via des canevas sur X,Y,Z puis il y a un mode modeleur avec un Geometric Kernel qui gère les formes plus complexe.

La conception paramétrique et procédurale n'est pas une nouvelle idée, mais sa mise en œuvre dans un logiciel de CAO peut être assez complexe. Ces concepts impliquent l'utilisation de paramètres pour définir des objets et des algorithmes pour générer des formes et des structures. Voici un aperçu de la manière dont vous pouvez intégrer ces concepts dans votre logiciel de CAO.

Conception Paramétrique

La conception paramétrique permet de créer des modèles en définissant des relations entre différents éléments du modèle à l'aide de paramètres. Par exemple, un cercle peut être défini par son rayon, et un rectangle par sa longueur et sa largeur. Voici un exemple simplifié en C++ :

Exemples de Classes Paramétriques

// include/mycaoproject/core/parametric_shapes.h
#ifndef PARAMETRIC_SHAPES_H
#define PARAMETRIC_SHAPES_H

#include <iostream>

class ParametricShape {
public:
    virtual void draw() const = 0;
    virtual ~ParametricShape() = default;
};

class Circle : public ParametricShape {
public:
    Circle(float radius) : radius(radius) {}
    void setRadius(float r) { radius = r; }
    float getRadius() const { return radius; }
    void draw() const override {
        std::cout << "Drawing a circle with radius " << radius << std::endl;
    }
private:
    float radius;
};

class Rectangle : public ParametricShape {
public:
    Rectangle(float width, float height) : width(width), height(height) {}
    void setWidth(float w) { width = w; }
    void setHeight(float h) { height = h; }
    float getWidth() const { return width; }
    float getHeight() const { return height; }
    void draw() const override {
        std::cout << "Drawing a rectangle with width " << width << " and height " << height << std::endl;
    }
private:
    float width, height;
};

#endif // PARAMETRIC_SHAPES_H

Utilisation des Classes Paramétriques

#include "mycaoproject/core/parametric_shapes.h"

int main() {
    Circle circle(5.0f);
    circle.draw();
    circle.setRadius(10.0f);
    circle.draw();

    Rectangle rectangle(3.0f, 4.0f);
    rectangle.draw();
    rectangle.setWidth(6.0f);
    rectangle.setHeight(8.0f);
    rectangle.draw();

    return 0;
}

Conception Procédurale

La conception procédurale implique l'utilisation d'algorithmes pour générer des modèles. Voici un exemple simple où nous générons une grille de points en utilisant des paramètres.

Exemple de Classe Procédurale

// include/mycaoproject/core/procedural_grid.h
#ifndef PROCEDURAL_GRID_H
#define PROCEDURAL_GRID_H

#include <vector>
#include <iostream>

struct Point {
    float x, y, z;
};

class ProceduralGrid {
public:
    ProceduralGrid(int rows, int cols, float spacing)
        : rows(rows), cols(cols), spacing(spacing) {}

    void generate() {
        points.clear();
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                points.push_back({ i * spacing, 0.0f, j * spacing });
            }
        }
    }

    void draw() const {
        for (const auto& point : points) {
            std::cout << "Point (" << point.x << ", " << point.y << ", " << point.z << ")\n";
        }
    }
private:
    int rows, cols;
    float spacing;
    std::vector<Point> points;
};

#endif // PROCEDURAL_GRID_H

Utilisation de la Classe Procédurale

#include "mycaoproject/core/procedural_grid.h"

int main() {
    ProceduralGrid grid(4, 4, 1.0f);
    grid.generate();
    grid.draw();

    return 0;
}

Intégration avec Lua pour la Scriptabilité

Vous pouvez utiliser Lua pour permettre aux utilisateurs de définir des formes et des algorithmes procéduraux de manière dynamique.

Exemple de Script Lua

-- scripts/generate_grid.lua
function generate_grid(rows, cols, spacing)
    for i = 1, rows do
        for j = 1, cols do
            print(string.format("Point (%f, %f, %f)", (i - 1) * spacing, 0.0, (j - 1) * spacing))
        end
    end
end

generate_grid(4, 4, 1.0)

Intégration de Lua dans C++

// include/mycaoproject/scripting/luascripting.h
#ifndef LUASCRIPTING_H
#define LUASCRIPTING_H

extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}

#include <iostream>
#include <string>

class LuaScripting {
public:
    LuaScripting() {
        L = luaL_newstate();
        luaL_openlibs(L);
    }

    ~LuaScripting() {
        lua_close(L);
    }

    void executeScript(const std::string& script) {
        if (luaL_dofile(L, script.c_str()) != LUA_OK) {
            std::cerr << "Error: " << lua_tostring(L, -1) << std::endl;
            lua_pop(L, 1);
        }
    }

private:
    lua_State* L;
};

#endif // LUASCRIPTING_H

Utilisation de Lua dans le Programme Principal

#include "mycaoproject/scripting/luascripting.h"

int main() {
    LuaScripting luaScripting;
    luaScripting.executeScript("scripts/generate_grid.lua");
    return 0;
}

Conclusion

Avec ces exemples, vous avez une base pour intégrer la conception paramétrique et procédurale dans votre logiciel de CAO. Vous pouvez étendre ces concepts pour inclure des formes plus complexes, des algorithmes de génération plus sophistiqués, et une intégration plus profonde avec Lua pour permettre aux utilisateurs de personnaliser et de programmer leur conception de manière dynamique.