Capítulo 5. Discusiones, conclusiones y recomendaciones
5.3 Recomendaciones para futuras investigaciones
Como primera instancia un punto importante que puede hacer mucha diferencia en cuanto al realismo, es que en un trabajo futuro se defina la manera en que se puedan crear polígonos de cualquier forma resolviendo las complejidades que se presentaron en los procedimientos, que no estén limitados solamente a cuatro vértices como lo están en esta implementación. Esto permitiría generar un mayor número de posibles formas que pueden tomar ya sean las calles y avenidas, así como también los lotes y cuadras.
Otro punto importante sería dar la posibilidad de trabajar con curvas en la implementación, de ésta manera podría abarcarse desde todo un nuevo patrón morfológico en la ciudad (el radiocéntrico), hasta detalles más a nivel local como glorietas o simplemente que las calles puedan tener curvatura. Este punto podría resolverse si se lograse implementar el método de Esch et al [6].
En cuanto a la implementación, se puede mejorar el modo en que se generan los lotes y construcciones tomando en cuenta datos extra que ayuden a definir cómo serán generados, en lugar de valerse de la aleatoriedad como actualmente se logró implementar. Algunos datos pueden ser por ejemplo de densidad poblacional, de modo que en zonas con mayor densidad se crean más lotes con construcciones más grandes y
38 en las de menor haya lotes más individuales y zonas vacías. Un modo de resolverse es implementar estos datos como mapas de bits, en donde, al sobreponer el mapa de bits en el de la ciudad, se verifica según la posición en la que se encuentre la cuadra, si ésta está en una zona de alta o en una de baja densidad, y así finalmente decidir cómo resultarán los lotes y construcciones. La transición entre zonas puede ser continua o discreta.
Otros datos extra pueden ser puntos de interés, como el centro de la ciudad o alguna zona comercial importante, esto mejoraría la manera en que se crean las avenidas al indicar el lugar en donde empieza y termina alguna avenida, asegurando que estas siempre conecten con los puntos de interés. La verificación se hace de la misma manera mencionada anteriormente, utilizando mapas de bits para indicar las posiciones y poder crear las líneas que representan a cada avenida.
En otra instancia se puede incrementar la complejidad que tendrá la forma de la ciudad total, buscando asemejar más a como son las ciudades en la realidad donde no siempre tienen figuras regulares, si no que presentan más bien formas irregulares debido principalmente a restricciones geográficas o patrones de crecimiento poblacional.
En cuanto a las restricciones geográficas, esto se puede lograr implementando un método que tome en cuenta las alturas del terreno en el que se creará la ciudad, se puede utilizar un heightmap (mapa de alturas) que viene siendo una imagen en escala de grises donde cada coordenada de la imagen representa una elevación según el tono de gris presente. La elevación es entonces utilizada como límite para saber si esa coordenada será excluida o no del área total de la ciudad.
El implementar éstas mejoras al proyecto daría como resultado una mejor base sobre la cual poder entonces avanzar a las siguientes fases de la generación de ciudades, que sería la texturización y los sistemas misceláneos de complejidad más avanzada (sistema de tráfico, vegetación, clima, etc.).
39
Referencias
[1] Y. I. Parish and P. Müller, "Procedural modeling of cities." in SIGGRAPH '01 Proceeding of the 28th annual conference an Computer graphics and interactive techniques., ACM New York, NY, USA, 2001, pp. 301-308.
[2] Esri. (2011, Noviembre) esri. Understanding our world. [Online].
"http://www.esri.com/software/c-ityengine/features.html"
[3] Stefan Greuter, Jeremy Parker, Nigel Stewart, and Geoff Leach, "Real-time procedural generation of pseudo infinite cities." in Proceeding of the 1st international conference on Computer graphics and interactive techniques., Australasia and South Esat Asia., 2003, pp. 87-ff.
[4] Brasil Weber, Pascal Müller, Peter Wonka, and Markus Gross, "Interactive Geometrics Simulation of 4D Cities.", Computer Graphics Forum, vol. 28, no. 2, pp. 481-492, April 2009.
[5] S.A. Groenewegen, R.M. Smelik, K.J. Kraker, and R. Bidarra, Procedural City Layout Generation Based on Urban Land Use Models.: EUROGRAPHICS 2009, 2009.
[6] G. Esch, G. Chen, P. Wonka, P. Müller, and E. Zhang, "Interactive Procedural Street Modeling.," ACM Transaction on Graphics (TOG)., vol. 27, no. 3, 2008.
[7] N. Rudzincz and C. Verbrugge, "An interated subdivision algorithm for procedural road plan generation." in Game-On NA., 2008.
[8] P. Müller, P. Wonka, S. Haegler, A. Ulmer, and L. V. Gool, "Procedural modeling of buildings." in SIGRAPH Internacional Conference on Computer Graphics and Interactive Techniques., ACM New York, NY, USA., 2006, pp. 614-623.
[9] Eugene Zhang, James Hays, and Greg Turk, "Interactive Tensor Field Design and Visualization on Surfaces", Transactions on Visualization and Computer Graphics, vol. 13, no. 1, pp. 94-106, January-February 2007.
[10] Juli Esteban Noguera, Elementos de ordenación urbana. Barcelona: Edicions UPC, Mayo 1998.
[11] Rodorlfo E. Castagna, Ciudad: Recidesia Total. Argentina: Ediciones Nueva Vision, 1984.
[12] Elvira Maycote P. and Fernando Lozada I., Gestión Urbana ¿Más estado o más
40 mercado? Mexico: Universidad Autónoma de Ciudad Juárez, 2010.
[13] Domingo Gómez O., Ordenación territorial. México: Ediciones Mundi-Prensa, 2008.
[14] Gideon Golany, Planificación de nuevas ciudades, principios y prácticas. México D.F.: Limusa, 1985.
[15] G. P., Diccionario de Geografía. Madrid, 1991.
[16] J. Bosque, Sistemas de Información Geográfica, 2nd ed. Madrid, Rialp, 1997.
[17] Max Weber, La dominación no legítima (Tipología de las ciudades). México:
Economía y Sociedad, 1964.
[18] Google, Google Maps. [Online]. “maps.google.com”.
41
Apéndices
Apéndice 1. Ecuaciones de Algebra Lineal.
Ecuación de la recta, no vertical:
𝑦 = 𝑚𝑥 + 𝑏
Ecuación de la recta, vertical:
𝑥 = 𝑎
Ecuación de la pendiente dados dos puntos, cuando x2 - x1 es diferente a 0:
𝑚 =𝑦2 − 𝑦1 𝑥2 − 𝑥1
Intersección entre dos rectas en un mismo plano, en donde para cada recta b es la ordenada al origen y m es la pendiente:
i. 𝑚1𝑥 + 𝑏1 = 𝑚2𝑥 + 𝑏2 ii. 𝑚1𝑥 − 𝑚2𝑥 = 𝑏2 − 𝑏1 iii. 𝑥(𝑚1 − 𝑚2) = 𝑏2 − 𝑏1
iv. 𝑥 = 𝑏2−𝑏1
𝑚1−𝑚2
Distancia entre dos puntos:
𝑑 = √(𝑦2 − 𝑦1)2+ (𝑥2 − 𝑥1)2
Área de un cuadrilátero en dos dimensiones, dados los puntos P1, P2, P3, P4:
á𝑟𝑒𝑎 = |(𝑃1𝑥 ∗ 𝑃2𝑦 − 𝑃1𝑦 ∗ 𝑃2𝑥) + (𝑃2𝑥 ∗ 𝑃3𝑦 − 𝑃2𝑦 ∗ 𝑃3𝑥)
+ (𝑃3𝑥 ∗ 𝑃4𝑦 − 𝑃3𝑦 ∗ 𝑃4𝑥) + (𝑃4𝑥 ∗ 𝑃1𝑦 − 𝑃4𝑦 ∗ 𝑃1𝑥)|
Apéndice 2. Inicialización de variables
#region Inicializacion de variables shapeBaseGlobal = new Shapes();
ListaShapeAvs = new List<Shapes>[2] { new List<Shapes>(), new List<Shapes>() };
int NCallesHor, NCallesVer;
float[] TmpSeparaciones = new float[2];
NCallesHor = RndNum2.Next(3, 7);
NCallesVer = RndNum2.Next(3, 7);
TmpSeparaciones[0] = ((Lims[3] - Lims[2]) / NCallesHor);
TmpSeparaciones[1] = ((Lims[1] - Lims[0]) / NCallesVer);
float TempAvance = TmpSeparaciones[0] * (0.6f);
float pendiente;
int rndnum = RndNum2.Next(3);
#endregion
Apéndice 3. Definición de la recta implementada
#region Definicion de la recta que representa la calle rndnum = RndNum2.Next(3);
switch (rndnum) // Decide la direccion de la calle, cada uno con probabilidad 1/3 { // direccion = pendiente
case 0: // Se inclina hacia arriba pendiente = (1.0f / (float)RndNum2.Next(12, 57));
42
break;
case 1: // Se inclina hacia abajo
pendiente = (-1.0f / (float)RndNum2.Next(12, 57));
break;
default:
pendiente = 0; // No tiene inclinacion break;
}
float b_nxt = (Lims[2] + TempAvance) - (pendiente * Lims[0]);
#endregion
Apéndice 4. Pseudocódigo de QuickSort
funcion quicksort('arreglo') Si longitud('arreglo') ≤ 1
--retornar 'arreglo' // un 'arreglo' de uno o cero elementos ya está acomodado Seleccionar y remover un valor pivote 'pivote' de 'arreglo'
crear dos listas 'menores' y 'mayores' Para cada 'x' en 'arreglo'
--Si 'x' ≤ 'pivote' entonces agregar 'x' a 'menores' --Si no agregar 'x' a 'mayores'
// la función concatenar concatena las listas de mayor a menor // hace cada vez dos llamadas recursivas
retornar concatenar(quicksort('menores'), 'pivote', quicksort('mayores'))
Apéndice 5. Calculo de los puntos de intersección
#region Calculo de los puntos if (ListaShapeAvs[0].Count != 0) {
float x_intersect, y_intersect;
// Se verifica si la recta que se creará es peralela o no a la anterior, de ser asi se tiene que evitar que intersecten.
if (pendiente - ListaShapeAvs[0][ListaShapeAvs[0].Count - 1].m != 0) // Son paralelas si la resta de las pendientes da 0, no se intersectarian
{ do {
x_intersect = (b_nxt - ListaShapeAvs[0][ListaShapeAvs[0].Count - 1].b) / (pendiente - ListaShapeAvs[0][ListaShapeAvs[0].Count - 1].m);
y_intersect = (pendiente * x_intersect) + b_nxt;
if (x_intersect > Lims[1] || x_intersect < Lims[0]) // No hay interseccion dentro del area global?
{
if ((float)Math.Round(pendiente * Lims[1], 0) + b_nxt < Lims[3]) // La Y en (X = Limite superior X Globlal) es menor al (Limite superior Y Globlal)??
{
ListaShapeAvs[0].Add(new Carretera(Lims, TempAvance, pendiente));
TempAvance += (TmpSeparaciones[0]);
}
else // Si no, modificar la pendiente pendiente -= 0.010f;
}
else // Hubo interseccion, modificar la pendiente pendiente += 0.006f;
} while (!(x_intersect > Lims[1] || x_intersect < Lims[0]) || !((pendiente * Lims[1]) + b_nxt <
Lims[3]));
}
else // Como son paralelas, solo se verifica que no salga del limite global Lims[]
43
{
ListaShapeAvs[0].Add(new Carretera(Lims, TempAvance, pendiente));
if (ListaShapeAvs[0][ListaShapeAvs[0].Count - 1].Vertices[0].Y < Lims[3] &&
ListaShapeAvs[0][ListaShapeAvs[0].Count - 1].Vertices[1].Y < Lims[3]) TempAvance += (TmpSeparaciones[0]);
else
ListaShapeAvs[0].RemoveAt(ListaShapeAvs[0].Count - 1);
} }
else // La primera avenida solo puede intersectar con el limite global Lims[]
{
ListaShapeAvs[0].Add(new Carretera(Lims, TempAvance, pendiente));
if (ListaShapeAvs[0][ListaShapeAvs[0].Count - 1].Vertices[0].Y > Lims[2] &&
ListaShapeAvs[0][ListaShapeAvs[0].Count - 1].Vertices[1].Y > Lims[2]) TempAvance += (TmpSeparaciones[0]);
else
ListaShapeAvs[0].RemoveAt(ListaShapeAvs[0].Count - 1);
}
#endregion
Apéndice 6. Procesos para obtener las Colonias
private void ObtenerColonias() {
…
ObtenerIntersecciones();
for (int i = 0; i < ListaIntersecciones.Length; i++) {
ListaIntersecSorteada[i] = QuickSort_XAsc(ListaIntersecciones[i]);
ListaIntersecSorteada[i].TrimExcess();
}
ObtenerAreasDeColonias();
… }
ObtenerIntersecciones() {
int LineasHor = tmpListaLineas[0].Count, LineasVer = tmpListaLineas[1].Count;
ListaIntersecciones = new List<Vector3>[LineasHor];
ListaIntersecSorteada = new List<Vector3>[LineasHor];
int n_linea = 0;
if (TotalAvenidas > 0) {
for (int i = 0; i < LineasHor; i++) {
ListaIntersecciones[n_linea] = new List<Vector3>();
#region Chequeo de calles horizontales-verticales for (int j = 0; j < LineasVer; j++)
{
float Xintersect, Yintersect;
if (!tmpListaLineas[1][j].IsVertical) {
#region Interseccion entre no vertical - no vertical // m1x + b1 = m2x + b2
// m1x - m2x = b2 - b1 --> x(m1-m2) = b2 - b1 // x = (b2-b1) / (m1-m2)
Xintersect = (tmpListaLineas[1][j].b - tmpListaLineas[0][i].b) / (tmpListaLineas[0][i].m - tmpListaLineas[1][j].m);
Xintersect = (float)Math.Round(Xintersect, 2);
44
// y = mx + b
Yintersect = (tmpListaLineas[0][i].m * Xintersect) + tmpListaLineas[0][i].b;
Yintersect = (float)Math.Round(Yintersect, 2);
if (Xintersect >= LimiteInfX &&
Xintersect <= LimiteSupX &&
Yintersect >= LimiteInfY &&
Yintersect <= LimiteSupY)
ListaIntersecciones[n_linea].Add(new Vector3(Xintersect, Yintersect, 1.0f));
#endregion }
else {
#region Interseccion entre no vertical - vertical Xintersect = tmpListaLineas[1][j].Vertices[0].X;
Xintersect = (float)Math.Round(Xintersect, 2);
Yintersect = (tmpListaLineas[0][i].m * Xintersect) + tmpListaLineas[0][i].b;
Yintersect = (float)Math.Round(Yintersect, 2);
if (Xintersect >= LimiteInfX &&
Xintersect <= LimiteSupX &&
Yintersect >= LimiteInfY &&
Yintersect <= LimiteSupY)
ListaIntersecciones[n_linea].Add(new Vector3(Xintersect, Yintersect, 1.0f));
#endregion }
}
#endregion }
#region
…Chequeo de calles horizontales-horizontales…
#endregion
if (ListaIntersecciones[n_linea].Count > 0) // Hubo intersecciones?
n_linea++;
} } }
private void ObtenerAreasDeColonias() {
ListaShapeColonias = new List<Shapes>();
Vector3[] tmpVectors;
for (int i = 0; i < ListaIntersecSorteada.Length; i++) for (int j = 0; j < ListaIntersecSorteada[i].Count; j++) {
if ((i + 1) >= ListaIntersecSorteada.Length) break;
if ((j + 1) >= ListaIntersecSorteada[i].Count || (j + 1) >= ListaIntersecSorteada[i + 1].Count) break;
tmpVectors = new Vector3[4];
tmpVectors[0] = new Vector3(ListaIntersecSorteada[i][j].X + offsetAnchoAvenida, ListaIntersecSorteada[i][j].Y + offsetAnchoAvenida, ListaIntersecSorteada[i][j].Z);
tmpVectors[1] = new Vector3(ListaIntersecSorteada[i + 1][j].X + offsetAnchoAvenida, ListaIntersecSorteada[i + 1][j].Y - offsetAnchoAvenida, ListaIntersecSorteada[i + 1][j].Z);
tmpVectors[2] = new Vector3(ListaIntersecSorteada[i + 1][j + 1].X - offsetAnchoAvenida, ListaIntersecSorteada[i + 1][j + 1].Y - offsetAnchoAvenida, ListaIntersecSorteada[i + 1][j + 1].Z);
tmpVectors[3] = new Vector3(ListaIntersecSorteada[i][j + 1].X - offsetAnchoAvenida, ListaIntersecSorteada[i][j + 1].Y + offsetAnchoAvenida, ListaIntersecSorteada[i][j + 1].Z);
ListaShapeColonias.Add(new Parcela(tmpVectors));
}
TotalColonias = ListaShapeColonias.Count;
…
45
}
Apéndice 7. Procedimientos para generar las calles secundarias
GenerarCalles_ItSub() {
…
for (int i = 0; i < TotalColonias; i++) {
ListaShapePOversized.Add(new Parcela(ListaShapeColonias[i].Vertices, true));
do {
float Ratio;
int iteraciones = 0; // Controla que el proceso no quede ciclado do
{
iteraciones++;
DatosBiseccion = new List<Vector3>[3] { new List<Vector3>(4), new List<Vector3>(4), new List<Vector3>(2) };
DatosBiseccion = ListaShapePOversized[0].getAcceptableBisector(Amin, Rmax, iteraciones,
!isCiudadOrtogonal);
Ratio = ListaShapePOversized[0].PolygonDiameterWidth_Ratio();
} while (Ratio > Rmax && iteraciones < 50);
if (iteraciones < 50) // Si se pudo biseccionar el poligono {
ListaShapeRoads.Add(new Carretera(DatosBiseccion[2].ToArray(), Color.White));
if (AreaCuadrilatero(DatosBiseccion[0]) > Amax)
ListaShapePOversized.Add(new Parcela(DatosBiseccion[0].ToArray(), true));
else {
Shapes tmpShape = new Parcela(DatosBiseccion[0].ToArray(), true);
float tmpratio = tmpShape.PolygonDiameterWidth_Ratio();
ListaShapeAllots.Add(new Parcela(DatosBiseccion[0].ToArray(), false, tmpratio));
}
if (AreaCuadrilatero(DatosBiseccion[1]) > Amax)
ListaShapePOversized.Add(new Parcela(DatosBiseccion[1].ToArray(), true));
else {
Shapes tmpShape = new Parcela(DatosBiseccion[1].ToArray(), true);
float tmpratio = tmpShape.PolygonDiameterWidth_Ratio();
ListaShapeAllots.Add(new Parcela(DatosBiseccion[1].ToArray(), false, tmpratio));
} }
else // No se pudo biseccionar, se agrega asi como esta a la lista de Cuadras ListaShapeAllots.Add(new Parcela(ListaShapePOversized[0].Vertices, false, 20));
ListaShapePOversized.RemoveAt(0);
} while (ListaShapePOversized.Count > 0);
} … }
Apéndice 8. Implementación de ItSub – Subdivision de polígonos
public List<Vector3>[] getAcceptableBisector(float AreaMin, float Rmax = 16, int contador = 0, bool bIrregular = false)
{
List<Vector3>[] PoligonosBisectados;
Vector3[] BisectorLine;
46
// Decide aleatoriamente si hacer la division a lo largo o a lo ancho switch (rand.Next(2))
{
case 0:
while (true) {
contador++; // Contador que sirve para controlar que no se cicle indefinidamente el proceso BisectorLine = new Vector3[2];
PoligonosBisectados = new List<Vector3>[3] { new List<Vector3>(4), new List<Vector3>(4), new List<Vector3>(2) };
BisectorLine = getBisectorLine(true, bIrregular);
PoligonosBisectados[0].Add(new Vector3(Vertices[0]));
PoligonosBisectados[0].Add(new Vector3(Vertices[1]));
PoligonosBisectados[0].Add(new Vector3(BisectorLine[1]));
PoligonosBisectados[0].Add(new Vector3(BisectorLine[0]));
PoligonosBisectados[1].Add(new Vector3(BisectorLine[0]));
PoligonosBisectados[1].Add(new Vector3(BisectorLine[1]));
PoligonosBisectados[1].Add(new Vector3(Vertices[2]));
PoligonosBisectados[1].Add(new Vector3(Vertices[3]));
if (PolygonDiameterWidth_Ratio(PoligonosBisectados[0].ToArray()) > Rmax || PolygonDiameterWidth_Ratio(PoligonosBisectados[1].ToArray()) > Rmax) if (contador < 100)
goto case 1;
float Area_1 = AreaCuadrilatero(PoligonosBisectados[0]);
float Area_2 = AreaCuadrilatero(PoligonosBisectados[1]);
if ((Area_1 >= AreaMin && Area_2 >= AreaMin) || contador >= 100) {
PoligonosBisectados[2].Add(new Vector3(BisectorLine[0]));
PoligonosBisectados[2].Add(new Vector3(BisectorLine[1]));
return PoligonosBisectados;
}
if (contador == 50) goto case 1;
} case 1:
while (true) {
contador++; // Contador que sirve para controlar que no se cicle indefinidamente el proceso BisectorLine = new Vector3[2];
PoligonosBisectados = new List<Vector3>[3] { new List<Vector3>(4), new List<Vector3>(4), new List<Vector3>(2) };
BisectorLine = getBisectorLine(false, bIrregular);
PoligonosBisectados[0].Add(new Vector3(Vertices[0]));
PoligonosBisectados[0].Add(new Vector3(BisectorLine[0]));
PoligonosBisectados[0].Add(new Vector3(BisectorLine[1]));
PoligonosBisectados[0].Add(new Vector3(Vertices[3]));
PoligonosBisectados[1].Add(new Vector3(BisectorLine[0]));
PoligonosBisectados[1].Add(new Vector3(Vertices[1]));
PoligonosBisectados[1].Add(new Vector3(Vertices[2]));
PoligonosBisectados[1].Add(new Vector3(BisectorLine[1]));
47
if (PolygonDiameterWidth_Ratio(PoligonosBisectados[0].ToArray()) > Rmax || PolygonDiameterWidth_Ratio(PoligonosBisectados[1].ToArray()) > Rmax) if (contador < 100)
goto case 0;
float Area_1 = AreaCuadrilatero(PoligonosBisectados[0]);
float Area_2 = AreaCuadrilatero(PoligonosBisectados[1]);
if ((Area_1 >= AreaMin && Area_2 >= AreaMin) || contador >= 100) {
PoligonosBisectados[2].Add(new Vector3(BisectorLine[0]));
PoligonosBisectados[2].Add(new Vector3(BisectorLine[1]));
return PoligonosBisectados;
}
if (contador == 50) goto case 0;
} } }
Apéndice 9. Implementación de ItSub – Como obtener la línea divisoria
private Vector3[] getBisectorLine(bool IsVertical, bool boIrregular) {
float X1, X2, Y1, Y2;
Vector3[] carretera = new Vector3[2] { new Vector3(), new Vector3() };
int divisor, maxmult, mult;
divisor = rand.Next(2, 4);
maxmult = divisor - 1;
if (maxmult > 1)
mult = rand.Next(1, maxmult);
else mult = 1;
if (IsVertical) {
#region Calculos de puntos mas sencillos
X1 = (Vertices[3].X - (Vertices[3].X - Vertices[0].X) / divisor) * mult;
Y1 = (Vertices[3].Y - (Vertices[3].Y - Vertices[0].Y) / divisor) * mult;
if (boIrregular) // boIrregular especifica si el punto final de la linea bisectora corresponde al punto inicial
{
divisor = rand.Next(2, 3);
maxmult = divisor - 1;
if (maxmult > 1)
mult = rand.Next(1, maxmult);
else
mult = 1;
}
X2 = (Vertices[2].X - (Vertices[2].X - Vertices[1].X) / divisor) * mult;
Y2 = (Vertices[2].Y - (Vertices[2].Y - Vertices[1].Y) / divisor) * mult;
carretera[0].X = X1;
carretera[0].Y = Y1;
carretera[0].Z = 1.0f;
carretera[1].X = X2;
carretera[1].Y = Y2;
carretera[1].Z = 1.0f;
#endregion }
else {
48
#region Calculos de puntos mas sencillos
X1 = (Vertices[1].X - (Vertices[1].X - Vertices[0].X) / divisor) * mult;
Y1 = (Vertices[1].Y - (Vertices[1].Y - Vertices[0].Y) / divisor) * mult;
X2 = (Vertices[2].X - (Vertices[2].X - Vertices[3].X) / divisor) * mult;
Y2 = (Vertices[2].Y - (Vertices[2].Y - Vertices[3].Y) / divisor) * mult;
carretera[0].X = X1;
carretera[0].Y = Y1;
carretera[0].Z = 1.0f;
carretera[1].X = X2;
carretera[1].Y = Y2;
carretera[1].Z = 1.0f;
#endregion }
return carretera;
}
Apéndice 10. Definición de los vértices de las Cuadras
prívate void GenerarCuadras() {
…
TotalCuadras = ListaShapeAllots.Count;
for (int i = 0; i < TotalCuadras; i++) {
ListaShapeAllots[i].Vertices[0].X += (offsetAnchoCalle / 2);
ListaShapeAllots[i].Vertices[0].Y += (offsetAnchoCalle / 2);
ListaShapeAllots[i].Vertices[1].X += (offsetAnchoCalle / 2);
ListaShapeAllots[i].Vertices[1].Y -= (offsetAnchoCalle / 2);
ListaShapeAllots[i].Vertices[2].X -= (offsetAnchoCalle / 2);
ListaShapeAllots[i].Vertices[2].Y -= (offsetAnchoCalle / 2);
ListaShapeAllots[i].Vertices[3].X -= (offsetAnchoCalle / 2);
ListaShapeAllots[i].Vertices[3].Y += (offsetAnchoCalle / 2);
} … }
Apéndice 11. Generación de los Lotes
prívate void GenerarLotes() {
…
// Categorizacion de cuadras por proporcion Diametro:Ancho for (int i = 0; i < TotalCuadras; i++)
{
float area = AreaCuadrilatero(ListaShapeAllots[i].Vertices);
float DiamWid_Ratio = ListaShapeAllots[i].PolygonDiameterWidth_Ratio();
if (area > Amax && DiamWid_Ratio > Rmax) // Area invalida muy grande, hacer lote valdio ListaShapeAllots[i].TipoDeLote = 0;
else if (area <= Amax && area > 3500 && DiamWid_Ratio < 7) // Area grande, sera para edificios
ListaShapeAllots[i].TipoDeLote = 1;
else // (area <= 3000) Area media-chica, o muy alargada. Puede ser residencial o areas verdes ListaShapeAllots[i].TipoDeLote = 2;
}
// Subdivision de las cuadras para obtener lotes (ItSub), segun el tipo de lote.
49
for (int i = 0; i < TotalCuadras; i++) {
int caso = ListaShapeAllots[i].TipoDeLote;
switch (caso) {
case 0: // Areas invalidas
ListaShapeLotes.Add(new Parcela(ListaShapeAllots[i].Vertices, false, Color.Black, caso, false));
break;
case 1: // Edificios
List<Vector3> resultz = ListaShapeAllots[i].CalcularLotes_Edificios();
for (int j = 0; j < resultz.Count; j += 4) {
ListaShapeLotes.Add(new Parcela(resultz.GetRange(j, 4).ToArray(), false, Color.CornflowerBlue, caso, false));
ListaShapeLotes_Contornos.Add(new Parcela(resultz.GetRange(j, 4).ToArray(), false, Color.Black, caso, true));
} break;
case 2: // Residencias
List<Vector3> results = ListaShapeAllots[i].CalcularLotes_Residencias();
for (int j = 0; j < results.Count; j += 4) {
ListaShapeLotes.Add(new Parcela(results.GetRange(j, 4).ToArray(), false, Color.LightGreen, caso, false));
ListaShapeLotes_Contornos.Add(new Parcela(results.GetRange(j, 4).ToArray(), false, Color.Black, caso, true));
} break;
default: throw new Exception("Error: tipo de Lote desconocido. Salio TipoDeLote < 0 o TipoDeLote > 2");
} } … }
Apéndice 12. Constructor de la función que genera las edificaciones.
public Construccion3D(Vector3[] Vertices_Base, int Tipo_deLote) {
NumeroDePisos = 0;
Vector3[] SiguientePiso;
ListaVertices = new List<Vector3>();
ListaColores = new List<int>();
ListaIndices = new List<int>();
ListaVertices.AddRange(Vertices_Base);
switch (Tipo_deLote) {
case 0: // Zona invalida, con genera modelo 3D break;
case 1: // Modelos 3D para los edificios NumeroDePisos = rand.Next(4, 11);
for (int i = 0; i < NumeroDePisos; i++) {
SiguientePiso = new Vector3[4];
float AlturaAdd = (float)rand.Next(5, 9);
for (int j = 0; j < 4; j++) {
SiguientePiso[j] = ListaVertices[(i * 4) + j];
50
SiguientePiso[j].Z += AlturaAdd;
}
ListaVertices.AddRange(SiguientePiso);
} break;
case 2: // Modelos 3D para las residencias NumeroDePisos = rand.Next(1, 4);
for (int i = 0; i < NumeroDePisos; i++) {
SiguientePiso = new Vector3[4];
float AlturaAdd = (float)rand.Next(5, 9);
for (int j = 0; j < 4; j++) {
SiguientePiso[j] = ListaVertices[(i * 4) + j];
SiguientePiso[j].Z += AlturaAdd;
}
ListaVertices.AddRange(SiguientePiso);
} break;
}
Vertices = ListaVertices.ToArray();
switch (Tipo_deLote) {
case 0: break;
case 1:
foreach (Vector3 vec in Vertices) // Color de los edificios ListaColores.Add(ColorToRgba32(Color.Blue));
break;
case 2:
foreach (Vector3 vec in Vertices) // Color de las residencias ListaColores.Add(ColorToRgba32(Color.Green));
break;
}
Colors = ListaColores.ToArray();
}
51
Anexo
Propuesta de investigación (Protocolo corto)
52
53