用两个dropdownlist实现主次选择

本文介绍了一个使用ASP.NET实现的级联DropDownList控件的例子。通过两个下拉列表,第一个选择省份,第二个根据所选省份显示对应的城市。利用SqlConnection连接数据库,SqlCommand执行SQL查询并填充下拉列表。

 

比如第1个选为省分,第2 个为相对的市,

如图:

http://xiaofam.blogbus.com/files/1144175908.jpg

代码:

Imports System.Data
Imports System.Data.SqlClient
Public Class WebForm1
    Inherits System.Web.UI.Page

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If Not IsPostBack Then
            Dim con As SqlConnection
            Dim cmd As SqlCommand
            Dim dr As SqlDataReader
            con = New SqlConnection("server=(local);uid=sa;pwd=;database=lab")
            cmd = New SqlCommand("select * from test1", con)
            con.Open()
            dr = cmd.ExecuteReader
            DropDownList1.DataSource = dr
            DropDownList1.DataTextField = "proName"
            DropDownList1.DataValueField = "proID"
            DropDownList1.DataBind()
            dr.Close()

            con.Close()

        End If

    End Sub

    Private Sub DropDownList1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
        Dim cmd2 As SqlCommand
        Dim dr2 As SqlDataReader
        Dim con2 As SqlConnection
        con2 = New SqlConnection("server=(local);uid=sa;pwd=;database=lab")
        cmd2 = New SqlCommand("select * from test2 where proID=" + DropDownList1.SelectedValue, con2)
        con2.Open()
        dr2 = cmd2.ExecuteReader
        DropDownList2.DataSource = dr2
        DropDownList2.DataTextField = "cityname"
        DropDownList2.DataValueField = "cityID"
        DropDownList2.DataBind()
        dr2.Close()
        con2.Close()
    End Sub
End Class

 

