private Lightmap( int zoom, ProvinceList provinces, AdjacencyTable adjacent, IDMap idmap ) { if ( zoom < 0 ) throw new InvalidZoomFactorException( zoom ); this.zoom = zoom; this.provinces = provinces; this.adjacent = adjacent; this.idmap = idmap; this.volatiledecompression = false; Size sz = CoordMap.ActualToZoomedBlocks( BaseSize ); blocks = new GenericMapBlock[sz.Width*sz.Height]; }
public AdjacencyTable BuildAdjacencyTable( Rectangle region, ProvinceList provinces ) { const int Offset = 2; // 1 is too small, it seems... AdjacencyTable table = new AdjacencyTable(); // Build a matrix of provinces by walking over the map and marking each adjacency in the matrix. int[,] matrix = new int[Province.InternalCount,Province.InternalCount]; int[,] rivers = new int[Province.InternalCount,Province.InternalCount]; // Fix region if ( region.Right > Lightmap.BaseWidth ) region.Width = Lightmap.BaseWidth - region.X; if ( region.Bottom > Lightmap.BaseHeight ) region.Height = Lightmap.BaseHeight - region.Y; ushort[] histogram = null; // Enlarge region (only if it's not encompassing the whole map). // This is necessary to detect changed on the border of the region specified... if ( region.X != 0 || region.Y != 0 || region.Width < Lightmap.BaseWidth || region.Width < Lightmap.BaseHeight ) { // Need to enlarge the region so that it *completely* encompasses all provinces in the original region // First, Get a map of all the IDs in the original region histogram = GetHistogram( region ); // Get all ids in the region ushort[] ids = GetIDs( region, false ); ProvinceBoundBox[] boxes = CalculateBoundBoxes(); for ( int i=0; i<ids.Length; ++i ) { region = Rectangle.Union( region, boxes[ids[i]].Box ); } // Fix region, again. if ( region.Right > Lightmap.BaseWidth ) region.Width = Lightmap.BaseWidth - region.X; if ( region.Bottom > Lightmap.BaseHeight ) region.Height = Lightmap.BaseHeight - region.Y; } int id1, id2; int[] places = new int[] { Offset*2, 0, 0, -Offset*2, Offset*4, -Offset*2, Offset*2, -Offset*4, Offset*6, -Offset*4, Offset*4, -Offset*6, Offset*8, -Offset*6, Offset*6, -Offset*8 }; for ( int y=region.Top; y<region.Bottom; ++y ) { // Walk over zones on this row int zleft = lines[y].LookupZoneIndex( region.Left ); int zright = lines[y].LookupZoneIndex( region.Right ); for ( int z=zleft; z<=zright; ++z ) { // Skip if we're TI if ( lines[y].GetZone( z ).ID == Province.TerraIncognitaID ) continue; // Process this zone. int left = lines[y].GetZone( z ).X; int right = left + lines[y].GetZoneLength( z ); for ( int x=left; x<right; ++x ) { #region Left/Right check // -- Left/right check first id1 = this[x-Offset,y]; id2 = this[x+Offset,y]; if ( id1 != Province.TerraIncognitaID && id2 != Province.TerraIncognitaID ) { if ( provinces[id2].IsRiver() ) { // The right one is a river... ++matrix[id1,id2]; ++matrix[id2,id1]; // Look for land... for ( int i=0; i<places.Length; i+=2 ) { id2 = this[x+places[i],y+places[i+1]]; if ( provinces[id2].IsLand() ) { ++matrix[id1,id2]; ++matrix[id2,id1]; // Also mark river adjacency ++rivers[id1,id2]; ++rivers[id2,id1]; break; } } // If not found, don't mark a thing } else { ++matrix[id1,id2]; ++matrix[id2,id1]; } } #endregion #region Up/down check // -- Up/down check next id1 = this[x,y-Offset]; id2 = this[x,y+Offset]; if ( id1 != 0 && id2 != 0 ) { if ( provinces[id2].IsRiver() ) { // The bottom one is a river... ++matrix[id1,id2]; ++matrix[id2,id1]; // Look further down for land... for ( int i=0; i<places.Length; i+=2 ) { id2 = this[x+(-places[i+1]),y+places[i]]; if ( provinces[id2].IsLand() ) { ++matrix[id1,id2]; ++matrix[id2,id1]; // Also mark river adjacency ++rivers[id1,id2]; ++rivers[id2,id1]; break; } } // If not found, don't mark a thing } else { ++matrix[id1,id2]; ++matrix[id2,id1]; } } #endregion } } } // Walk over the matrix, and build an actual list of adjacencies for each province. const int Threshold = 8; // we need a certain amount of matches to have adjacency... // Start iterating at 1, no need to incorporate TI... for ( ushort ph=1; ph<Province.Count; ++ph ) { // Skip ids not present in the original region if ( histogram != null && histogram[ph] <= 0 ) continue; // Do "normal" adjacencies first for ( ushort pv=1; pv<Province.Count; ++pv ) { if ( ph == pv || provinces[pv].IsRiver() ) continue; // Check for the threshold if ( matrix[ph,pv] <= Threshold ) continue; table.Add( ph, new Adjacent( pv, rivers[ph,pv] == matrix[ph,pv] ? AdjacencyType.River : AdjacencyType.Normal ) ); } // Do "river" adjacencies next for ( ushort pv=1; pv<Province.Count; ++pv ) { if ( ph == pv || !provinces[pv].IsRiver() ) continue; // Check for the threshold if ( matrix[ph,pv] <= Threshold ) continue; table.Add( ph, new Adjacent( pv, AdjacencyType.Normal ) ); } } return table; }
public ushort FindClosestLand( int x, int y, ushort skipid, int range, ProvinceList provinces, AdjacencyTable adjacent ) { int halfwidth = (range >> 1); int halfheight = (range >> 1); ushort closest_id = skipid; // -- Build a bitmap around this point x = Lightmap.BaseNormalizeX( x ); int max_distance = MaxDistance; ushort[,] map = ExportBitmapGrid( x-halfwidth, y-halfheight, range, range ); for ( int my=0; my<range; ++my ) { for ( int mx=0; mx<range; ++mx ) { // -- Skip for TI and pixels belonging to this province if ( map[mx,my] == Province.TerraIncognitaID || map[mx,my] == skipid ) continue; if ( !provinces[map[mx,my]].IsLandNoTI() ) continue; // Only land // Also check if adjacency exists if ( adjacent != null && skipid != 0 ) { int adj = adjacent.GetAdjacencyIndex( skipid, map[mx,my] ); if ( adj < 0 || adj >= 16 ) continue; } // -- This pixel qualifies: check the distance. // Normally, we should need a sqrt() too, but it doesn't really matter here, // as we just want "the smallest" and not how small it actually is. int distance = ((mx-halfwidth)*(mx-halfwidth)) + ((my-halfheight)*(my-halfheight)); if ( distance < max_distance ) { max_distance = distance; closest_id = map[mx,my]; } } } return closest_id; }
public ushort FindClosestLand( int x, int y, ushort skipid, ProvinceList provinces, AdjacencyTable adjacent ) { return FindClosestLand( x, y, skipid, Lightmap.BlockSize, provinces, adjacent); }
public ushort[] BuildAdjacencyTable( AdjacencyTable mergeWith, Rectangle region, ProvinceList provinces ) { return mergeWith.Merge( BuildAdjacencyTable( region, provinces ) ); }
private Lightmap( int zoom, ProvinceList provinces, AdjacencyTable adjacent, IDMap idmap, BinaryReader reader ) : this(zoom, provinces, adjacent, idmap) { ReadFrom( reader ); }
public void Attach( ProvinceList provinces, AdjacencyTable adjacent, IDMap idmap ) { this.provinces = provinces; this.adjacent = adjacent; this.idmap = idmap; }
public static Lightmap FromStream( int zoom, ProvinceList provinces, AdjacencyTable adjacent, IDMap idmap, BinaryReader reader ) { return new Lightmap( zoom, provinces, adjacent, idmap, reader ); }
public static Lightmap FromFile( int zoom, ProvinceList provinces, AdjacencyTable adjacent, IDMap idmap, string path ) { FileStream stream = null; try { stream = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.Read ); return new Lightmap( zoom, provinces, adjacent, idmap, new BinaryReader( stream ) ); } finally { if ( stream != null ) stream.Close(); } }
public static Lightmap CreateEmpty( int zoom, ProvinceList provinces, AdjacencyTable adjacent, IDMap idmap ) { Lightmap result = new Lightmap( zoom, provinces, adjacent, idmap ); for ( int i=0; i<result.blocks.Length; ++i ) result.blocks[i] = new MapBlock(); return result; }
public ushort[] Merge( AdjacencyTable other ) { int[] tagged = new int[Province.InternalCount]; for ( int fromId=1; fromId<other.table.Length; ++fromId ) { if ( other.table[fromId] == null || other.table[fromId].Length == 0 ) continue; ++tagged[fromId]; table[fromId] = new Adjacent[other.table[fromId].Length]; other.table[fromId].CopyTo( table[fromId], 0 ); for ( int t=0; t<table[fromId].Length; ++t ) ++tagged[table[fromId][t].ID]; } // Count affected ids int count = 0; for ( ushort i=0; i<tagged.Length; ++i ) { if ( tagged[i] > 0 ) count++; } ushort[] affected = new ushort[count]; count = 0; for ( ushort i=0; i<tagged.Length; ++i ) { if ( tagged[i] > 0 ) affected[count++] = i; } return affected; }