From 3e50fee099c7515f4bcbb0a50e323a815c56de6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Sun, 11 Dec 2011 20:00:14 +0100 Subject: [PATCH] =?UTF-8?q?Tiles=20de=20forme=20triangulaire=20(aucune=20p?= =?UTF-8?q?our=20l'instant),=20redressement=20des=20quadrilat=C3=A8res=20a?= =?UTF-8?q?vec=20des=20angles=20trop=20forts.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- all_includes.hh | 3 +++ angle.hh | 6 ++++++ quad.cpp | 46 +++++++++++++++++++++++++--------------- quad.hh | 4 ++++ rules/carrefour.hh | 1 + rules/chose.cpp | 2 +- rules/quadangle.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++ rules/quadangle.hh | 15 +++++++++++++ rules/quadrilatere.cpp | 35 +++++++++++++----------------- rules/tiletri.cpp | 45 +++++++++++++++++++++++++++++++++++++++ rules/tiletri.hh | 17 +++++++++++++++ triangle.cpp | 17 +++++++++++++++ triangle.hh | 3 +++ 13 files changed, 204 insertions(+), 38 deletions(-) create mode 100644 angle.hh create mode 100644 rules/quadangle.cpp create mode 100644 rules/quadangle.hh create mode 100644 rules/tiletri.cpp create mode 100644 rules/tiletri.hh diff --git a/all_includes.hh b/all_includes.hh index e0696f9..4a3f619 100644 --- a/all_includes.hh +++ b/all_includes.hh @@ -15,6 +15,7 @@ class Chose; #include #include +#include "angle.hh" #include "directions.hh" #include "vertex.hh" #include "segment.hh" @@ -31,6 +32,8 @@ class Chose; #include "rules/quadrilatere.hh" #include "rules/quadcroix.hh" #include "rules/quadrect.hh" +#include "rules/quadangle.hh" #include "rules/quadherbe.hh" +#include "rules/tiletri.hh" #endif diff --git a/angle.hh b/angle.hh new file mode 100644 index 0000000..2b07c35 --- /dev/null +++ b/angle.hh @@ -0,0 +1,6 @@ +namespace Angle { + const float Pi = 3.141592653589793238462643383279; + const double dPi = 3.141592653589793238462643383279; + float r2d(float rad) { return rad / Pi * 180; } + float d2r(float deg) { return deg / 180 * Pi; } +}; diff --git a/quad.cpp b/quad.cpp index 2d89012..80af3ad 100644 --- a/quad.cpp +++ b/quad.cpp @@ -15,30 +15,42 @@ void Quad::offset(/*Cardinal*/int side, int offset) { corner[NW + side] = corner[NW + side] + voffset.projectOn(corner[NW + side]-corner[SW + side]); } -int Quad::minLength() { +int Quad::minLengthNS() { return std::min( - std::min( - Segment(corner[NE],corner[SE]).length(), - Segment(corner[SE],corner[SW]).length() - ), std::min( - Segment(corner[SW],corner[NW]).length(), - Segment(corner[NW],corner[NE]).length() - ) + Segment(corner[NW],corner[NE]).length(), + Segment(corner[SE],corner[SW]).length() ); } -int Quad::maxLength() { - return std::max( - std::max( - Segment(corner[NE],corner[SE]).length(), - Segment(corner[SE],corner[SW]).length() - ), std::max( - Segment(corner[SW],corner[NW]).length(), - Segment(corner[NW],corner[NE]).length() - ) +int Quad::minLengthEW() { + return std::min( + Segment(corner[NE],corner[SE]).length(), + Segment(corner[SW],corner[NW]).length() ); } +int Quad::maxLengthNS() { + return std::max( + Segment(corner[NW],corner[NE]).length(), + Segment(corner[SE],corner[SW]).length() + ); +} + +int Quad::maxLengthEW() { + return std::max( + Segment(corner[NE],corner[SE]).length(), + Segment(corner[SW],corner[NW]).length() + ); +} + +int Quad::minLength() { + return std::min(minLengthNS(), minLengthEW()); +} + +int Quad::maxLength() { + return std::max(maxLengthNS(), maxLengthEW()); +} + float Quad::minAngle() { float a = 370; // > 360. for (int i = 0; i < 4; i++) { diff --git a/quad.hh b/quad.hh index 1759855..533fe38 100644 --- a/quad.hh +++ b/quad.hh @@ -11,6 +11,10 @@ public: Quad(); Quad(Vertex ne, Vertex se, Vertex sw, Vertex nw); void offset(/*Cardinal*/int side, int offset); + int minLengthNS(); + int minLengthEW(); + int maxLengthNS(); + int maxLengthEW(); int minLength(); int maxLength(); float minAngle(); diff --git a/rules/carrefour.hh b/rules/carrefour.hh index ee63f9f..1aed848 100644 --- a/rules/carrefour.hh +++ b/rules/carrefour.hh @@ -13,6 +13,7 @@ public: Carrefour(Vertex ne, Vertex se, Vertex sw, Vertex nw); virtual bool subdivide(); virtual void triangulation(); + // TODO : Carrefour::replacePoint (pour pouvoir transformer un carrefour 4 en carrefour 5 et +). public: friend std::ostream& operator<<(std::ostream& os, const Carrefour& c); friend std::ostream& operator<<(std::ostream& os, const Carrefour* c); diff --git a/rules/chose.cpp b/rules/chose.cpp index be0f9f2..7f1c0c2 100644 --- a/rules/chose.cpp +++ b/rules/chose.cpp @@ -35,4 +35,4 @@ void Chose::display() { } } -unsigned int Chose::initialSeed = random_seed(); +unsigned int Chose::initialSeed = 1814949558;//random_seed(); diff --git a/rules/quadangle.cpp b/rules/quadangle.cpp new file mode 100644 index 0000000..b6feda6 --- /dev/null +++ b/rules/quadangle.cpp @@ -0,0 +1,48 @@ +#include "all_includes.hh" + +QuadAngle::QuadAngle(Vertex ne, Vertex se, Vertex sw, Vertex nw) : Quadrilatere(ne, se, sw, nw) { + triangulation(); +} + +bool QuadAngle::subdivide() { + for (int i = 0; i < 4; i++) { + if (Triangle(corner[NW+i], corner[NE+i], corner[SE+i]).angle() >= Angle::d2r(130)) { + Triangle t1(corner[NE+i], corner[SE+i], corner[SW+i]); + t1.offsetBase(-hrw); + Triangle t2(corner[SW+i], corner[NW+i], corner[NE+i]); + t2.offsetBase(-hrw); + addChild(TileTri::factory(seed, 0, t1.v1, t1.v2, t1.v3)); + addChild(TileTri::factory(seed, 1, t2.v1, t2.v2, t2.v3)); + addChild(new Route(t1.v1, t1.v3, t2.v1, t2.v3)); + return true; + } + } + + for (int i = 0; i < 4; i++) { + if (Triangle(corner[NW+i], corner[NE+i], corner[SE+i]).angle() <= Angle::d2r(50)) { + // "couper ce coin". + Vertex n = (corner[NW+i] + corner[NE+i]) / 2; + Vertex e = (corner[NE+i] + corner[SE+i]) / 2; + Triangle tn = Triangle(n, corner[NE+i], corner[SE+i]); + Triangle te = Triangle(corner[NW+i], corner[NE+i], e); + Triangle t; + Quad q; + if (tn.minAngle() > te.minAngle()) { + t = tn; + q = Quad(n, corner[SE+i], corner[SW+i], corner[NW+i]); + } else { + t = te; + q = Quad(corner[NW+i], e, corner[SE+i], corner[SW+i]); + } + t.offsetBase(-hrw); + addChild(TileTri::factory(seed, 0, t.v1, t.v2, t.v3)); + q.offset(E, -hrw); + addChild(Quadrilatere::factory(seed, 1, q.corner[0], q.corner[1], q.corner[2], q.corner[3])); + addChild(new Route(t.v1, t.v3, q.corner[1], q.corner[0])); + return true; + } + } + // Ne devait jamais arriver ici ! + addChild(new QuadHerbe(corner[NE], corner[SE], corner[SW], corner[NW])); + return true; +} diff --git a/rules/quadangle.hh b/rules/quadangle.hh new file mode 100644 index 0000000..d3e5c54 --- /dev/null +++ b/rules/quadangle.hh @@ -0,0 +1,15 @@ +#ifndef _RULES_QUAD_ANGLE_HH_ +#define _RULES_QUAD_ANGLE_HH_ + +#include "all_includes.hh" + +// QuadAngle est un quadrilatère avec des angles malfichus (< 90-40 ou > 90+40). +class QuadAngle : public Quadrilatere { +private: + static const int hrw = 150; // half road width : 2,50m. +public: + QuadAngle(Vertex ne, Vertex se, Vertex sw, Vertex nw); + virtual bool subdivide(); +}; + +#endif diff --git a/rules/quadrilatere.cpp b/rules/quadrilatere.cpp index a660f02..ef80c2f 100644 --- a/rules/quadrilatere.cpp +++ b/rules/quadrilatere.cpp @@ -10,28 +10,23 @@ Quadrilatere::Quadrilatere(Vertex ne, Vertex se, Vertex sw, Vertex nw) : Chose() Chose* Quadrilatere::factory(int seed, int n, Vertex ne, Vertex se, Vertex sw, Vertex nw) { Quad q = Quad(ne,se,sw,nw); - int minLength = q.minLength(); - int maxLength = q.maxLength(); - float minAngle = q.minAngle(); - float maxAngle = q.maxAngle(); - if (minLength < 2500 && maxLength > 5000 && proba(seed, n, 1, 20)) { + bool small = q.minLength() < 2500; + bool big = q.maxLength() >= 5000; + bool anglesAcceptable = q.minAngle() > Angle::d2r(30) && q.maxAngle() < Angle::d2r(150); + bool anglesOk = q.minAngle() > Angle::d2r(50) && q.maxAngle() < Angle::d2r(130); + bool tooWideX = q.minLengthEW() * 2 < q.maxLengthNS(); // trop allongé (côté E ou W deux fois plus petit que le côté N ou S). + bool tooWideY = q.minLengthNS() * 2 < q.maxLengthEW(); // trop allongé (côté N ou S deux fois plus petit que le côté E ou W). + if (!big && proba(seed, n, 1, 20)) { return new QuadHerbe(ne, se, sw, nw); - } else if (minLength < 2500 && minAngle > 50/180.f*3.1415926535 && maxAngle < 130/180.f*3.1415926535) { // + contrainte sur les angles + } else if (small && anglesAcceptable) { return new Batiment(ne, se, sw, nw); - } else if (minAngle <= 50/180.f*3.1415926535 && maxAngle >= 130/180.f*3.1415926535) { - // angles trop pointus - return new QuadHerbe(0xff, ne, se, sw, nw); - } else if (minLength > 2500 && - 2*std::min(Segment(nw,ne).length(), Segment(se,sw).length()) - < std::max(Segment(ne,se).length(), Segment(sw,nw).length())) { - // trop allongé (côté N ou S deux fois plus petit que le côté E ou W). - return new QuadRect(nw, ne, se, sw); // TODO - } else if (minLength > 2500 && - 2*std::min(Segment(ne,se).length(), Segment(sw,nw).length()) - < std::max(Segment(nw,ne).length(), Segment(se,sw).length())) { - // trop allongé (côté E ou W deux fois plus petit que le côté N ou S). - return new QuadRect(ne, se, sw, nw); // TODO - } else if (minLength > 2500) { + } else if (!small && !anglesOk) { + return new QuadAngle(ne, se, sw, nw); + } else if (!small && tooWideY) { + return new QuadRect(nw, ne, se, sw); + } else if (!small && tooWideX) { + return new QuadRect(ne, se, sw, nw); + } else if (!small) { return new QuadCroix(ne, se, sw, nw); } else { return new QuadHerbe(ne, se, sw, nw); diff --git a/rules/tiletri.cpp b/rules/tiletri.cpp new file mode 100644 index 0000000..2720a7f --- /dev/null +++ b/rules/tiletri.cpp @@ -0,0 +1,45 @@ +#include "all_includes.hh" + +TileTri::TileTri(Vertex left, Vertex top, Vertex right) : Chose() { + addEntropy(left, top, right); + corner[0] = left; + corner[1] = top; + corner[2] = right; + triangulation(); +} + +Chose* TileTri::factory(int seed, int n, Vertex left, Vertex top, Vertex right) { + (void)seed; + (void)n; + return new TileTri(left, top, right); + // Quad q = Quad(ne,se,sw,nw); + // bool small = q.minLength() < 2500; + // bool big = q.maxLength() >= 5000; + // bool anglesOk = q.minAngle() > Angle::d2r(50) && q.maxAngle() < Angle::d2r(130); + // bool tooWideX = q.minLengthEW() * 2 < q.maxLengthNS(); // trop allongé (côté E ou W deux fois plus petit que le côté N ou S). + // bool tooWideY = q.minLengthNS() * 2 < q.maxLengthEW(); // trop allongé (côté N ou S deux fois plus petit que le côté E ou W). + // if (!big && proba(seed, n, 1, 20)) { + // return new QuadHerbe(ne, se, sw, nw); + // } else if (small && anglesOk) { + // return new Batiment(ne, se, sw, nw); + // } else if (!anglesOk) { + // return new QuadAngle(ne, se, sw, nw); + // } else if (!small && tooWideY) { + // return new QuadRect(nw, ne, se, sw); + // } else if (!small && tooWideX) { + // return new QuadRect(ne, se, sw, nw); + // } else if (!small) { + // return new QuadCroix(ne, se, sw, nw); + // } else { + // return new QuadHerbe(ne, se, sw, nw); + // } +} + +bool TileTri::subdivide() { + return false; +} + +void TileTri::triangulation() { + triangles.reserve(1); + addTriangle(new Triangle(corner[0], corner[1], corner[2], 0xf0, 0xc0, 0xc0)); +} diff --git a/rules/tiletri.hh b/rules/tiletri.hh new file mode 100644 index 0000000..8844660 --- /dev/null +++ b/rules/tiletri.hh @@ -0,0 +1,17 @@ +#ifndef _RULES_TRIANGLE_HH_ +#define _RULES_TRIANGLE_HH_ + +#include "all_includes.hh" + +// RectangleRoutes est un quadrilatère de routes avec des angles aux coins égaux à 90°. +class TileTri : public Chose { +public: + Vertex corner[3]; +public: + TileTri(Vertex left, Vertex top, Vertex right); + virtual bool subdivide(); + virtual void triangulation(); + static Chose* factory(int seed, int n, Vertex left, Vertex top, Vertex right); +}; + +#endif diff --git a/triangle.cpp b/triangle.cpp index 87026bf..299973c 100644 --- a/triangle.cpp +++ b/triangle.cpp @@ -4,6 +4,8 @@ // être une superclasse de "triangle". Pour calculer le cosinus // d'angles, on crée un objet triangle assez gros. C'est du // gaspillage. +Triangle::Triangle() { +} Triangle::Triangle(Vertex v1, Vertex v2, Vertex v3): v1(v1), v2(v2), v3(v3) { } @@ -32,6 +34,21 @@ float Triangle::angle() { return std::acos(cosAngle()); } +float Triangle::minAngle() { + float a2 = angle(); + float a3 = Triangle(v2,v3,v1).angle(); + float a1 = Angle::Pi - a2 - a3; + return std::min(std::min(a1, a2), a3); +} + +void Triangle::offsetBase(int offset) { + Quad q = Quad(v2, v1, v3, v2); + q.offset(S, -offset); + v1 = q.corner[1]; + v2 = q.corner[0]; + v3 = q.corner[2]; +} + void Triangle::display() { // glDisable(GL_LIGHTING); // glDisable(GL_TEXTURE_2D); diff --git a/triangle.hh b/triangle.hh index f4d7511..fb25d99 100644 --- a/triangle.hh +++ b/triangle.hh @@ -16,10 +16,13 @@ class Triangle { public: friend std::ostream& operator<<(std::ostream& os, const Triangle* t); friend std::ostream& operator<<(std::ostream& os, const Triangle& t); + Triangle(); Triangle(Vertex v1, Vertex v2, Vertex v3); Triangle(Vertex v1, Vertex v2, Vertex v3, unsigned char r, unsigned char g, unsigned char b); float cosAngle(); // cosinus de l'angle en v2. float angle(); // angle en v2, en degrés. TODO : le calcul ne donne que des angles entre 0 et 180 ! + float minAngle(); // angle minimum du triangle (en v1, v2 ou v3). + void offsetBase(int offset); void display(); private :