1、梁下次龙骨设置;布置方向,当选择“横向或垂直”时“间距”输入栏呈现灰色不输入 2、梁下主龙骨设置;布置方向,当选择“横向或垂直”时“间距”输入栏呈现灰色不输入 3、启用梁侧设置;次龙骨;布置方向,当选择“横向或垂直”时“间距”输入栏呈现灰色不输入 4、板下次龙骨设置;布置方向,当选择“横向或垂直”时“间距”输入栏呈现灰色不输入 5、板下主龙骨设置;布置方向,顶托内方钢数量,当布置方向选择“横向或垂直”时“顶托内方钢数量”输入栏呈现灰色不输入 6、当绘制第二个点后选择板厚A输入值后就自动错误闭合了,没有循环重复第一个点开始的绘制;具体绘制要求: 局里:假如我从左侧开始根据结构图纸参照梁边线绘制第一个点(也就是梁的左侧第一根线这第一个点也是X和Y轴的基准0坐标点)至第二个点(也就是梁的左侧向右的第二根线)时两点之间自动绘制多段线,在提示输入梁高时假设1000mm高,梁内绘制的多段线0坐标点向下偏移1000mm,1000mm梁的右侧若有降板或者有不同的板厚时根据"[板厚(A)/升降板(S)] [A/S]“选项输入值,选择板厚A输入值假如200mm(并记忆输入值可重复利用)厚楼板,假如梁的右侧是降板那就要选择升降板输入值假设0坐标点向下偏移500mm那么在绘制从左向右第二道梁边线点时两道梁之间的多段线0坐标点向下偏移500mm,在绘制结构梁线之间的线段,若有降板或者有不同的板厚时根据”[板厚(A)/升降板(S)] [A/S]"选项输入值重复以上步骤…;绘制的多段线从第一个点开始至最后一个点结束中间多段线是连续绘制的不能间断绘制
08-03
using WinFormsFont = System.Drawing.Font; using WinFormsSize = System.Drawing.Size; using WinFormsPoint = System.Drawing.Point; using WinFormsFontStyle = System.Drawing.FontStyle; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using SystemException = System.Exception; using AcadRuntimeException = Autodesk.AutoCAD.Runtime.Exception; using Point = System.Drawing.Point; using Size = System.Drawing.Size; using Label = System.Windows.Forms.Label; using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application; using WinFormsDialogResult = System.Windows.Forms.DialogResult; namespace BeamSectionPlugin { #region 参数类 public class BeamParameters { public int Thickness { get; set; } = 15; public double DefaultSlabThickness { get; set; } = 120; // 默认板厚 public BeamBottomSetting BeamBottom { get; set; } = new BeamBottomSetting(); public BeamSideSetting BeamSide { get; set; } = new BeamSideSetting(); public SlabSetting Slab { get; set; } = new SlabSetting(); } public class BeamBottomSetting { public string SecondaryMaterial { get; set; } = "木方"; public string SecondarySpec { get; set; } = "40x90"; public string SecondaryDirection { get; set; } = "横向"; public string SecondarySpacing { get; set; } = "@200"; public string PrimaryMaterial { get; set; } = "木方"; public string PrimarySpec { get; set; } = "100x100"; public string PrimaryDirection { get; set; } = "纵向"; public string PrimarySpacing { get; set; } = ""; } public class BeamSideSetting { public bool Enabled { get; set; } = false; public string SecondaryMaterial { get; set; } = "木方"; public string SecondarySpec { get; set; } = "40x90"; public string SecondaryDirection { get; set; } = "垂直"; public string SecondarySpacing { get; set; } = "@200"; public string PrimaryMaterial { get; set; } = "木方"; public string PrimarySpec { get; set; } = "100x100"; public string PrimaryLayout { get; set; } = "双拼"; public double BoltDiameter { get; set; } = 12; public double BoltStartHeight { get; set; } = 50; public double BoltSlabHeight { get; set; } = 250; public double BoltSpacing { get; set; } = 500; } public class SlabSetting { public string SecondaryMaterial { get; set; } = "木方"; public string SecondarySpec { get; set; } = "40x90"; public string SecondaryDirection { get; set; } = "横向"; public double SecondarySpacing { get; set; } = 200; public string PrimaryMaterial { get; set; } = "木方"; public string PrimarySpec { get; set; } = "100x100"; public string PrimaryDirection { get; set; } = "纵向"; public int SteelCount { get; set; } = 1; // 顶托内方钢数量 } public class SlabParams { public double Thickness { get; set; } = 120; // 默认120mm public double Offset { get; set; } = 0; // 升降板高度 } public class BeamSegment { public Point3d Start { get; set; } public Point3d End { get; set; } public double Height { get; set; } public SlabParams Slab { get; set; } public Point3d BeamTopStart { get; set; } // 梁顶起点 public Point3d BeamTopEnd { get; set; } // 梁顶终点 public Point3d SlabTopStart { get; set; } // 板顶起点 public Point3d SlabTopEnd { get; set; } // 板顶终点 } #endregion #region WinForms 窗体 public class BeamSectionForm : Form { // 材料库数据 private readonly Dictionary<string, List<string>> materialLib = new Dictionary<string, List<string>> { {"木方", new List<string>{"40x90", "50x100", "100x100"}}, {"钢管", new List<string>{"Φ48x2.5", "Φ48x2.7", "Φ48x3"}}, {"方钢", new List<string>{"40x40x1.5", "50x50x1.5", "50x100x3"}}, {"工字钢", new List<string>{"I8", "I10", "I12", "I14", "I16"}} }; // UI 控件声明 private TabControl mainTabControl; private Button btnDraw; private TextBox txtThickness; private TextBox txtDefaultSlabThickness; // 默认板厚输入框 private ComboBox cmbBeamBottomSecMaterial, cmbBeamBottomSecSpec, cmbBeamBottomSecDirection; private TextBox txtBeamBottomSecSpacing, txtBeamBottomPriSpacing; private ComboBox cmbBeamBottomPriMaterial, cmbBeamBottomPriSpec, cmbBeamBottomPriDirection; private CheckBox chkBeamSideEnabled; private ComboBox cmbBeamSideSecMaterial, cmbBeamSideSecSpec, cmbBeamSideSecDirection; private TextBox txtBeamSideSecSpacing; private ComboBox cmbBeamSidePriMaterial, cmbBeamSidePriSpec, cmbBeamSidePriLayout; private TextBox txtBoltDiameter, txtBoltStartHeight, txtBoltSlabHeight, txtBoltSpacing; private ComboBox cmbSlabSecMaterial, cmbSlabSecSpec, cmbSlabSecDirection; private TextBox txtSlabSecSpacing; private ComboBox cmbSlabPriMaterial, cmbSlabPriSpec, cmbSlabPriDirection; private TextBox txtSlabPriSteelCount; // 顶托内方钢数量 public BeamSectionForm() { InitializeComponents(); } private void InitializeComponents() { try { // 窗体设置 (更紧凑) this.Size = new WinFormsSize(650, 300); this.Text = "梁板剖面图参数设置"; this.StartPosition = FormStartPosition.CenterScreen; this.Font = new WinFormsFont("Microsoft YaHei UI", 9F); // 主选项卡 mainTabControl = new TabControl { Location = new WinFormsPoint(10, 40), Size = new WinFormsSize(620, 480), Font = new WinFormsFont("Microsoft YaHei UI", 9F) }; this.Controls.Add(mainTabControl); // 创建选项卡 CreateBeamBottomTab(); CreateSlabTab(); // 模板厚度设置 Label lblThickness = new Label { Text = "梁板统一模板厚(mm):", Location = new WinFormsPoint(20, 15), AutoSize = true }; txtThickness = new TextBox { Location = new WinFormsPoint(150, 12), Width = 50, Text = "15" }; this.Controls.Add(lblThickness); this.Controls.Add(txtThickness); // 添加默认板厚设置 Label lblDefaultSlab = new Label { Text = "默认板厚(mm):", Location = new WinFormsPoint(220, 15), AutoSize = true }; txtDefaultSlabThickness = new TextBox { Location = new WinFormsPoint(310, 12), Width = 50, Text = "120" }; this.Controls.Add(lblDefaultSlab); this.Controls.Add(txtDefaultSlabThickness); // 绘制按钮 btnDraw = new Button { Text = "开始绘制", Location = new WinFormsPoint(280, 530), Size = new WinFormsSize(100, 35), Font = new WinFormsFont("Microsoft YaHei UI", 9.75F, WinFormsFontStyle.Bold) }; btnDraw.Click += BtnDraw_Click; this.Controls.Add(btnDraw); } catch (SystemException ex) { MessageBox.Show($"窗体初始化错误: {ex.Message}\n{ex.StackTrace}", "严重错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void CreateBeamBottomTab() { try { TabPage tabBeam = new TabPage("梁下及梁侧设置"); mainTabControl.TabPages.Add(tabBeam); // 梁下次龙骨设置 GroupBox gbBeamBottomSecondary = new GroupBox { Text = "梁下次龙骨设置", Location = new Point(10, 10), Size = new Size(700, 60) }; tabBeam.Controls.Add(gbBeamBottomSecondary); int yPos = 25; AddMaterialControls(gbBeamBottomSecondary, ref yPos, out cmbBeamBottomSecMaterial, out cmbBeamBottomSecSpec, out cmbBeamBottomSecDirection, out txtBeamBottomSecSpacing, true); // 梁下主龙骨设置 GroupBox gbBeamBottomPrimary = new GroupBox { Text = "梁下主龙骨设置", Location = new Point(10, 100), Size = new Size(700, 60) }; tabBeam.Controls.Add(gbBeamBottomPrimary); yPos = 25; AddMaterialControls(gbBeamBottomPrimary, ref yPos, out cmbBeamBottomPriMaterial, out cmbBeamBottomPriSpec, out cmbBeamBottomPriDirection, out txtBeamBottomPriSpacing, true); // 梁侧设置 GroupBox gbBeamSide = new GroupBox { Text = "梁侧龙骨设置", Location = new Point(10, 180), Size = new Size(700, 150) }; tabBeam.Controls.Add(gbBeamSide); // 启用梁侧设置 chkBeamSideEnabled = new CheckBox { Text = "启用梁侧设置", Location = new Point(20, 25), Checked = false }; chkBeamSideEnabled.CheckedChanged += ChkBeamSideEnabled_CheckedChanged; gbBeamSide.Controls.Add(chkBeamSideEnabled); // 梁侧次龙骨 GroupBox gbBeamSideSecondary = new GroupBox { Text = "次龙骨", Location = new Point(20, 50), Size = new Size(660, 40) }; gbBeamSide.Controls.Add(gbBeamSideSecondary); int subYPos = 15; AddMaterialControls(gbBeamSideSecondary, ref subYPos, out cmbBeamSideSecMaterial, out cmbBeamSideSecSpec, out cmbBeamSideSecDirection, out txtBeamSideSecSpacing, true); // 梁侧主龙骨 (移除间距输入框) GroupBox gbBeamSidePrimary = new GroupBox { Text = "主龙骨", Location = new Point(20, 100), Size = new Size(660, 40) }; gbBeamSide.Controls.Add(gbBeamSidePrimary); subYPos = 15; // 材料选择 Label lblPriMaterial = new Label { Text = "材料:", Location = new Point(20, subYPos), AutoSize = true }; gbBeamSidePrimary.Controls.Add(lblPriMaterial); cmbBeamSidePriMaterial = new ComboBox { Location = new Point(60, subYPos), Width = 80, DropDownStyle = ComboBoxStyle.DropDownList }; cmbBeamSidePriMaterial.Items.AddRange(new object[] { "木方", "钢管", "方钢", "工字钢" }); cmbBeamSidePriMaterial.SelectedIndex = 0; cmbBeamSidePriMaterial.SelectedIndexChanged += Material_SelectedIndexChanged; gbBeamSidePrimary.Controls.Add(cmbBeamSidePriMaterial); // 规格选择 Label lblPriSpec = new Label { Text = "规格:", Location = new Point(150, subYPos), AutoSize = true }; gbBeamSidePrimary.Controls.Add(lblPriSpec); cmbBeamSidePriSpec = new ComboBox { Location = new Point(190, subYPos), Width = 80 }; UpdateSpecOptions(cmbBeamSidePriMaterial, cmbBeamSidePriSpec); gbBeamSidePrimary.Controls.Add(cmbBeamSidePriSpec); // 布置方式 Label lblPriLayout = new Label { Text = "布置方式:", Location = new Point(300, subYPos), AutoSize = true }; gbBeamSidePrimary.Controls.Add(lblPriLayout); cmbBeamSidePriLayout = new ComboBox { Location = new Point(370, subYPos), Width = 80 }; cmbBeamSidePriLayout.Items.AddRange(new object[] { "双拼", "单根" }); cmbBeamSidePriLayout.SelectedIndex = 0; gbBeamSidePrimary.Controls.Add(cmbBeamSidePriLayout); // 对拉螺栓设置 GroupBox gbBolts = new GroupBox { Text = "对拉螺栓设置", Location = new Point(10, 350), Size = new Size(700, 80) }; tabBeam.Controls.Add(gbBolts); // 螺栓参数 int xPos = 20; int yBoltPos = 25; AddBoltControl(gbBolts, "螺栓直径(mm):", ref xPos, yBoltPos, out txtBoltDiameter, "12"); AddBoltControl(gbBolts, "底部距梁底高(mm):", ref xPos, yBoltPos, out txtBoltStartHeight, "50"); xPos = 20; yBoltPos = 55; AddBoltControl(gbBolts, "板底距螺栓高(mm):", ref xPos, yBoltPos, out txtBoltSlabHeight, "250"); AddBoltControl(gbBolts, "螺栓间距(mm):", ref xPos, yBoltPos, out txtBoltSpacing, "500"); } catch (SystemException ex) { MessageBox.Show($"创建梁下选项卡错误: {ex.Message}\n{ex.StackTrace}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void CreateSlabTab() { try { TabPage tabSlab = new TabPage("板下设置"); mainTabControl.TabPages.Add(tabSlab); // 板下次龙骨设置 GroupBox gbSlabSecondary = new GroupBox { Text = "板下次龙骨设置", Location = new Point(10, 20), Size = new Size(700, 100) }; tabSlab.Controls.Add(gbSlabSecondary); int yPos = 25; AddMaterialControls(gbSlabSecondary, ref yPos, out cmbSlabSecMaterial, out cmbSlabSecSpec, out cmbSlabSecDirection, out txtSlabSecSpacing, true); // 板下主龙骨设置 (修改为顶托内方钢数量) GroupBox gbSlabPrimary = new GroupBox { Text = "板下主龙骨设置", Location = new Point(10, 130), Size = new Size(700, 100) }; tabSlab.Controls.Add(gbSlabPrimary); yPos = 25; // 材料选择 Label lblPriMaterial = new Label { Text = "材料:", Location = new Point(20, yPos), AutoSize = true }; gbSlabPrimary.Controls.Add(lblPriMaterial); cmbSlabPriMaterial = new ComboBox { Location = new Point(60, yPos), Width = 80, DropDownStyle = ComboBoxStyle.DropDownList }; cmbSlabPriMaterial.Items.AddRange(new object[] { "木方", "钢管", "方钢", "工字钢" }); cmbSlabPriMaterial.SelectedIndex = 0; cmbSlabPriMaterial.SelectedIndexChanged += Material_SelectedIndexChanged; gbSlabPrimary.Controls.Add(cmbSlabPriMaterial); // 规格选择 Label lblPriSpec = new Label { Text = "规格:", Location = new Point(150, yPos), AutoSize = true }; gbSlabPrimary.Controls.Add(lblPriSpec); cmbSlabPriSpec = new ComboBox { Location = new Point(190, yPos), Width = 80 }; UpdateSpecOptions(cmbSlabPriMaterial, cmbSlabPriSpec); gbSlabPrimary.Controls.Add(cmbSlabPriSpec); // 布置方向 Label lblDirection = new Label { Text = "布置方向:", Location = new Point(280, yPos), AutoSize = true }; gbSlabPrimary.Controls.Add(lblDirection); cmbSlabPriDirection = new ComboBox { Location = new Point(350, yPos), Width = 70 }; cmbSlabPriDirection.Items.AddRange(new object[] { "横向", "纵向", "垂直" }); cmbSlabPriDirection.SelectedIndex = 0; gbSlabPrimary.Controls.Add(cmbSlabPriDirection); // 顶托内方钢数量 (修改后的字段) Label lblSteelCount = new Label { Text = "顶托方钢数量:", Location = new Point(450, yPos), AutoSize = true }; gbSlabPrimary.Controls.Add(lblSteelCount); txtSlabPriSteelCount = new TextBox { Location = new Point(540, yPos), Width = 40, Text = "1" }; gbSlabPrimary.Controls.Add(txtSlabPriSteelCount); // 根据方向更新控件状态 - 修改为纵向时启用 cmbSlabPriDirection.SelectedIndexChanged += (s, e) => { string direction = cmbSlabPriDirection.SelectedItem?.ToString() ?? ""; bool isLongitudinal = direction == "纵向"; txtSlabPriSteelCount.Enabled = isLongitudinal; txtSlabPriSteelCount.BackColor = isLongitudinal ? SystemColors.Window : SystemColors.Control; }; // 初始状态 txtSlabPriSteelCount.Enabled = (cmbSlabPriDirection.SelectedItem?.ToString() == "纵向"); } catch (SystemException ex) { MessageBox.Show($"创建板下选项卡错误: {ex.Message}\n{ex.StackTrace}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void AddMaterialControls(Control parent, ref int yPos, out ComboBox cmbMaterial, out ComboBox cmbSpec, out ComboBox cmbDirection, out TextBox txtSpacing, bool includeSpacing) { cmbMaterial = null; cmbSpec = null; cmbDirection = null; txtSpacing = null; try { // 材料选择 Label lblMaterial = new Label { Text = "材料:", Location = new Point(20, yPos), AutoSize = true }; parent.Controls.Add(lblMaterial); cmbMaterial = new ComboBox { Location = new Point(60, yPos), Width = 80, DropDownStyle = ComboBoxStyle.DropDownList }; cmbMaterial.Items.AddRange(new object[] { "木方", "钢管", "方钢", "工字钢" }); cmbMaterial.SelectedIndex = 0; cmbMaterial.SelectedIndexChanged += Material_SelectedIndexChanged; parent.Controls.Add(cmbMaterial); // 规格选择 Label lblSpec = new Label { Text = "规格:", Location = new Point(150, yPos), AutoSize = true }; parent.Controls.Add(lblSpec); cmbSpec = new ComboBox { Location = new Point(190, yPos), Width = 80 }; UpdateSpecOptions(cmbMaterial, cmbSpec); parent.Controls.Add(cmbSpec); // 布置方向 Label lblDirection = new Label { Text = "布置方向:", Location = new Point(300, yPos), AutoSize = true }; parent.Controls.Add(lblDirection); cmbDirection = new ComboBox { Location = new Point(370, yPos), Width = 80 }; cmbDirection.Items.AddRange(new object[] { "横向", "纵向", "垂直" }); cmbDirection.SelectedIndex = 0; parent.Controls.Add(cmbDirection); // 间距设置 if (includeSpacing) { Label lblSpacing = new Label { Text = "间距:", Location = new Point(460, yPos), AutoSize = true }; parent.Controls.Add(lblSpacing); txtSpacing = new TextBox { Location = new Point(500, yPos), Width = 70, Tag = parent.Text }; parent.Controls.Add(txtSpacing); // 使用局部变量解决闭包问题 var localCmbDirection = cmbDirection; var localTxtSpacing = txtSpacing; var localLblSpacing = lblSpacing; // 订阅方向改变事件 - 修改为纵向时启用 cmbDirection.SelectedIndexChanged += (s, e) => { UpdateDirectionControls(localCmbDirection, localTxtSpacing, localLblSpacing, parent.Text); }; // 初始化时更新控件状态 UpdateDirectionControls(cmbDirection, txtSpacing, lblSpacing, parent.Text); } yPos += 30; } catch (SystemException ex) { MessageBox.Show($"添加材料控件错误: {ex.Message}\n{ex.StackTrace}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // 关键修改:纵向时启用间距输入 private void UpdateDirectionControls(ComboBox cmbDirection, TextBox txtSpacing, Label lblSpacing, string parentText) { if (cmbDirection == null || txtSpacing == null || lblSpacing == null) return; string direction = cmbDirection.SelectedItem?.ToString() ?? ""; bool isLongitudinal = direction == "纵向"; // 修改为纵向时启用 // 规则:只有纵向方向启用间距输入 txtSpacing.Enabled = isLongitudinal; txtSpacing.BackColor = isLongitudinal ? SystemColors.Window : SystemColors.Control; lblSpacing.Enabled = isLongitudinal; } private void AddBoltControl(Control parent, string label, ref int xPos, int yPos, out TextBox textBox, string defaultValue) { textBox = new TextBox(); try { Label lbl = new Label { Text = label, Location = new Point(xPos, yPos), AutoSize = true }; parent.Controls.Add(lbl); textBox = new TextBox { Location = new Point(xPos + lbl.Width + 5, yPos), Width = 80, Text = defaultValue }; parent.Controls.Add(textBox); xPos += lbl.Width + 90; } catch (SystemException ex) { MessageBox.Show($"添加螺栓控件错误: {ex.Message}\n{ex.StackTrace}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void Material_SelectedIndexChanged(object sender, EventArgs e) { try { ComboBox cmbMaterial = sender as ComboBox; if (cmbMaterial == null) return; foreach (Control ctrl in cmbMaterial.Parent.Controls) { if (ctrl is ComboBox cmbSpec && ctrl != cmbMaterial && ctrl.Location.Y == cmbMaterial.Location.Y) { UpdateSpecOptions(cmbMaterial, cmbSpec); break; } } } catch (SystemException ex) { MessageBox.Show($"材料选择变更错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void UpdateSpecOptions(ComboBox cmbMaterial, ComboBox cmbSpec) { try { if (cmbMaterial?.SelectedItem == null) return; var material = cmbMaterial.SelectedItem.ToString(); if (cmbSpec == null) return; cmbSpec.Items.Clear(); if (materialLib.ContainsKey(material)) { cmbSpec.Items.AddRange(materialLib[material].ToArray()); if (cmbSpec.Items.Count > 0) cmbSpec.SelectedIndex = 0; } } catch (SystemException ex) { MessageBox.Show($"更新规格选项错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void ChkBeamSideEnabled_CheckedChanged(object sender, EventArgs e) { try { bool enabled = chkBeamSideEnabled.Checked; // 启用/禁用所有梁侧控件 cmbBeamSideSecMaterial.Enabled = enabled; cmbBeamSideSecSpec.Enabled = enabled; cmbBeamSideSecDirection.Enabled = enabled; txtBeamSideSecSpacing.Enabled = enabled; cmbBeamSidePriMaterial.Enabled = enabled; cmbBeamSidePriSpec.Enabled = enabled; cmbBeamSidePriLayout.Enabled = enabled; txtBoltDiameter.Enabled = enabled; txtBoltStartHeight.Enabled = enabled; txtBoltSlabHeight.Enabled = enabled; txtBoltSpacing.Enabled = enabled; } catch (SystemException ex) { MessageBox.Show($"梁侧启用状态变更错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void BtnDraw_Click(object sender, EventArgs e) { try { if (!ValidateInputs()) { MessageBox.Show("请填写所有必填参数", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } this.DialogResult = WinFormsDialogResult.OK; this.Close(); } catch (SystemException ex) { MessageBox.Show($"按钮点击错误: {ex.Message}\n{ex.StackTrace}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private bool ValidateInputs() { try { // 验证模板厚度 if (string.IsNullOrEmpty(txtThickness.Text) || !int.TryParse(txtThickness.Text, out _)) return false; // 验证默认板厚 if (string.IsNullOrEmpty(txtDefaultSlabThickness.Text) || !double.TryParse(txtDefaultSlabThickness.Text, out _)) return false; // 验证梁下次龙骨 - 修改为纵向时验证 if (cmbBeamBottomSecDirection.SelectedItem?.ToString() == "纵向" && string.IsNullOrEmpty(txtBeamBottomSecSpacing.Text)) return false; // 验证梁下主龙骨 - 修改为纵向时验证 string beamBottomPriDirection = cmbBeamBottomPriDirection?.SelectedItem?.ToString(); if (beamBottomPriDirection == "纵向" && (string.IsNullOrEmpty(txtBeamBottomPriSpacing.Text) || !double.TryParse(txtBeamBottomPriSpacing.Text, out _))) return false; // 验证梁侧设置 if (chkBeamSideEnabled.Checked) { // 梁侧次龙骨 - 修改为纵向时验证 if (cmbBeamSideSecDirection.SelectedItem?.ToString() == "纵向" && string.IsNullOrEmpty(txtBeamSideSecSpacing.Text)) return false; if (!double.TryParse(txtBoltDiameter.Text, out _) || !double.TryParse(txtBoltStartHeight.Text, out _) || !double.TryParse(txtBoltSlabHeight.Text, out _) || !double.TryParse(txtBoltSpacing.Text, out _)) return false; } // 验证板下次龙骨 - 修改为纵向时验证 if (cmbSlabSecDirection.SelectedItem?.ToString() == "纵向" && !double.TryParse(txtSlabSecSpacing.Text, out _)) return false; // 验证板下主龙骨 string slabPriDirection = cmbSlabPriDirection?.SelectedItem?.ToString(); if (slabPriDirection == "纵向" && (string.IsNullOrEmpty(txtSlabPriSteelCount.Text) || !int.TryParse(txtSlabPriSteelCount.Text, out _))) return false; return true; } catch (SystemException ex) { MessageBox.Show($"输入验证错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } } public BeamParameters GetParameters() { try { return new BeamParameters { Thickness = int.TryParse(txtThickness.Text, out int thick) ? thick : 15, DefaultSlabThickness = double.TryParse(txtDefaultSlabThickness.Text, out double slabThick) ? slabThick : 120, BeamBottom = new BeamBottomSetting { SecondaryMaterial = cmbBeamBottomSecMaterial?.SelectedItem?.ToString() ?? "木方", SecondarySpec = cmbBeamBottomSecSpec?.SelectedItem?.ToString() ?? "40x90", SecondaryDirection = cmbBeamBottomSecDirection?.SelectedItem?.ToString() ?? "横向", SecondarySpacing = txtBeamBottomSecSpacing?.Text ?? "@200", PrimaryMaterial = cmbBeamBottomPriMaterial?.SelectedItem?.ToString() ?? "木方", PrimarySpec = cmbBeamBottomPriSpec?.SelectedItem?.ToString() ?? "100x100", PrimaryDirection = cmbBeamBottomPriDirection?.SelectedItem?.ToString() ?? "纵向", PrimarySpacing = txtBeamBottomPriSpacing?.Text ?? "" }, BeamSide = new BeamSideSetting { Enabled = chkBeamSideEnabled.Checked, SecondaryMaterial = cmbBeamSideSecMaterial?.SelectedItem?.ToString() ?? "木方", SecondarySpec = cmbBeamSideSecSpec?.SelectedItem?.ToString() ?? "40x90", SecondaryDirection = cmbBeamSideSecDirection?.SelectedItem?.ToString() ?? "垂直", SecondarySpacing = txtBeamSideSecSpacing?.Text ?? "@200", PrimaryMaterial = cmbBeamSidePriMaterial?.SelectedItem?.ToString() ?? "木方", PrimarySpec = cmbBeamSidePriSpec?.SelectedItem?.ToString() ?? "100x100", PrimaryLayout = cmbBeamSidePriLayout?.SelectedItem?.ToString() ?? "双拼", BoltDiameter = double.TryParse(txtBoltDiameter.Text, out double boltDia) ? boltDia : 12, BoltStartHeight = double.TryParse(txtBoltStartHeight.Text, out double boltStart) ? boltStart : 50, BoltSlabHeight = double.TryParse(txtBoltSlabHeight.Text, out double boltSlab) ? boltSlab : 250, BoltSpacing = double.TryParse(txtBoltSpacing.Text, out double boltSpace) ? boltSpace : 500 }, Slab = new SlabSetting { SecondaryMaterial = cmbSlabSecMaterial?.SelectedItem?.ToString() ?? "木方", SecondarySpec = cmbSlabSecSpec?.SelectedItem?.ToString() ?? "40x90", SecondaryDirection = cmbSlabSecDirection?.SelectedItem?.ToString() ?? "横向", SecondarySpacing = double.TryParse(txtSlabSecSpacing.Text, out double secSpacing) ? secSpacing : 200, PrimaryMaterial = cmbSlabPriMaterial?.SelectedItem?.ToString() ?? "木方", PrimarySpec = cmbSlabPriSpec?.SelectedItem?.ToString() ?? "100x100", PrimaryDirection = cmbSlabPriDirection?.SelectedItem?.ToString() ?? "纵向", SteelCount = int.TryParse(txtSlabPriSteelCount.Text, out int steelCount) ? steelCount : 1 } }; } catch (SystemException ex) { MessageBox.Show($"获取参数错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return new BeamParameters(); } } } #endregion #region AutoCAD 命令 public class BeamSectionCommands { [CommandMethod("DB")] public static void DrawBeamSection() { try { var doc = AcadApplication.DocumentManager.MdiActiveDocument; if (doc == null) { AcadApplication.ShowAlertDialog("没有活动文档!"); return; } var db = doc.Database; var ed = doc.Editor; using (var form = new BeamSectionForm()) { var res = AcadApplication.ShowModalDialog(form); if (res != WinFormsDialogResult.OK) { ed.WriteMessage("\n用户取消操作。"); return; } // 获取参数 var parameters = form.GetParameters(); // 开始连续绘制 DrawContinuousBeamSections(ed, db, parameters); } } catch (SystemException ex) { var doc = AcadApplication.DocumentManager.MdiActiveDocument; if (doc != null) { var ed = doc.Editor; ed.WriteMessage($"\n严重错误: {ex.Message}\n{ex.StackTrace}"); } else { MessageBox.Show($"严重错误: {ex.Message}", "梁板剖面图错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } private static void DrawContinuousBeamSections(Editor ed, Database db, BeamParameters parameters) { try { List<BeamSegment> segments = new List<BeamSegment>(); double currentSlabThickness = parameters.DefaultSlabThickness; double currentSlabOffset = 0; bool isFirstSegment = true; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTableRecord btr = (BlockTableRecord)tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite); // 1. 获取第一点 Point3d startPt = GetPoint(ed, "请点击梁的第一点(按ESC结束):"); if (double.IsNaN(startPt.X)) return; Point3d currentPt = startPt; double previousBeamHeight = 0; while (true) { // 2. 获取第二点(后续段增加选项) string promptMsg = isFirstSegment ? "请点击梁的第二点(按ESC结束):" : "请点击梁的第二点[板厚(A)/升降板(S)]:"; Point3d endPt = GetPoint(ed, promptMsg, currentPt); if (double.IsNaN(endPt.X)) break; // 3. 第一段需要输入梁高 double beamHeight; if (isFirstSegment) { beamHeight = GetHeight(ed); if (double.IsNaN(beamHeight)) break; previousBeamHeight = beamHeight; isFirstSegment = false; } else { beamHeight = previousBeamHeight; // 4. 处理板厚/升降板选项 var pko = new PromptKeywordOptions("\n设置板参数[板厚(A)/升降板(S)/继续(C)] <C>:"); pko.Keywords.Add("A"); pko.Keywords.Add("S"); pko.Keywords.Add("C"); pko.Keywords.Default = "C"; var pkr = ed.GetKeywords(pko); if (pkr.Status != PromptStatus.OK) break; if (pkr.StringResult == "A") { var pdo = new PromptDoubleOptions("\n输入板厚(mm):"); pdo.DefaultValue = currentSlabThickness; pdo.UseDefaultValue = true; pdo.AllowNegative = false; var pdr = ed.GetDouble(pdo); if (pdr.Status != PromptStatus.OK) break; currentSlabThickness = pdr.Value; } else if (pkr.StringResult == "S") { var pdo = new PromptDoubleOptions("\n请输入升降板高度(升板为正数,降板为负数)mm:"); pdo.DefaultValue = currentSlabOffset; pdo.UseDefaultValue = true; pdo.AllowNegative = true; var pdr = ed.GetDouble(pdo); if (pdr.Status != PromptStatus.OK) break; currentSlabOffset = pdr.Value; } } // 创建梁段 var segment = new BeamSegment { Start = currentPt, End = endPt, Height = beamHeight, Slab = new SlabParams { Thickness = currentSlabThickness, Offset = currentSlabOffset } }; segments.Add(segment); currentPt = endPt; previousBeamHeight = beamHeight; } // 绘制所有梁段 if (segments.Count > 0) { DrawBeamSegments(ed, btr, tr, segments, parameters); tr.Commit(); ed.WriteMessage($"\n成功绘制 {segments.Count} 段梁板剖面!"); } else { tr.Abort(); ed.WriteMessage("\n未绘制任何梁段。"); } } } catch (SystemException ex) { ed.WriteMessage($"\n错误: {ex.Message}"); } } private static void DrawBeamSegments(Editor ed, BlockTableRecord btr, Transaction tr, List<BeamSegment> segments, BeamParameters parameters) { try { // 创建多段线 Polyline poly = new Polyline(); poly.SetDatabaseDefaults(); // 添加起点 Point3d startPt = segments[0].Start; poly.AddVertexAt(0, new Point2d(startPt.X, startPt.Y), 0, 0, 0); // 遍历所有梁段 foreach (var segment in segments) { // 计算梁底位置 (向下偏移梁高) Point3d beamBottomPt = new Point3d( segment.End.X, segment.End.Y + segment.Height, segment.End.Z); // 计算板底位置 (梁底再向下偏移板厚) Point3d slabBottomPt = new Point3d( segment.End.X, beamBottomPt.Y + segment.Slab.Thickness, segment.End.Z); // 添加顶点 poly.AddVertexAt(poly.NumberOfVertices, new Point2d(segment.End.X, segment.End.Y), 0, 0, 0); poly.AddVertexAt(poly.NumberOfVertices, new Point2d(beamBottomPt.X, beamBottomPt.Y), 0, 0, 0); poly.AddVertexAt(poly.NumberOfVertices, new Point2d(slabBottomPt.X, slabBottomPt.Y), 0, 0, 0); } // 闭合多段线 poly.Closed = true; btr.AppendEntity(poly); tr.AddNewlyCreatedDBObject(poly, true); // 添加混凝土填充 Hatch hatch = new Hatch(); hatch.SetDatabaseDefaults(); hatch.SetHatchPattern(HatchPatternType.PreDefined, "ANSI31"); hatch.PatternScale = 50; hatch.ColorIndex = 8; btr.AppendEntity(hatch); tr.AddNewlyCreatedDBObject(hatch, true); hatch.Associative = true; hatch.AppendLoop(HatchLoopTypes.Outermost, new ObjectIdCollection { poly.ObjectId }); // 添加标注 DrawAllDimensionsAndMembers(ed, btr, tr, segments, parameters); } catch (SystemException ex) { ed.WriteMessage($"\n绘制梁段错误: {ex.Message}"); } } private static void DrawAllDimensionsAndMembers(Editor ed, BlockTableRecord btr, Transaction tr, List<BeamSegment> segments, BeamParameters parameters) { try { // 绘制每个梁段的尺寸标注 foreach (var segment in segments) { // 梁宽标注 var dimWidth = new AlignedDimension(); dimWidth.SetDatabaseDefaults(); dimWidth.XLine1Point = segment.Start; dimWidth.XLine2Point = new Point3d(segment.End.X, segment.Start.Y, segment.Start.Z); dimWidth.DimLinePoint = new Point3d( (segment.Start.X + segment.End.X) / 2, segment.Start.Y - 50, segment.Start.Z); btr.AppendEntity(dimWidth); tr.AddNewlyCreatedDBObject(dimWidth, true); // 梁高标注 var dimHeight = new AlignedDimension(); dimHeight.SetDatabaseDefaults(); dimHeight.XLine1Point = segment.Start; dimHeight.XLine2Point = new Point3d(segment.Start.X, segment.Start.Y + segment.Height, segment.Start.Z); dimHeight.DimLinePoint = new Point3d( segment.Start.X - 50, (segment.Start.Y + segment.Start.Y + segment.Height) / 2, segment.Start.Z); btr.AppendEntity(dimHeight); tr.AddNewlyCreatedDBObject(dimHeight, true); // 板厚标注 Point3d beamBottom = new Point3d( segment.End.X, segment.End.Y + segment.Height, segment.End.Z); Point3d slabBottom = new Point3d( segment.End.X, beamBottom.Y + segment.Slab.Thickness, segment.End.Z); var dimSlab = new AlignedDimension(); dimSlab.SetDatabaseDefaults(); dimSlab.XLine1Point = beamBottom; dimSlab.XLine2Point = slabBottom; dimSlab.DimLinePoint = new Point3d( segment.End.X + 50, (beamBottom.Y + slabBottom.Y) / 2, segment.End.Z); btr.AppendEntity(dimSlab); tr.AddNewlyCreatedDBObject(dimSlab, true); } // 绘制主次龙骨(简化的实现) // 实际应用中应根据参数设置详细绘制 } catch (SystemException ex) { ed.WriteMessage($"\n标注和龙骨绘制错误: {ex.Message}"); } } private static Point3d GetPoint(Editor ed, string message, Point3d? basePoint = null) { try { var opts = new PromptPointOptions(message); if (basePoint.HasValue) { opts.UseBasePoint = true; opts.BasePoint = basePoint.Value; } var res = ed.GetPoint(opts); return res.Status == PromptStatus.OK ? res.Value : new Point3d(double.NaN, double.NaN, double.NaN); } catch { return new Point3d(double.NaN, double.NaN, double.NaN); } } private static double GetHeight(Editor ed) { try { var opts = new PromptDoubleOptions("请输入梁高(mm):"); opts.AllowNegative = false; var res = ed.GetDouble(opts); return res.Status == PromptStatus.OK ? res.Value : double.NaN; } catch { return double.NaN; } } private static void DrawBeamBottomMembers(BlockTableRecord btr, Transaction tr, Polyline beamPoly, BeamParameters parameters) { double beamLength = beamPoly.Length; // 梁下次龙骨 if (parameters.BeamBottom.SecondaryDirection == "纵向") { double spacing = ParseSpacing(parameters.BeamBottom.SecondarySpacing, beamLength); for (double pos = spacing; pos < beamLength; pos += spacing) { Point3d loc = beamPoly.GetPointAtDist(pos); DrawMemberSection(btr, tr, loc, parameters.BeamBottom.SecondarySpec, 0); } } // 梁下主龙骨 if (parameters.BeamBottom.PrimaryDirection == "纵向") { if (double.TryParse(parameters.BeamBottom.PrimarySpacing, out double spacing)) { for (double pos = spacing; pos < beamLength; pos += spacing) { Point3d loc = beamPoly.GetPointAtDist(pos); DrawMemberSection(btr, tr, loc, parameters.BeamBottom.PrimarySpec, 0); } } } else if (parameters.BeamBottom.PrimaryDirection == "纵向") { double spacing = 1000; // 默认纵向间距 for (double pos = spacing; pos < beamLength; pos += spacing) { Point3d loc = beamPoly.GetPointAtDist(pos); DrawMemberSection(btr, tr, loc, parameters.BeamBottom.PrimarySpec, 0); } } // 梁侧龙骨(如果启用) if (parameters.BeamSide.Enabled) { // 实现梁侧龙骨绘制逻辑... } } private static void DrawSlabMembers(BlockTableRecord btr, Transaction tr, Polyline beamPoly, BeamParameters parameters) { // 板下次龙骨 if (parameters.Slab.SecondaryDirection == "纵向") { double spacing = parameters.Slab.SecondarySpacing; for (double pos = spacing; pos < beamPoly.Length; pos += spacing) { Point3d loc = beamPoly.GetPointAtDist(pos); DrawMemberSection(btr, tr, loc, parameters.Slab.SecondarySpec, 0); } } // 板下主龙骨 if (parameters.Slab.PrimaryDirection == "纵向") { // 根据顶托内方钢数量绘制 for (int i = 0; i < parameters.Slab.SteelCount; i++) { // 绘制顶托内的方钢 // 这里需要根据实际位置计算 } } else if (parameters.Slab.PrimaryDirection == "纵向") { double spacing = 1000; // 默认纵向间距 for (double pos = spacing; pos < beamPoly.Length; pos += spacing) { Point3d loc = beamPoly.GetPointAtDist(pos); DrawMemberSection(btr, tr, loc, parameters.Slab.PrimarySpec, 0); } } } private static void DrawMemberSection(BlockTableRecord btr, Transaction tr, Point3d loc, string spec, double angle) { double width = 10, height = 10; ParseMemberSpec(spec, ref width, ref height); var rect = new Polyline(); rect.AddVertexAt(0, new Point2d(loc.X - width / 2, loc.Y - height / 2), 0, 0, 0); rect.AddVertexAt(1, new Point2d(loc.X + width / 2, loc.Y - height / 2), 0, 0, 0); rect.AddVertexAt(2, new Point2d(loc.X + width / 2, loc.Y + height / 2), 0, 0, 0); rect.AddVertexAt(3, new Point2d(loc.X - width / 2, loc.Y + height / 2), 0, 0, 0); rect.Closed = true; if (angle != 0) { Matrix3d rotation = Matrix3d.Rotation(angle, Vector3d.ZAxis, loc); rect.TransformBy(rotation); } btr.AppendEntity(rect); tr.AddNewlyCreatedDBObject(rect, true); } private static void ParseMemberSpec(string spec, ref double width, ref double height) { if (spec.Contains("x") && !spec.Contains("Φ")) { string[] parts = spec.Split('x'); if (parts.Length >= 2) { string wStr = new string(parts[0].Where(c => char.IsDigit(c) || c == '.').ToArray()); string hStr = new string(parts[1].Where(c => char.IsDigit(c) || c == '.').ToArray()); double.TryParse(wStr, out width); double.TryParse(hStr, out height); } } else if (spec.Contains("Φ")) { string diamPart = spec.Split('x')[0].Replace("Φ", ""); string wStr = new string(diamPart.Where(c => char.IsDigit(c) || c == '.').ToArray()); double.TryParse(wStr, out width); height = width; } else if (spec.StartsWith("I")) { string num = new string(spec.Where(char.IsDigit).ToArray()); if (int.TryParse(num, out int size)) { width = size * 0.5; height = size; } } if (width <= 0) width = 10; if (height <= 0) height = 10; } private static double ParseSpacing(string input, double totalLength) { if (input.Contains("@")) { string numPart = new string(input.Replace("@", "").Where(c => char.IsDigit(c) || c == '.').ToArray()); if (double.TryParse(numPart, out double spacing)) return spacing; } else if (input.Contains("根")) { string numPart = new string(input.Where(char.IsDigit).ToArray()); if (int.TryParse(numPart, out int count) && count > 1) return totalLength / (count - 1); } return 200; } } #endregion } 命令: NETLOAD 命令: DB 请点击梁的第一点(按ESC结束): 请点击梁的第二点(按ESC结束): <正交 开> 请输入梁高(mm): 1000 请点击梁的第二点[板厚(A)/升降板(S)]: A 点无效。 请点击梁的第二点[板厚(A)/升降板(S)]: S 点无效。 请点击梁的第二点[板厚(A)/升降板(S)]: 设置板参数[板厚(A)/升降板(S)/继续(C)] <C> [A/S/C] <C>: C 请点击梁的第二点[板厚(A)/升降板(S)]: 设置板参数[板厚(A)/升降板(S)/继续(C)] <C> [A/S/C] <C>: *取消* 成功绘制 2 段梁板剖面! 命令: 正在重生成模型。 绘制步骤错误,未按以下步骤实现绘制: 1、命令栏显示:请点击梁的第一点: 2、命令栏显示:点击梁的第二点: 3、命令栏显示:请输入梁高(mm): 4、命令栏显示:请点击梁的第一点: 5、命令栏显示:请点击梁的第二点[板厚(A)升降板(S)]: 如果选(A): 5.1、命令栏显示:输入板厚(mm)<120>: 6、命令栏显示:请点击梁的第二点[板厚(A)升降板(S)]: 如果选(S): 6.1、命令栏显示:请输入升降板高度(升板为正数,降板为负数)mm<0.00>: 7、命令栏显示:请点击梁的第二点[板厚(A)升降板(S)]: 如果无需选择(A)(S) 7.1、命令栏显示:请点击梁的第二点: 8、命令栏显示:请点击梁高(mm): 接下来重复4至8步骤 4、命令栏显示:请点击梁的第一点: 5、命令栏显示:请点击梁的第二点[板厚(A)升降板(S)]: 如果选(A): 5.1、命令栏显示:输入板厚(mm)<120>: 6、命令栏显示:请点击梁的第二点[板厚(A)升降板(S)]: 如果选(S): 6.1、命令栏显示:请输入升降板高度(升板为正数,降板为负数)mm<0.00>: 7、命令栏显示:请点击梁的第二点[板厚(A)升降板(S)]: 如果无需选择(A)(S) 7.1、命令栏显示:请点击梁的第二点: 9、命令栏显示:请点击梁高(mm):
08-07
using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Linq; using System.Windows.Forms; using OxyPlot; using OxyPlot.Series; using OxyPlot.WindowsForms; using OxyPlot.Axes; using MathNet.Numerics; using MathNet.Numerics.Interpolation; using Microsoft.VisualBasic.FileIO; using PdfSharp.Pdf; using PdfSharp.Drawing; namespace TestPro { public partial class Form1 : Form { private List<double> depthData = new List<double>(); private List<double> gammaData = new List<double>(); private PlotModel plotModel; private PlotView plotView; private Panel plotPanel; private ComboBox interpolationComboBox; private Button exportPdfButton; private Label statusLabel; private double scaleRatio = 200; // 默认比例尺1:200 private double minVisibleDepth = 0; private double maxVisibleDepth = 100; private const double VisibleDepthRange = 100; // 初始可见深度范围 private double pixelsPerMeter = 20; // 增加默认每米像素数 private double visibleDepthRange = 100; // 可见深度范围(米) private double minDepth = 0; private double maxDepth = 0; private VScrollBar depthScrollBar; // 垂直滚动条 private double totalDepthRange = 0; // 总深度范围 private bool isScrollBarDragging = false; // 标记是否正在拖动滚动条 private double dpi = 96; // 默认DPI值 public Form1() { InitializeComponent(); InitializeCustomComponents(); LoadData(); SetupPlotModel(); SetupScrollBar(); } private void InitializeCustomComponents() { this.Text = "自然伽马测井曲线可视化工具"; this.Size = new Size(1200, 800); this.StartPosition = FormStartPosition.CenterScreen; // 获取系统DPI using (Graphics g = this.CreateGraphics()) { dpi = g.DpiY; } // 创建主布局面板 var mainPanel = new Panel { Dock = DockStyle.Fill }; this.Controls.Add(mainPanel); // 创建顶部控制面板 var controlPanel = new Panel { Dock = DockStyle.Top, Height = 50, BackColor = Color.LightGray }; mainPanel.Controls.Add(controlPanel); // 创建插值方法选择下拉框 interpolationComboBox = new ComboBox { Location = new Point(20, 15), Width = 150, DropDownStyle = ComboBoxStyle.DropDownList }; interpolationComboBox.Items.AddRange(new object[] { "线性插值", "三次样条", "PCHIP", "Akima" }); interpolationComboBox.SelectedIndex = 2; // 默认选择PCHIP interpolationComboBox.SelectedIndexChanged += InterpolationComboBox_SelectedIndexChanged; controlPanel.Controls.Add(interpolationComboBox); // 添加比例尺选择 var scaleLabel = new Label { Text = "比例尺:", Location = new Point(190, 18), AutoSize = true }; controlPanel.Controls.Add(scaleLabel); var scaleComboBox = new ComboBox { Location = new Point(240, 15), Width = 80, DropDownStyle = ComboBoxStyle.DropDownList }; scaleComboBox.Items.AddRange(new object[] { "1:100", "1:200", "1:500" }); scaleComboBox.SelectedIndex = 1; // 默认1:200 // 初始计算像素/米 - 使用优化的公式 pixelsPerMeter = CalculatePixelsPerMeter(200, dpi); scaleComboBox.SelectedIndexChanged += (s, e) => { string selectedScale = scaleComboBox.SelectedItem.ToString(); switch (selectedScale) { case "1:100": scaleRatio = 100; pixelsPerMeter = CalculatePixelsPerMeter(100, dpi); break; case "1:200": scaleRatio = 200; pixelsPerMeter = CalculatePixelsPerMeter(200, dpi); break; case "1:500": scaleRatio = 500; pixelsPerMeter = CalculatePixelsPerMeter(500, dpi); break; } // 重新计算可见深度范围 CalculateVisibleDepthRange(); // 更新图表 UpdatePlot(); // 更新滚动条 UpdateScrollBar(); }; controlPanel.Controls.Add(scaleComboBox); // 比例因子调整滑块 - 修改为仅影响深度范围 var scaleFactorTrackBar = new TrackBar { Location = new Point(520, 15), Width = 150, Minimum = 50, Maximum = 200, Value = 100, TickFrequency = 10 }; scaleFactorTrackBar.ValueChanged += (s, e) => { double factor = scaleFactorTrackBar.Value / 100.0; double basePixels = CalculatePixelsPerMeter(scaleRatio, dpi); pixelsPerMeter = basePixels * factor; // 仅更新可见范围和图表 CalculateVisibleDepthRange(); UpdatePlot(); UpdateScrollBar(); }; controlPanel.Controls.Add(scaleFactorTrackBar); // 创建PDF导出按钮 exportPdfButton = new Button { Text = "导出PDF", Location = new Point(690, 15), Size = new Size(80, 25) }; exportPdfButton.Click += ExportPdfButton_Click; controlPanel.Controls.Add(exportPdfButton); // 创建状态标签 statusLabel = new Label { Dock = DockStyle.Bottom, Height = 20, Text = "就绪", TextAlign = ContentAlignment.MiddleLeft, BorderStyle = BorderStyle.FixedSingle }; mainPanel.Controls.Add(statusLabel); // 创建绘图面板容器 var plotContainer = new Panel { Dock = DockStyle.Fill, BackColor = Color.White }; mainPanel.Controls.Add(plotContainer); // 创建绘图面板(带滚动条) plotPanel = new Panel { Dock = DockStyle.Left, //Location = new Point(0, 0), Width = 365, //Height = plotContainer.Height, BackColor = Color.White }; plotContainer.Controls.Add(plotPanel); // 创建垂直滚动条 depthScrollBar = new VScrollBar { Dock = DockStyle.Right, Width = 20 }; depthScrollBar.Scroll += DepthScrollBar_Scroll; depthScrollBar.MouseDown += (s, e) => isScrollBarDragging = true; depthScrollBar.MouseUp += (s, e) => isScrollBarDragging = false; plotContainer.Controls.Add(depthScrollBar); // 创建PlotView plotView = new PlotView { Dock = DockStyle.Fill, BackColor = Color.White }; // 创建自定义控制器并禁用所有交互 var customController = new PlotController(); customController.UnbindAll(); // 解绑所有默认操作 plotView.Controller = customController; // 使用标准的MouseWheel事件处理 plotView.MouseWheel += PlotView_MouseWheel; plotPanel.Controls.Add(plotView); // 添加Resize事件处理 this.Resize += Form1_Resize; } // 优化的每米像素计算 private double CalculatePixelsPerMeter(double scaleRatio, double dpi) { // 比例尺1:100表示1厘米代表1米 // 公式: pixelsPerMeter = (100 / scaleRatio) * (dpi / 2.54) return (100.0 / scaleRatio) * (dpi / 2.54); } private void SetupScrollBar() { if (depthData.Count == 0) return; // 计算总深度范围 totalDepthRange = maxDepth - minDepth; // 设置滚动条范围 depthScrollBar.Minimum = 0; depthScrollBar.Maximum = (int)Math.Ceiling(totalDepthRange - visibleDepthRange); depthScrollBar.SmallChange = 1; // 滚动步长为1米 depthScrollBar.LargeChange = (int)visibleDepthRange; // 一页的大小为当前可见深度范围 // 设置滚动条当前位置 depthScrollBar.Value = (int)(minVisibleDepth - minDepth); } private void UpdateScrollBar() { if (depthData.Count == 0) return; // 更新滚动条范围 depthScrollBar.Maximum = (int)Math.Ceiling(totalDepthRange - visibleDepthRange); depthScrollBar.LargeChange = (int)visibleDepthRange; // 更新滚动条位置 depthScrollBar.Value = Math.Max(0, Math.Min(depthScrollBar.Maximum, (int)(minVisibleDepth - minDepth))); } private void DepthScrollBar_Scroll(object sender, ScrollEventArgs e) { // 实时更新,不再检查ScrollEventType double newMinDepth = minDepth + e.NewValue; double newMaxDepth = newMinDepth + visibleDepthRange; // 只有当深度范围确实变化时才更新 if (Math.Abs(newMinDepth - minVisibleDepth) > 0.01 || Math.Abs(newMaxDepth - maxVisibleDepth) > 0.01) { minVisibleDepth = newMinDepth; maxVisibleDepth = newMaxDepth; // 确保不超出数据范围 if (maxVisibleDepth > maxDepth) { maxVisibleDepth = maxDepth; minVisibleDepth = maxDepth - visibleDepthRange; } if (minVisibleDepth < minDepth) { minVisibleDepth = minDepth; maxVisibleDepth = minDepth + visibleDepthRange; } // 立即更新图表 UpdatePlot(); // 如果正在拖动,强制重绘滚动条 if (isScrollBarDragging) { depthScrollBar.Refresh(); } } } private void Form1_Resize(object sender, EventArgs e) { // 仅重新计算可见深度范围(不改变每米像素数) CalculateVisibleDepthRange(); UpdateScrollBar(); UpdatePlot(); } private void CalculateVisibleDepthRange() { // 根据屏幕高度和固定的pixelsPerMeter计算可见深度范围 if (plotView != null && plotView.Height > 0) { // 获取绘图区域高度(像素) int plotAreaHeight = plotView.Height; // 使用固定的pixelsPerMeter计算可见深度范围(米) visibleDepthRange = plotAreaHeight / pixelsPerMeter; // 确保可见范围至少为10米 if (visibleDepthRange < 10) visibleDepthRange = 10; // 确保不超过总深度范围 if (visibleDepthRange > totalDepthRange) { visibleDepthRange = totalDepthRange; } // 更新当前可见范围 maxVisibleDepth = minVisibleDepth + visibleDepthRange; // 确保不超过最大深度 if (maxVisibleDepth > maxDepth) { maxVisibleDepth = maxDepth; minVisibleDepth = maxDepth - visibleDepthRange; if (minVisibleDepth < minDepth) minVisibleDepth = minDepth; } } } private void LoadData() { try { // 使用OpenFileDialog选择CSV文件 using (var openFileDialog = new OpenFileDialog()) { openFileDialog.Filter = "CSV文件|*.csv|所有文件|*.*"; openFileDialog.Title = "选择测井数据文件"; if (openFileDialog.ShowDialog() == DialogResult.OK) { statusLabel.Text = "正在加载数据..."; Application.DoEvents(); // 使用TextFieldParser读取CSV using (var parser = new TextFieldParser(openFileDialog.FileName)) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); parser.HasFieldsEnclosedInQuotes = true; // 跳过前3行头信息 for (int i = 0; i < 4; i++) { parser.ReadLine(); } // 读取数据 while (!parser.EndOfData) { string[] fields = parser.ReadFields(); if (fields.Length >= 2) { // 修复:先声明变量再在TryParse中使用 double depth; double gamma; // 假设第一列是深度,第二列是伽马值 if (double.TryParse(fields[2], out depth) && double.TryParse(fields[6], out gamma)) { depthData.Add(depth); gammaData.Add(gamma); } } } } statusLabel.Text = $"已加载 {depthData.Count} 个数据点"; } else { statusLabel.Text = "未选择文件,使用示例数据"; GenerateSampleData(); } } if (depthData.Count > 0) { minDepth = depthData.Min(); maxDepth = depthData.Max(); totalDepthRange = maxDepth - minDepth; // 设置初始可见深度范围 CalculateVisibleDepthRange(); minVisibleDepth = minDepth; maxVisibleDepth = minDepth + visibleDepthRange; // 确保不超过最大深度 if (maxVisibleDepth > maxDepth) { maxVisibleDepth = maxDepth; minVisibleDepth = maxDepth - visibleDepthRange; if (minVisibleDepth < minDepth) minVisibleDepth = minDepth; } } } catch (Exception ex) { statusLabel.Text = $"错误: {ex.Message}"; GenerateSampleData(); } } private void GenerateSampleData() { // 生成示例数据 depthData.Clear(); gammaData.Clear(); double depth = 1000; Random rand = new Random(); for (int i = 0; i < 500; i++) { depth += 0.5; double gamma = 50 + 30 * Math.Sin(depth / 50) + rand.NextDouble() * 10; depthData.Add(depth); gammaData.Add(gamma); } // 设置示例数据的深度范围 minDepth = depthData.Min(); maxDepth = depthData.Max(); totalDepthRange = maxDepth - minDepth; // 设置初始可见深度范围 CalculateVisibleDepthRange(); minVisibleDepth = minDepth; maxVisibleDepth = minDepth + visibleDepthRange; } private void SetupPlotModel() { plotModel = new PlotModel { Title = "自然伽马测井曲线", TitleFontSize = 14, TitleFontWeight = OxyPlot.FontWeights.Bold, PlotMargins = new OxyThickness(60, 40, 60, 60) }; // 设置Y轴(深度)在右侧 - 固定网格间距 var depthAxis = new LinearAxis { Position = AxisPosition.Right, Title = "深度 (m)", Key = "Depth", StartPosition = 1, EndPosition = 0, // 反转Y轴 MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, MajorGridlineColor = OxyColor.FromRgb(180, 180, 180), MinorGridlineColor = OxyColor.FromRgb(220, 220, 220), Minimum = minVisibleDepth, Maximum = maxVisibleDepth, // 固定网格间距:每5米主网格,每1米次网格 MajorStep = 5, // 固定值,不随窗体变化 MinorStep = 1, // 固定值 // 添加以下属性确保步长绝对不变 IsPanEnabled = false, IsZoomEnabled = false, AbsoluteMaximum = double.MaxValue, AbsoluteMinimum = double.MinValue, AxislineThickness = 2, ExtraGridlineThickness = 2 }; plotModel.Axes.Add(depthAxis); // 设置X轴(伽马值)在顶部 var gammaAxis = new LinearAxis { Position = AxisPosition.Top, Title = "伽马值 (API)", Key = "Gamma", Minimum = 0, Maximum = 200, MajorStep = 20, // 10个刻度 (200/20=10) MinorStep = 5, MajorGridlineStyle = LineStyle.Solid, //MinorGridlineStyle = LineStyle.Dot, MajorGridlineColor = OxyColor.FromRgb(180, 180, 180), //MinorGridlineColor = OxyColor.FromRgb(220, 220, 220), AxislineThickness = 2 }; plotModel.Axes.Add(gammaAxis); // 添加原始数据点 //var scatterSeries = new ScatterSeries //{ // Title = "原始数据点", // MarkerType = MarkerType.Circle, // MarkerSize = 2, // MarkerFill = OxyColor.FromRgb(100, 100, 100) //}; //for (int i = 0; i < depthData.Count; i++) //{ // scatterSeries.Points.Add(new ScatterPoint(gammaData[i], depthData[i])); //} //plotModel.Series.Add(scatterSeries); plotView.Model = plotModel; } private void PlotView_MouseWheel(object sender, MouseEventArgs e) { // 计算滚轮方向 double direction = e.Delta > 0 ? -1 : 1; double scrollAmount = direction * 1; // 每次滚动1米 // 更新可见深度范围 minVisibleDepth += scrollAmount; maxVisibleDepth += scrollAmount; // 确保不超出数据范围 if (minVisibleDepth < minDepth) { minVisibleDepth = minDepth; maxVisibleDepth = minDepth + visibleDepthRange; } if (maxVisibleDepth > maxDepth) { maxVisibleDepth = maxDepth; minVisibleDepth = maxDepth - visibleDepthRange; } // 更新滚动条位置 depthScrollBar.Value = (int)(minVisibleDepth - minDepth); // 更新图表 UpdatePlot(); } private void InterpolationComboBox_SelectedIndexChanged(object sender, EventArgs e) { UpdatePlot(); } private void UpdatePlot() { if (depthData.Count == 0) return; // 更新深度轴范围 var depthAxis = plotModel.Axes.FirstOrDefault(a => a.Key == "Depth") as LinearAxis; if (depthAxis != null) { depthAxis.Minimum = minVisibleDepth; depthAxis.Maximum = maxVisibleDepth; } // 移除之前的插值曲线 var seriesToRemove = plotModel.Series.Where(s => s is LineSeries).ToList(); foreach (var series in seriesToRemove) { plotModel.Series.Remove(series); } // 获取选择的插值方法 string method = interpolationComboBox.SelectedItem.ToString(); // 执行插值 IInterpolation interpolationFunc = CreateInterpolationFunction(depthData, gammaData, method); // 创建插值曲线 - 使用正确的平滑设置 var lineSeries = new LineSeries { Title = $"{method}插值", Color = OxyColor.FromRgb(0, 100, 200), StrokeThickness = 1.5 }; // 根据插值方法选择合适的平滑算法 if (method == "线性插值") { // 线性插值不需要额外平滑 } else { // 使用Catmull-Rom样条插值算法 lineSeries.InterpolationAlgorithm = InterpolationAlgorithms.CatmullRomSpline; // 使用CanonicalSpline并设置张力参数(如果可用) // lineSeries.InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline; // lineSeries.CanonicalSplineTension = 0.5; } // 添加当前可见范围内的点 double step = Math.Max(0.1, visibleDepthRange / 500); for (double d = minVisibleDepth; d <= maxVisibleDepth; d += step) { double gamma = interpolationFunc.Interpolate(d); lineSeries.Points.Add(new DataPoint(gamma, d)); } plotModel.Series.Add(lineSeries); plotModel.InvalidatePlot(true); // 计算5米网格线对应的像素距离 double gridSpacingPixels = 5 * pixelsPerMeter; statusLabel.Text = $"显示深度: {minVisibleDepth:F1}m - {maxVisibleDepth:F1}m ({visibleDepthRange:F1}m) | 总深度: {minDepth:F1}m - {maxDepth:F1}m | 插值: {method} | 比例: 1:{scaleRatio} | 网格间距: {gridSpacingPixels:F1}像素"; } private Tuple<List<double>, List<double>> SmoothCurve(List<double> depth, List<double> gamma, string method) { // 去除重复深度值 var uniqueDepth = new List<double>(); var uniqueGamma = new List<double>(); var seen = new HashSet<double>(); for (int i = 0; i < depth.Count; i++) { if (seen.Contains(depth[i])) continue; seen.Add(depth[i]); uniqueDepth.Add(depth[i]); uniqueGamma.Add(gamma[i]); } // 排序 var sorted = uniqueDepth.Select((d, i) => new { Depth = d, Gamma = uniqueGamma[i] }) .OrderBy(x => x.Depth) .ToList(); var sortedDepth = sorted.Select(x => x.Depth).ToArray(); var sortedGamma = sorted.Select(x => x.Gamma).ToArray(); // 生成新的深度点(用于插值) double minDepth = sortedDepth.Min(); double maxDepth = sortedDepth.Max(); int numPoints = 1000; // 插值点数 var xnew = Generate.LinearSpaced(numPoints, minDepth, maxDepth).ToList(); // 根据选择的插值方法进行插值 List<double> ynew; IInterpolation interpolation = null; switch (method) { case "线性插值": interpolation = Interpolate.Linear(sortedDepth, sortedGamma); break; case "三次样条": interpolation = Interpolate.CubicSpline(sortedDepth, sortedGamma); break; case "PCHIP": interpolation = CubicSpline.InterpolatePchipSorted(sortedDepth, sortedGamma); break; case "Akima": interpolation = CubicSpline.InterpolateAkima(sortedDepth, sortedGamma); break; default: interpolation = Interpolate.Linear(sortedDepth, sortedGamma); break; } ynew = xnew.Select(d => interpolation.Interpolate(d)).ToList(); return Tuple.Create(xnew, ynew); } private void ExportPdfButton_Click(object sender, EventArgs e) { if (depthData.Count == 0) return; using (var saveFileDialog = new SaveFileDialog()) { saveFileDialog.Filter = "PDF文件|*.pdf"; saveFileDialog.Title = "导出PDF"; saveFileDialog.FileName = "GammaLogCurve.pdf"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { statusLabel.Text = "正在生成PDF..."; Application.DoEvents(); try { GeneratePdfReport(saveFileDialog.FileName); statusLabel.Text = $"PDF已成功导出到: {saveFileDialog.FileName}"; } catch (Exception ex) { statusLabel.Text = $"PDF导出错误: {ex.Message}"; } } } } private void GeneratePdfReport(string filePath) { try { statusLabel.Text = "正在准备PDF导出..."; Application.DoEvents(); // 获取plotPanel的宽度(365像素) double panelWidth = plotPanel.Width; // 计算每米对应的点(point)数(1点=1/72英寸) double dotsPerMeter = pixelsPerMeter * (72.0 / dpi); double minDepth = depthData.Min(); double maxDepth = depthData.Max(); double depthRange = maxDepth - minDepth; // 设置横轴宽度为plotPanel的宽度(转换为点) double gammaAxisWidth = panelWidth * (72.0 / dpi); // 保持页面宽度不变(与之前相同) double pageWidth = 500 + 100; // 伽马轴宽度500点 + 左右边距100点 // 计算图形在页面中的起始位置(居左显示) double graphStartX = 40; // 左边距40点 // 创建PDF文档 var document = new PdfDocument(); document.Info.Title = "自然伽马测井曲线报告"; document.Info.Author = "测井曲线可视化工具"; // 分页参数 const double maxPageHeight = 14400; // 200英寸 * 72点/英寸 double currentStartDepth = minDepth; int pageIndex = 0; int maxPages = 1000; // 安全限制,防止无限循环 bool isLastPage = false; // 获取插值方法 string method = interpolationComboBox.SelectedItem.ToString(); // 创建整个深度范围的插值函数 IInterpolation interpolationFunc = CreateInterpolationFunction(depthData, gammaData, method); // 计算总页数(用于页码显示) int totalPages = (int)Math.Ceiling(depthRange / (maxPageHeight / dotsPerMeter)); while (pageIndex < maxPages && !isLastPage) { statusLabel.Text = $"正在生成第 {pageIndex + 1} 页..."; Application.DoEvents(); // 计算当前页的深度范围 double currentPageDepthRange = maxPageHeight / dotsPerMeter; double currentEndDepth = currentStartDepth + currentPageDepthRange; // 检查是否是最后一页 if (currentEndDepth >= maxDepth - 0.001) // 使用容差避免浮点误差 { currentEndDepth = maxDepth; isLastPage = true; } // 计算当前页实际高度 double pageHeight = (currentEndDepth - currentStartDepth) * dotsPerMeter; // 创建页面(动态高度) var page = document.AddPage(); page.Width = pageWidth; page.Height = pageHeight; page.Orientation = PdfSharp.PageOrientation.Portrait; using (var xgraphics = XGraphics.FromPdfPage(page)) { // 设置边距 double margin = 40; double topMargin = 0; // 上边距为0 double bottomMargin = 0; // 下边距为0 double usableHeight = page.Height - topMargin - bottomMargin; // 计算比例因子 double gammaRange = 200; // 伽马值范围0-200 double gammaScale = gammaAxisWidth / gammaRange; double depthScale = usableHeight / (currentEndDepth - currentStartDepth); // 仅在第一页绘制标题 if (pageIndex == 0) { var titleFont = new XFont("Arial", 16, XFontStyle.Bold); xgraphics.DrawString("自然伽马测井曲线", titleFont, XBrushes.Navy, new XPoint(page.Width / 2, 10), new XStringFormat { Alignment = XStringAlignment.Center }); } // 绘制坐标轴框架 - 居左显示 var axisPen = new XPen(XColors.Black, 1.5); double leftAxisX = graphStartX + 30; // 左边距+标签空间 double rightAxisX = leftAxisX + gammaAxisWidth; // Y轴(深度)从顶部到底部边缘 xgraphics.DrawLine(axisPen, leftAxisX, topMargin, leftAxisX, topMargin + usableHeight); // X轴(伽马值)- 只在第一页绘制顶部轴 if (pageIndex == 0) { xgraphics.DrawLine(axisPen, leftAxisX, topMargin, rightAxisX, topMargin); } // 绘制网格线 - 深度(Y轴)延伸到页面底部 var gridPen = new XPen(XColors.LightGray, 0.3); var majorGridPen = new XPen(XColors.Gray, 0.6); // 计算起始网格深度 double startGridDepth = Math.Floor(currentStartDepth); double endGridDepth = Math.Ceiling(currentEndDepth); for (double i = startGridDepth; i <= endGridDepth; i += 1) { double y = topMargin + (i - currentStartDepth) * depthScale; // 确保y在页面范围内 if (y < topMargin || y > topMargin + usableHeight) continue; // 每5米主网格 if (i % 5 == 0) { xgraphics.DrawLine(majorGridPen, leftAxisX, y, rightAxisX, y); // 主刻度标签 var labelFont = new XFont("Arial", 8, XFontStyle.Bold); xgraphics.DrawString($"{i:F1}", labelFont, XBrushes.Black, new XPoint(leftAxisX - 5, y), new XStringFormat { Alignment = XStringAlignment.Far, LineAlignment = XLineAlignment.Center }); } else // 1米次网格 { xgraphics.DrawLine(gridPen, leftAxisX, y, rightAxisX, y); } } // 绘制网格线 - 伽马值(X轴)每20单位,延伸到页面底部 for (int i = 0; i <= 10; i++) { double gammaValue = i * 20; double x = leftAxisX + gammaValue * gammaScale; xgraphics.DrawLine(majorGridPen, x, topMargin, x, topMargin + usableHeight); // 刻度标签(顶部)- 只在第一页绘制 if (pageIndex == 0) { var labelFont = new XFont("Arial", 8); xgraphics.DrawString($"{gammaValue}", labelFont, XBrushes.Black, new XPoint(x, topMargin - 10), new XStringFormat { Alignment = XStringAlignment.Center, LineAlignment = XLineAlignment.Far }); } } // 绘制原始数据点(仅当前页范围内的点) var pointPen = new XPen(XColors.Gray, 0.5); for (int i = 0; i < depthData.Count; i++) { double depth = depthData[i]; double gamma = gammaData[i]; if (depth >= currentStartDepth && depth <= currentEndDepth) { double x = leftAxisX + gamma * gammaScale; double y = topMargin + (depth - currentStartDepth) * depthScale; // 只绘制在有效伽马值范围内的点 if (gamma >= 0 && gamma <= 200) { xgraphics.DrawEllipse(pointPen, x - 0.5, y - 0.5, 1, 1); } } } // ===== 平滑曲线绘制部分 ===== var curvePen = new XPen(XColor.FromArgb(0, 100, 200), 1.5); // 收集当前页所有有效点 var validPoints = new List<XPoint>(); // 按0.1米步长生成当前页深度范围内的点 double step = 0.1; double d = currentStartDepth; while (d <= currentEndDepth) { double gamma = interpolationFunc.Interpolate(d); if (gamma >= 0 && gamma <= 200) // 只处理有效范围内的点 { double x = leftAxisX + gamma * gammaScale; double y = topMargin + (d - currentStartDepth) * depthScale; validPoints.Add(new XPoint(x, y)); } d += step; } // 使用直线连接密集的点(点足够密时看起来是平滑的) if (validPoints.Count >= 2) { xgraphics.DrawLines(curvePen, validPoints.ToArray()); } // ===== 结束平滑曲线绘制部分 ===== // 添加坐标轴标签 var axisFont = new XFont("Arial", 10, XFontStyle.Bold); // 深度标签(垂直文本) var depthLabelState = xgraphics.Save(); xgraphics.TranslateTransform(graphStartX, topMargin + usableHeight / 2); xgraphics.RotateTransform(-90); xgraphics.DrawString("深度 (m)", axisFont, XBrushes.Black, 0, 0, new XStringFormat { Alignment = XStringAlignment.Center, LineAlignment = XLineAlignment.Center }); xgraphics.Restore(depthLabelState); // 伽马值标签 - 只在第一页绘制 if (pageIndex == 0) { xgraphics.DrawString("伽马值 (API)", axisFont, XBrushes.Black, new XPoint(leftAxisX + gammaAxisWidth / 2, topMargin - 20), new XStringFormat { Alignment = XStringAlignment.Center }); } } // 更新下一页的起始深度 currentStartDepth = currentEndDepth; pageIndex++; // 终止条件检查 if (currentStartDepth >= maxDepth - 0.001 || pageIndex >= maxPages) { isLastPage = true; } } // 保存PDF document.Save(filePath); statusLabel.Text = $"PDF导出完成,共 {pageIndex} 页"; } catch (Exception ex) { statusLabel.Text = $"PDF导出错误: {ex.Message}"; MessageBox.Show($"导出PDF时发生错误:\n{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // 创建插值函数的方法 private IInterpolation CreateInterpolationFunction(List<double> depth, List<double> gamma, string method) { // 去除重复深度值 var uniqueDepth = new List<double>(); var uniqueGamma = new List<double>(); var seen = new HashSet<double>(); for (int i = 0; i < depth.Count; i++) { if (seen.Contains(depth[i])) continue; seen.Add(depth[i]); uniqueDepth.Add(depth[i]); uniqueGamma.Add(gamma[i]); } // 排序 var sorted = uniqueDepth.Select((d, i) => new { Depth = d, Gamma = uniqueGamma[i] }) .OrderBy(x => x.Depth) .ToList(); var sortedDepth = sorted.Select(x => x.Depth).ToArray(); var sortedGamma = sorted.Select(x => x.Gamma).ToArray(); // 根据选择的插值方法进行插值 IInterpolation interpolation = null; switch (method) { case "线性插值": interpolation = Interpolate.Linear(sortedDepth, sortedGamma); break; case "三次样条": interpolation = Interpolate.CubicSpline(sortedDepth, sortedGamma); break; case "PCHIP": interpolation = CubicSpline.InterpolatePchipSorted(sortedDepth, sortedGamma); break; case "Akima": try { // 尝试使用Akima插值(如果可用) interpolation = CubicSpline.InterpolateAkima(sortedDepth, sortedGamma); } catch { // 如果Akima不可用,回退到PCHIP interpolation = CubicSpline.InterpolatePchipSorted(sortedDepth, sortedGamma); } break; default: interpolation = Interpolate.Linear(sortedDepth, sortedGamma); break; } return interpolation; } } }该程序中,使用像素代表米数。当窗体变化时,网格间距也发生了变化。我们希望的是当窗体减小3米对应的像素时,图形最大值显示比之前少3米,网格线少三条,无论是主网格还是次网格,而其他的网格线数量以及网格间距不发生任何的改变
最新发布
08-16
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值