diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/World')
-rw-r--r-- | OpenSim/Region/CoreModules/World/Land/LandObject.cs | 290 |
1 files changed, 274 insertions, 16 deletions
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 040c90b..16d26c4 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs | |||
@@ -864,17 +864,17 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
864 | 864 | ||
865 | public bool[,] BasicFullRegionLandBitmap() | 865 | public bool[,] BasicFullRegionLandBitmap() |
866 | { | 866 | { |
867 | return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY); | 867 | return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY, true); |
868 | } | 868 | } |
869 | 869 | ||
870 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) | 870 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y, bool set_value = true) |
871 | { | 871 | { |
872 | // Empty bitmap for the whole region | 872 | // Empty bitmap for the whole region |
873 | bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | 873 | bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; |
874 | tempBitmap.Initialize(); | 874 | tempBitmap.Initialize(); |
875 | 875 | ||
876 | // Fill the bitmap square area specified by state and end | 876 | // Fill the bitmap square area specified by state and end |
877 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); | 877 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, set_value); |
878 | // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>", | 878 | // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>", |
879 | // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1)); | 879 | // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1)); |
880 | return tempBitmap; | 880 | return tempBitmap; |
@@ -944,10 +944,224 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
944 | } | 944 | } |
945 | 945 | ||
946 | /// <summary> | 946 | /// <summary> |
947 | /// Remap a land bitmap. Takes the supplied land bitmap and rotates it, crops it and finally offsets it into | ||
948 | /// a final land bitmap of the target region size. | ||
949 | /// </summary> | ||
950 | /// <param name="bitmap_base">The original parcel bitmap</param> | ||
951 | /// <param name="rotationDegrees"></param> | ||
952 | /// <param name="displacement"><x,y,?></param> | ||
953 | /// <param name="boundingOrigin"><x,y,?></param> | ||
954 | /// <param name="boundingSize"><x,y,?></param> | ||
955 | /// <param name="regionSize"><x,y,?></param> | ||
956 | /// <param name="isEmptyNow">out: This is set if the resultant bitmap is now empty</param> | ||
957 | /// <param name="AABBMin">out: parcel.AABBMin <x,y,0></param> | ||
958 | /// <param name="AABBMax">out: parcel.AABBMax <x,y,0></param> | ||
959 | /// <returns>New parcel bitmap</returns> | ||
960 | public bool[,] RemapLandBitmap(bool[,] bitmap_base, Vector2 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Vector2 regionSize, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax) | ||
961 | { | ||
962 | // get the size of the incoming bitmap | ||
963 | int baseX = bitmap_base.GetLength(0); | ||
964 | int baseY = bitmap_base.GetLength(1); | ||
965 | |||
966 | // create an intermediate bitmap that is 25% bigger on each side that we can work with to handle rotations | ||
967 | int offsetX = baseX / 4; // the original origin will now be at these coordinates so now we can have imaginary negative coordinates ;) | ||
968 | int offsetY = baseY / 4; | ||
969 | int tmpX = baseX + baseX / 2; | ||
970 | int tmpY = baseY + baseY / 2; | ||
971 | int centreX = tmpX / 2; | ||
972 | int centreY = tmpY / 2; | ||
973 | bool[,] bitmap_tmp = new bool[tmpX, tmpY]; | ||
974 | |||
975 | double radianRotation = Math.PI * rotationDegrees / 180f; | ||
976 | double cosR = Math.Cos(radianRotation); | ||
977 | double sinR = Math.Sin(radianRotation); | ||
978 | if (rotationDegrees < 0f) rotationDegrees += 360f; //-90=270 -180=180 -270=90 | ||
979 | |||
980 | // So first we apply the rotation to the incoming bitmap, storing the result in bitmap_tmp | ||
981 | // We special case orthogonal rotations for accuracy because even using double precision math, Math.Cos(90 degrees) is never fully 0 | ||
982 | // and we can never rotate around a centre pixel because the bitmap size is always even | ||
983 | int x, y, sx, sy; | ||
984 | for (y = 0; y <= tmpY; y++) | ||
985 | { | ||
986 | for (x = 0; x <= tmpX; x++) | ||
987 | { | ||
988 | if (rotationDegrees == 0f) | ||
989 | { | ||
990 | sx = x - offsetX; | ||
991 | sy = y - offsetY; | ||
992 | } | ||
993 | else if (rotationDegrees == 90f) | ||
994 | { | ||
995 | sx = y - offsetX; | ||
996 | sy = tmpY - 1 - x - offsetY; | ||
997 | } | ||
998 | else if (rotationDegrees == 180f) | ||
999 | { | ||
1000 | sx = tmpX - 1 - x - offsetX; | ||
1001 | sy = tmpY - 1 - y - offsetY; | ||
1002 | } | ||
1003 | else if (rotationDegrees == 270f) | ||
1004 | { | ||
1005 | sx = tmpX - 1 - y - offsetX; | ||
1006 | sy = x - offsetY; | ||
1007 | } | ||
1008 | else | ||
1009 | { | ||
1010 | // arbitary rotation: hmmm should I be using (centreX - 0.5) and (centreY - 0.5) and round cosR and sinR to say only 5 decimal places? | ||
1011 | sx = centreX + (int)Math.Round((((double)x - centreX) * cosR) + (((double)y - centreY) * sinR)) - offsetX; | ||
1012 | sy = centreY + (int)Math.Round((((double)y - centreY) * cosR) - (((double)x - centreX) * sinR)) - offsetY; | ||
1013 | } | ||
1014 | if (sx >= 0 && sx < baseX && sy >= 0 && sy < baseY) | ||
1015 | { | ||
1016 | try | ||
1017 | { | ||
1018 | if (bitmap_base[sx, sy]) bitmap_tmp[x, y] = true; | ||
1019 | } | ||
1020 | catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) | ||
1021 | { | ||
1022 | m_log.DebugFormat("{0} RemapLandBitmap Rotate: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, sx, sy, x, y); | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | // We could also incorporate the next steps, bounding-rectangle and displacement in the loop above, but it's simpler to visualise if done separately | ||
1029 | // and will also make it much easier when later I want the option for maybe a circular or oval bounding shape too ;). | ||
1030 | // So... our output land bitmap must be the size of the current region but rememeber, parcel landbitmaps are landUnit metres (4x4 metres) per point, | ||
1031 | // and region sizes, boundaries and displacements are in metres so we need to scale down | ||
1032 | |||
1033 | int newX = (int)(regionSize.X / landUnit); | ||
1034 | int newY = (int)(regionSize.Y / landUnit); | ||
1035 | bool[,] bitmap_new = new bool[newX, newY]; | ||
1036 | // displacement is relative to <0,0> in the destination region and defines where the origin of the data selected by the bounding-rectangle is placed | ||
1037 | int dispX = (int)Math.Floor(displacement.X / landUnit); | ||
1038 | int dispY = (int)Math.Floor(displacement.Y / landUnit); | ||
1039 | |||
1040 | // startX/Y and endX/Y are coordinates in bitmap_tmp | ||
1041 | int startX = (int)Math.Floor(boundingOrigin.X / landUnit) + offsetX; | ||
1042 | if (startX > tmpX) startX = tmpX; | ||
1043 | if (startX < 0) startX = 0; | ||
1044 | int startY = (int)Math.Floor(boundingOrigin.Y / landUnit) + offsetY; | ||
1045 | if (startY > tmpY) startY = tmpY; | ||
1046 | if (startY < 0) startY = 0; | ||
1047 | |||
1048 | int endX = (int)Math.Floor((boundingOrigin.X + boundingSize.X) / landUnit) + offsetX; | ||
1049 | if (endX > tmpX) endX = tmpX; | ||
1050 | if (endX < 0) endX = 0; | ||
1051 | int endY = (int)Math.Floor((boundingOrigin.Y + boundingSize.Y) / landUnit) + offsetY; | ||
1052 | if (endY > tmpY) endY = tmpY; | ||
1053 | if (endY < 0) endY = 0; | ||
1054 | |||
1055 | //m_log.DebugFormat("{0} RemapLandBitmap: inSize=<{1},{2}>, disp=<{3},{4}> rot={5}, offset=<{6},{7}>, boundingStart=<{8},{9}>, boundingEnd=<{10},{11}>, cosR={12}, sinR={13}, outSize=<{14},{15}>", LogHeader, | ||
1056 | // baseX, baseY, dispX, dispY, radianRotation, offsetX, offsetY, startX, startY, endX, endY, cosR, sinR, newX, newY); | ||
1057 | |||
1058 | isEmptyNow = true; | ||
1059 | int minX = newX; | ||
1060 | int minY = newY; | ||
1061 | int maxX = 0; | ||
1062 | int maxY = 0; | ||
1063 | |||
1064 | int dx, dy; | ||
1065 | for (y = startY; y < endY; y++) | ||
1066 | { | ||
1067 | for (x = startX; x < endX; x++) | ||
1068 | { | ||
1069 | dx = x - startX + dispX; | ||
1070 | dy = y - startY + dispY; | ||
1071 | if (dx >= 0 && dx < newX && dy >= 0 && dy < newY) | ||
1072 | { | ||
1073 | try | ||
1074 | { | ||
1075 | if (bitmap_tmp[x, y]) | ||
1076 | { | ||
1077 | bitmap_new[dx, dy] = true; | ||
1078 | isEmptyNow = false; | ||
1079 | if (dx < minX) minX = dx; | ||
1080 | if (dy < minY) minY = dy; | ||
1081 | if (dx > maxX) maxX = dx; | ||
1082 | if (dy > maxY) maxY = dy; | ||
1083 | } | ||
1084 | } | ||
1085 | catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) | ||
1086 | { | ||
1087 | m_log.DebugFormat("{0} RemapLandBitmap - Bound & Displace: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, x, y, dx, dy); | ||
1088 | } | ||
1089 | } | ||
1090 | } | ||
1091 | } | ||
1092 | if (isEmptyNow) | ||
1093 | { | ||
1094 | //m_log.DebugFormat("{0} RemapLandBitmap: Land bitmap is marked as Empty", LogHeader); | ||
1095 | minX = 0; | ||
1096 | minY = 0; | ||
1097 | } | ||
1098 | |||
1099 | AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0); | ||
1100 | AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0); | ||
1101 | return bitmap_new; | ||
1102 | } | ||
1103 | |||
1104 | /// <summary> | ||
1105 | /// Clears any parcel data in bitmap_base where there exists parcel data in bitmap_new. In other words the parcel data | ||
1106 | /// in bitmap_new takes over the space of the parcel data in bitmap_base. | ||
1107 | /// </summary> | ||
1108 | /// <param name="bitmap_base"></param> | ||
1109 | /// <param name="bitmap_new"></param> | ||
1110 | /// <param name="isEmptyNow">out: This is set if the resultant bitmap is now empty</param> | ||
1111 | /// <param name="AABBMin">out: parcel.AABBMin <x,y,0></param> | ||
1112 | /// <param name="AABBMax">out: parcel.AABBMax <x,y,0></param> | ||
1113 | /// <returns>New parcel bitmap</returns> | ||
1114 | public bool[,] RemoveFromLandBitmap(bool[,] bitmap_base, bool[,] bitmap_new, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax) | ||
1115 | { | ||
1116 | // get the size of the incoming bitmaps | ||
1117 | int baseX = bitmap_base.GetLength(0); | ||
1118 | int baseY = bitmap_base.GetLength(1); | ||
1119 | int newX = bitmap_new.GetLength(0); | ||
1120 | int newY = bitmap_new.GetLength(1); | ||
1121 | |||
1122 | if (baseX != newX || baseY != newY) | ||
1123 | { | ||
1124 | throw new Exception( | ||
1125 | String.Format("{0} RemoveFromLandBitmap: Land bitmaps are not the same size! baseX={1} baseY={2} newX={3} newY={4}", LogHeader, baseX, baseY, newX, newY)); | ||
1126 | } | ||
1127 | |||
1128 | isEmptyNow = true; | ||
1129 | int minX = baseX; | ||
1130 | int minY = baseY; | ||
1131 | int maxX = 0; | ||
1132 | int maxY = 0; | ||
1133 | |||
1134 | for (int y = 0; y < baseY; y++) | ||
1135 | { | ||
1136 | for (int x = 0; x < baseX; x++) | ||
1137 | { | ||
1138 | if (bitmap_new[x, y]) bitmap_base[x, y] = false; | ||
1139 | if (bitmap_base[x, y]) | ||
1140 | { | ||
1141 | isEmptyNow = false; | ||
1142 | if (x < minX) minX = x; | ||
1143 | if (y < minY) minY = y; | ||
1144 | if (x > maxX) maxX = x; | ||
1145 | if (y > maxY) maxY = y; | ||
1146 | } | ||
1147 | } | ||
1148 | } | ||
1149 | if (isEmptyNow) | ||
1150 | { | ||
1151 | //m_log.DebugFormat("{0} RemoveFromLandBitmap: Land bitmap is marked as Empty", LogHeader); | ||
1152 | minX = 0; | ||
1153 | minY = 0; | ||
1154 | } | ||
1155 | AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0); | ||
1156 | AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0); | ||
1157 | return bitmap_base; | ||
1158 | } | ||
1159 | |||
1160 | /// <summary> | ||
947 | /// Converts the land bitmap to a packet friendly byte array | 1161 | /// Converts the land bitmap to a packet friendly byte array |
948 | /// </summary> | 1162 | /// </summary> |
949 | /// <returns></returns> | 1163 | /// <returns></returns> |
950 | private byte[] ConvertLandBitmapToBytes() | 1164 | public byte[] ConvertLandBitmapToBytes() |
951 | { | 1165 | { |
952 | byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; | 1166 | byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; |
953 | 1167 | ||
@@ -994,23 +1208,41 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
994 | return tempConvertArr; | 1208 | return tempConvertArr; |
995 | } | 1209 | } |
996 | 1210 | ||
997 | private bool[,] ConvertBytesToLandBitmap() | 1211 | public bool[,] ConvertBytesToLandBitmap(bool overrideRegionSize = false) |
998 | { | 1212 | { |
999 | bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | 1213 | int bitmapLen; |
1000 | tempConvertMap.Initialize(); | 1214 | int xLen; |
1001 | byte tempByte = 0; | 1215 | bool[,] tempConvertMap; |
1002 | // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. | 1216 | |
1003 | int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); | 1217 | if (overrideRegionSize) |
1004 | int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); | ||
1005 | |||
1006 | if (bitmapLen == 512) | ||
1007 | { | 1218 | { |
1008 | // Legacy bitmap being passed in. Use the legacy region size | 1219 | // Importing land parcel data from an OAR where the source region is a different size to the dest region requires us |
1009 | // and only set the lower area of the larger region. | 1220 | // to make a LandBitmap that's not derived from the current region's size. We use the LandData.Bitmap size in bytes |
1010 | xLen = (int)(Constants.RegionSize / landUnit); | 1221 | // to figure out what the OAR's region dimensions are. (Is there a better way to get the src region x and y from the OAR?) |
1222 | // This method assumes we always will have square regions | ||
1223 | |||
1224 | bitmapLen = LandData.Bitmap.Length; | ||
1225 | xLen = (int)Math.Abs(Math.Sqrt(bitmapLen * 8)); | ||
1226 | tempConvertMap = new bool[xLen, xLen]; | ||
1227 | tempConvertMap.Initialize(); | ||
1228 | } | ||
1229 | else | ||
1230 | { | ||
1231 | tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | ||
1232 | tempConvertMap.Initialize(); | ||
1233 | // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. | ||
1234 | bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); | ||
1235 | xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); | ||
1236 | if (bitmapLen == 512) | ||
1237 | { | ||
1238 | // Legacy bitmap being passed in. Use the legacy region size | ||
1239 | // and only set the lower area of the larger region. | ||
1240 | xLen = (int)(Constants.RegionSize / landUnit); | ||
1241 | } | ||
1011 | } | 1242 | } |
1012 | // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen); | 1243 | // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen); |
1013 | 1244 | ||
1245 | byte tempByte; | ||
1014 | int x = 0, y = 0; | 1246 | int x = 0, y = 0; |
1015 | for (int i = 0; i < bitmapLen; i++) | 1247 | for (int i = 0; i < bitmapLen; i++) |
1016 | { | 1248 | { |
@@ -1038,6 +1270,32 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1038 | return tempConvertMap; | 1270 | return tempConvertMap; |
1039 | } | 1271 | } |
1040 | 1272 | ||
1273 | public bool IsLandBitmapEmpty(bool[,] landBitmap) | ||
1274 | { | ||
1275 | for (int y = 0; y < landBitmap.GetLength(1); y++) | ||
1276 | { | ||
1277 | for (int x = 0; x < landBitmap.GetLength(0); x++) | ||
1278 | { | ||
1279 | if (landBitmap[x, y]) return false; | ||
1280 | } | ||
1281 | } | ||
1282 | return true; | ||
1283 | } | ||
1284 | |||
1285 | public void DebugLandBitmap(bool[,] landBitmap) | ||
1286 | { | ||
1287 | m_log.InfoFormat("{0}: Map Key: #=claimed land .=unclaimed land.", LogHeader); | ||
1288 | for (int y = landBitmap.GetLength(1) - 1; y >= 0; y--) | ||
1289 | { | ||
1290 | string row = ""; | ||
1291 | for (int x = 0; x < landBitmap.GetLength(0); x++) | ||
1292 | { | ||
1293 | row += landBitmap[x, y] ? "#" : "."; | ||
1294 | } | ||
1295 | m_log.InfoFormat("{0}: {1}", LogHeader, row); | ||
1296 | } | ||
1297 | } | ||
1298 | |||
1041 | #endregion | 1299 | #endregion |
1042 | 1300 | ||
1043 | #region Object Select and Object Owner Listing | 1301 | #region Object Select and Object Owner Listing |