oujood.com

Comment Générer automatiquement une géométrie à l’aide du module autogeometry de pymunk

Découvrez les fonctions du module pymunk.autogeometry pour la génération automatique de géométrie à partir d'une image, y compris des exemples pratiques.

Le module pymunk.autogeometry: Définition

Le module pymunk.autogeometry fournit des fonctions pour la génération automatique de géométrie, par exemple à partir d'une image ou d'une colection de points( un t.

Fonctions du module geometry de Pymunk

Le module pymunk.autogeometry fournit les fonctions suivantes :

  • march_soft() : génère une géométrie à partir d'une image en utilisant un algorithme de marche aléatoire.
  • march_hard() : génère une géométrie à partir d'une image en utilisant un algorithme de marche linéaire.
  • add_segment_to_polyline_set() : ajoute un segment à un ensemble de polylignes.
  • area_for_poly() : Calcule l'aire d'un polygone.
  • convex_decomposition() : Décompose un polygone en un ensemble de polygones convexes.
  • is_closed() : Teste si un polygone est fermé.
  • simplify_curves() : Simplifie une polyligne en supprimant les points redondants.
  • simplify_vertexes() : Simplifie une polyligne en supprimant les points redondants et en fusionnant les segments adjacents.
  • to_convex_hull() : Convertit un polygone en son enveloppe convexe.

Syntaxe des fonctions pymunk

  • march_soft(bb, resolution, cell_size, threshold, sample_func)
  • march_hard(bb, resolution, cell_size, threshold, sample_func)
  • add_segment_to_polyline_set(polyline_set, a, b)
  • area_for_poly(poly)
  • convex_decomposition(poly)
  • is_closed(poly)
  • simplify_curves(poly)
  • simplify_vertexes(poly)
  • to_convex_hull(poly)

Propriétés du module geometry de Pymunk

Le module geometry de Pymunk fournit aussi les propriétés suivantes :

  • area_for_poly : Retourne la surface d'un polygone.
  • convex_decomposition : Décompose un polygone en un ensemble de polygones convexes.
  • ffi : Retourne la bibliothèque de liens dynamiques (DLL) utilisée par Pymunk.
  • is_closed : Indique si un polygone est fermé.
  • lib : Retourne la bibliothèque statique (lib) utilisée par Pymunk.
  • march_hard : Permet de générer la géometrie.
  • march_soft : Permet de générer la géometrie.
  • overload : Indique si Pymunk est en mode surcharge.
  • simplify_curves : Simplifie les courbes d'un polygone.
  • simplify_vertexes : Simplifie les sommets d'un polygone.
  • to_convex_hull : Retourne l'enveloppe convexe d'un polygone.
area_for_poly
def area_for_poly(poly):

Cette propriété retourne la surface d'un polygone. Le polygone doit être représenté par une liste de points.

Syntaxe
area_for_poly([(x1, y1), (x2, y2), ..., (xn, yn)])
convex_decomposition
def convex_decomposition(poly):

Cette propriété décompose un polygone en un ensemble de polygones convexes. Le polygone doit être représenté par une liste de points.

Syntaxe
convex_decomposition([(x1, y1), (x2, y2), ..., (xn, yn)])
ffi
def ffi():

Cette propriété retourne la bibliothèque de liens dynamiques (DLL) utilisée par Pymunk.

Syntaxe
ffi()
is_closed
def is_closed(poly):

Cette propriété indique si un polygone est fermé. Le polygone doit être représenté par une liste de points.

Syntaxe
is_closed([(x1, y1), (x2, y2), ..., (xn, yn)])
lib
def lib():

Cette propriété retourne la bibliothèque statique (lib) utilisée par Pymunk.

Syntaxe
lib()
march_hard
def march_hard(poly, x0, y0, x1, y1):

Cette propriété effectue un marcheur de terrain dur sur un polygone. Le polygone doit être représenté par une liste de points. Les coordonnées x0, y0 et x1, y1 indiquent le rectangle dans lequel le marcheur de terrain s'exécute.

Syntaxe
march_hard([(x1, y1), (x2, y2), ..., (xn, yn)], x0, y0, x1, y1)
march_soft
def march_soft(poly, x0, y0, x1, y1):

Cette propriété effectue un marcheur de terrain doux sur un polygone. Le polygone doit être représenté par une liste de points. Les coordonnées x0, y0 et x1, y1 indiquent le rectangle dans lequel le marcheur de terrain s'exécute.

Syntaxe
march_soft([(x1, y1), (x2, y2), ..., (xn, yn)], x0, y0, x1, y1)
overload
def overload():

Cette propriété indique si Pymunk est en mode surcharge.

Syntaxe
overload()
simplify_curves
def simplify_curves(poly):

Cette propriété simplifie les courbes d'un polygone. Le polygone doit être représenté par une liste de points.

Syntaxe
simplify_curves([(x1, y1), (x2, y2), ..., (xn, yn)])
simplify_vertexes
def simplify_vertexes(poly):

Cette propriété simplifie les sommets d'un polygone. Le polygone doit être représenté par une liste de points.

Syntaxe
simplify_vertexes([(x1, y1), (x2, y2), ..., (xn, yn)])
to_convex_hull
def to_convex_hull(poly):

Cette propriété retourne l'enveloppe convexe d'un polygone. Le polygone doit être représenté par une liste de points.

Syntaxe
to_convex_hull([(x1, y1), (x2, y2), ..., (xn, yn)])
Exemples

Exemple :       Copier le code

import pymunk
from pymunk importbgeometry

# Créer un polygone
poly = [(0, 0), (1, 0), (1, 1), (0, 1)]

# Calculer la surface du polygone
area = geometry.area_for_poly(poly)

# Décomposer le polygone en un ensemble de polygones convexes
convex_polys = geometry.convex_decomposition(poly)

# Vérifier si le polygone est fermé
is_closed = geometry.is_closed(poly)

# Génération de la géometrie
points = geometry.march_hard(poly, 0, 0, 10, 10)

# Génération de la géometrie
points = geometry.march_soft(poly, 0, 0, 10, 10)

# Indique si Pymunk est en mode surcharge
overload = geometry.overload()

# Simplifie les courbes du polygone
simplified_poly = geometry.simplify_curves(poly)

# Simplifie les sommets du polygone
simplified_poly = geometry.simplify_vertexes(poly)

# Retourne l'enveloppe convexe du polygone
convex_hull = geometry.to_convex_hull(poly)
Remarques:
  • Les propriétés area_for_poly, is_closed et overload ne prennent pas de paramètres.
  • Les propriétés convex_decomposition, march_hard, march_soft, simplify_curves, to_convex_hull et simplify_vertexes prennent un polygone en paramètre. Le polygone doit être représenté par une liste de points.

Exemples pratiques

Génération d'une forme à partir d'une image

Dans l’exemple, nous fournissons une liste de chaînes de caractères représentant une image où 's' signifie espace et 'x' signifie une partie solide., la liste contient 7 éléments donc elle est d’une hauteur de 7`pixels, chaque éléments contient 7 caractères donc une largeur de l’image de 7 pixels, vous pouvez utiliser autant d’éléments que vous voulez et n’importe quel autre caractère à la place de ‘s’ et ‘x’.

img = ["sssssss","sxxxxxs","sxxxxss","ssxxxxs","ssxxxxs","sxxxxxs","sssssss"]

Nous définissons en suite une fonction qui prend un point (une paire de coordonnées x, y) et renvoie 1 si le caractère correspondant dans l'image est 'x', sinon renvoie 0.

def sample_func(point):
    x = int(point[0])  # Récupère la première coordonnée du point en tant que valeur entière.
    y = int(point[1])  # Récupère la deuxième coordonnée du point en tant que valeur entière.
    return 1 if img[y][x] == "x" else 0

Crée une boîte englobante (bounding box) en utilisant les coordonnées du coin supérieur gauche (0,0) et du coin inférieur droit (6,6).

bb = pymunk.BB(0, 0, 6, 6)
threshold = 0.5 # Un seuil (threshold) fixé à 0,5.

Appelle la fonction "march_hard" ou "march_soft" avec les arguments spécifiés pour générer des segments de lignes

La syntaxe de la fonction est :

 pymunk.autogeometry.march_hard(bb : BB, x_samples : entier, y_samples : entier, seuil : flottant, sample_func : Callable[[float, float]], float]) → PolylineSet

Tracez une courbe crénelée d’une image le long d’un seuil particulier.
Le nombre donné d’échantillons sera prélevé et réparti sur toute la frontière à l’aide de la fonction et du contexte d’échantillonnage.

Paramètres : La fonction march_hard (march_soft) prend 5 paramètres

  • bb (BB) – Boîte englobante de la zone à échantillonner
  • x_samples (int) – Nombre d’échantillons dans x
  • y_samples (int) – Nombre d’échantillons dans y
  • threshold (float) – Une valeur plus élevée signifie qu’une plus grande quantité d’erreur est tolérée
  • sample_func () – La fonction d’échantillonnage sera appelée pour x_samples * y_samples répartis sur toute la zone de la boîte englobante et renvoie un nombre à virgule flottante.func(point: Tuple[float, float]) -> float Retourne : PolylineSet avec les polylignes trouvées.

Dans notre exemple en fonction de la boîte englobante, de la résolution 7x7, du seuil 0.5 et de la fonction d'échantillonnage.

segments = march_hard(bb, 7, 7, threshold, sample_func)
echelle = 30  # Une échelle fixée à 30. 

On crée un segment de ligne dans un espace physique (pymunk) entre les points a et b, en utilisant un corps statique.

for poly_line in segments:
    for i in range(len(poly_line) - 1):
        a = poly_line[i] * echelle
        b = poly_line[i + 1] * echelle
        # Multiplie chaque point dans la ligne par l'échelle.
        segment = pymunk.Segment(space.static_body, a, b, 1)
        

En fin on ajoute le segment de ligne à l'espace physique.

        space.add(segment)        

ce qui donne le code suivant

Exemple :       Copier le code

import pygame
from pygame.locals import *

import pymunk
from pymunk.pygame_util import *
from pymunk.autogeometry import *
from pymunk import Vec2d

space = pymunk.Space()

# Pour afficher la géométrie qui sera créée
class App:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((700, 400))
        self.draw_options = pymunk.pygame_util.DrawOptions(self.screen)
        self.running = True

    def run(self):
        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False
                    pygame.image.save(self.screen, 'pymunk.png')

            self.screen.fill((255, 255, 255))
            space.debug_draw(self.draw_options)
            pygame.display.update()
            space.step(0.01)

        pygame.quit()
# création de la géométrie 
img = ["sssssss","sxxxxxs","sxxxxss","ssxxxxs","ssxxxxs","sxxxxxs","sssssss"]

def sample_func(point):
    x = int(point[0])
    y = int(point[1])
    return 1 if img[y][x] == "x" else 0

bb = pymunk.BB(0, 0, 6, 6)
threshold = 0.5
segments = march_hard(bb, 7, 7, threshold, sample_func)

echelle= 30
for poly_line in segments:
    for i in range(len(poly_line) - 1):
        a = poly_line[i]*echelle
        b = poly_line[i + 1]*echelle
        segment = pymunk.Segment(space.static_body, a, b, 1)  
        space.add(segment)
#On fait  appel à l’application pour l’affichage
App().run()

Ce qui affiche :

rendu de march_hard

Si on remplace la fonction march_hard() par la fonction march_soft() le redue sera comme suit :

rendu de march_soft Exemple 2

Voici un autre exemple avec une image png qui représente le logo de pymunk

Lien pour télécharger l’image

Exemple :       Copier le code

import random
import sys
import os.path
import pygame
import pymunk
import pymunk.autogeometry as autogeometry
import pymunk.pygame_util
from pymunk import Vec2d

# Configuration de la fréquence d'images par seconde et initialisation de Pygame
fps = 60
pygame.init()
écran = pygame.display.set_mode((690, 300))
clock = pygame.time.Clock()

# Limiter le taux de rafraîchissement de l'écran à 1 FPS
clock.tick(1)

# Configuration de la simulation physique
scene = pymunk.Space()
scene.gravity = 0, 900
scene.sleep_time_threshold = 0.3

# Options de dessin pour Pygame
draw_options = pymunk.pygame_util.DrawOptions(écran)
pymunk.pygame_util.positive_y_is_up = False

# Chargement de l'image du logo Pymunk
logo_img = pygame.image.load(
    os.path.join(os.path.dirname(os.path.abspath(__file__)), "images\pymunk_logo.png")
)
logo_bb = pymunk.BB(0, 0, logo_img.get_width(), logo_img.get_height())

# Fonction d'échantillonnage pour obtenir la couleur des pixels de l'image
def sample_func(point):
    try:
        p = pymunk.pygame_util.to_pygame(point, logo_img)
        color = logo_img.get_at(p)
        return color.a
    except:
        return 0

# Verrouillage de l'image du logo pour l'accès aux pixels
logo_img.lock()

# Génération de la géométrie à partir de l'image du logo
line_set = pymunk.autogeometry.march_hard(
    logo_bb, logo_img.get_width(), logo_img.get_height(), 99, sample_func
)

# Déverrouillage de l'image
logo_img.unlock()

# Rayon initial pour les éléments graphiques
r = 10

# Groupe de lettres
letter_group = 0

# Boucle pour traiter les lignes de géométrie générées
for line in line_set:
    # Simplification des courbes dans la géométrie
    line = pymunk.autogeometry.simplify_curves(line, 0.7)

    # Calcul des dimensions
    max_x = 0
    min_x = 1000
    max_y = 0
    min_y = 1000
    for l in line:
        max_x = max(max_x, l.x)
        min_x = min(min_x, l.x)
        max_y = max(max_y, l.y)
        min_y = min(min_y, l.y)
    w, h = max_x - min_x, max_y - min_y

    # On saute les lignes qui ont une hauteur inférieure à 35
    if h < 35:
        continue

    # Calcul du centre de la géométrie
    center = Vec2d(min_x + w / 2.0, min_y + h / 2.0)
    t = pymunk.Transform(a=1.0, d=1.0, tx=-center.x, ty=-center.y)

    r += 30
    if r > 255:
        r = 0

    if True:
        for i in range(len(line) - 1):
            # Création d'un segment physique à ajouter à l'escene
            shape = pymunk.Segment(scene.static_body, line[i], line[i + 1], 1)
            shape.friction = 0.5
            shape.color = (255, 255, 255, 255)
            scene.add(shape)

# Identifiant d'événement personnalisé pour générer périodiquement de petites billes
BILLE = pygame.USEREVENT + 1
pygame.time.set_timer(BILLE, 100)

# Nombre de petites billes à générer
billes = 200

# Temps total écoulé
total_time = 0

# Boucle principale de l'animation
while True:
    for event in pygame.event.get():
        if (
            event.type == pygame.QUIT
            or event.type == pygame.KEYDOWN
            and (event.key in [pygame.K_ESCAPE, pygame.K_q])
        ):
            sys.exit(0)
        elif event.type == BILLE:
            if  billes <= 0:
                pygame.time.set_timer(BILLE, 0)
            for x in range(10):
                billes -= 1
                mass = 1
                radius = 4
                moment = pymunk.moment_for_circle(mass, 0, radius)
                b = pymunk.Body(mass, moment)
                c = pymunk.Circle(b, radius)
                c.friction = 1
                x = random.randint(100, 400)
                b.position = x, 0
                scene.add(b, c)

    scene.step(1.0 / fps)

    écran.fill(pygame.Color("white"))

    scene.debug_draw(draw_options)
    écran.blit(logo_img, (0, 0))

    pygame.display.flip()

    dt = clock.tick(fps)
    total_time += dt / 1000.0

Exemple 3

Voici une autre version du premier exemple ci-haut, avec cette fois l’image représenté par une chaine de caractères, et où on utilise la méthode split() de python

La méthode .split() découpe une chaîne de caractères en plusieurs éléments appelés champs, en utilisant comme séparateur n'importe quelle combinaison « d'espace(s) blanc(s) ».

Lien pour télécharger l’image

Exemple :       Copier le code

# Importation des bibliothèques nécessaires
import pygame
from pygame.locals import *
import pymunk
from pymunk.pygame_util import *
from pymunk.autogeometry import march_soft
from pymunk import Vec2d

# Création de l'espace Pymunk
space = pymunk.Space()

# Définition de la classe de l'application
class App:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((700, 400))  # Crée une fenêtre Pygame
        self.draw_options = pymunk.pygame_util.DrawOptions(self.screen)  # Options de dessin Pymunk pour Pygame
        self.running = True

    def run(self):
        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:  # Gestion de l'événement de fermeture de la fenêtre
                    self.running = False
                    pygame.image.save(self.screen, 'pymunk.png')  # Enregistre une capture d'écran en tant que 'pymunk.png'

            self.screen.fill((255, 255, 255))  # Remplit l'écran en blanc
            space.debug_draw(self.draw_options)  # Dessine l'espace Pymunk
            pygame.display.update()  # Met à jour l'affichage
            space.step(0.01)  # Fait avancer la simulation Pymunk

        pygame.quit()  # Ferme Pygame

# Représentation de l'image en caractères 'x' et '.' dans une liste de chaînes
img = """
.......
.xxx...
.xxx...
..xx...
..xxxx.
..xxxx.
.......
""".split()

# Fonction pour échantillonner un point et déterminer s'il est à l'intérieur de la forme
def sample_func(point):
    x, y = int(point[0]), int(point[1])  # Accéder aux coordonnées x et y du point
    y = 6 - y  # Inverser la coordonnée y car l'image est inversée
    return 1 if img[y][x] == 'x' else 0  # Renvoie 1 si le point est à l'intérieur de la forme, sinon 0

# Crée une zone englobante (bounding box) pour l'échantillonnage et définit un seuil
bb = pymunk.BB(0, 0, 6, 6)
threshold = 0.5

# Génère des segments en utilisant l'algorithme de marche douce (march_soft)
segments = march_soft(bb, 7, 7, threshold, sample_func)

# Crée un nouvel espace Pymunk pour les segments
space = pymunk.Space()

# Facteur d'échelle pour ajuster la taille des segments
echelle = 30

# Crée des segments Pymunk à partir des polygones générés
for poly_line in segments:
    for i in range(len(poly_line) - 1):
        a = poly_line[i] * echelle
        b = poly_line[i + 1] * echelle
        segment = pymunk.Segment(space.static_body, a, b, 1)  # Crée un segment Pymunk
        space.add(segment)  # Ajoute le segment à l'espace Pymunk

# Lance l'application Pygame
App().run()



Voir aussi nos tutoriel :

Système de panier d'achat avec PHP et MySQL

Créer un système de panier d'achat avec PHP et MySQL. Le système de panier d'achat permettra aux visiteurs du site Web de rechercher des produits, d'ajouter des produits au panier et de passer des commandes.

glisser et déplacer

Glisser et Déplacer

PHP gestion d'erreur

Gestion d'erreur