/// <summary> /// 导出桥梁,隧道或路基的中线 /// </summary> /// <param name="latlonPoints"></param> /// <param name="TXT"></param> private void exportMiddleLine(CRailwayProject prj, StreamWriter DoubleFile, StreamWriter SingleFile, string prjType) { string fileNameExt = ".max.x"; StreamWriter TXT; OnePrj aprj; List <Vector3d> earthCoreSysPoints = new List <Vector3d>(); List <Vector3d> dsMaxPoints = new List <Vector3d>(); List <int> sIndex = new List <int>(); // 如果工点里程过长,拆分为不超过3.5 KM作为一段生成模型 int startN = 0; // int n = 0; if (!prj.mIsValid) { return; } for (startN = 0; startN < prj.mPath.mPointCount - 350; startN += 300) { sIndex.Add(startN); } sIndex.Add(startN); double[] m, x, y, z, d; bool isDouble; string sp; isDouble = prj.mPath.getMiddleLine(out m, out x, out y, out z, out d); if (isDouble) { TXT = DoubleFile; sp = "d"; } else { TXT = SingleFile; sp = "s"; } for (int j = 0; j < sIndex.Count; j++) { int fromIdx = sIndex[j]; int toIdx; if (j == sIndex.Count - 1) { toIdx = m.Length - 1; } else { toIdx = sIndex[j + 1]; } double prjLength = prj.mPath.mLength; switch (prjType) { case "bridge": if (isDouble) { dbridgeCount++; aprj = new OnePrj(j, prjType, prj.ProjectName, sp + prjType + dbridgeCount + fileNameExt, prjLength, x[sIndex[j]], y[sIndex[j]], z[sIndex[j]]); } else { sbridgeCount++; aprj = new OnePrj(j, prjType, prj.ProjectName, sp + prjType + sbridgeCount + fileNameExt, prjLength, x[sIndex[j]], y[sIndex[j]], z[sIndex[j]]); } projectList.Add(aprj); break; case "road": if (isDouble) { droadCount++; aprj = new OnePrj(j, prjType, prj.ProjectName, sp + prjType + droadCount + fileNameExt, prjLength, x[sIndex[j]], y[sIndex[j]], z[sIndex[j]]); } else { sroadCount++; aprj = new OnePrj(j, prjType, prj.ProjectName, sp + prjType + sroadCount + fileNameExt, prjLength, x[sIndex[j]], y[sIndex[j]], z[sIndex[j]]); } projectList.Add(aprj); break; case "tunnel": if (isDouble) { dtunnelCount++; aprj = new OnePrj(j, prjType, prj.ProjectName, sp + prjType + dtunnelCount + fileNameExt, prjLength, x[sIndex[j]], y[sIndex[j]], z[sIndex[j]]); } else { stunnelCount++; aprj = new OnePrj(j, prjType, prj.ProjectName, sp + prjType + stunnelCount + fileNameExt, prjLength, x[sIndex[j]], y[sIndex[j]], z[sIndex[j]]); } projectList.Add(aprj); break; } TXT.Write(prjLength + " "); TXT.Write(prj.ProjectName + " "); TXT.WriteLine(j); earthCoreSysPoints.Clear(); dsMaxPoints.Clear(); for (int i = fromIdx; i <= toIdx; i++) { double radius = WorldSettings.EquatorialRadius /* 米 */ + z[i]; earthCoreSysPoints.Add(MathEngine.SphericalToCartesianD(y[i], x[i], radius)); // 米 } //foreach (LatLonAl p in latlonPoints) //{ // double radius = WorldSettings.EquatorialRadius/* 米 */ + p.altitude; // earthCoreSysPoints.Add(MathEngine.SphericalToCartesianD(p.latitude, p.longitude, radius)); // 米 //} // 经测试 地球窗口的世界坐标系原点在地球球心,x轴指向0纬0经,右手系,z轴指向北极点,测试语句: // Vector3 latlon_test = MathEngine.CartesianToSpherical(5001,1, 1); Vector3d k_prime = new Vector3d(earthCoreSysPoints[0]); k_prime = k_prime.Normalize(); Vector3d i_prime = Vector3d.Transform(earthCoreSys_YAxis, Matrix4d.RotationZ((prj.mPath.mx[fromIdx] * PI / 180))); Vector3d j_prime = Vector3d.Cross(k_prime, i_prime); j_prime = j_prime.Normalize(); Matrix4d mm = new Matrix4d(); // mm是正交矩阵,求逆就是求转置。 mm.M11 = i_prime.X; mm.M12 = j_prime.X; mm.M13 = k_prime.X; mm.M21 = i_prime.Y; mm.M22 = j_prime.Y; mm.M23 = k_prime.Y; mm.M31 = i_prime.Z; mm.M32 = j_prime.Z; mm.M33 = k_prime.Z; mm.M41 = mm.M42 = mm.M43 = 0; mm.M14 = mm.M24 = mm.M34 = 0; mm.M44 = 1; // 把三维中线(地球球心坐标系)上 起点之外的点 转换为 3ds max世界坐标 (起点作原点) for (int i = 1; i <= toIdx - fromIdx; i++) { Vector3d vv = new Vector3d(earthCoreSysPoints[i].X - earthCoreSysPoints[0].X, earthCoreSysPoints[i].Y - earthCoreSysPoints[0].Y, earthCoreSysPoints[i].Z - earthCoreSysPoints[0].Z); dsMaxPoints.Add(Vector3d.Transform(vv, mm)); } // 输出 List <Vector3d> straight_opt = new List <Vector3d>(); straight_opt.Add(dsMaxPoints[0]); straight_opt.Add(dsMaxPoints[1]); for (int i = 2; i < dsMaxPoints.Count; i++) { Vector3d a = dsMaxPoints[i] - straight_opt[straight_opt.Count - 1]; Vector3d b = straight_opt[straight_opt.Count - 1] - straight_opt[straight_opt.Count - 2]; double costheta = Vector3d.Dot(a, b) / a.Length / b.Length; double sintheta = Math.Sqrt(1 - costheta * costheta); if (sintheta < Threshold) { straight_opt.Last().X = dsMaxPoints[i].X; straight_opt.Last().Y = dsMaxPoints[i].Y; straight_opt.Last().Z = dsMaxPoints[i].Z; } else { straight_opt.Add(dsMaxPoints[i]); } } foreach (Vector3d p in straight_opt) { TXT.Write(p.X); TXT.Write(' '); TXT.Write(p.Y); TXT.Write(' '); TXT.Write(p.Z); TXT.Write(' '); } TXT.WriteLine(); } }
/// <summary> /// This is where we do our rendering /// Called from UI thread = UI code safe in this function /// </summary> public override void Render(DrawArgs drawArgs) { if (!isInitialized || (this.world.Name == "Earth" && World.Settings.EnableAtmosphericScattering)) { return; } // Camera & Device shortcuts ;) CameraBase camera = drawArgs.WorldCamera; Device device = drawArgs.device; //if(camera.Altitude > 200e3) return; Point3d cameraPos = camera.Position; double distToCenterOfPlanet = (camera.Altitude + camera.WorldRadius); // Create or refresh SkyGradient dome if (mesh == null || lastAltitude != camera.Altitude) { // Compute distance to horizon and dome radius double tangentalDistance = Math.Sqrt(distToCenterOfPlanet * distToCenterOfPlanet - camera.WorldRadius * camera.WorldRadius); double domeRadius = tangentalDistance; // horizon latitude double horizonLat = (-Math.PI / 2 + Math.Acos(tangentalDistance / distToCenterOfPlanet)) * 180 / Math.PI; // zenith latitude double zenithLat = 90; if (camera.Altitude >= thickness) { double tangentalDistanceZenith = Math.Sqrt(distToCenterOfPlanet * distToCenterOfPlanet - (camera.WorldRadius + thickness) * (camera.WorldRadius + thickness)); zenithLat = (-Math.PI / 2 + Math.Acos(tangentalDistanceZenith / distToCenterOfPlanet)) * 180 / Math.PI; } if (camera.Altitude < thickness && camera.Altitude > thickness * 0.8) { zenithLat = (thickness - camera.Altitude) / (thickness - thickness * 0.8) * 90; } // new mesh if (mesh != null) { mesh.Dispose(); } mesh = ColoredSphere(device, domeRadius, horizonLat, zenithLat, 128, 24); lastAltitude = camera.Altitude; } // set texture to null device.SetTexture(0, null); device.TextureState[0].ColorOperation = TextureOperation.BlendCurrentAlpha; device.VertexFormat = CustomVertex.PositionColored.Format; // save world and projection transform Matrix origWorld = device.Transform.World; Matrix origProjection = device.Transform.Projection; // move SkyGradient dome Matrix4d SkyGradientTrans; Point3d cameraCoord = MathEngine.CartesianToSpherical(cameraPos.X, cameraPos.Y, cameraPos.Z); double camLat = cameraCoord.Y; double camLon = cameraCoord.Z; SkyGradientTrans = Matrix4d.Translation(0, 0, distToCenterOfPlanet); SkyGradientTrans = Matrix4d.Multiply(SkyGradientTrans, Matrix4d.RotationY(-camLat + Math.PI / 2)); SkyGradientTrans = Matrix4d.Multiply(SkyGradientTrans, Matrix4d.RotationZ(camLon)); device.Transform.World = ConvertDX.FromMatrix4d(SkyGradientTrans); // Recenter Recenter(drawArgs); // Save fog status bool origFog = device.RenderState.FogEnable; device.RenderState.FogEnable = false; // Set new one (to avoid being clipped) - probably better ways of doing this? double aspectRatio = (double)device.Viewport.Width / device.Viewport.Height; device.Transform.Projection = ConvertDX.FromMatrix4d(Matrix4d.PerspectiveFovRH(camera.Fov.Radians, aspectRatio, 1000, 30000000.0)); // draw //device.RenderState.FillMode = FillMode.WireFrame; mesh.DrawSubset(0); // Restore device states device.RenderState.FillMode = FillMode.Solid; device.Transform.World = origWorld; device.Transform.Projection = origProjection; device.RenderState.FogEnable = origFog; device.RenderState.ZBufferEnable = true; // Fog effect if (useFog) { // Compute distance to horizon and camera altitude double tangentalDistance = Math.Sqrt(distToCenterOfPlanet * distToCenterOfPlanet - camera.WorldRadius * camera.WorldRadius); double a = camera.Altitude; device.RenderState.FogEnable = true; device.RenderState.FogColor = horizonColor; device.RenderState.FogTableMode = FogMode.Linear; device.RenderState.FogStart = (float)(a * nearFactor); device.RenderState.FogEnd = (float)(tangentalDistance * farFactor); } }