OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ErodeSphere.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using OpenSim.Region.Framework.Interfaces;
30 using OpenSim.Region.Framework.Scenes;
31 
32 namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
33 {
38  {
39  private const double rainHeight = 0.2;
40  private const int rounds = 10;
41  private const NeighbourSystem type = NeighbourSystem.Moore;
42  private const double waterSaturation = 0.30;
43 
44  #region Supporting Functions
45 
46  private static int[] Neighbours(NeighbourSystem neighbourType, int index)
47  {
48  int[] coord = new int[2];
49 
50  index++;
51 
52  switch (neighbourType)
53  {
54  case NeighbourSystem.Moore:
55  switch (index)
56  {
57  case 1:
58  coord[0] = -1;
59  coord[1] = -1;
60  break;
61 
62  case 2:
63  coord[0] = -0;
64  coord[1] = -1;
65  break;
66 
67  case 3:
68  coord[0] = +1;
69  coord[1] = -1;
70  break;
71 
72  case 4:
73  coord[0] = -1;
74  coord[1] = -0;
75  break;
76 
77  case 5:
78  coord[0] = -0;
79  coord[1] = -0;
80  break;
81 
82  case 6:
83  coord[0] = +1;
84  coord[1] = -0;
85  break;
86 
87  case 7:
88  coord[0] = -1;
89  coord[1] = +1;
90  break;
91 
92  case 8:
93  coord[0] = -0;
94  coord[1] = +1;
95  break;
96 
97  case 9:
98  coord[0] = +1;
99  coord[1] = +1;
100  break;
101 
102  default:
103  break;
104  }
105  break;
106 
107  case NeighbourSystem.VonNeumann:
108  switch (index)
109  {
110  case 1:
111  coord[0] = 0;
112  coord[1] = -1;
113  break;
114 
115  case 2:
116  coord[0] = -1;
117  coord[1] = 0;
118  break;
119 
120  case 3:
121  coord[0] = +1;
122  coord[1] = 0;
123  break;
124 
125  case 4:
126  coord[0] = 0;
127  coord[1] = +1;
128  break;
129 
130  case 5:
131  coord[0] = -0;
132  coord[1] = -0;
133  break;
134 
135  default:
136  break;
137  }
138  break;
139  }
140 
141  return coord;
142  }
143 
144  private enum NeighbourSystem
145  {
146  Moore,
147  VonNeumann
148  } ;
149 
150  #endregion
151 
152  #region ITerrainPaintableEffect Members
153 
154  public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz,
155  double strength, double duration, int startX, int endX, int startY, int endY)
156  {
157  strength = TerrainUtil.MetersToSphericalStrength(strength);
158 
159  int x, y;
160  // Using one 'rain' round for this, so skipping a useless loop
161  // Will need to adapt back in for the Flood brush
162 
163  ITerrainChannel water = new TerrainChannel(map.Width, map.Height);
164  ITerrainChannel sediment = new TerrainChannel(map.Width, map.Height);
165 
166  // Fill with rain
167  for (x = startX; x <= endX; x++)
168  {
169  for (y = startY; y <= endY; y++)
170  {
171  if (mask[x, y])
172  water[x, y] = Math.Max(0.0, TerrainUtil.SphericalFactor(x, y, rx, ry, strength) * rainHeight * duration);
173  }
174  }
175 
176  for (int i = 0; i < rounds; i++)
177  {
178  // Erode underlying terrain
179  for (x = startX; x <= endX; x++)
180  {
181  for (y = startY; y <= endY; y++)
182  {
183  if (mask[x, y])
184  {
185  const double solConst = (1.0 / rounds);
186  double sedDelta = water[x, y] * solConst;
187  map[x, y] -= sedDelta;
188  sediment[x, y] += sedDelta;
189  }
190  }
191  }
192 
193  // Move water
194  for (x = startX; x <= endX; x++)
195  {
196  for (y = startY; y <= endY; y++)
197  {
198  if (water[x, y] <= 0)
199  continue;
200 
201  // Step 1. Calculate average of neighbours
202 
203  int neighbours = 0;
204  double altitudeTotal = 0.0;
205  double altitudeMe = map[x, y] + water[x, y];
206 
207  const int NEIGHBOUR_ME = 4;
208  const int NEIGHBOUR_MAX = 9;
209 
210  for (int j = 0; j < NEIGHBOUR_MAX; j++)
211  {
212  if (j != NEIGHBOUR_ME)
213  {
214  int[] coords = Neighbours(type, j);
215 
216  coords[0] += x;
217  coords[1] += y;
218 
219  if (coords[0] > map.Width - 1)
220  continue;
221  if (coords[1] > map.Height - 1)
222  continue;
223  if (coords[0] < 0)
224  continue;
225  if (coords[1] < 0)
226  continue;
227 
228  // Calculate total height of this neighbour
229  double altitudeNeighbour = water[coords[0], coords[1]] + map[coords[0], coords[1]];
230 
231  // If it's greater than me...
232  if (altitudeNeighbour - altitudeMe < 0)
233  {
234  // Add it to our calculations
235  neighbours++;
236  altitudeTotal += altitudeNeighbour;
237  }
238  }
239  }
240 
241  if (neighbours == 0)
242  continue;
243 
244  double altitudeAvg = altitudeTotal / neighbours;
245 
246  // Step 2. Allocate water to neighbours.
247  for (int j = 0; j < NEIGHBOUR_MAX; j++)
248  {
249  if (j != NEIGHBOUR_ME)
250  {
251  int[] coords = Neighbours(type, j);
252 
253  coords[0] += x;
254  coords[1] += y;
255 
256  if (coords[0] > map.Width - 1)
257  continue;
258  if (coords[1] > map.Height - 1)
259  continue;
260  if (coords[0] < 0)
261  continue;
262  if (coords[1] < 0)
263  continue;
264 
265  // Skip if we dont have water to begin with.
266  if (water[x, y] < 0)
267  continue;
268 
269  // Calculate our delta average
270  double altitudeDelta = altitudeMe - altitudeAvg;
271 
272  if (altitudeDelta < 0)
273  continue;
274 
275  // Calculate how much water we can move
276  double waterMin = Math.Min(water[x, y], altitudeDelta);
277  double waterDelta = waterMin * ((water[coords[0], coords[1]] + map[coords[0], coords[1]])
278  / altitudeTotal);
279 
280  double sedimentDelta = sediment[x, y] * (waterDelta / water[x, y]);
281 
282  if (sedimentDelta > 0)
283  {
284  sediment[x, y] -= sedimentDelta;
285  sediment[coords[0], coords[1]] += sedimentDelta;
286  }
287  }
288  }
289  }
290  }
291 
292  // Evaporate
293 
294  for (x = 0; x < water.Width; x++)
295  {
296  for (y = 0; y < water.Height; y++)
297  {
298  water[x, y] *= 1.0 - (rainHeight / rounds);
299 
300  double waterCapacity = waterSaturation * water[x, y];
301 
302  double sedimentDeposit = sediment[x, y] - waterCapacity;
303  if (sedimentDeposit > 0)
304  {
305  if (mask[x, y])
306  {
307  sediment[x, y] -= sedimentDeposit;
308  map[x, y] += sedimentDeposit;
309  }
310  }
311  }
312  }
313  }
314 
315  // Deposit any remainder (should be minimal)
316  for (x = 0; x < water.Width; x++)
317  for (y = 0; y < water.Height; y++)
318  if (mask[x, y] && sediment[x, y] > 0)
319  map[x, y] += sediment[x, y];
320  }
321  #endregion
322  }
323 }
void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration, int startX, int endX, int startY, int endY)
Definition: ErodeSphere.cs:154
Interactive OpenSim region server
Definition: OpenSim.cs:55
A new version of the old Channel class, simplified