File indexing completed on 2024-04-28 03:40:49

0001 /*************************************************************************************
0002  *  Copyright (C) 2012 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com>      *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "marchingsquares.h"
0020 #include <QDebug>
0021 #include <QPolygon>
0022 #include <QVector2D>
0023 
0024 sMarching_Square MarchingSquares::evaluar_cubo(const Square& cubo)
0025 {
0026     sMarching_Square res;
0027     res.centro = cubo.center();
0028     res.medio_lado = cubo.halfEdge();
0029 
0030     double x = res.centro.x();
0031     double y = res.centro.y();
0032     double hedge = res.medio_lado;
0033 
0034     res.vertices[0] = evalScalarField(x-hedge, y-hedge);
0035     res.vertices[1] = evalScalarField(x-hedge, y+hedge);
0036     res.vertices[2] = evalScalarField(x+hedge, y-hedge);
0037     res.vertices[3] = evalScalarField(x+hedge, y+hedge);
0038 
0039 
0040 //  -----
0041 //  |1|3|
0042 //  -----
0043 //  |0|2|
0044 //  -----
0045 
0046     res.tipo = 0;
0047 
0048     if (res.vertices[1]>0)
0049         res.tipo += 8;
0050 
0051     if (res.vertices[3]>0)
0052         res.tipo += 4;
0053 
0054     if (res.vertices[2]>0)
0055         res.tipo += 2;
0056 
0057     if (res.vertices[0]>0)
0058         res.tipo += 1;
0059 
0060     return res;
0061 }
0062 
0063 QList<Square> MarchingSquares::breadth_rec(int cubos_lado) {
0064     Square cubo;
0065     sMarching_Square m_cubo;
0066     bool salir = false;
0067     QList<Square> cubos;
0068     cubo.setHalfEdge(largo_mundo/(2*cubos_lado));
0069 
0070     double x = 0;
0071     double y = 0;
0072 
0073     static const double iteration_square_val = 0.5;
0074     
0075     for(double i=mundo.minX; i<=mundo.maxX; i+=iteration_square_val) 
0076     {
0077         x = (2*i+1)*cubo.halfEdge();
0078 
0079         for(double j=mundo.minY; j<=mundo.maxY; j+=iteration_square_val) 
0080         {
0081             y = (2*j+1)*cubo.halfEdge();
0082             cubo.setCenter(x,y);
0083             m_cubo = evaluar_cubo(cubo);
0084             if(m_cubo.tipo != 0 && m_cubo.tipo != 15) {
0085                 //Esta dentro del cubo. Detener busqueda
0086                 salir = true;
0087                 cubos.append(cubo);
0088             }
0089         }
0090     }
0091     
0092     if(!salir && 2*cubo.halfEdge() > min_grid) 
0093         cubos.append(breadth_rec(cubos_lado*2));
0094     
0095     return cubos;
0096 }
0097 
0098 QList<sMarching_Square> MarchingSquares::depth_rec(Quadtree *arbol, QNode *nodo) {
0099     QList<sMarching_Square> cubos;
0100     sMarching_Square m_cubo;
0101 
0102     m_cubo = evaluar_cubo(nodo->cubo);
0103 
0104     if(m_cubo.tipo != 0 && m_cubo.tipo != 15) {
0105         if(m_cubo.medio_lado*2 > min_grid) {
0106             arbol->bajarNivel(nodo);
0107             for(unsigned int i=0; i<4; i++) {
0108                 cubos.append(depth_rec(arbol,nodo->nodos[i]));
0109             }
0110         } else {
0111             cubos.append(m_cubo);
0112         }
0113     }
0114     return cubos;
0115 }
0116 
0117 MarchingSquares::MarchingSquares(/*double min_grid, double arista_mundo, sLimitesEspacio2D limites*/
0118 
0119 ) {
0120 }
0121 
0122 MarchingSquares::~MarchingSquares() {
0123 }
0124 
0125 QList<sMarching_Square> MarchingSquares::ejecutar() {
0126     QList<sMarching_Square> cubos;
0127     QList<Square> encontrados;
0128     Square iterador;
0129     Quadtree *arbol;
0130 
0131     encontrados = breadth_rec(largo_mundo);
0132     if(encontrados.isEmpty()) {
0133         return cubos;
0134     }
0135 
0136     foreach(iterador, encontrados) {
0137         arbol = new Quadtree(iterador);
0138         cubos.append(depth_rec(arbol, arbol->get_raiz()));
0139         delete arbol;
0140     }
0141 
0142     return cubos;
0143 }
0144 
0145 void MarchingSquares::_addTri(const QPointF& a, const QPointF& b)
0146 {
0147     QPair<QPointF,QPointF> _f = qMakePair(a,b);
0148     _faces_.append(_f);
0149 
0150 }
0151 
0152 QList<sArista2D> MarchingSquares::calcular_cortes(const sMarching_Square &cubo) {
0153     QList<sArista2D> aristas;
0154     sArista2D temp;
0155 //  -----
0156 //  |1|3|
0157 //  -----
0158 //  |0|2|
0159 //  -----
0160 
0161     //0-1
0162     if(signo_opuesto(cubo.vertices[0],cubo.vertices[1])) {
0163         //al primero luego sumale
0164         temp.corte = QPointF(cubo.centro.x()-cubo.medio_lado,
0165                              cubo.centro.y()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[0],cubo.vertices[1]));
0166         temp.vertices[0] = 0;
0167         temp.vertices[1] = 1;
0168         aristas.append(temp);
0169     }
0170 
0171     //1-3
0172     if(signo_opuesto(cubo.vertices[1],cubo.vertices[3])) {
0173         temp.corte = QPointF(cubo.centro.x()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[1],cubo.vertices[3]),
0174                              cubo.centro.y()+cubo.medio_lado);
0175         temp.vertices[0] = 1;
0176         temp.vertices[1] = 3;
0177         aristas.append(temp);
0178     }
0179 
0180     //2-3
0181     if(signo_opuesto(cubo.vertices[2],cubo.vertices[3])) {
0182         temp.corte = QPointF(cubo.centro.x()+cubo.medio_lado,
0183                              cubo.centro.y()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[2],cubo.vertices[3]));
0184         temp.vertices[0] = 2;
0185         temp.vertices[1] = 3;
0186         aristas.append(temp);
0187     }
0188 
0189 //  -----
0190 //  |1|3|
0191 //  -----
0192 //  |0|2|
0193 //  -----
0194 
0195     //0-2
0196     if(signo_opuesto(cubo.vertices[0],cubo.vertices[2])) {
0197         temp.corte = QPointF(cubo.centro.x()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[0],cubo.vertices[2]),
0198                              cubo.centro.y()-cubo.medio_lado);
0199         temp.vertices[0] = 0;
0200         temp.vertices[1] = 2;
0201         aristas.append(temp);
0202     }
0203 
0204     return aristas;
0205 }
0206 
0207 bool MarchingSquares::signo_opuesto(double a, double b) {
0208     return ((a > 0 && b <= 0) || (a <= 0 && b > 0));
0209 }
0210 
0211 double MarchingSquares::lineal(double vert_1, double vert_2) {
0212     return qAbs(vert_1/(vert_1 - vert_2));
0213 }
0214 
0215 void MarchingSquares::agregar_triangulos(QList<QPointF> &lista_triangulos) {
0216 
0217     for(int i=0; i<lista_triangulos.count(); i+=2) {
0218 
0219         if (lista_triangulos.size()-2 < i)
0220             continue;
0221 
0222         _addTri(lista_triangulos.at(i),lista_triangulos.at(i+1));
0223 
0224     }
0225 }
0226 
0227 void MarchingSquares::identificar_tipo(const sMarching_Square &cubo) {
0228 
0229     QList<sArista2D> aristas;
0230     QList<unsigned int> vertices;
0231 
0232     aristas = calcular_cortes(cubo);
0233 
0234     unsigned short int type = cubo.tipo;
0235 
0236     switch (type)
0237     {
0238     case 1:
0239     case 2:
0240     case 3:
0241     case 4:
0242     case 6:
0243     case 7:
0244     case 8:
0245     case 9:
0246     case 11:
0247     case 12:
0248     case 13:
0249     case 14:
0250     {
0251         tipo01(aristas);
0252 
0253         break;
0254     }
0255     case 5:
0256     case 10:
0257     {
0258         tipo05(aristas, cubo);
0259 
0260         break;
0261     }
0262     }
0263 }
0264 
0265 void MarchingSquares::tipo01(QList<sArista2D> aristas)
0266 {
0267     
0268     if (aristas.size()<2) return;
0269 
0270     QList<QPointF> triangulos;
0271 
0272     triangulos << aristas[0].corte << aristas[1].corte;
0273 
0274     agregar_triangulos(triangulos);
0275 }
0276 
0277 void MarchingSquares::tipo05(QList<sArista2D> aristas,const sMarching_Square &cubo)
0278 {
0279     if (aristas.isEmpty()) return;
0280     
0281     QList<QPointF> triangulos;
0282 
0283 //  -----
0284 //  |1|3|
0285 //  -----
0286 //  |0|2|
0287 //  -----
0288 
0289 
0290     if (cubo.tipo == 5) 
0291         triangulos << aristas[0].corte << aristas[2].corte;
0292     else if (cubo.tipo == 10)
0293         triangulos << aristas[1].corte << aristas[3].corte;
0294 
0295     agregar_triangulos(triangulos);
0296 }
0297 void MarchingSquares::buildGeometry()
0298 {
0299     _faces_.clear();
0300 
0301     QList<sMarching_Square> cubos;
0302     sMarching_Square cubo;
0303 
0304     cubos = ejecutar();
0305 
0306     foreach(cubo,cubos) {
0307         identificar_tipo(cubo);
0308     }
0309 
0310 }
0311 void MarchingSquares::setWorld(double minx, double maxx, double miny, double maxy)
0312 {
0313     sLimitesEspacio2D _esp;
0314 
0315     _esp.minX = minx;
0316     _esp.maxX = maxx;
0317     _esp.minY = miny;
0318     _esp.maxY = maxy;
0319 
0320     largo_mundo = 1;
0321 
0322     min_grid = qMin(fabs(maxx-minx), fabs(maxy-miny))/256;
0323 
0324     if (min_grid>0.05 && min_grid < 1)
0325         min_grid = 0.05;
0326 
0327     mundo = _esp;
0328 }