diff --git a/all_includes.hh b/all_includes.hh index edd2b24..438902e 100644 --- a/all_includes.hh +++ b/all_includes.hh @@ -36,6 +36,7 @@ class Chose; #include "rules/architecture/arche.hh" #include "rules/architecture/toit.hh" +#include "rules/architecture/quartier.hh" #include "rules/batiment/batimentquad.hh" #include "rules/batiment/batimentquadmaison.hh" diff --git a/geometry/directions.hh b/geometry/directions.hh index 31054eb..087d2e0 100644 --- a/geometry/directions.hh +++ b/geometry/directions.hh @@ -111,22 +111,6 @@ const CoteTriangle LEFTSIDE = CoteTriangle(0); const CoteTriangle RIGHTSIDE = CoteTriangle(1); const CoteTriangle BASE = CoteTriangle(2); -/* -enum SommetTriangle { - LEFT = 0, - TOP = 1, - RIGHT = 2 -}; - -inline SommetTriangle operator+(SommetTriangle c, int i) { - return SommetTriangle((((int(c) + int(i)) % 3 ) + 3) % 3); -} - -inline SommetTriangle operator-(SommetTriangle c, int i) { - return SommetTriangle((((int(c) - int(i)) % 3 ) + 3) % 3); -} -*/ - // Plus ou moins la même chose que CoteTriangle. class SommetTriangle { private: diff --git a/geometry/quad.cpp b/geometry/quad.cpp index c7cb159..6e79ce8 100644 --- a/geometry/quad.cpp +++ b/geometry/quad.cpp @@ -93,20 +93,46 @@ float Quad::maxLength() const { return std::max(maxLengthNS(), maxLengthEW()); } +float Quad::angle(Coin corner) const { + return Triangle(c[NW+corner], c[NE+corner], c[SE+corner]).angle(); +} + float Quad::minAngle() const { - float a = 370; // > 360. - for (int i = 0; i < 4; i++) { - a = std::min(a, Triangle(c[NE+i], c[SE+i], c[SW+i]).angle()); - } - return a; + float ane = angle(NE); + float ase = angle(SE); + float asw = angle(SW); + float anw = 2*Angle::Pi - (ane + ase + asw); + return std::min(std::min(ane, ase), std::min(asw, anw)); } float Quad::maxAngle() const { - float a = 0; - for (int i = 0; i < 4; i++) { - a = std::max(a, Triangle(c[NE+i], c[SE+i], c[SW+i]).angle()); - } - return a; + float ane = angle(NE); + float ase = angle(SE); + float asw = angle(SW); + float anw = 2*Angle::Pi - (ane + ase + asw); + return std::max(std::max(ane, ase), std::max(asw, anw)); +} + +Coin Quad::minAngleCorner() const { + float ane = angle(NE); + float ase = angle(SE); + float asw = angle(SW); + float anw = 2*Angle::Pi - (ane + ase + asw); + if (ane < ase && ane < asw && ane < anw) return NE; + else if (ase < asw && ase < anw) return SE; + else if (asw < anw) return SW; + else return NW; +} + +Coin Quad::maxAngleCorner() const { + float ane = angle(NE); + float ase = angle(SE); + float asw = angle(SW); + float anw = 2*Angle::Pi - (ane + ase + asw); + if (ane > ase && ane > asw && ane > anw) return NE; + else if (ase > asw && ase > anw) return SE; + else if (asw > anw) return SW; + else return NW; } Quad operator+(const Quad& q, const Vertex& v) { diff --git a/geometry/quad.hh b/geometry/quad.hh index 73b9371..8842340 100644 --- a/geometry/quad.hh +++ b/geometry/quad.hh @@ -35,8 +35,11 @@ class Quad { float maxLengthEW() const; float minLength() const; float maxLength() const; + float angle(Coin corner) const; float minAngle() const; float maxAngle() const; + Coin minAngleCorner() const; + Coin maxAngleCorner() const; Vertex randomPoint(int seed, int n) const; float surface() const; //void cutCornerCorner(Coin from) const; diff --git a/geometry/triangle.cpp b/geometry/triangle.cpp index dc6b135..c0088c4 100644 --- a/geometry/triangle.cpp +++ b/geometry/triangle.cpp @@ -28,6 +28,24 @@ float Triangle::maxAngle() const { return std::max(std::max(al, at), ar); } +SommetTriangle Triangle::maxAngleCorner() const { + float at = angle(); + float ar = Triangle(c[TOP],c[RIGHT],c[LEFT]).angle(); + float al = Angle::Pi - at - ar; + if (al > at && al > ar) return LEFT; + else if (at > ar) return TOP; + else return RIGHT; +} + +SommetTriangle Triangle::minAngleCorner() const { + float at = angle(); + float ar = Triangle(c[TOP],c[RIGHT],c[LEFT]).angle(); + float al = Angle::Pi - at - ar; + if (al < at && al < ar) return LEFT; + else if (at < ar) return TOP; + else return RIGHT; +} + float Triangle::minLength() const { return std::min(std::min((c[LEFT] - c[TOP]).norm(), (c[TOP] - c[RIGHT]).norm()), (c[RIGHT] - c[LEFT]).norm()); } diff --git a/geometry/triangle.hh b/geometry/triangle.hh index fdeffee..dfe05d9 100644 --- a/geometry/triangle.hh +++ b/geometry/triangle.hh @@ -24,9 +24,11 @@ public : } friend Triangle operator+(const Triangle& t, const Vertex& v); float cosAngle() const; // cosinus de l'angle en c[1]. - float angle() const; // angle en c[1], en degrés. TODO : le calcul ne donne que des angles entre 0 et 180 ! + float angle() const; // angle en c[TOP], en degrés. float minAngle() const; // angle minimum du triangle (en LEFT, TOP ou RIGHT). float maxAngle() const; // angle maximum du triangle (en LEFT, TOP ou RIGHT). + SommetTriangle minAngleCorner() const; + SommetTriangle maxAngleCorner() const; float minLength() const; float maxLength() const; float surface() const; diff --git a/rules/architecture/arche.cpp b/rules/architecture/arche.cpp index 100dbc2..9ef1f55 100644 --- a/rules/architecture/arche.cpp +++ b/rules/architecture/arche.cpp @@ -32,12 +32,10 @@ float ArcheQuad::f(float x) { } } -// Fonction fausse float ArcheQuad::ogive(float x) { return sin(acos(abs(x / 2.f) + 1.f/2.f)); } -// Fonction fausse float ArcheQuad::berceau(float x) { return sin(acos(x)); } diff --git a/rules/architecture/arche.hh b/rules/architecture/arche.hh index c01d637..91b65e5 100644 --- a/rules/architecture/arche.hh +++ b/rules/architecture/arche.hh @@ -19,9 +19,9 @@ public: float berceau(float x); private: // TODO : couleur de l'arche - static const char r = 0xF1; - static const char g = 0xE0; - static const char b = 0xE0; + static const char r = 0xF1; // TODO : factoriser cette couleur (couleur des murs des faux bâtiments). + static const char g = 0xE3; + static const char b = 0xAD; }; #endif diff --git a/rules/architecture/quartier.cpp b/rules/architecture/quartier.cpp new file mode 100644 index 0000000..e18d1a0 --- /dev/null +++ b/rules/architecture/quartier.cpp @@ -0,0 +1,214 @@ +#include "all_includes.hh" + +QuartierQuad_::QuartierQuad_(Quad _c) : c(_c) { + addEntropy(c); +} + +void QuartierQuad_::getBoundingBoxPoints() { + addBBPoints(c, 6000); // TODO : factoriser cette longueur (hauteur max des bâtiments). +} + +bool QuartierQuad_::split() { + bool small = c.minLength() < 3500; + bool big = c.maxLength() >= 6000; + bool isConcave = c.maxAngle() > Angle::d2r(160); + bool anglesOk = c.minAngle() > Angle::d2r(90-40) && c.maxAngle() < Angle::d2r(90+40); + bool tooWideX = c.minLengthEW() * 2 < c.maxLengthNS(); // trop allongé (côté E ou W deux fois plus petit que le côté N ou S). + bool tooWideY = c.minLengthNS() * 2 < c.maxLengthEW(); // trop allongé (côté N ou S deux fois plus petit que le côté E ou W). + if (isConcave) + concave(); + else if (!big && proba(seed, -1, 1, 20)) + batiments(); + else if (!small && !anglesOk) + angleAngle(); // TODO + else if (!small && tooWideY) + rect(); // TODO : Quad(c[NW], c[NE], c[SE], c[SW]) + else if (!small && tooWideX) + rect(); // TODO : fusion avec ci-dessus + else if (!small) + carre(); + else + batiments(); + return true; +} + +void QuartierQuad_::triangulation() { + Quad ci = c.insetNESW(250 + 140); // TODO : factoriser cette longueur (largeur route + largeur trottoir). + Quad cih = c.offsetNormal(6000); // TODO : factoriser cette longueur (hauteur max des bâtiments). + addGPUQuad(c, 0x36, 0x36, 0x36); // TODO : factoriser cette couleur (couleur de la route). + addGPUQuad(cih, 0xF1, 0xE0, 0xE0); // TODO : factoriser cette couleur (couleur des toits). + for (int i = 0; i < 4; i++) + addGPUQuad(Quad(ci[NE+i], ci[SE+i], cih[SE+i], cih[NE+i]), 0xF1, 0xE3, 0xAD); // TODO : factoriser cette couleur (couleur des murs des faux bâtiments). +} + +void QuartierQuad_::concave() { + // TODO +} + +void QuartierQuad_::angleCote() { + Quad q = c << c.maxAngleCorner(); + Vertex s = Segment(q[SE], q[SW]).randomPos(seed, 1, 0.4f, 0.6f); + Vertex w = Segment(q[SW], q[NW]).randomPos(seed, 0, 0.4f, 0.6f); + Triangle ts(q[SE], s, q[NE]); + Triangle tw(q[NE], w, q[NW]); + if (ts.minAngle() > tw.minAngle()) { + addChild(new QuartierTri_(ts)); + addChild(new QuartierQuad_(Quad(q[NE], s, q[SW], q[NW]))); + } else { + addChild(new QuartierTri_(tw)); + addChild(new QuartierQuad_(Quad(q[NE], q[SE], q[SW], w))); + } +} + +void QuartierQuad_::angleAngle() { + Quad q = c << c.maxAngleCorner(); + addChild(new QuartierTri_(Triangle(q[NE], q[SE], q[SW]))); + addChild(new QuartierTri_(Triangle(q[SW], q[NW], q[NE]))); +} + +void QuartierQuad_::rect() { + Vertex n = Segment(c[NW], c[NE]).randomPos(seed, 0, 1.f/3.f, 2.f/3.f); + Vertex s = Segment(c[SE], c[SW]).randomPos(seed, 1, 1.f/3.f, 2.f/3.f); + + addChild(new QuartierQuad_(Quad(c[NE], c[SE], s, n))); + addChild(new QuartierQuad_(Quad(c[SW], c[NW], n, s))); +} + +void QuartierQuad_::carre() { + // TODO : insetProportionnal(); + Vertex center = c.insetNESW(c.minLength() / 4.f).randomPoint(seed, 0); + Vertex middle[4]; + for (int i = 0; i < 4; i++) + middle[N+i] = Segment(c[NW+i], c[NE+i]).randomPos(seed, i + 1, 0.25, 0.75); + + for (int i = 0; i < 4; i++) + addChild(new QuartierQuad_(Quad(c[NE+i], middle[E+i], center, middle[N+i]))); +} + +void QuartierQuad_::batiments() { + float hauteurTrottoir = 20; // TODO : factoriser + ajouter ça à la hauteur max d'un bâtiment dans les autres calculs. + Quad qtrottoir = c.insetNESW(250); + Quad qinterieur = qtrottoir.insetNESW(140); + Quad qbatiments = qinterieur.offsetNormal(hauteurTrottoir); + + for (int i = 0; i < 4; i++) { + addChild(new RouteQuadChaussee(Quad(c[NE+i],c[SE+i],qtrottoir[SE+i],qtrottoir[NE+i]))); + addChild(new TrottoirQuadNormal(Quad(qtrottoir[NE+i],qtrottoir[SE+i],qinterieur[SE+i],qinterieur[NE+i]),hauteurTrottoir)); + } + + // TODO : + + bool small = c.minLength() < 2500; + bool big = c.maxLength() >= 5000; + bool anglesAcceptable = c.minAngle() > Angle::d2r(90-60) && c.maxAngle() < Angle::d2r(90+60); + + if (!big && proba(seed, 0, 1, 20)) { + addChild(new TerrainQuadHerbe(qbatiments)); + } else if (small && anglesAcceptable) { + addChild(new BatimentQuad(qbatiments)); + } else { + addChild(new TerrainQuadHerbe(qbatiments)); + } +} + +QuartierTri_::QuartierTri_(Triangle _c) : c(_c) { + addEntropy(c); +} + +void QuartierTri_::getBoundingBoxPoints() { + addBBPoints(c, 6000); // TODO : factoriser cette longueur (hauteur max des bâtiments). +} + +bool QuartierTri_::split() { + bool small = c.minLength() < 5000; + bool big = c.maxLength() >= 10000; + float minAngle = c.minAngle(); + float maxAngle = c.maxAngle(); + bool equilateral = maxAngle < Angle::d2r(60+15) && minAngle > Angle::d2r(60-15); + bool angleObtus = maxAngle > Angle::d2r(120); + bool angleAigu = minAngle < Angle::d2r(30); + bool anglesAcceptable = !angleAigu && !angleObtus; + if (!big && proba(seed, -1, 1, 20)) { + batiments(); // TODO : RouteTrottoirTri(c); + } else if (big && anglesAcceptable) { + switch (hash2(seed, -2) % 3) { + case 0: centre(); break; + case 1: hauteur(); break; + case 2: + default: trapeze(); break; + } + } else if (!small && equilateral) { + centre(); + } else if (!small && angleObtus) { + hauteur(); + } else if (!small) { + trapeze(); + } else { + batiments(); + } + return true; +} + +void QuartierTri_::triangulation() { + Triangle ci = c.insetLTR(250 + 140); // TODO : factoriser cette longueur (largeur route + largeur trottoir). + Triangle cih = c.offsetNormal(6000); // TODO : factoriser cette longueur (hauteur max des bâtiments). + addGPUTriangle(c, 0x36, 0x36, 0x36); // TODO : factoriser cette couleur (couleur de la route). + addGPUTriangle(cih, 0xF1, 0xE0, 0xE0); // TODO : factoriser cette couleur (couleur des toits). + for (int i = 0; i < 3; i++) + addGPUQuad(Quad(ci[LEFT+i], ci[TOP+i], cih[TOP+i], cih[LEFT+i]), 0xF1, 0xE3, 0xAD); // TODO : factoriser cette couleur (couleur des murs des faux bâtiments). +} + +void QuartierTri_::centre() { + // TODO : maxLength / 6 au lieu de 1000 + // TODO : insetProportionnal(); + Vertex center = c.insetLTR(c.maxLength() / 6).randomPoint(seed, 0); + Vertex edge[3]; + for (int i = 0; i < 3; i++) + edge[LEFTSIDE+i] = Segment(c[LEFT+i], c[TOP+i]).randomPos(seed, i+1, 1.f/3.f, 2.f/3.f); + + for (int i = 0; i < 3; i++) + addChild(new QuartierQuad_(Quad(c[TOP+i], edge[RIGHTSIDE+i], center, edge[LEFTSIDE+i]))); +} + +void QuartierTri_::hauteur() { + Triangle t = c << c.maxAngleCorner(); + Vertex opposite = Segment(t[TOP], t[RIGHT]).randomPos(seed, 0, 1.f/3.f, 2.f/3.f); + + addChild(new QuartierTri_(Triangle(t[TOP], opposite, t[LEFT]))); + addChild(new QuartierTri_(Triangle(t[LEFT], opposite, t[RIGHT]))); +} + +void QuartierTri_::trapeze() { + Triangle t = c << c.minAngleCorner(); + Vertex left = Segment(t[LEFT], t[TOP]).randomPos(seed, 0, 1.f/3.f, 2.f/3.f); + Vertex base = Segment(t[RIGHT], t[LEFT]).randomPos(seed, 1, 1.f/3.f, 2.f/3.f); + + addChild(new QuartierTri_(Triangle(base, t[TOP], left))); + addChild(new QuartierQuad_(Quad(left, t[TOP], t[RIGHT], base))); +} + +void QuartierTri_::batiments() { + float hauteurTrottoir = 20; // TODO : factoriser + ajouter ça à la hauteur max d'un bâtiment dans les autres calculs. + Triangle ttrottoir = c.insetLTR(250); + Triangle tinterieur = ttrottoir.insetLTR(140); + Triangle tbatiments = tinterieur.offsetNormal(hauteurTrottoir); + + for (int i = 0; i < 3; i++) { + addChild(new RouteQuadChaussee(Quad(c[LEFT+i],c[TOP+i],ttrottoir[TOP+i],ttrottoir[LEFT+i]))); + addChild(new TrottoirQuadNormal(Quad(ttrottoir[LEFT+i],ttrottoir[TOP+i],tinterieur[TOP+i],tinterieur[LEFT+i]),hauteurTrottoir)); + } + + // TODO : + + bool small = tbatiments.minLength() < 3000; + bool big = tbatiments.maxLength() >= 5000; + bool anglesAcceptable = tbatiments.minAngle() > Angle::d2r(30) && tbatiments.maxAngle() < Angle::d2r(120); + + if (!big && proba(seed, 0, 1, 20)) { + addChild(new TerrainTriHerbe(tbatiments)); + } else if (small && anglesAcceptable) { + addChild(new BatimentTri(tbatiments)); + } else { + addChild(new TerrainTriHerbe(tbatiments)); + } +} diff --git a/rules/architecture/quartier.hh b/rules/architecture/quartier.hh new file mode 100644 index 0000000..adc348f --- /dev/null +++ b/rules/architecture/quartier.hh @@ -0,0 +1,38 @@ +#ifndef _RULES_ARCHITECTURE_QUARTIER_HH_ +#define _RULES_ARCHITECTURE_QUARTIER_HH_ + +#include "all_includes.hh" + +class QuartierQuad_: public Chose { +private: + Quad c; +public: + QuartierQuad_(Quad _c); + virtual void getBoundingBoxPoints(); + virtual bool split(); + virtual void triangulation(); +private: + void concave(); + void angleAngle(); + void angleCote(); + void rect(); + void carre(); + void batiments(); +}; + +class QuartierTri_: public Chose { +private: + Triangle c; +public: + QuartierTri_(Triangle _c); + virtual void getBoundingBoxPoints(); + virtual bool split(); + virtual void triangulation(); +private: + void centre(); + void hauteur(); + void trapeze(); + void batiments(); +}; + +#endif diff --git a/rules/architecture/toit.cpp b/rules/architecture/toit.cpp index 201fb78..675b73a 100644 --- a/rules/architecture/toit.cpp +++ b/rules/architecture/toit.cpp @@ -1,6 +1,6 @@ #include "all_includes.hh" -// TODO : les x.insetNESW_LTR(x.minLength() / 3.f) sont faux (on risque d'avoir un triangle plus petit qu'1/3), il faudrait une fonction inset qui prend un float entre 0 et 1. +// TODO : les x.insetNESW_LTR(x.minLength() / 3.f) sont faux (on risque d'avoir un triangle plus petit qu'⅓), il faudrait une fonction inset qui prend un float entre 0 et 1. ToitQuad::ToitQuad(Quad _c, float _height) : Chose(), c(_c), height(_height) { addEntropy(c); @@ -15,7 +15,7 @@ void ToitQuad::triangulation() { switch (hash2(seed, -1) % 4) { case 0: pointCentral(); break; case 1: deuxPoints(); break; - case 2: deuxPointsVerticaux(); + case 2: deuxPointsVerticaux(); break; case 3: default: plat(); break; } diff --git a/tiles.md b/tiles.md index f5b9351..ad4f88c 100644 --- a/tiles.md +++ b/tiles.md @@ -1,44 +1,41 @@ -Rules -===== +Déjà fait +========= + +* toit + * quad : point central, deux points, deux points verticalement au-dessus des murs, plat. + * tri : point central, trois points, un points verticalement au-dessus des murs, deux points verticaux, plat. +* arche + * en berceau + * d'ogive +* quartier + * quad : concave, angleAngle angleCote, rectangle, carre, (contient route + trottoir) + * tri : centre, hauteur, trapeze, batiments (contient route + trottoir) + +À faire +======= -* chose * batiment - * batimentquad (sorte de factory interne, fait un addChild : trottoirs (chosit le bon type), jardin (choisir le bon type, batimentquadmaison ou batimentquadimmeuble ou …) - * batimentquadmaison - * batimentquadimmeuble - * etagequad (factory, représente un étage d'une maison ou d'un immeuble par ex). - * piecequad (factory, représente une pièce d'un étage) - * ouverturequad (factory, paramètre décide si porte ou fenêtre, génère 2 ou 3 modèles de portes ou fenêtre) - * pareil pour les tri et penta - * ponts, ponts avec maison au-dessus, … + * jardin + * cour intérieure + * 1 étage, 2 étages, immeuble + * étages + * découpage en pièces + * position des portes, fenêtres, escaliers * mobilier (intérieur et extérieur) + * murs + * portes + * fenêtres * escalier * table - * statue + * chaises * banc -* quartier - * quartierquad (factory) - * quartierquadangle - * quartierquadcarre - * quartierquadrect - * quartiertri (factory) - * quartiertrihauteur (coupe le triangle selon sa hauteur) - * quartiertriverscarre (coupe un coin du triangle pour en faire un carré) - * quartiertriverspenta (coupe un coin du triangle pour en faire un pentagone) - * quartierpenta (factory) - * quelques motifs quartierpenta* - * quelques motifs qui prévoient des ponts -* route - * routequad (factory, paramètre indique si l'on veut un carrefour ou une chaussee ou …) - * routequadcarrefour - * routequadchaussee - * routequadparking - * trottoirquad (factory, paramètre indique s'il faut un bateau, …) - * trottoirquadnormal - * trottoirquadbas (la partie basse du bateau) - * trottoirquadpente (la pente du bateau) - * trottoirquadbateau (se subdivise en 3 trottoirquad* : pente + bas + pente) - * un motif pour faire une place + * au moins une statue, fontaine ou autre. +* quartiers spéciaux + * longue route bordée de deux enfilades de maisons (prévoir la place pour un / des bâtiment(s) avec arche dans le sens de la rue). + * longue enfilade de maisons bordée de deux routes (prévoir la place pour un / des bâtiment(s) avec arche qui fait un raccourci pour ne pas faire tout le tour). + * place (polygone de route d'une couleur différente, avec possiblement un petit bâtiment au milieu). + * canaux + ponts + bâtiment(s) avec arche au-dessus. +* route + trottoir * terrain - * terrainquadherbe - * d'autres terrains… + * herbe + * mettre un peu de relief dans l'herbe