{"id":18,"date":"2026-01-26T19:07:46","date_gmt":"2026-01-26T19:07:46","guid":{"rendered":"https:\/\/domaineencoudon.fr\/?page_id=18"},"modified":"2026-06-15T14:19:03","modified_gmt":"2026-06-15T14:19:03","slug":"contact","status":"publish","type":"page","link":"https:\/\/domaineencoudon.fr\/index.php\/contact\/","title":{"rendered":"Contact"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"18\" class=\"elementor elementor-18\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3f66a6d e-flex e-con-boxed e-con e-parent\" data-id=\"3f66a6d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1699a60 elementor-widget elementor-widget-html\" data-id=\"1699a60\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Lato:wght@300;400;700&display=swap\" rel=\"stylesheet\">\r\n\r\n<style>\r\n    \/* 1. REGLAGES DE BASE *\/\r\n    body {\r\n        font-family: 'Lato', sans-serif;\r\n        background-color: #F4F1EA; \r\n        margin: 0;\r\n    }\r\n    \r\n    h1, h2, h3 {\r\n        font-family: 'Playfair Display', serif; \r\n    }\r\n\r\n    \/* 2. LE MENU (BANDEAU) *\/\r\n    .custom-navbar {\r\n        position: fixed; \r\n        top: 0;\r\n        left: 0;\r\n        width: 100%;\r\n        height: 80px;\r\n        background-color: #F4F1EA; \r\n        box-shadow: 0 2px 10px rgba(0,0,0,0.6);\r\n        display: flex;\r\n        justify-content: space-between;\r\n        align-items: center;\r\n        padding: 0 40px;\r\n        box-sizing: border-box;\r\n        z-index: 9999;\r\n        transition: transform 0.4s ease-in-out; \r\n    }\r\n\r\n    .custom-navbar.nav-hidden {\r\n        transform: translateY(-100%); \r\n    }\r\n\r\n    \/* STYLE POUR LE LOGO IMAGE *\/\r\n    .nav-logo {\r\n        display: flex;\r\n        align-items: center;\r\n        height: 100%; \r\n        text-decoration: none;\r\n    }\r\n\r\n    .nav-logo img {\r\n        max-height: 65px; \r\n        width: auto; \r\n        object-fit: contain;\r\n        transition: transform 0.3s ease; \r\n    }\r\n\r\n    .nav-logo img:hover {\r\n        transform: scale(1.03); \r\n    }\r\n\r\n    \/* STYLE DES LIENS DU MENU (Ordinateur) *\/\r\n    .nav-links {\r\n        display: flex;\r\n        gap: 20px;\r\n        align-items: center;\r\n    }\r\n\r\n    .nav-btn {\r\n        font-family: 'Lato', sans-serif; \r\n        text-decoration: none;\r\n        color: #333; \r\n        font-weight: 500;\r\n        text-transform: uppercase;\r\n        font-size: 0.85rem;\r\n        letter-spacing: 1px;\r\n        padding: 10px 15px;\r\n        transition: color 0.3s, background-color 0.3s;\r\n    }\r\n\r\n    .nav-btn:hover {\r\n        color: #E2725B; \r\n    }\r\n\r\n    .nav-btn-cta {\r\n        background-color: #556B2F; \r\n        color: white !important;\r\n        border-radius: 2px;\r\n        padding: 10px 20px;\r\n    }\r\n    \r\n    .nav-btn-cta:hover {\r\n        background-color: #3e4f22; \r\n        color: white !important;\r\n    }\r\n\r\n    .menu-burger {\r\n        display: none;\r\n        flex-direction: column;\r\n        justify-content: space-around;\r\n        width: 30px;\r\n        height: 24px;\r\n        background: transparent;\r\n        border: none;\r\n        cursor: pointer;\r\n        padding: 0;\r\n        z-index: 10000;\r\n    }\r\n\r\n    .menu-burger span {\r\n        width: 30px;\r\n        height: 2px;\r\n        background: #333; \r\n        transition: all 0.3s linear;\r\n        position: relative;\r\n        transform-origin: 1px;\r\n    }\r\n\r\n    .menu-burger.ouvert span:first-child { transform: rotate(45deg); }\r\n    .menu-burger.ouvert span:nth-child(2) { opacity: 0; transform: translateX(20px); }\r\n    .menu-burger.ouvert span:nth-child(3) { transform: rotate(-45deg); }\r\n\r\n    \/* GESTION DES MOBILES (Smartphones) *\/\r\n    @media (max-width: 768px) {\r\n        .custom-navbar { \r\n            padding: 0 15px; \r\n            height: 60px; \r\n        }\r\n        \r\n        .nav-logo img { \r\n            max-height: 45px; \r\n        }\r\n\r\n        .menu-burger { \r\n            display: flex; \r\n        }\r\n\r\n\r\n        .nav-links { \r\n            position: fixed;\r\n            top: 60px; \/* Commence sous le menu *\/\r\n            right: -100%; \/* Cach\u00e9 hors \u00e9cran *\/\r\n            width: 100%;\r\n            height: calc(100vh - 60px);\r\n            background-color: #F4F1EA;\r\n            flex-direction: column;\r\n            justify-content: flex-start;\r\n            padding-top: 40px;\r\n            transition: right 0.4s ease-in-out;\r\n            box-shadow: -2px 5px 10px rgba(0,0,0,0.1);\r\n        }\r\n\r\n\r\n        .nav-links.actif {\r\n            right: 0;\r\n        }\r\n\r\n        \/* Style des liens sur mobile *\/\r\n        .nav-btn {\r\n            font-size: 1.2rem;\r\n            padding: 15px 0;\r\n            width: 80%;\r\n            text-align: center;\r\n            border-bottom: 1px solid rgba(0,0,0,0.05);\r\n        }\r\n        \r\n        .nav-btn-cta {\r\n            margin-top: 20px;\r\n            width: auto;\r\n        }\r\n    }\r\n\r\n<\/style>\r\n\r\n<nav class=\"custom-navbar\" id=\"autoHideNav\">\r\n    <a href=\"https:\/\/domaineencoudon.fr\/index.php\/accueil\/\" class=\"nav-logo\">\r\n        <img decoding=\"async\" src=\"https:\/\/domaineencoudon.fr\/wp-content\/uploads\/2026\/03\/image-removebg-preview.png\" alt=\"Logo Domaine en Coudon\">\r\n    <\/a> \r\n    \r\n    <button class=\"menu-burger\" id=\"btnBurger\" aria-label=\"Menu\">\r\n        <span><\/span>\r\n        <span><\/span>\r\n        <span><\/span>\r\n    <\/button>\r\n    \r\n    <div class=\"nav-links\" id=\"menuLiens\">\r\n        <a href=\"https:\/\/domaineencoudon.fr\/index.php\/accueil\/\" class=\"nav-btn\">Accueil<\/a>\r\n        <a href=\"https:\/\/domaineencoudon.fr\/index.php\/photos\/\" class=\"nav-btn\">Le G\u00eete<\/a>\r\n        <a href=\"https:\/\/domaineencoudon.fr\/index.php\/alentours\/\" class=\"nav-btn\">Alentours<\/a>\r\n        <a href=\"https:\/\/domaineencoudon.fr\/index.php\/contact\/\" class=\"nav-btn\">Contact<\/a>\r\n        <a href=\"https:\/\/domaineencoudon.fr\/index.php\/reserver\/\" class=\"nav-btn nav-btn-cta\">R\u00e9server<\/a>\r\n    <\/div>\r\n<\/nav>\r\n\r\n<script>\r\n\r\n    let dernierePositionScroll = 0;\r\n    \r\n    window.addEventListener('scroll', function() {\r\n        var navbar = document.getElementById('autoHideNav');\r\n        let positionActuelleScroll = window.scrollY;\r\n\r\n        if (!document.getElementById('menuLiens').classList.contains('actif')) {\r\n            if (positionActuelleScroll > 100 && positionActuelleScroll > dernierePositionScroll) {\r\n                navbar.classList.add('nav-hidden'); \r\n            } else {\r\n                navbar.classList.remove('nav-hidden'); \r\n            }\r\n        }\r\n        dernierePositionScroll = positionActuelleScroll;\r\n    });\r\n\r\n    \/\/ 2. Gestion du Menu Burger Mobile\r\n    const btnBurger = document.getElementById('btnBurger');\r\n    const menuLiens = document.getElementById('menuLiens');\r\n\r\n    btnBurger.addEventListener('click', () => {\r\n        btnBurger.classList.toggle('ouvert');\r\n        menuLiens.classList.toggle('actif');\r\n    });\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-54865f3 e-flex e-con-boxed e-con e-parent\" data-id=\"54865f3\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e8f4161 elementor-widget elementor-widget-html\" data-id=\"e8f4161\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Lato:wght@300;400;500;700&display=swap\" rel=\"stylesheet\">\r\n\r\n<style>\r\n    \/* =========================================\r\n       POLICES ET COULEURS DE BASE\r\n       ========================================= *\/\r\n    body {\r\n        font-family: 'Lato', sans-serif;\r\n        background-color: #FFFFFF; \r\n        margin: 0;\r\n        color: #444;\r\n    }\r\n\r\n    h1, h2, h3, h4 {\r\n        font-family: 'Playfair Display', serif;\r\n        color: #556B2F; \r\n        font-weight: normal;\r\n        margin-top: 0;\r\n    }\r\n\r\n    \/* =========================================\r\n       SECTION 1 : INFORMATIONS PRATIQUES\r\n       ========================================= *\/\r\n    .infos-section {\r\n        max-width: 1200px;\r\n        margin: 0 auto;\r\n        padding: 40px 20px 90px 20px; \/* Paddings r\u00e9duits *\/\r\n    }\r\n\r\n    .infos-header {\r\n        text-align: center;\r\n        margin-bottom: 40px; \/* Marge r\u00e9duite *\/\r\n    }\r\n\r\n    .infos-header h1 {\r\n        font-size: 2.8rem;\r\n        margin-bottom: 15px;\r\n    }\r\n\r\n    .infos-separateur {\r\n        width: 50px;\r\n        height: 2px;\r\n        background-color: #E2725B; \r\n        margin: 0 auto;\r\n    }\r\n\r\n    .infos-grid {\r\n        display: grid;\r\n        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\r\n        gap: 30px; \/* \u00c9cart r\u00e9duit entre les cartes *\/\r\n    }\r\n\r\n    .info-card {\r\n        border-top: 2px solid #556B2F; \r\n        padding-top: 15px; \/* Espace r\u00e9duit au-dessus du texte *\/\r\n    }\r\n\r\n    .info-card h4 {\r\n        font-family: 'Lato', sans-serif;\r\n        font-size: 0.9rem;\r\n        text-transform: uppercase;\r\n        letter-spacing: 1.5px;\r\n        color: #888; \r\n        margin-bottom: 5px; \/* Marge r\u00e9duite *\/\r\n    }\r\n\r\n    .info-card p {\r\n        font-size: 1.1rem;\r\n        line-height: 1.5; \/* Interligne l\u00e9g\u00e8rement r\u00e9duit *\/\r\n        color: #333;\r\n        margin: 0;\r\n    }\r\n\r\n    \/* =========================================\r\n       SECTION 2 : CONTACT ET CARTE \r\n       ========================================= *\/\r\n    .contact-container {\r\n        max-width: 1100px;\r\n        margin: -50px auto 40px auto; \/* Chevauchement et marge inf\u00e9rieure r\u00e9duits *\/\r\n        display: flex;\r\n        flex-wrap: wrap;\r\n        box-shadow: 0 15px 40px rgba(0,0,0,0.06); \r\n        border-radius: 8px;\r\n        overflow: hidden; \r\n        position: relative;\r\n        z-index: 10; \r\n        background-color: #F4F1EA; \r\n    }\r\n\r\n    .contact-details {\r\n        flex: 1 1 400px; \r\n        padding: 40px 40px; \/* Paddings int\u00e9rieurs r\u00e9duits *\/\r\n    }\r\n\r\n    .contact-details h2 {\r\n        font-size: 2.2rem;\r\n        margin-bottom: 10px;\r\n    }\r\n\r\n    .contact-intro {\r\n        margin-bottom: 30px; \/* Marge r\u00e9duite *\/\r\n        line-height: 1.5;\r\n        color: #555;\r\n        font-size: 1.1rem;\r\n    }\r\n\r\n    .contact-block {\r\n        margin-bottom: 25px; \/* Marge r\u00e9duite *\/\r\n    }\r\n\r\n    .contact-block h4 {\r\n        font-family: 'Lato', sans-serif;\r\n        font-size: 0.85rem;\r\n        text-transform: uppercase;\r\n        letter-spacing: 2px;\r\n        color: #888;\r\n        margin: 0 0 5px 0;\r\n    }\r\n\r\n    .contact-block p, \r\n    .contact-block a {\r\n        font-size: 1.25rem;\r\n        color: #333;\r\n        text-decoration: none;\r\n        margin: 0;\r\n        font-weight: 500;\r\n        display: block;\r\n    }\r\n\r\n    .contact-block a:hover {\r\n        color: #E2725B; \r\n    }\r\n\r\n    .map-container {\r\n        flex: 1 1 400px;\r\n        min-height: 100%; \r\n        position: relative;\r\n    }\r\n\r\n    .map-frame {\r\n        width: 100%;\r\n        height: 100%;\r\n        min-height: 400px; \/* Hauteur minimale r\u00e9duite *\/\r\n        border: 0;\r\n        display: block;\r\n    }\r\n\r\n    \/* GESTION MOBILE *\/\r\n    @media (max-width: 900px) {\r\n        .infos-section { padding: 30px 20px 60px 20px; }\r\n        .contact-container { margin: -30px 20px 30px 20px; } \r\n        .contact-details { padding: 30px 20px; }\r\n        .map-frame { min-height: 300px; }\r\n    }\r\n<\/style>\r\n\r\n<div class=\"infos-section\">\r\n    <div class=\"infos-header\">\r\n        <h1>Informations pratiques<\/h1>\r\n        <div class=\"infos-separateur\"><\/div>\r\n    <\/div>\r\n\r\n    <div class=\"infos-grid\">\r\n        <div class=\"info-card\">\r\n            <h4>Inclus dans le tarif<\/h4>\r\n            <p>M\u00e9nage de fin de s\u00e9jour, eau, \u00e9lectricit\u00e9, chauffage, climatisation et taxes diverses.<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"info-card\">\r\n            <h4>Arriv\u00e9es & D\u00e9parts<\/h4>\r\n            <p><strong>Arriv\u00e9e :<\/strong> Vendredi ou Samedi \u00e0 16h.<br><strong>D\u00e9part :<\/strong> Samedi ou Dimanche \u00e0 10h.<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"info-card\">\r\n            <h4>Langues parl\u00e9es<\/h4>\r\n            <p>Fran\u00e7ais, Espagnol, Anglais, Allemand.<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"info-card\">\r\n            <h4>Pour les plus petits<\/h4>\r\n            <p>Mise \u00e0 disposition gratuite d'un lit b\u00e9b\u00e9 pliant et d'une chaise haute.<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"info-card\">\r\n            <h4>Nos amis les animaux<\/h4>\r\n            <p>Nous partageons le domaine avec 2 adorables chiens tr\u00e8s affectueux. De ce fait, nous ne pouvons malheureusement pas accepter d'autres chiens ou chats.<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"info-card\">\r\n            <h4>Stationnement & T\u00e9l\u00e9travail<\/h4>\r\n            <p>Parking priv\u00e9 sur place (accueil des motards). Possibilit\u00e9 d'am\u00e9nager un espace d\u00e9di\u00e9 au t\u00e9l\u00e9travail.<\/p>\r\n        <\/div>\r\n    <\/div>\r\n<\/div>\r\n\r\n<div class=\"contact-container\">\r\n    \r\n    <div class=\"contact-details\">\r\n        <h2>Nous contacter<\/h2>\r\n        <p class=\"contact-intro\">\r\n            Une question sur les \u00e9quipements ou les disponibilit\u00e9s ? \r\n            N'h\u00e9sitez pas \u00e0 nous appeler ou \u00e0 nous envoyer un email. \r\n            Nous vous r\u00e9pondrons avec plaisir.\r\n        <\/p>\r\n\r\n        <div class=\"contact-block\">\r\n            <h4>T\u00e9l\u00e9phone<\/h4>\r\n            <p>+33 6 77 88 78 85<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"contact-block\">\r\n            <h4>Email<\/h4>\r\n            <a href=\"mailto:Domaine.encoudon@gmail.com\">domaine.encoudon@gmail.com<\/a>\r\n        <\/div>\r\n\r\n        <div class=\"contact-block\">\r\n            <h4>Adresse<\/h4>\r\n            <p>194 Route des cr\u00eates<br>31590 Gaur\u00e9<\/p>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"map-container\">\r\n        <iframe class=\"map-frame\" \r\n            src=\"https:\/\/www.google.com\/maps\/embed?pb=!1m18!1m12!1m3!1d11553.655588152575!2d1.6438112469703956!3d43.61874367196188!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x12ae9073a98ebbd9%3A0x38992068dd0b2e54!2sDomaine%20en%20Coudon!5e0!3m2!1sfr!2sfr!4v1773247137162!5m2!1sfr!2sfr\" \r\n            allowfullscreen=\"\" \r\n            loading=\"lazy\" \r\n            referrerpolicy=\"no-referrer-when-downgrade\">\r\n        <\/iframe>\r\n    <\/div>\r\n\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1832c25 elementor-widget elementor-widget-text-editor\" data-id=\"1832c25\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>\u00ab\u00a0\u00a0\u00bb\u00a0\u00bb<br \/>Module pour r\u00e9soudre le probl\u00e8me de placement de n\u0153uds dans un graphe multi-graphe.<\/p><p>Ce module utilise le solveur CP-SAT d&rsquo;OR-Tools pour placer des n\u0153uds de diff\u00e9rents types<br \/>(externaux, splices, relais) sur une grille, en respectant des contraintes de positionnement<br \/>et de routage des ar\u00eates.<br \/>\u00ab\u00a0\u00a0\u00bb\u00a0\u00bb<\/p><p>import networkx as nx<br \/>from networkx.classes import number_of_edges<br \/>from ortools.sat.python import cp_model<br \/>from collections import defaultdict<\/p><p># Nettoyage et fusion des routes<br \/>def clean_and_merge_route(route):<br \/>if not route or len(route) &lt;= 2: return route<br \/>dedup = [route[0]]<br \/>for p in route[1:]:<br \/>if p != dedup[-1]: dedup.append(p)<br \/>if len(dedup) &lt;= 2: return dedup<br \/>clean = [dedup[0]]<br \/>for i in range(1, len(dedup) &#8211; 1):<br \/>prev = clean[-1]<br \/>curr = dedup[i]<br \/>nxt = dedup[i + 1]<br \/>if (prev[1] == curr[1] == nxt[1]) or (prev[0] == curr[0] == nxt[0]): continue<br \/>clean.append(curr)<br \/>clean.append(dedup[-1])<br \/>return clean<\/p><p>def max_equipment_edges(G):<br \/>\u00ab\u00a0\u00a0\u00bb\u00a0\u00bb<br \/>Retourne le nombre maximum d&rsquo;ar\u00eates reli\u00e9es \u00e0 un m\u00eame \u00e9quipement dans le graphe.<\/p><p>Args:<br \/>G: Un objet MultiGraph NetworkX<\/p><p>Returns:<br \/>tuple: (nom_equipement, nombre_ar\u00eates)<br \/>\u00ab\u00a0\u00a0\u00bb\u00a0\u00bb<br \/>equipment_counts = defaultdict(int)<\/p><p>for u, v, k, data in G.edges(keys=True, data=True):<br \/>equip1 = G.nodes[u].get(&lsquo;equipment&rsquo;, &lsquo;NEQ&rsquo;)<br \/>equip2 = G.nodes[v].get(&lsquo;equipment&rsquo;, &lsquo;NEQ&rsquo;)<br \/>equipment_counts[equip1] += 1<br \/>equipment_counts[equip2] += 1<\/p><p>equipment_counts[&lsquo;NEQ&rsquo;] = 0<br \/>if equipment_counts:<br \/>max_equipment = max(equipment_counts.items(), key=lambda x: x[1])<br \/>return max_equipment[0], max_equipment[1] + 30<br \/>else:<br \/>return None, 0<\/p><p><br \/>def solve_nx_placement(G: nx.MultiGraph, backbone_orientation: str = &lsquo;vertical&rsquo;, allow_bent_leaves: bool = False) -&gt; nx.MultiGraph:<br \/>\u00ab\u00a0\u00a0\u00bb\u00a0\u00bb<br \/>R\u00e9sout le probl\u00e8me de placement des n\u0153uds dans un graphe multi-graphe.<\/p><p>Args:<br \/>G: Le graphe multi-graphe \u00e0 placer<br \/>backbone_orientation: Orientation des backbones (&lsquo;vertical&rsquo; ou &lsquo;horizontal&rsquo;)<br \/>allow_bent_leaves: On permet ou non les virages pour les ar\u00eates<br \/>feuilles (qui relient au moins un noeud avec un unique voisin)<br \/><br \/>Returns:<br \/>Le graphe avec les n\u0153uds plac\u00e9s et les routes calcul\u00e9es, ou un graphe vide si la r\u00e9solution \u00e9choue<br \/>\u00ab\u00a0\u00a0\u00bb\u00a0\u00bb<\/p><p>model = cp_model.CpModel()<\/p><p>_, grid_size = max_equipment_edges(G)<br \/><br \/># Clause de garde architecturale : stopper si la grille est nulle (graphe vide)<br \/>if grid_size == 0:<br \/>return G<br \/><br \/>print(grid_size)<\/p><p>node_vars = {} <br \/>equipment_groups = {} <br \/>relays_of_node = {n: [] for n in G.nodes()}<\/p><p>halo_x_ints, halo_y_ints = [], []<br \/>routing_h_x_ints, routing_h_y_ints = [], []<br \/>routing_v_x_ints, routing_v_y_ints = [], []<br \/>collision_blocks = []<\/p><p># ==========================================<br \/># 1. D\u00c9CLARATION DES N\u0152UDS &amp; SPLICES<br \/># ==========================================<\/p><p>for n in G.nodes():<br \/>data = G.nodes[n]<\/p><p>if data.get(\u00ab\u00a0type\u00a0\u00bb) == \u00ab\u00a0external\u00a0\u00bb:<br \/>x = model.NewIntVar(0, grid_size, f\u00a0\u00bbx_{n}\u00a0\u00bb)<br \/>y = model.NewIntVar(0, grid_size, f\u00a0\u00bby_{n}\u00a0\u00bb)<\/p><p>b_top = model.NewBoolVar(f\u00a0\u00bbext_top_{n}\u00a0\u00bb)<br \/>b_bot = model.NewBoolVar(f\u00a0\u00bbext_bot_{n}\u00a0\u00bb)<br \/>b_left = model.NewBoolVar(f\u00a0\u00bbext_left_{n}\u00a0\u00bb)<br \/>b_right = model.NewBoolVar(f\u00a0\u00bbext_right_{n}\u00a0\u00bb)<\/p><p>model.Add(y == 0).OnlyEnforceIf(b_top)<br \/>model.Add(y == grid_size).OnlyEnforceIf(b_bot)<br \/>model.Add(x == 0).OnlyEnforceIf(b_left)<br \/>model.Add(x == grid_size).OnlyEnforceIf(b_right)<\/p><p>model.AddBoolOr([b_top, b_bot, b_left, b_right])<\/p><p>node_vars[n] = {<br \/>\u00ab\u00a0is_external\u00a0\u00bb: True,<br \/>\u00ab\u00a0is_splice\u00a0\u00bb: False,<br \/>\u00ab\u00a0is_relay\u00a0\u00bb: False,<br \/>\u00ab\u00a0x\u00a0\u00bb: x,<br \/>\u00ab\u00a0y\u00a0\u00bb: y<br \/>}<br \/>continue<\/p><p>if data.get(\u00ab\u00a0type\u00a0\u00bb) == \u00ab\u00a0splice\u00a0\u00bb:<br \/>deg = G.degree(n)<br \/>is_backbone = deg &gt;= 5<\/p><p>p_x = model.NewIntVar(0, grid_size, f\u00a0\u00bbx_{n}\u00a0\u00bb)<br \/>p_y = model.NewIntVar(0, grid_size, f\u00a0\u00bby_{n}\u00a0\u00bb)<\/p><p>L = model.NewIntVar(1, grid_size, f\u00a0\u00bbL_{n}\u00a0\u00bb) if is_backbone else model.NewIntVar(0, 0, f\u00a0\u00bbL_{n}\u00a0\u00bb)<\/p><p>node_vars[n] = {<br \/>\u00ab\u00a0is_external\u00a0\u00bb: False,<br \/>\u00ab\u00a0is_splice\u00a0\u00bb: True,<br \/>\u00ab\u00a0is_relay\u00a0\u00bb: False,<br \/>\u00ab\u00a0x\u00a0\u00bb: p_x,<br \/>\u00ab\u00a0y\u00a0\u00bb: p_y,<br \/>\u00ab\u00a0is_backbone\u00a0\u00bb: is_backbone,<br \/>\u00ab\u00a0L\u00a0\u00bb: L<br \/>}<\/p><p>if is_backbone:<br \/>if backbone_orientation == \u00ab\u00a0horizontal\u00a0\u00bb:<br \/>x_end = model.NewIntVar(0, grid_size, \u00ab\u00a0\u00a0\u00bb)<br \/>model.Add(x_end == p_x + L)<br \/>routing_h_x_ints.append(model.NewIntervalVar(p_x, L, x_end, \u00ab\u00a0\u00a0\u00bb))<br \/>routing_h_y_ints.append(model.NewIntervalVar(p_y, 1, p_y + 1, \u00ab\u00a0\u00a0\u00bb))<br \/>else:<br \/>y_end = model.NewIntVar(0, grid_size, \u00ab\u00a0\u00a0\u00bb)<br \/>model.Add(y_end == p_y + L)<br \/>routing_v_x_ints.append(model.NewIntervalVar(p_x, 1, p_x + 1, \u00ab\u00a0\u00a0\u00bb))<br \/>routing_v_y_ints.append(model.NewIntervalVar(p_y, L, y_end, \u00ab\u00a0\u00a0\u00bb))<br \/>continue<\/p><p>if data.get(&lsquo;type&rsquo;) == &lsquo;relay&rsquo;:<br \/>neighbors = list(G.neighbors(n))<br \/>principal = None<br \/>h_relay = 0<\/p><p>for neighbor in set(neighbors):<br \/>edge_count = G.number_of_edges(n, neighbor)<br \/>if G.nodes[neighbor].get(&lsquo;type&rsquo;) not in [&lsquo;relay&rsquo;, &lsquo;splice&rsquo;, &lsquo;external&rsquo;]:<br \/>principal = neighbor<br \/>h_relay = edge_count<br \/>break<\/p><p>w = 1<br \/>x = model.NewIntVar(0, grid_size &#8211; w, f&rsquo;x_{n}&rsquo;)<br \/>y = model.NewIntVar(0, grid_size, f&rsquo;y_{n}&rsquo;)<br \/>h = h_relay if h_relay &gt; 0 else 1<br \/>y_end = model.NewIntVar(0, grid_size, f&rsquo;y_end_{n}&rsquo;)<br \/>model.Add(y_end == y + h)<\/p><p>is_left = model.NewBoolVar(f&rsquo;relay_left_{n}&rsquo;)<\/p><p>node_vars[n] = {<br \/>&lsquo;is_external&rsquo;: False,<br \/>&lsquo;is_splice&rsquo;: False,<br \/>&lsquo;is_relay&rsquo;: True,<br \/>&lsquo;x&rsquo;: x,<br \/>&lsquo;y&rsquo;: y,<br \/>&lsquo;h&rsquo;: h,<br \/>&lsquo;w&rsquo;: w,<br \/>&lsquo;y_end&rsquo;: y_end,<br \/>&lsquo;principal&rsquo;: principal,<br \/>&lsquo;is_left&rsquo;: is_left<br \/>}<\/p><p>relays_of_node[principal].append(n)<\/p><p>x_exact_int = model.NewIntervalVar(x, w, x + w, \u00a0\u00bb)<br \/>y_exact_int = model.NewIntervalVar(y, h, y_end, \u00a0\u00bb)<br \/>routing_h_x_ints.append(x_exact_int)<br \/>routing_h_y_ints.append(y_exact_int)<br \/>routing_v_x_ints.append(x_exact_int)<br \/>routing_v_y_ints.append(y_exact_int)<\/p><p>wend = model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.Add(wend == x + w)<br \/>collision_blocks.append({&lsquo;x&rsquo;: x, &lsquo;wend&rsquo;: wend, &lsquo;y_min&rsquo;: y, &lsquo;y_max&rsquo;: y_end, &lsquo;is_relay&rsquo;: True})<br \/>continue<\/p><p>equipment_raw = data.get(&lsquo;equipment&rsquo;, \u00a0\u00bb)<br \/>is_cut = data.get(&lsquo;type&rsquo;) == &lsquo;cut&rsquo;<\/p><p>if is_cut:<br \/>equipment = f&rsquo;cut_{n}&rsquo;<br \/>min_h = max(1, (G.degree(n) \/\/ 2) + 1)<br \/>else:<br \/>equipment = equipment_raw<br \/>min_h = max(1, G.degree(n) + 1)<\/p><p>w = 1<br \/>x = model.NewIntVar(0, grid_size &#8211; w, f&rsquo;x_{n}&rsquo;)<br \/>y = model.NewIntVar(0, grid_size, f&rsquo;y_{n}&rsquo;)<br \/>h = model.NewIntVar(min_h, grid_size, f&rsquo;h_{n}&rsquo;)<br \/>y_end = model.NewIntVar(0, grid_size, f&rsquo;y_end_{n}&rsquo;)<br \/>model.Add(y_end == y + h)<\/p><p>node_vars[n] = {<br \/>&lsquo;is_external&rsquo;: False,<br \/>&lsquo;is_splice&rsquo;: False,<br \/>&lsquo;is_relay&rsquo;: False,<br \/>&lsquo;x&rsquo;: x,<br \/>&lsquo;y&rsquo;: y,<br \/>&lsquo;h&rsquo;: h,<br \/>&lsquo;w&rsquo;: w,<br \/>&lsquo;y_end&rsquo;: y_end,<br \/>&lsquo;equipment&rsquo;: equipment,<br \/>&lsquo;is_cut&rsquo;: is_cut<br \/>}<\/p><p>if equipment not in equipment_groups:<br \/>equipment_groups[equipment] = []<br \/>equipment_groups[equipment].append(n)<\/p><p>if is_cut:<br \/>x_exact_int = model.NewIntervalVar(x, w, x + w, \u00a0\u00bb)<br \/>y_exact_int = model.NewIntervalVar(y, h, y_end, \u00a0\u00bb)<br \/>routing_h_x_ints.append(x_exact_int)<br \/>routing_h_y_ints.append(y_exact_int)<br \/>routing_v_x_ints.append(x_exact_int)<br \/>routing_v_y_ints.append(y_exact_int)<\/p><p>wend = model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.Add(wend == x + w)<br \/>collision_blocks.append({&lsquo;x&rsquo;: x, &lsquo;wend&rsquo;: wend, &lsquo;y_min&rsquo;: y, &lsquo;y_max&rsquo;: y_end})<\/p><p># ==========================================<br \/># 2. ALIGNEMENT ET BO\u00ceTES VIRTUELLES<br \/># ==========================================<\/p><p>for n, v in node_vars.items():<br \/>if v.get(&lsquo;is_relay&rsquo;, False):<br \/>p_var = node_vars[v[&lsquo;principal&rsquo;]]<br \/>model.Add(v[&lsquo;x&rsquo;] + v[&lsquo;w&rsquo;] == p_var[&lsquo;x&rsquo;]).OnlyEnforceIf(v[&lsquo;is_left&rsquo;])<br \/>model.Add(v[&lsquo;x&rsquo;] == p_var[&lsquo;x&rsquo;] + p_var[&lsquo;w&rsquo;]).OnlyEnforceIf(v[&lsquo;is_left&rsquo;].Not())<br \/>model.Add(v[&lsquo;y&rsquo;] &gt;= p_var[&lsquo;y&rsquo;] + 1)<br \/>model.Add(v[&lsquo;y_end&rsquo;] &lt;= p_var[&lsquo;y_end&rsquo;] &#8211; 1)<\/p><p>equipment_side_vars = {}<br \/>virtual_boxes_info = {}<\/p><p>for equipment, nodes_in_equipment in equipment_groups.items():<br \/>if equipment.startswith(&lsquo;cut_&rsquo;): continue<br \/><br \/>equipment_side_vars[equipment] = model.NewBoolVar(f&rsquo;side_{equipment}&rsquo;)<br \/>first_node = nodes_in_equipment[0]<\/p><p>if len(nodes_in_equipment) &gt; 1:<br \/>for i in range(1, len(nodes_in_equipment)):<br \/>curr_node = nodes_in_equipment[i]<br \/>model.Add(node_vars[curr_node][&lsquo;x&rsquo;] == node_vars[first_node][&lsquo;x&rsquo;])<\/p><p>for i in range(len(nodes_in_equipment)):<br \/>for j in range(i + 1, len(nodes_in_equipment)):<br \/>node_a = nodes_in_equipment[i]<br \/>node_b = nodes_in_equipment[j]<br \/>a_above_b = model.NewBoolVar(f'{node_a}_above_{node_b}&rsquo;)<br \/>model.Add(node_vars[node_a][&lsquo;y_end&rsquo;] + 1 &lt;= node_vars[node_b][&lsquo;y&rsquo;]).OnlyEnforceIf(a_above_b)<br \/>model.Add(node_vars[node_b][&lsquo;y_end&rsquo;] + 1 &lt;= node_vars[node_a][&lsquo;y&rsquo;]).OnlyEnforceIf(a_above_b.Not())<\/p><p>vbox_x = node_vars[first_node][&lsquo;x&rsquo;]<br \/>vbox_y_min = model.NewIntVar(0, grid_size, f&rsquo;vbox_y_min_{equipment}&rsquo;)<br \/>vbox_y_max = model.NewIntVar(0, grid_size, f&rsquo;vbox_y_max_{equipment}&rsquo;)<\/p><p>model.AddMinEquality(vbox_y_min, [node_vars[n][&lsquo;y&rsquo;] for n in nodes_in_equipment])<br \/>model.AddMaxEquality(vbox_y_max, [node_vars[n][&lsquo;y_end&rsquo;] for n in nodes_in_equipment])<br \/>vbox_h = model.NewIntVar(1, grid_size, f&rsquo;vbox_h_{equipment}&rsquo;)<br \/>model.Add(vbox_h == vbox_y_max &#8211; vbox_y_min)<\/p><p># BLOC R\u00c9INT\u00c9GR\u00c9 : Ajout des intervalles de routage pour la bo\u00eete virtuelle<br \/>x_exact_int = model.NewIntervalVar(vbox_x, 1, vbox_x + 1, \u00a0\u00bb)<br \/>y_exact_int = model.NewIntervalVar(vbox_y_min, vbox_h, vbox_y_max, \u00a0\u00bb)<br \/>routing_h_x_ints.append(x_exact_int)<br \/>routing_h_y_ints.append(y_exact_int)<br \/>routing_v_x_ints.append(x_exact_int)<br \/>routing_v_y_ints.append(y_exact_int)<\/p><p>virtual_boxes_info[equipment] = {<br \/>&lsquo;name&rsquo;: equipment,<br \/>&lsquo;x&rsquo;: vbox_x,<br \/>&lsquo;y_min&rsquo;: vbox_y_min,<br \/>&lsquo;h&rsquo;: vbox_h<br \/>}<\/p><p>has_relay_right = model.NewBoolVar(f&rsquo;vbox_has_relay_right_{equipment}&rsquo;)<br \/>all_relays_in_vbox = []<br \/>for child in nodes_in_equipment:<br \/>all_relays_in_vbox.extend(relays_of_node[child])<\/p><p>if all_relays_in_vbox:<br \/>model.AddMaxEquality(has_relay_right, [node_vars[r][&lsquo;is_left&rsquo;].Not() for r in all_relays_in_vbox])<br \/>else:<br \/>model.Add(has_relay_right == 0)<\/p><p>w_halo = model.NewIntVar(1, 2, f&rsquo;vbox_w_halo_{equipment}&rsquo;)<br \/>model.Add(w_halo == 1).OnlyEnforceIf(has_relay_right)<br \/>model.Add(w_halo == 2).OnlyEnforceIf(has_relay_right.Not())<\/p><p>x_halo_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(x_halo_end == vbox_x + w_halo)<br \/>halo_x_ints.append(model.NewIntervalVar(vbox_x, w_halo, x_halo_end, \u00a0\u00bb))<\/p><p>h_halo = model.NewIntVar(1, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(h_halo == vbox_h + 1)<br \/>y_halo_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(y_halo_end == vbox_y_min + h_halo)<br \/>halo_y_ints.append(model.NewIntervalVar(vbox_y_min, h_halo, y_halo_end, \u00a0\u00bb))<\/p><p>vbox_wend = model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.Add(vbox_wend == vbox_x + 1)<br \/>collision_blocks.append({&lsquo;x&rsquo;: vbox_x, &lsquo;wend&rsquo;: vbox_wend, &lsquo;y_min&rsquo;: vbox_y_min, &lsquo;y_max&rsquo;: vbox_y_max})<\/p><p>for n, v in node_vars.items():<br \/>if v.get(&lsquo;is_relay&rsquo;):<br \/>w, x, y, h = v[&lsquo;w&rsquo;], v[&lsquo;x&rsquo;], v[&lsquo;y&rsquo;], v[&lsquo;h&rsquo;]<br \/>is_left = v[&lsquo;is_left&rsquo;]<\/p><p>w_halo = model.NewIntVar(w, w + 1, f&rsquo;w_halo_{n}&rsquo;)<br \/>model.Add(w_halo == w).OnlyEnforceIf(is_left)<br \/>model.Add(w_halo == w + 1).OnlyEnforceIf(is_left.Not())<\/p><p>x_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(x_end == x + w_halo)<br \/>halo_x_ints.append(model.NewIntervalVar(x, w_halo, x_end, \u00a0\u00bb))<\/p><p>h_padded = model.NewIntVar(2, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(h_padded == h + 1)<br \/>y_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(y_end == y + h_padded)<br \/>halo_y_ints.append(model.NewIntervalVar(y, h_padded, y_end, \u00a0\u00bb))<\/p><p>elif not v.get(&lsquo;is_external&rsquo;) and not v.get(&lsquo;is_splice&rsquo;) and v.get(&lsquo;is_cut&rsquo;):<br \/>w, x, y, h = v[&lsquo;w&rsquo;], v[&lsquo;x&rsquo;], v[&lsquo;y&rsquo;], v[&lsquo;h&rsquo;]<br \/>has_relay_right = model.NewBoolVar(f&rsquo;has_relay_right_{n}&rsquo;)<br \/>my_relays = relays_of_node[n]<\/p><p>if my_relays:<br \/>model.AddMaxEquality(has_relay_right, [node_vars[r][&lsquo;is_left&rsquo;].Not() for r in my_relays])<br \/>else:<br \/>model.Add(has_relay_right == 0)<\/p><p>w_halo = model.NewIntVar(w, w + 1, f&rsquo;w_halo_{n}&rsquo;)<br \/>model.Add(w_halo == w).OnlyEnforceIf(has_relay_right)<br \/>model.Add(w_halo == w + 1).OnlyEnforceIf(has_relay_right.Not())<\/p><p>x_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(x_end == x + w_halo)<br \/>halo_x_ints.append(model.NewIntervalVar(x, w_halo, x_end, \u00a0\u00bb))<\/p><p>h_padded = model.NewIntVar(2, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(h_padded == h + 1)<br \/>y_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(y_end == y + h_padded)<br \/>halo_y_ints.append(model.NewIntervalVar(y, h_padded, y_end, \u00a0\u00bb))<\/p><p>model.AddNoOverlap2D(halo_x_ints, halo_y_ints)<\/p><p>point_nodes = [n for n, v in node_vars.items() if v.get(\u00ab\u00a0is_external\u00a0\u00bb) or v.get(\u00ab\u00a0is_splice\u00a0\u00bb)]<br \/>if len(point_nodes) &gt; 1:<br \/>MULTI = 1000 <br \/>point_ids = []<br \/>for n in point_nodes:<br \/>pid = model.NewIntVar(0, grid_size * MULTI + grid_size, f\u00a0\u00bbpid_{n}\u00a0\u00bb)<br \/>model.Add(pid == node_vars[n][\u00ab\u00a0x\u00a0\u00bb] * MULTI + node_vars[n][\u00ab\u00a0y\u00a0\u00bb])<br \/>point_ids.append(pid)<br \/>model.AddAllDifferent(point_ids)<\/p><p># ==========================================<br \/># 2.5 ESPACEMENT COLONNE INTER-\u00c9QUIPEMENTS<br \/># ==========================================<\/p><p>vbox_keys = list(virtual_boxes_info.keys())<br \/>for i in range(len(vbox_keys)):<br \/>for j in range(i + 1, len(vbox_keys)):<br \/>eqA = vbox_keys[i]<br \/>eqB = vbox_keys[j]<br \/>boxA = virtual_boxes_info[eqA]<br \/>boxB = virtual_boxes_info[eqB]<\/p><p>same_x = model.NewBoolVar(f&rsquo;same_x_{eqA}_{eqB}&rsquo;)<br \/>model.Add(boxA[\u00ab\u00a0x\u00a0\u00bb] == boxB[\u00ab\u00a0x\u00a0\u00bb]).OnlyEnforceIf(same_x)<br \/>model.Add(boxA[\u00ab\u00a0x\u00a0\u00bb] != boxB[\u00ab\u00a0x\u00a0\u00bb]).OnlyEnforceIf(same_x.Not())<\/p><p>a_above_b = model.NewBoolVar(f'{eqA}_above_{eqB}&rsquo;)<br \/>b_above_a = model.NewBoolVar(f'{eqB}_above_{eqA}&rsquo;)<\/p><p>model.Add(boxB[\u00ab\u00a0y_min\u00a0\u00bb] &gt;= boxA[\u00ab\u00a0y_min\u00a0\u00bb] + boxA[\u00ab\u00a0h\u00a0\u00bb] + 2).OnlyEnforceIf(a_above_b)<br \/>model.Add(boxA[\u00ab\u00a0y_min\u00a0\u00bb] &gt;= boxB[\u00ab\u00a0y_min\u00a0\u00bb] + boxB[\u00ab\u00a0h\u00a0\u00bb] + 2).OnlyEnforceIf(b_above_a)<\/p><p>model.AddBoolOr([a_above_b, b_above_a]).OnlyEnforceIf(same_x)<\/p><p>for n, v in node_vars.items():<br \/>if v.get(&lsquo;is_relay&rsquo;):<br \/>principal = v[&lsquo;principal&rsquo;]<br \/>p_data = node_vars[principal]<br \/>if not p_data.get(&lsquo;is_cut&rsquo;):<br \/>p_side_var = equipment_side_vars[p_data[&lsquo;equipment&rsquo;]]<br \/>model.Add(v[&lsquo;is_left&rsquo;] != p_side_var)<\/p><p># ==========================================<br \/># 3. ROUTAGE DES AR\u00caTES<br \/># ==========================================<\/p><p>node_ports = {n: [] for n in G.nodes()}<br \/>cut_side_vars = {n: [] for n in G.nodes() if not node_vars[n].get(&lsquo;is_external&rsquo;)<br \/>and not node_vars[n].get(&lsquo;is_splice&rsquo;) and not node_vars[n].get(&lsquo;is_relay&rsquo;)<br \/>and node_vars[n].get(&lsquo;is_cut&rsquo;)}<br \/>edges_info = []<br \/><br \/># CORRECTION ARCHITECTURALE : Initialisation explicite de la liste des p\u00e9nalit\u00e9s<br \/>soft_penalties = []<\/p><p># CORRECTION ARCHITECTURALE : Injection de key_str et edge_alias pour \u00e9viter les fuites de port\u00e9e<br \/>def setup_port(node_id, role, neighbor_id, key_str, edge_alias):<br \/>if node_vars[node_id].get(\u00ab\u00a0is_external\u00a0\u00bb):<br \/>p_x = node_vars[node_id][\u00ab\u00a0x\u00a0\u00bb]<br \/>p_y = node_vars[node_id][\u00ab\u00a0y\u00a0\u00bb]<br \/>node_ports[node_id].append({\u00ab\u00a0x\u00a0\u00bb: p_x, \u00ab\u00a0y\u00a0\u00bb: p_y})<br \/>return p_x, p_y, None<\/p><p>if node_vars[node_id].get(\u00ab\u00a0is_splice\u00a0\u00bb):<br \/>v_splice = node_vars[node_id]<br \/>if v_splice.get(\u00ab\u00a0is_backbone\u00a0\u00bb):<br \/>p_x = model.NewIntVar(0, grid_size, f\u00a0\u00bbp_x_{node_id}_{key_str}_{role}\u00a0\u00bb)<br \/>p_y = model.NewIntVar(0, grid_size, f\u00a0\u00bbp_y_{node_id}_{key_str}_{role}\u00a0\u00bb)<br \/>if backbone_orientation == \u00ab\u00a0horizontal\u00a0\u00bb:<br \/>model.Add(p_y == v_splice[\u00ab\u00a0y\u00a0\u00bb])<br \/>model.Add(p_x &gt;= v_splice[\u00ab\u00a0x\u00a0\u00bb])<br \/>model.Add(p_x &lt;= v_splice[\u00ab\u00a0x\u00a0\u00bb] + v_splice[\u00ab\u00a0L\u00a0\u00bb])<br \/>else:<br \/>model.Add(p_x == v_splice[\u00ab\u00a0x\u00a0\u00bb])<br \/>model.Add(p_y &gt;= v_splice[\u00ab\u00a0y\u00a0\u00bb])<br \/>model.Add(p_y &lt;= v_splice[\u00ab\u00a0y\u00a0\u00bb] + v_splice[\u00ab\u00a0L\u00a0\u00bb])<br \/>node_ports[node_id].append({\u00ab\u00a0x\u00a0\u00bb: p_x, \u00ab\u00a0y\u00a0\u00bb: p_y})<br \/>return p_x, p_y, None<br \/>else:<br \/>p_x, p_y = v_splice[\u00ab\u00a0x\u00a0\u00bb], v_splice[\u00ab\u00a0y\u00a0\u00bb]<br \/>node_ports[node_id].append({\u00ab\u00a0x\u00a0\u00bb: p_x, \u00ab\u00a0y\u00a0\u00bb: p_y})<br \/>return p_x, p_y, None<\/p><p>if node_vars[node_id].get(&lsquo;is_relay&rsquo;):<br \/>v_relay = node_vars[node_id]<br \/>p_y = model.NewIntVar(0, grid_size, f&rsquo;py_{node_id}_{key_str}_{role}&rsquo;)<br \/>model.Add(p_y == v_relay[&lsquo;y&rsquo;] + v_relay[&lsquo;h&rsquo;] \/\/ 2)<br \/>p_x = model.NewIntVar(0, grid_size, f&rsquo;px_{node_id}_{key_str}_{role}&rsquo;)<br \/>model.Add(p_x == v_relay[&lsquo;x&rsquo;]).OnlyEnforceIf(v_relay[&lsquo;is_left&rsquo;])<br \/>model.Add(p_x == v_relay[&lsquo;x&rsquo;] + v_relay[&lsquo;w&rsquo;]).OnlyEnforceIf(v_relay[&lsquo;is_left&rsquo;].Not())<br \/>side_var = v_relay[&lsquo;is_left&rsquo;].Not()<br \/>node_ports[node_id].append({&lsquo;x&rsquo;: p_x, &lsquo;y&rsquo;: p_y, &lsquo;side&rsquo;: side_var, &lsquo;neighbor&rsquo;: neighbor_id, &lsquo;alias&rsquo;: edge_alias})<br \/>return p_x, p_y, side_var<\/p><p>is_cut = node_vars[node_id].get(&lsquo;is_cut&rsquo;, False)<br \/>if is_cut:<br \/>side_var = model.NewBoolVar(f&rsquo;side_{node_id}_{key_str}_{role}&rsquo;)<br \/>cut_side_vars[node_id].append(side_var)<br \/>else:<br \/>side_var = equipment_side_vars[node_vars[node_id][&lsquo;equipment&rsquo;]]<\/p><p>p_y = model.NewIntVar(0, grid_size, f&rsquo;py_{node_id}_{key_str}_{role}&rsquo;)<br \/>model.Add(p_y &gt;= node_vars[node_id][&lsquo;y&rsquo;] + 1)<br \/>model.Add(p_y &lt;= node_vars[node_id][&lsquo;y_end&rsquo;] &#8211; 1)<br \/>p_x = model.NewIntVar(0, grid_size, f&rsquo;px_{node_id}_{key_str}_{role}&rsquo;)<br \/>model.Add(p_x == node_vars[node_id][&lsquo;x&rsquo;]).OnlyEnforceIf(side_var)<br \/>model.Add(p_x == node_vars[node_id][&lsquo;x&rsquo;] + node_vars[node_id][&lsquo;w&rsquo;]).OnlyEnforceIf(side_var.Not())<br \/>node_ports[node_id].append({&lsquo;x&rsquo;: p_x, &lsquo;y&rsquo;: p_y, &lsquo;side&rsquo;: side_var, &lsquo;neighbor&rsquo;: neighbor_id, &lsquo;alias&rsquo;: edge_alias})<br \/>return p_x, p_y, side_var<\/p><p>for u, v, key in G.edges(keys=True):<br \/>if node_vars[u].get(&lsquo;is_relay&rsquo;, False) and v == node_vars[u].get(&lsquo;principal&rsquo;): continue<br \/>if node_vars[v].get(&lsquo;is_relay&rsquo;, False) and u == node_vars[v].get(&lsquo;principal&rsquo;): continue<\/p><p>key_str = f'{u}_{v}_{key}&rsquo;<br \/>edge_alias = (G.edges[u, v, key].get(&lsquo;alias&rsquo;, \u00a0\u00bb) + G.edges[u, v, key].get(&lsquo;sub_alias&rsquo;, \u00a0\u00bb))<\/p><p>p_ux, p_uy, side_u = setup_port(u, &lsquo;u&rsquo;, v, key_str, edge_alias)<br \/>p_vx, p_vy, side_v = setup_port(v, &lsquo;v&rsquo;, u, key_str, edge_alias)<\/p><p>e_vx = model.NewIntVar(0, grid_size, f&rsquo;e_vx_{key_str}&rsquo;)<\/p><p>if G.degree(u) == 1 or G.degree(v) == 1:<br \/>is_u_splice = node_vars[u].get(\u00ab\u00a0is_splice\u00a0\u00bb, False)<br \/>is_v_splice = node_vars[v].get(\u00ab\u00a0is_splice\u00a0\u00bb, False)<br \/>if not is_u_splice and not is_v_splice:<br \/>if node_vars[u].get(\u00ab\u00a0equipment\u00a0\u00bb) != node_vars[v].get(\u00ab\u00a0equipment\u00a0\u00bb):<br \/>if not allow_bent_leaves:<br \/>model.Add(p_uy == p_vy)<br \/>model.Add(p_ux != p_vx)<br \/>else:<br \/>keep_straight = model.NewBoolVar(f&rsquo;keep_straight_{key_str}&rsquo;)<br \/>model.Add(p_uy == p_vy).OnlyEnforceIf(keep_straight)<br \/>model.Add(p_ux != p_vx)<br \/>soft_penalties.append(keep_straight.Not())<\/p><p>if side_u is not None:<br \/>model.Add(e_vx &gt;= p_ux + 1).OnlyEnforceIf(side_u)<br \/>model.Add(e_vx &lt;= p_ux &#8211; 1).OnlyEnforceIf(side_u.Not())<br \/>if side_v is not None:<br \/>model.Add(e_vx &gt;= p_vx + 1).OnlyEnforceIf(side_v)<br \/>model.Add(e_vx &lt;= p_vx &#8211; 1).OnlyEnforceIf(side_v.Not())<\/p><p>for block in collision_blocks:<br \/>model.Add(e_vx != block[&lsquo;x&rsquo;])<br \/>model.Add(e_vx != block[&lsquo;wend&rsquo;])<br \/>if not block.get(&lsquo;is_relay&rsquo;, False):<br \/>model.Add(p_uy != block[&lsquo;y_min&rsquo;])<br \/>model.Add(p_uy != block[&lsquo;y_max&rsquo;])<br \/>model.Add(p_vy != block[&lsquo;y_min&rsquo;])<br \/>model.Add(p_vy != block[&lsquo;y_max&rsquo;])<\/p><p>if not node_vars[u].get(&lsquo;is_external&rsquo;) and not node_vars[v].get(&lsquo;is_external&rsquo;):<br \/>model.Add(e_vx &gt; 0)<br \/>model.Add(e_vx &lt; grid_size)<br \/>model.Add(p_uy &gt; 0)<br \/>model.Add(p_uy &lt; grid_size)<br \/>model.Add(p_vy &gt; 0)<br \/>model.Add(p_vy &lt; grid_size)<\/p><p>h1_xmin, h1_xmax = model.NewIntVar(0, grid_size, \u00a0\u00bb), model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.AddMinEquality(h1_xmin, [p_ux, e_vx])<br \/>model.AddMaxEquality(h1_xmax, [p_ux, e_vx])<br \/>h1_len = model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.Add(h1_len == h1_xmax &#8211; h1_xmin)<br \/>h1_y_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(h1_y_end == p_uy + 1)<br \/>routing_h_x_ints.append(model.NewIntervalVar(h1_xmin, h1_len, h1_xmax, \u00a0\u00bb))<br \/>routing_h_y_ints.append(model.NewIntervalVar(p_uy, 1, h1_y_end, \u00a0\u00bb))<\/p><p>v_ymin, v_ymax = model.NewIntVar(0, grid_size, \u00a0\u00bb), model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.AddMinEquality(v_ymin, [p_uy, p_vy])<br \/>model.AddMaxEquality(v_ymax, [p_uy, p_vy])<br \/>v_len = model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.Add(v_len == v_ymax &#8211; v_ymin)<br \/>v_x_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(v_x_end == e_vx + 1)<br \/>routing_v_x_ints.append(model.NewIntervalVar(e_vx, 1, v_x_end, \u00a0\u00bb))<br \/>routing_v_y_ints.append(model.NewIntervalVar(v_ymin, v_len, v_ymax, \u00a0\u00bb))<\/p><p>h2_xmin, h2_xmax = model.NewIntVar(0, grid_size, \u00a0\u00bb), model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.AddMinEquality(h2_xmin, [e_vx, p_vx])<br \/>model.AddMaxEquality(h2_xmax, [e_vx, p_vx])<br \/>h2_len = model.NewIntVar(0, grid_size, \u00a0\u00bb)<br \/>model.Add(h2_len == h2_xmax &#8211; h2_xmin)<br \/>h2_y_end = model.NewIntVar(0, grid_size + 5, \u00a0\u00bb)<br \/>model.Add(h2_y_end == p_vy + 1)<br \/>routing_h_x_ints.append(model.NewIntervalVar(h2_xmin, h2_len, h2_xmax, \u00a0\u00bb))<br \/>routing_h_y_ints.append(model.NewIntervalVar(p_vy, 1, h2_y_end, \u00a0\u00bb))<\/p><p>edges_info.append({<br \/>&lsquo;u&rsquo;: u, &lsquo;v&rsquo;: v, &lsquo;key&rsquo;: key, &lsquo;p_ux&rsquo;: p_ux, &lsquo;p_uy&rsquo;: p_uy, &lsquo;p_vx&rsquo;: p_vx, &lsquo;p_vy&rsquo;: p_vy,<br \/>&lsquo;e_vx&rsquo;: e_vx, &lsquo;key_str&rsquo;: key_str,<br \/>&lsquo;h1_len&rsquo;: h1_len, &lsquo;v_len&rsquo;: v_len, &lsquo;h2_len&rsquo;: h2_len,<br \/>&lsquo;seg_H1&rsquo;: {&lsquo;y&rsquo;: p_uy, &lsquo;xmin&rsquo;: h1_xmin, &lsquo;xmax&rsquo;: h1_xmax},<br \/>&lsquo;seg_H2&rsquo;: {&lsquo;y&rsquo;: p_vy, &lsquo;xmin&rsquo;: h2_xmin, &lsquo;xmax&rsquo;: h2_xmax},<br \/>&lsquo;seg_V&rsquo;: {&lsquo;x&rsquo;: e_vx, &lsquo;ymin&rsquo;: v_ymin, &lsquo;ymax&rsquo;: v_ymax}<br \/>})<\/p><p>MULTI_C = 1000<br \/>for e in edges_info:<br \/>e[&lsquo;corner_ids&rsquo;] = []<br \/>pts = [(e[&lsquo;p_ux&rsquo;], e[&lsquo;p_uy&rsquo;]), (e[&lsquo;e_vx&rsquo;], e[&lsquo;p_uy&rsquo;]), (e[&lsquo;e_vx&rsquo;], e[&lsquo;p_vy&rsquo;]), (e[&lsquo;p_vx&rsquo;], e[&lsquo;p_vy&rsquo;])]<br \/>for i, (px, py) in enumerate(pts):<br \/>cid = model.NewIntVar(0, grid_size * MULTI_C + grid_size, f&rsquo;cid_{e[\u00ab\u00a0key_str\u00a0\u00bb]}_{i}&rsquo;)<br \/>model.Add(cid == px * MULTI_C + py)<br \/>e[&lsquo;corner_ids&rsquo;].append(cid)<\/p><p>for i in range(len(edges_info)):<br \/>for j in range(i + 1, len(edges_info)):<br \/>eA = edges_info[i]<br \/>eB = edges_info[j]<br \/>shared_nodes = set([eA[&lsquo;u&rsquo;], eA[&lsquo;v&rsquo;]]).intersection([eB[&lsquo;u&rsquo;], eB[&lsquo;v&rsquo;]])<br \/>has_shared_splice = any(node_vars[n].get(&lsquo;is_splice&rsquo;) for n in shared_nodes)<br \/>if has_shared_splice:<br \/>continue<br \/>for cid_A in eA[&lsquo;corner_ids&rsquo;]:<br \/>for cid_B in eB[&lsquo;corner_ids&rsquo;]:<br \/>model.Add(cid_A != cid_B)<\/p><p>for cut_node, side_vars in cut_side_vars.items():<br \/>my_relays = relays_of_node[cut_node]<br \/>total_edges = len(side_vars) + sum(node_vars[r][&lsquo;h&rsquo;] for r in my_relays)<br \/>if total_edges &gt; 0:<br \/>right_count = model.NewIntVar(0, total_edges, f&rsquo;right_count_{cut_node}&rsquo;)<br \/>right_relay_edge_vars = []<br \/>for r in my_relays:<br \/>h_r = node_vars[r][&lsquo;h&rsquo;]<br \/>r_right = model.NewIntVar(0, h_r, f&rsquo;r_right_{r}&rsquo;)<br \/>model.Add(r_right == h_r).OnlyEnforceIf(node_vars[r][&lsquo;is_left&rsquo;].Not())<br \/>model.Add(r_right == 0).OnlyEnforceIf(node_vars[r][&lsquo;is_left&rsquo;])<br \/>right_relay_edge_vars.append(r_right)<br \/>model.Add(right_count == sum(side_vars) + sum(right_relay_edge_vars))<br \/>model.Add(right_count == total_edges \/\/ 2)<\/p><p>for n in G.nodes():<br \/>if node_vars[n].get(&lsquo;is_splice&rsquo;) or node_vars[n].get(&lsquo;is_relay&rsquo;): continue<br \/>ports = node_ports[n]<br \/>if len(ports) &lt;= 1: continue<br \/>if node_vars[n].get(&lsquo;is_external&rsquo;):<br \/>for i in range(len(ports)):<br \/>for j in range(i + 1, len(ports)):<br \/>diff_x, diff_y = model.NewBoolVar(\u00a0\u00bb), model.NewBoolVar(\u00a0\u00bb)<br \/>model.Add(ports[i][&lsquo;x&rsquo;] != ports[j][&lsquo;x&rsquo;]).OnlyEnforceIf(diff_x)<br \/>model.Add(ports[i][&lsquo;y&rsquo;] != ports[j][&lsquo;y&rsquo;]).OnlyEnforceIf(diff_y)<br \/>model.AddBoolOr([diff_x, diff_y])<br \/>elif not node_vars[n].get(&lsquo;is_cut&rsquo;) and not node_vars[n].get(&lsquo;is_splice&rsquo;):<br \/>model.AddAllDifferent([p[&lsquo;y&rsquo;] for p in ports])<br \/>else:<br \/>for i in range(len(ports)):<br \/>for j in range(i + 1, len(ports)):<br \/>same_side = model.NewBoolVar(f&rsquo;same_side_{n}_{i}_{j}&rsquo;)<br \/>model.Add(ports[i][&lsquo;side&rsquo;] == ports[j][&lsquo;side&rsquo;]).OnlyEnforceIf(same_side)<br \/>model.Add(ports[i][&lsquo;side&rsquo;] != ports[j][&lsquo;side&rsquo;]).OnlyEnforceIf(same_side.Not())<br \/>alias_i = ports[i].get(&lsquo;alias&rsquo;, \u00a0\u00bb)<br \/>alias_j = ports[j].get(&lsquo;alias&rsquo;, \u00a0\u00bb)<br \/>if (alias_i is not None and alias_i != \u00a0\u00bb) and alias_i == alias_j:<br \/>model.Add(same_side == 0)<br \/>model.Add(ports[i][&lsquo;y&rsquo;] != ports[j][&lsquo;y&rsquo;]).OnlyEnforceIf(same_side)<\/p><p>model.AddNoOverlap2D(routing_h_x_ints, routing_h_y_ints)<br \/>model.AddNoOverlap2D(routing_v_x_ints, routing_v_y_ints)<\/p><p># ==========================================<br \/># 4. FONCTION OBJECTIVE &amp; D\u00c9TECTION CROISEMENT<br \/># ==========================================<\/p><p>POIDS_FEUILLE_DROITE = 100<br \/>POIDS_CROISEMENT = 100<br \/>POIDS_VIRAGE = 10<br \/>POIDS_HAUTEUR = 5<br \/>POIDS_DISTANCE = 1<br \/>POIDS_SPLICE_L = 0.5<br \/>POIDS_RATIO = 0<br \/>POIDS_ANCRAGES = 30<\/p><p>cost_elements = []<br \/>max_x = model.NewIntVar(0, grid_size, &lsquo;max_x&rsquo;)<br \/>max_y = model.NewIntVar(0, grid_size, &lsquo;max_y&rsquo;)<br \/>all_x_vars = []<br \/>all_y_vars = []<\/p><p>for n, v in node_vars.items():<br \/>if v.get(&lsquo;is_external&rsquo;): continue<br \/>all_x_vars.append(v[&lsquo;x&rsquo;] + v.get(&lsquo;w&rsquo;, 0))<br \/>if &lsquo;y_end&rsquo; in v:<br \/>all_y_vars.append(v[&lsquo;y_end&rsquo;])<br \/>else:<br \/>all_y_vars.append(v[&lsquo;y&rsquo;])<\/p><p>for e in edges_info:<br \/>all_x_vars.extend([e[&lsquo;seg_H1&rsquo;][&lsquo;xmax&rsquo;], e[&lsquo;seg_H2&rsquo;][&lsquo;xmax&rsquo;], e[&lsquo;seg_V&rsquo;][&lsquo;x&rsquo;]])<br \/>all_y_vars.extend([e[&lsquo;seg_H1&rsquo;][&lsquo;y&rsquo;], e[&lsquo;seg_H2&rsquo;][&lsquo;y&rsquo;], e[&lsquo;seg_V&rsquo;][&lsquo;ymax&rsquo;]])<\/p><p>if all_x_vars and all_y_vars:<br \/>model.AddMaxEquality(max_x, all_x_vars)<br \/>model.AddMaxEquality(max_y, all_y_vars)<\/p><p>target_y = model.NewIntVar(0, grid_size * 3, &lsquo;target_y&rsquo;)<br \/>model.Add(target_y == 3 * max_x)<br \/>ratio_penalty = model.NewIntVar(0, grid_size * 3, &lsquo;ratio_penalty&rsquo;)<br \/>model.AddAbsEquality(ratio_penalty, max_y &#8211; target_y)<br \/>cost_elements.append(POIDS_RATIO * ratio_penalty)<\/p><p>if allow_bent_leaves and soft_penalties:<br \/>for penalty in soft_penalties:<br \/>cost_elements.append(POIDS_FEUILLE_DROITE * penalty)<\/p><p>global_min_x = model.NewIntVar(0, grid_size, &lsquo;global_min_x&rsquo;)<br \/>global_min_y = model.NewIntVar(0, grid_size, &lsquo;global_min_y&rsquo;)<br \/>min_candidates_x = []<br \/>min_candidates_y = []<\/p><p>for n, v in node_vars.items():<br \/>if v.get(&lsquo;is_external&rsquo;): continue<br \/>min_candidates_x.append(v[&lsquo;x&rsquo;])<br \/>min_candidates_y.append(v[&lsquo;y&rsquo;])<\/p><p>for e in edges_info:<br \/>min_candidates_x.extend([e[&lsquo;seg_H1&rsquo;][&lsquo;xmin&rsquo;], e[&lsquo;seg_H2&rsquo;][&lsquo;xmin&rsquo;], e[&lsquo;seg_V&rsquo;][&lsquo;x&rsquo;]])<br \/>min_candidates_y.extend([e[&lsquo;seg_H1&rsquo;][&lsquo;y&rsquo;], e[&lsquo;seg_H2&rsquo;][&lsquo;y&rsquo;], e[&lsquo;seg_V&rsquo;][&lsquo;ymin&rsquo;]])<\/p><p>if min_candidates_x and min_candidates_y:<br \/>model.AddMinEquality(global_min_x, min_candidates_x)<br \/>model.AddMinEquality(global_min_y, min_candidates_y)<\/p><p>for n in G.nodes():<br \/>v = node_vars[n]<br \/>if v.get(\u00ab\u00a0is_splice\u00a0\u00bb) and v.get(\u00ab\u00a0is_backbone\u00a0\u00bb):<br \/>cost_elements.append(POIDS_SPLICE_L * v[\u00ab\u00a0L\u00a0\u00bb])<br \/>elif not v.get(\u00ab\u00a0is_external\u00a0\u00bb) and not v.get(\u00ab\u00a0is_splice\u00a0\u00bb) and not v.get(\u00ab\u00a0is_relay\u00a0\u00bb):<br \/>cost_elements.append(POIDS_HAUTEUR * v[\u00ab\u00a0h\u00a0\u00bb])<\/p><p>for n, v in node_vars.items():<br \/>if v.get(\u00ab\u00a0is_splice\u00a0\u00bb) and v.get(\u00ab\u00a0is_backbone\u00a0\u00bb):<br \/>ports = node_ports[n]<br \/>if not ports: continue<br \/>used_positions = []<br \/>for k in range(grid_size + 1):<br \/>pos_used = model.NewBoolVar(f\u00a0\u00bbpos_used_{n}_{k}\u00a0\u00bb)<br \/>port_at_pos = []<br \/>for i, p in enumerate(ports):<br \/>coord_var = p[\u00ab\u00a0x\u00a0\u00bb] if backbone_orientation == \u00ab\u00a0horizontal\u00a0\u00bb else p[\u00ab\u00a0y\u00a0\u00bb]<br \/>is_here = model.NewBoolVar(f\u00a0\u00bbis_here_{n}_{k}_{i}\u00a0\u00bb)<br \/>model.Add(coord_var == k).OnlyEnforceIf(is_here)<br \/>model.Add(coord_var != k).OnlyEnforceIf(is_here.Not())<br \/>port_at_pos.append(is_here)<br \/>model.AddMaxEquality(pos_used, port_at_pos)<br \/>used_positions.append(pos_used)<br \/>nb_ancrages = model.NewIntVar(1, len(ports), f\u00a0\u00bbnb_ancrages_{n}\u00a0\u00bb)<br \/>model.Add(nb_ancrages == sum(used_positions))<br \/>cost_elements.append(POIDS_ANCRAGES * nb_ancrages)<\/p><p>for e in edges_info:<br \/>cost_elements.append(POIDS_DISTANCE * e[&lsquo;h1_len&rsquo;])<br \/>cost_elements.append(POIDS_DISTANCE * e[&lsquo;v_len&rsquo;])<br \/>cost_elements.append(POIDS_DISTANCE * e[&lsquo;h2_len&rsquo;])<br \/>is_turning = model.NewBoolVar(f&rsquo;is_turning_{e[\u00ab\u00a0key_str\u00a0\u00bb]}&rsquo;)<br \/>model.Add(e[&lsquo;v_len&rsquo;] &gt; 0).OnlyEnforceIf(is_turning)<br \/>model.Add(e[&lsquo;v_len&rsquo;] == 0).OnlyEnforceIf(is_turning.Not())<br \/>cost_elements.append(POIDS_VIRAGE * is_turning)<\/p><p>def add_crossing_detection(h_seg, v_seg, prefix):<br \/>cross_var = model.NewBoolVar(f&rsquo;cross_{prefix}&rsquo;)<br \/>c1, c2, c3, c4 = [model.NewBoolVar(\u00a0\u00bb) for _ in range(4)]<br \/>model.Add(h_seg[&lsquo;xmin&rsquo;] &lt;= v_seg[&lsquo;x&rsquo;]).OnlyEnforceIf(c1)<br \/>model.Add(h_seg[&lsquo;xmin&rsquo;] &gt; v_seg[&lsquo;x&rsquo;]).OnlyEnforceIf(c1.Not())<br \/>model.Add(v_seg[&lsquo;x&rsquo;] &lt;= h_seg[&lsquo;xmax&rsquo;]).OnlyEnforceIf(c2)<br \/>model.Add(v_seg[&lsquo;x&rsquo;] &gt; h_seg[&lsquo;xmax&rsquo;]).OnlyEnforceIf(c2.Not())<br \/>model.Add(v_seg[&lsquo;ymin&rsquo;] &lt;= h_seg[&lsquo;y&rsquo;]).OnlyEnforceIf(c3)<br \/>model.Add(v_seg[&lsquo;ymin&rsquo;] &gt; h_seg[&lsquo;y&rsquo;]).OnlyEnforceIf(c3.Not())<br \/>model.Add(h_seg[&lsquo;y&rsquo;] &lt;= v_seg[&lsquo;ymax&rsquo;]).OnlyEnforceIf(c4)<br \/>model.Add(h_seg[&lsquo;y&rsquo;] &gt; v_seg[&lsquo;ymax&rsquo;]).OnlyEnforceIf(c4.Not())<br \/>model.AddBoolAnd([c1, c2, c3, c4]).OnlyEnforceIf(cross_var)<br \/>model.AddBoolOr([c1.Not(), c2.Not(), c3.Not(), c4.Not()]).OnlyEnforceIf(cross_var.Not())<br \/>return cross_var<\/p><p>for i in range(len(edges_info)):<br \/>for j in range(i + 1, len(edges_info)):<br \/>eA = edges_info[i]<br \/>eB = edges_info[j]<br \/>if eA[&lsquo;u&rsquo;] in (eB[&lsquo;u&rsquo;], eB[&lsquo;v&rsquo;]) or eA[&lsquo;v&rsquo;] in (eB[&lsquo;u&rsquo;], eB[&lsquo;v&rsquo;]): continue<br \/>cross1 = add_crossing_detection(eA[&lsquo;seg_H1&rsquo;], eB[&lsquo;seg_V&rsquo;], f'{eA[\u00ab\u00a0key_str\u00a0\u00bb]}_{eB[\u00ab\u00a0key_str\u00a0\u00bb]}_H1_V&rsquo;)<br \/>cross2 = add_crossing_detection(eA[&lsquo;seg_H2&rsquo;], eB[&lsquo;seg_V&rsquo;], f'{eA[\u00ab\u00a0key_str\u00a0\u00bb]}_{eB[\u00ab\u00a0key_str\u00a0\u00bb]}_H2_V&rsquo;)<br \/>cross3 = add_crossing_detection(eB[&lsquo;seg_H1&rsquo;], eA[&lsquo;seg_V&rsquo;], f'{eB[\u00ab\u00a0key_str\u00a0\u00bb]}_{eA[\u00ab\u00a0key_str\u00a0\u00bb]}_H1_V&rsquo;)<br \/>cross4 = add_crossing_detection(eB[&lsquo;seg_H2&rsquo;], eA[&lsquo;seg_V&rsquo;], f'{eB[\u00ab\u00a0key_str\u00a0\u00bb]}_{eA[\u00ab\u00a0key_str\u00a0\u00bb]}_H2_V&rsquo;)<br \/>cost_elements.extend([<br \/>POIDS_CROISEMENT * cross1,<br \/>POIDS_CROISEMENT * cross2,<br \/>POIDS_CROISEMENT * cross3,<br \/>POIDS_CROISEMENT * cross4<br \/>])<\/p><p>model.Minimize(sum(cost_elements))<\/p><p># ==========================================<br \/># 5. R\u00c9SOLUTION ET SAUVEGARDE<br \/># ==========================================<\/p><p>solver = cp_model.CpSolver()<br \/>solver.parameters.num_search_workers = 14<br \/>number_of_calculated_edges = 0.0<\/p><p>for u, v, data in G.edges(data=True):<br \/>t_u, t_v = G.nodes[u].get(&lsquo;type&rsquo;), G.nodes[v].get(&lsquo;type&rsquo;)<br \/>if t_u == &lsquo;relay&rsquo; or t_v == &lsquo;relay&rsquo;:<br \/>if t_u == t_v or t_u in [&lsquo;external&rsquo;, &lsquo;splice&rsquo;] or t_v in [&lsquo;external&rsquo;, &lsquo;splice&rsquo;]:<br \/>number_of_calculated_edges += 1.0<br \/>else:<br \/>number_of_calculated_edges += 1.0<\/p><p>print(number_of_calculated_edges)<br \/>solver.parameters.max_time_in_seconds = max(5, 5 * number_of_calculated_edges)<br \/>status = solver.Solve(model)<\/p><p>if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:<br \/>for n, v in node_vars.items():<br \/>if v.get(&lsquo;is_external&rsquo;):<br \/>G.nodes[n][&lsquo;type&rsquo;] = &lsquo;external&rsquo;<br \/>elif v.get(&lsquo;is_splice&rsquo;):<br \/>G.nodes[n][\u00ab\u00a0type\u00a0\u00bb] = \u00ab\u00a0splice\u00a0\u00bb<br \/>G.nodes[n][\u00ab\u00a0x\u00a0\u00bb] = solver.Value(v[\u00ab\u00a0x\u00a0\u00bb])<br \/>G.nodes[n][\u00ab\u00a0y\u00a0\u00bb] = solver.Value(v[\u00ab\u00a0y\u00a0\u00bb])<br \/>G.nodes[n][\u00ab\u00a0w\u00a0\u00bb] = 0<br \/>G.nodes[n][\u00ab\u00a0h\u00a0\u00bb] = 0<br \/>if v.get(\u00ab\u00a0is_backbone\u00a0\u00bb):<br \/>G.nodes[n][\u00ab\u00a0is_backbone\u00a0\u00bb] = True<br \/>G.nodes[n][\u00ab\u00a0L\u00a0\u00bb] = solver.Value(v[\u00ab\u00a0L\u00a0\u00bb])<br \/>G.nodes[n][\u00ab\u00a0backbone_orientation\u00a0\u00bb] = backbone_orientation<br \/>else:<br \/>G.nodes[n][\u00ab\u00a0is_backbone\u00a0\u00bb] = False<br \/>elif v.get(&lsquo;is_relay&rsquo;):<br \/>G.nodes[n][&lsquo;type&rsquo;] = &lsquo;relay&rsquo;<br \/>G.nodes[n][&lsquo;x&rsquo;] = solver.Value(v[&lsquo;x&rsquo;])<br \/>G.nodes[n][&lsquo;y&rsquo;] = solver.Value(v[&lsquo;y&rsquo;])<br \/>G.nodes[n][&lsquo;w&rsquo;] = v[&lsquo;w&rsquo;]<br \/>G.nodes[n][&lsquo;h&rsquo;] = v[&lsquo;h&rsquo;]<br \/>G.nodes[n][&lsquo;is_left&rsquo;] = solver.Value(v[&lsquo;is_left&rsquo;]) == 1<br \/>else:<br \/>G.nodes[n][&lsquo;x&rsquo;] = solver.Value(v[&lsquo;x&rsquo;])<br \/>G.nodes[n][&lsquo;y&rsquo;] = solver.Value(v[&lsquo;y&rsquo;])<br \/>G.nodes[n][&lsquo;w&rsquo;] = v[&lsquo;w&rsquo;]<br \/>G.nodes[n][&lsquo;h&rsquo;] = solver.Value(v[&lsquo;h&rsquo;])<br \/>ports = node_ports.get(n, [])<br \/>equipment = v[&lsquo;equipment&rsquo;]<br \/>side_var_val = solver.Value(equipment_side_vars[equipment])<br \/>G.nodes[n][&lsquo;is_left&rsquo;] = (side_var_val == 0)<\/p><p>for e in edges_info:<br \/>start_x = solver.Value(e[&lsquo;p_ux&rsquo;])<br \/>start_y = solver.Value(e[&lsquo;p_uy&rsquo;])<br \/>vx = solver.Value(e[&lsquo;e_vx&rsquo;])<br \/>end_x = solver.Value(e[&lsquo;p_vx&rsquo;])<br \/>end_y = solver.Value(e[&lsquo;p_vy&rsquo;])<br \/>route = [(start_x, start_y), (vx, start_y), (vx, end_y), (end_x, end_y)]<br \/>G.edges[e[&lsquo;u&rsquo;], e[&lsquo;v&rsquo;], e[&lsquo;key&rsquo;]][&lsquo;route&rsquo;] = route<br \/><br \/>if node_vars[e[&lsquo;u&rsquo;]].get(&lsquo;is_external&rsquo;):<br \/>G.nodes[e[&lsquo;u&rsquo;]][&lsquo;port_x&rsquo;] = start_x<br \/>G.nodes[e[&lsquo;u&rsquo;]][&lsquo;port_y&rsquo;] = start_y<br \/>if node_vars[e[&lsquo;v&rsquo;]].get(&lsquo;is_external&rsquo;):<br \/>G.nodes[e[&lsquo;v&rsquo;]][&lsquo;port_x&rsquo;] = end_x<br \/>G.nodes[e[&lsquo;v&rsquo;]][&lsquo;port_y&rsquo;] = end_y<\/p><p>virtual_boxes_results = {}<br \/>for vbox in virtual_boxes_info.keys():<br \/>virtual_boxes_results[vbox] = {<br \/>&lsquo;name&rsquo;: virtual_boxes_info[vbox][&lsquo;name&rsquo;],<br \/>&lsquo;x&rsquo;: solver.Value(virtual_boxes_info[vbox][&lsquo;x&rsquo;]),<br \/>&lsquo;y&rsquo;: solver.Value(virtual_boxes_info[vbox][&lsquo;y_min&rsquo;]),<br \/>&lsquo;w&rsquo;: 1,<br \/>&lsquo;h&rsquo;: solver.Value(virtual_boxes_info[vbox][&lsquo;h&rsquo;])<br \/>}<br \/>G.graph[&lsquo;virtual_boxes&rsquo;] = virtual_boxes_results<\/p><p>relays = [n for n, v in node_vars.items() if v.get(&lsquo;is_relay&rsquo;)]<br \/>for relay in relays:<br \/>r_data = G.nodes[relay]<br \/>r_x, r_y, r_h = r_data[&lsquo;x&rsquo;], r_data[&lsquo;y&rsquo;], r_data[&lsquo;h&rsquo;]<br \/>is_left = r_data[&lsquo;is_left&rsquo;]<br \/>principal = node_vars[relay][&lsquo;principal&rsquo;]<br \/>internal_edges = []<br \/>outgoing_edges = []<br \/><br \/>for u, v, k in G.edges(relay, keys=True):<br \/>if v == principal or u == principal:<br \/>internal_edges.append((u, v, k))<br \/>else:<br \/>outgoing_edges.append((u, v, k))<br \/><br \/>if not outgoing_edges: continue<br \/><br \/>out_u, out_v, out_k = outgoing_edges[0]<br \/>out_route = G.edges[out_u, out_v, out_k][&lsquo;route&rsquo;]<br \/>JX = r_x if is_left else r_x + 1<br \/>JY = r_y + r_h \/\/ 2<br \/>PX = r_x + 1 if is_left else r_x<br \/>y_slots = [r_y + i for i in range(r_h)]<br \/><br \/>for i, (u, v, k) in enumerate(internal_edges):<br \/>PY = y_slots[i]<br \/>if u == principal:<br \/>final_route = [(PX, PY), (JX, PY), (JX, JY)]<br \/>else:<br \/>final_route = [(JX, JY), (JX, PY), (PX, PY)]<br \/>G.edges[u, v, k][&lsquo;route&rsquo;] = final_route<br \/>if &lsquo;ports&rsquo; not in G.nodes[principal]:<br \/>G.nodes[principal][&lsquo;ports&rsquo;] = []<br \/>G.nodes[principal][&lsquo;ports&rsquo;].append((PX, PY))<br \/><br \/>G.nodes[relay][&lsquo;x&rsquo;] = JX<br \/>G.nodes[relay][&lsquo;y&rsquo;] = JY<br \/>G.nodes[relay][&lsquo;w&rsquo;] = 0<br \/>G.nodes[relay][&lsquo;h&rsquo;] = 0<br \/>G.nodes[relay][&lsquo;principal&rsquo;] = principal<\/p><p>def extract_backbones_to_chains(G: nx.MultiGraph) -&gt; nx.MultiGraph:<br \/>\u00ab\u00a0\u00a0\u00bb\u00a0\u00bbTransforme les splices \u00e9tendus (backbones) en cha\u00eenes de splices ponctuels.\u00a0\u00bb\u00a0\u00bb\u00a0\u00bb<br \/>backbones = {n: d for n, d in G.nodes(data=True) if d.get(\u00ab\u00a0type\u00a0\u00bb) == \u00ab\u00a0splice\u00a0\u00bb and d.get(\u00ab\u00a0is_backbone\u00a0\u00bb)}<br \/>if not backbones: return G<br \/><br \/>bb_points = {n: set() for n in backbones}<br \/>edges_to_rebuild = []<br \/><br \/>for u, v, k, d in G.edges(keys=True, data=True):<br \/>route = d.get(\u00ab\u00a0route\u00a0\u00bb, [])<br \/>if not route: continue<br \/>if u in backbones: bb_points[u].add(route[0])<br \/>if v in backbones: bb_points[v].add(route[-1])<br \/>edges_to_rebuild.append((u, v, k, d))<br \/><br \/>bb_mapping = {n: {} for n in backbones}<br \/>for b_node, b_data in backbones.items():<br \/>is_horizontal = b_data.get(\u00ab\u00a0backbone_orientation\u00a0\u00bb) == \u00ab\u00a0horizontal\u00a0\u00bb<br \/>b_alias, b_sub_alias = None, None<br \/>for original_u, original_v, k, d in edges_to_rebuild:<br \/>if original_u == b_node or original_v == b_node:<br \/>b_alias = d.get(\u00ab\u00a0alias\u00a0\u00bb)<br \/>b_sub_alias = d.get(\u00ab\u00a0sub_alias\u00a0\u00bb)<br \/>break<br \/><br \/>if is_horizontal:<br \/>sorted_pts = sorted(list(bb_points[b_node]), key=lambda p: p[0])<br \/>else:<br \/>sorted_pts = sorted(list(bb_points[b_node]), key=lambda p: p[1])<br \/>sub_nodes = []<br \/>for i, pt in enumerate(sorted_pts):<br \/>sub_node_id = f\u00a0\u00bb{b_node}_sub_{i}\u00a0\u00bb<br \/>sub_nodes.append(sub_node_id)<br \/>bb_mapping[b_node][pt] = sub_node_id<br \/>G.add_node(sub_node_id, type=\u00a0\u00bbsplice\u00a0\u00bb, x=pt[0], y=pt[1], w=0, h=0, <br \/>is_backbone=False, alias=b_alias, sub_alias=b_sub_alias)<br \/><br \/>for i in range(len(sub_nodes) &#8211; 1):<br \/>node_a = sub_nodes[i]<br \/>node_b = sub_nodes[i + 1]<br \/>pt_a = sorted_pts[i]<br \/>pt_b = sorted_pts[i + 1]<br \/>chain_route = [pt_a, pt_b]<br \/>G.add_edge(node_a, node_b, type=\u00a0\u00bbconnection\u00a0\u00bb, route=chain_route, <br \/>alias=b_alias, sub_alias=b_sub_alias)<br \/><br \/>for b_node in backbones: G.remove_node(b_node)<br \/><br \/>for original_u, original_v, k, d in edges_to_rebuild:<br \/>new_u = original_u<br \/>new_v = original_v<br \/>if original_u in backbones:<br \/>pt_u = d[\u00ab\u00a0route\u00a0\u00bb][0]<br \/>new_u = bb_mapping[original_u][pt_u]<br \/>if original_v in backbones:<br \/>pt_v = d[\u00ab\u00a0route\u00a0\u00bb][-1]<br \/>new_v = bb_mapping[original_v][pt_v]<br \/>G.add_edge(new_u, new_v, key=k, **d)<br \/>return G<\/p><p>for u, v, k in G.edges(keys=True):<br \/>if &lsquo;route&rsquo; in G.edges[u, v, k]:<br \/>G.edges[u, v, k][&lsquo;route&rsquo;] = clean_and_merge_route(G.edges[u, v, k][&lsquo;route&rsquo;])<br \/><br \/>G = extract_backbones_to_chains(G)<br \/>return G<br \/>else:<br \/># CORRECTION ARCHITECTURALE : alignement de la signature lors de l&rsquo;appel r\u00e9cursif<br \/>if not allow_bent_leaves:<br \/>print(&lsquo;Placement strict impossible (INFEASIBLE). Relance avec rel\u00e2chement des ar\u00eates droites&rsquo;)<br \/>return solve_nx_placement(G, backbone_orientation=backbone_orientation, allow_bent_leaves=True)<br \/>print(&lsquo;Placement totalement non r\u00e9ussi (m\u00eame avec rel\u00e2chement)&rsquo;)<br \/>return nx.MultiGraph()<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0aee240 e-flex e-con-boxed e-con e-parent\" data-id=\"0aee240\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e7e6b14 elementor-widget elementor-widget-html\" data-id=\"e7e6b14\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style>\r\n    html, body {\r\n        margin: 0 !important;\r\n        padding: 0 !important;\r\n        overflow-x: hidden; \r\n    }\r\n\r\n    .footer-medium-cols {\r\n        width: 100vw; \r\n        position: relative;\r\n        left: 50%;\r\n        right: 50%;\r\n        margin-left: -50vw;\r\n        margin-right: -50vw;\r\n        margin-top: -5px !important; \r\n        \r\n        box-sizing: border-box; \r\n        background-color: #F4F1EA; \r\n        color: #333; \r\n        font-family: 'Lato', sans-serif;\r\n        padding: 40px 50px 20px 50px; \r\n    }\r\n\r\n    .footer-content-row {\r\n        display: flex;\r\n        justify-content: space-between;\r\n        align-items: flex-start;\r\n        flex-wrap: wrap;\r\n        max-width: 1200px; \r\n        margin: 0 auto;\r\n        gap: 20px;\r\n    }\r\n\r\n    .f-col {\r\n        flex: 1;\r\n        min-width: 200px;\r\n    }\r\n\r\n    .f-title {\r\n        font-family: 'Playfair Display', serif;\r\n        font-size: 1.1rem;\r\n        font-weight: bold;\r\n        margin-top: 0;\r\n        margin-bottom: 15px;\r\n        color: #222;\r\n        text-transform: uppercase;\r\n        letter-spacing: 1px;\r\n    }\r\n\r\n    .f-list {\r\n        list-style: none;\r\n        padding: 0;\r\n        margin: 0;\r\n        font-size: 0.9rem;\r\n        line-height: 1.8;\r\n    }\r\n\r\n    .f-link {\r\n        text-decoration: none;\r\n        color: #555;\r\n        transition: color 0.3s, padding-left 0.3s;\r\n    }\r\n\r\n    .f-link:hover {\r\n        color: #E2725B; \r\n        padding-left: 3px;\r\n    }\r\n\r\n    .f-text {\r\n        font-size: 0.9rem;\r\n        line-height: 1.6;\r\n        color: #555;\r\n        margin: 0;\r\n    }\r\n\r\n    .f-copyright {\r\n        margin-top: 30px;\r\n        padding-top: 15px;\r\n        border-top: 1px solid rgba(0,0,0,0.1); \r\n        text-align: center;\r\n        font-size: 0.75rem;\r\n        color: #666;\r\n    }\r\n\r\n    @media (max-width: 768px) {\r\n        .footer-medium-cols { padding: 30px 20px; }\r\n        .footer-content-row { flex-direction: column; gap: 30px; text-align: center; }\r\n        .f-col { width: 100%; }\r\n    }\r\n<\/style>\r\n\r\n<footer class=\"footer-medium-cols\" itemscope itemtype=\"http:\/\/schema.org\/LodgingBusiness\">\r\n    <div class=\"footer-content-row\">\r\n        \r\n        <div class=\"f-col\">\r\n            <h2 class=\"f-title\" itemprop=\"name\">Domaine en Coudon<\/h2>\r\n            <p class=\"f-text\" itemprop=\"description\">\r\n                G\u00eete de Charme \u00e0 Gaur\u00e9.<br>\r\n                Un lieu unique pour se ressourcer.\r\n            <\/p>\r\n        <\/div>\r\n\r\n        <div class=\"f-col\">\r\n            <h2 class=\"f-title\" id=\"titre-menu-footer\">Menu<\/h2>\r\n            <nav aria-labelledby=\"titre-menu-footer\">\r\n                <ul class=\"f-list\">\r\n                    <li><a href=\"https:\/\/domaineencoudon.fr\/\" class=\"f-link\">Accueil<\/a><\/li>\r\n                    <li><a href=\"https:\/\/domaineencoudon.fr\/index.php\/photos\" class=\"f-link\">Le G\u00eete & Photos<\/a><\/li>\r\n                    <li><a href=\"https:\/\/domaineencoudon.fr\/index.php\/alentours\" class=\"f-link\">Alentours<\/a><\/li>\r\n                    <li><a href=\"https:\/\/domaineencoudon.fr\/index.php\/reserver\" class=\"f-link\" style=\"color:#E2725B; font-weight:bold;\" title=\"Acc\u00e9der \u00e0 la plateforme de r\u00e9servation\">R\u00e9server maintenant<\/a><\/li>\r\n                <\/ul>\r\n            <\/nav>\r\n        <\/div>\r\n\r\n        <div class=\"f-col\">\r\n            <h2 class=\"f-title\">Contact<\/h2>\r\n            <address class=\"f-list\" style=\"font-style: normal;\" itemprop=\"address\" itemscope itemtype=\"http:\/\/schema.org\/PostalAddress\">\r\n                <span class=\"f-text\" itemprop=\"streetAddress\">194 Route des cr\u00eates<\/span><br>\r\n                <span class=\"f-text\">\r\n                    <span itemprop=\"postalCode\">31590<\/span> \r\n                    <span itemprop=\"addressLocality\">Gaur\u00e9<\/span>, \r\n                    <span itemprop=\"addressCountry\">France<\/span>\r\n                <\/span><br>\r\n                <a href=\"tel:+33677887885\" class=\"f-link\" itemprop=\"telephone\" title=\"Appeler le Domaine en Coudon\">06 77 88 78 85<\/a><br>\r\n                <a href=\"mailto:contact@domaineencoudon.fr\" class=\"f-link\" itemprop=\"email\" title=\"Envoyer un e-mail au Domaine en Coudon\">domaine.encoudon@gmail.com<\/a>\r\n            <\/address>\r\n        <\/div>\r\n\r\n    <\/div>\r\n\r\n    <div class=\"f-copyright\">\r\n        &copy; 2026 Domaine en Coudon - <a href=\"https:\/\/domaineencoudon.fr\/mentions-legales\" class=\"f-link\" title=\"Consulter les mentions l\u00e9gales\">Mentions L\u00e9gales<\/a>\r\n    <\/div>\r\n<\/footer>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Accueil Le G\u00eete Alentours Contact R\u00e9server Informations pratiques Inclus dans le tarif M\u00e9nage de fin de s\u00e9jour, eau, \u00e9lectricit\u00e9, chauffage, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-18","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/pages\/18","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/comments?post=18"}],"version-history":[{"count":1142,"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/pages\/18\/revisions"}],"predecessor-version":[{"id":1932,"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/pages\/18\/revisions\/1932"}],"wp:attachment":[{"href":"https:\/\/domaineencoudon.fr\/index.php\/wp-json\/wp\/v2\/media?parent=18"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}