void addNewSub(int idxx, int idxy) { if (subCurve.Find(p => p.idxx == idxx && p.idxy == idxy) == null) { EarthData newearthdata; string modelkey = string.Format("{0}.{1}.{2}", layer + 1, idxx, idxy); if (!MapHelper.models.TryGetValue(modelkey, out newearthdata)) { newearthdata = new EarthData(earthmanager, this, idxx, idxy); if (MapHelper.models.Count > 500) { MapHelper.models.Remove(MapHelper.models.Keys.ElementAt(0)); } MapHelper.models.Add(modelkey, newearthdata); } else { newearthdata.parent = this; newearthdata.handled = false; newearthdata.prehandled = false; newearthdata.curStatus = EStatus.none; newearthdata.oprStatus = EStatus.none; newearthdata.operate = EOperate.none; } subCurve.Add(newearthdata); } }
/// <summary>判断弧面的四角点是否有面向相机,并且与视锥体相交</summary> private bool isFaceAndIntersect(EarthData node) { Vector3 vecDir = earth.camera.cameraDirection - earth.camera.cameraPosition; Vector3[] normals = node.normals; bool isface = false; for (int i = 0; i < normals.Length; i++) { if (Vector3.Dot(normals[i], vecDir) < 0) { isface = true; break; } } if (isface) { //BoundingFrustum cameraFrustum = new BoundingFrustum(global.camera.view * global.camera.projection); //BoundingFrustum cameraFrustum = new BoundingFrustum(global.camera.view * Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4*1.2f, (float)global.ScreenWidth / global.ScreenHeight, 0.1f, 100f)); //if (cameraFrustum.Intersects(node.boundingBox)) if (earth.camera.cameraFrustum.Intersects(node.boundingBox)) { return(true); } } return(false); }
///<summary>获得tile的屏幕2D点</summary> public static Vector2[] GetTileCorner(EarthData node, Earth earth) { Vector2[] v2s = new Vector2[node.normals.Length]; for (int i = 0; i < node.normals.Length; i++) { v2s[i] = Helpler.GetProjectPoint2D(node.normals[i], earth.camera.view, earth.camera.projection, earth.global.ScreenWidth, earth.global.ScreenHeight); } return(v2s); }
///<summary>获得tile的屏幕rect</summary> public static Rect GetTileRect(EarthData node, Earth earth) { Vector2[] v2s = new Vector2[node.normals.Length]; for (int i = 0; i < node.normals.Length; i++) { v2s[i] = Helpler.GetProjectPoint2D(node.normals[i], earth.camera.view, earth.camera.projection, earth.global.ScreenWidth, earth.global.ScreenHeight); } double minx = v2s.Min(p => p.X); double miny = v2s.Min(p => p.Y); double maxx = v2s.Max(p => p.X); double maxy = v2s.Max(p => p.Y); return(new Rect(minx, miny, maxx - minx, maxy - miny)); }
public EarthManager(Earth pearth) { datas = new EarthData(this, null, 0, 0); earth = pearth; bworker.DoWork += new DoWorkEventHandler(bworker_DoWork); bworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bworker_RunWorkerCompleted); //==== 初始化c#相机 float tmp = 1.001f * Para.scalepara; earth.camera = new Camera(new Vector3(2175.563f, 4090f, 4384f) * tmp, new Vector3(0, 0, 0), Vector3.Up, earth); //==== 初始化d3d相机 initEarth(); }
internal EarthData(EarthManager Earthmanager, EarthData Parent, int idxX, int idxY) { earthmanager = Earthmanager; parent = Parent; if (Parent == null) { layer = 0; } else { layer = parent.layer + 1; } idxx = idxX; idxy = idxY; quadkey = MapHelper.TileXYToQuadKey(layer, idxx, idxy); id = string.Format("{0}_{1}_{2}", layer, idxx, idxy); hashcode = id.GetHashCode(); }
///<summary>获取瓦片节点的高度列表</summary> internal static List <float> getHeigList(EarthData node) { List <float> result = new List <float>(); float jd, wd; double spanjd = node.range.Width / node.terrainSliceCount; for (int j = 0; j < node.terrainSliceCount + 1; j++) { for (int i = 0; i < node.terrainSliceCount + 1; i++) { jd = (float)(node.range.X + spanjd * i); double tileLength = 2.0 * Math.PI / Math.Pow(2, node.layer); //2*pi/power(2,layer) 假定半径为1, 平面地图坐标系下该层划分块的长和宽度 wd = (float)((Math.Atan(Math.Exp(Math.PI - (node.idxy + (float)j / node.terrainSliceCount) * tileLength)) * 2 - Math.PI / 2) / Math.PI * 180); result.Add(getHigh(jd, wd, node.earthmanager.TerrainMinHeight, node.earthmanager.TerrainDropHeight)); } } return(result); }
public EarthData searchNode(int zlayer, int zidxx, int zidxy) { if (layer == zlayer && idxx == zidxx && idxy == zidxy) { return(this); } else { EarthData result = null; foreach (EarthData item in subCurve) { result = item.searchNode(zlayer, zidxx, zidxy); if (result != null) { return(result); } } return(result); } }
/// <summary> /// 遍历进行操作 /// </summary> /// <param name="node"></param> private void update(EarthData node) //遍历进行更新操作 { while (node.subCurve.Count(p => !p.handled) > 0) { update(node.subCurve.First(p => !p.handled)); } switch (node.operate) { case EOperate.节点模型删除: //mapTiles.Remove(node.id); //Earth.DelMapTile(node.layer,node.idxx,node.idxy); node.parent.subCurve.Remove(node); node.parent = null; break; case EOperate.节点删除: node.parent.subCurve.Remove(node); node.parent = null; break; case EOperate.模型删除: //mapTiles.Remove(node.id); //Earth.DelMapTile(node.layer,node.idxx,node.idxy); node.curStatus = node.oprStatus; break; case EOperate.模型加入: //mapTiles.Add(node.id, updateTiles[node.id]); { if (node.mustModelStatus == EMeshStatus.维) { int count = node.terrainHeigList.Count; IntPtr ipHigh = Marshal.AllocCoTaskMem(Marshal.SizeOf(node.terrainHeigList[0]) * count); //传递点序列结构数组指针 for (int i = 0; i < count; i++) { Marshal.StructureToPtr(node.terrainHeigList[i], (IntPtr)(ipHigh.ToInt32() + i * Marshal.SizeOf(node.terrainHeigList[i])), false); } D3DManager.AddMapTile(earth.earthkey, node.hashcode, node.layer, node.idxx, node.idxy, node.mustModelStatus == EMeshStatus.维, node.terrainSliceCount, ipHigh); // 当isshowterrain为true且terrainspan与原值不同,将会重建地形mesh Marshal.FreeCoTaskMem(ipHigh); } else { D3DManager.AddMapTile(earth.earthkey, node.hashcode, node.layer, node.idxx, node.idxy, false, 0, IntPtr.Zero); //isShowTerrain为false时,不会更改地形相关数据,仅为开关控制 } } node.curStatus = node.oprStatus; break; case EOperate.模型更新: { if (node.mustModelStatus == EMeshStatus.维) { int count = node.terrainHeigList.Count; IntPtr ipHigh = Marshal.AllocCoTaskMem(Marshal.SizeOf(node.terrainHeigList[0]) * count); //传递点序列结构数组指针 for (int i = 0; i < count; i++) { Marshal.StructureToPtr(node.terrainHeigList[i], (IntPtr)(ipHigh.ToInt32() + i * Marshal.SizeOf(node.terrainHeigList[i])), false); } D3DManager.AddMapTile(earth.earthkey, node.hashcode, node.layer, node.idxx, node.idxy, node.mustModelStatus == EMeshStatus.维, node.terrainSliceCount, ipHigh); // 当isshowterrain为true且terrainspan与原值不同,将会重建地形mesh Marshal.FreeCoTaskMem(ipHigh); } else { D3DManager.AddMapTile(earth.earthkey, node.hashcode, node.layer, node.idxx, node.idxy, false, 0, IntPtr.Zero); //isShowTerrain为false时,不会更改地形相关数据,仅为开关控制 } } //D3DManager.AddMapTile(earth.earthkey, node.hashcode, node.layer, node.idxx, node.idxy); //models.Remove(node.model); //node.updateModel(); //models.Add(node.model); //node.curStatus = node.oprStatus; break; case EOperate.none: node.curStatus = node.oprStatus; break; } node.operate = EOperate.none; node.handled = true; }
///<summary>迭代遍历刷新,设置操作指令和状态</summary> private void scan(EarthData node) { if (earth.global.maxlayer < node.layer) { earth.global.maxlayer = node.layer; earth.global.maxlayertileinfo = string.Format("{0}-{1}-{2}", node.layer, node.idxx, node.idxy); } node.handled = false; node.prehandled = false; node.tileStatus = ETileStatus.可见; node.isShowTerrain = false; node.info = "0"; //Rect rectViewport = new Rect(-1000, -1000, earth.global.ScreenWidth + 2000, earth.global.ScreenHeight + 2000); Rect rectViewport = new Rect(0, 0, earth.global.ScreenWidth, earth.global.ScreenHeight); double LimitWH = 400; if ((earth.earthManager.mapType == EMapType.卫星 && node.layer + 1 <= Config.satmaxLayer) || (earth.earthManager.mapType != EMapType.卫星 && node.layer + 1 <= Config.roadmaxLayer))//下一级不大于允许最大级 { node.info = "1"; //===判断可见性 //int ycount = (int)Math.Pow(2, node.layer); //double angle = 360.0 / ycount; if ((node.layer < (earthpara.SceneMode == ESceneMode.地球? 3:earthpara.StartLayer) || isFaceAndIntersect(node))) //检测是否面向相机或层级小于2且与视锥体相交 { //首先考虑换一种验证大小面积的方法,用屏幕转换为地面,与块对比,这种方法与现用的块转换屏幕相反,(块转换屏幕在斜视下不可得,因为块平面与相机近平面相交了) //新判断方式,以瓦片的实际经纬与屏幕映射相比较来判定 if (node.range.Contains(earth.camera.curCamearaViewRange.rect)) //块包括屏幕 { node.setExpand(); foreach (EarthData item in node.subCurve) { scan(item); } } else if (node.range.IntersectsWith(earth.camera.curCamearaViewRange.rect)) //块与屏幕相交 { bool handle = false; foreach (var rec in earth.camera.curCamearaViewRange.rects) { if (node.range.IntersectsWith(rec)) { if (node.range.Width > 0.3 * rec.Width) //zh注:以后可以优化,通过预先计算纬度带的屏高,以计算面积来判定是否分拆 { node.setExpand(); foreach (EarthData item in node.subCurve) { scan(item); } } else { node.setFold(); node.isShowTerrain = true; //地形注:只有可见才可以显示地形 } handle = true; break; } } if (!handle) //指在矩形中的梯形的其余部分,未真正与屏幕相交 { node.setFold(); } } else //不相交, 应不出现 { node.setFold(); } #region ===== 旧的判断方式 ===== //node.info = "2"; //Rect rectsub = MapHelper.GetTileRect(node,earth.global); //node.rect = rectsub; //if (rectsub.Contains(rectViewport) || node.layer < (earthpara.SceneMode == ESceneMode.地球 ? 3 : earthpara.StartLayer)) //弧面包含屏幕, 转下一层级 //{ // node.info = "3"; // node.setExpand(); // foreach (EarthData item in node.subCurve) // scan(item); //} //else //{ // node.info = "4"; // if (rectViewport.IntersectsWith(rectsub)) //相交 // { // node.info = "5"; // if (rectsub.Width * rectsub.Height > LimitWH * LimitWH || rectsub.Width>1000 )//用面积判断是否切分 // { // node.info = "6"; // node.setExpand(); // foreach (EarthData item in node.subCurve) // scan(item); // } // else // { // node.info = "7"; // node.tileStatus = ETileStatus.部分可见; // node.isShowTerrain = true; // node.setFold(); // node.texture = "box3"; // } // } // else //不相交, 此,原本不应出现,三3D相交,2D不相交,计算上有问题,由于3D包围盒 // { // if (rectsub.Width > 5000) // { // node.setExpand(); // foreach (EarthData item in node.subCurve) // scan(item); // } // else // { // node.info = "8"; // node.tileStatus = ETileStatus.部分可见; // node.isShowTerrain = true; // //node.setDelete(); // node.setFold(); // node.texture = "box2"; // } // } //} #endregion } else //不可见 { //node.setDelete(); node.setFold(); node.texture = "box"; } } else //最小级 { node.info = "a"; //node.setDelete(); node.setFold(); node.texture = "box4"; } }