Files
2024-10-07 12:14:32 +08:00

391 lines
14 KiB
C#
Raw Permalink Blame History

using System;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Threading.Tasks;
using netDxf;
using netDxf.Entities;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
namespace GeneralDWGViewer
{
public partial class Form1 : Form
{
private string? odaConverterPath;
private List<EntityObject> entities = new List<EntityObject>();
private float scale = 1.0f;
private PointF pan = new PointF(0, 0);
private bool isPanning = false;
private System.Drawing.Point lastMousePosition;
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
this.MouseWheel += Form1_MouseWheel;
this.MouseDown += Form1_MouseDown;
this.MouseMove += Form1_MouseMove;
this.MouseUp += Form1_MouseUp;
InitializeOdaConverterPath();
}
private void InitializeOdaConverterPath()
{
odaConverterPath = Environment.GetEnvironmentVariable("ODA_CONVERTER_PATH");
if (string.IsNullOrEmpty(odaConverterPath))
{
odaConverterPath = ConfigurationManager.AppSettings["OdaConverterPath"];
}
if (string.IsNullOrEmpty(odaConverterPath))
{
string[] commonPaths = new string[]
{
@"C:\Program Files\ODA\ODAFileConverter 25.8.0\ODAFileConverter.exe",
@"C:\Program Files\ODA\ODAFileConverter\ODAFileConverter.exe",
@"C:\Program Files (x86)\ODA\ODAFileConverter\ODAFileConverter.exe"
};
foreach (string path in commonPaths)
{
if (File.Exists(path))
{
odaConverterPath = path;
break;
}
}
}
if (string.IsNullOrEmpty(odaConverterPath))
{
PromptInstallOdaConverter();
}
}
private void PromptInstallOdaConverter()
{
DialogResult result = MessageBox.Show(
"ODA File Converter is not found on your system. This software is required to open DWG files.\n\n" +
"Would you like to visit the ODA website to download and install ODA File Converter?",
"ODA File Converter Not Found",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question
);
if (result == DialogResult.Yes)
{
// <20><><EFBFBD><EFBFBD> ODA <20><>վ
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = "https://www.opendesign.com/guestfiles/oda_file_converter",
UseShellExecute = true
});
MessageBox.Show(
"After installing ODA File Converter, please restart this application.\n\n" +
"If the application still cannot find ODA File Converter, you can manually set the path in the application settings.",
"Installation Instructions",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
}
else
{
MessageBox.Show(
"Without ODA File Converter, you will not be able to open DWG files.\n" +
"You can still use this application to view DXF files.",
"ODA File Converter Not Installed",
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
}
}
private void Form1_MouseWheel(object? sender, MouseEventArgs e)
{
float oldScale = scale;
if (e.Delta > 0)
scale *= 1.1f;
else
scale /= 1.1f;
if (Math.Abs(scale) < 0.0001f)
{
scale = 0.0001f * Math.Sign(scale);
}
PointF mousePos = e.Location;
pan.X = mousePos.X - (mousePos.X - pan.X) * scale / oldScale;
pan.Y = mousePos.Y - (mousePos.Y - pan.Y) * scale / oldScale;
this.Invalidate();
}
#nullable disable
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isPanning = true;
lastMousePosition = e.Location;
Cursor = Cursors.Hand;
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (isPanning)
{
int dx = e.X - lastMousePosition.X;
int dy = e.Y - lastMousePosition.Y;
pan.X += dx;
pan.Y += dy;
lastMousePosition = e.Location;
this.Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isPanning = false;
Cursor = Cursors.Default;
}
}
#nullable enable
private void loadButton_Click(object sender, EventArgs e)
{
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "CAD files (*.dwg;*.dxf)|*.dwg;*.dxf|All files (*.*)|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string filePath = openFileDialog.FileName;
if (Path.GetExtension(filePath).ToLower() == ".dwg" && string.IsNullOrEmpty(odaConverterPath))
{
MessageBox.Show(
"ODA File Converter is not installed. You cannot open DWG files.\n" +
"Please install ODA File Converter and restart the application.",
"Cannot Open DWG File",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
return;
}
_ = ProcessCadFileAsync(filePath);
}
}
}
private async Task ProcessCadFileAsync(string filePath)
{
try
{
loadButton.Enabled = false;
progressBar.Visible = true;
string fileExtension = Path.GetExtension(filePath).ToLower();
string dxfFilePath = filePath;
if (fileExtension == ".dwg")
{
dxfFilePath = await ConvertDwgToDxfAsync(filePath);
}
await ProcessDxfFileAsync(dxfFilePath);
if (fileExtension == ".dwg")
{
File.Delete(dxfFilePath);
}
CalculateScaleAndPan();
this.Invalidate();
}
catch (Exception ex)
{
MessageBox.Show($"Error processing file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
loadButton.Enabled = true;
progressBar.Visible = false;
}
}
private async Task<string> ConvertDwgToDxfAsync(string dwgFilePath)
{
if (string.IsNullOrEmpty(odaConverterPath) || !File.Exists(odaConverterPath))
{
throw new Exception("ODA File Converter not found. Please set the correct path.");
}
string dxfFilePath = Path.ChangeExtension(dwgFilePath, ".dxf");
string outputDir = Path.GetDirectoryName(dxfFilePath) ?? string.Empty;
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = odaConverterPath,
Arguments = $"\"{Path.GetDirectoryName(dwgFilePath)}\" \"{outputDir}\" \"ACAD2018\" \"DXF\" \"0\" \"1\" \"{Path.GetFileName(dwgFilePath)}\"",
CreateNoWindow = true,
UseShellExecute = false
};
using (Process process = new Process { StartInfo = psi })
{
process.Start();
await process.WaitForExitAsync();
}
if (!File.Exists(dxfFilePath))
{
throw new Exception("Failed to convert DWG to DXF");
}
return dxfFilePath;
}
private async Task ProcessDxfFileAsync(string filePath)
{
await Task.Run(() =>
{
DxfDocument dxf = DxfDocument.Load(filePath);
entities.Clear();
entities.AddRange(dxf.Entities.Lines);
entities.AddRange(dxf.Entities.Circles);
entities.AddRange(dxf.Entities.Arcs);
entities.AddRange(dxf.Entities.Polylines2D);
entities.AddRange(dxf.Entities.Polylines3D);
});
}
private void CalculateScaleAndPan()
{
if (entities.Count == 0) return;
double minX = double.MaxValue, minY = double.MaxValue;
double maxX = double.MinValue, maxY = double.MinValue;
foreach (var entity in entities)
{
UpdateBoundingBox(entity, ref minX, ref minY, ref maxX, ref maxY);
}
double width = maxX - minX;
double height = maxY - minY;
float scaleX = (this.ClientSize.Width - 20) / (float)width;
float scaleY = (this.ClientSize.Height - 20) / (float)height;
scale = Math.Min(scaleX, scaleY);
if (Math.Abs(scale) < 0.0001f)
{
scale = 0.0001f * Math.Sign(scale);
}
pan = new PointF(
(float)(-minX * scale + (this.ClientSize.Width - (float)width * scale) / 2),
(float)(maxY * scale + (this.ClientSize.Height - (float)height * scale) / 2)
);
}
private void UpdateBoundingBox(EntityObject entity, ref double minX, ref double minY, ref double maxX, ref double maxY)
{
switch (entity)
{
case Line line:
UpdateMinMax(line.StartPoint.X, line.StartPoint.Y, ref minX, ref minY, ref maxX, ref maxY);
UpdateMinMax(line.EndPoint.X, line.EndPoint.Y, ref minX, ref minY, ref maxX, ref maxY);
break;
case Circle circle:
UpdateMinMax(circle.Center.X - circle.Radius, circle.Center.Y - circle.Radius, ref minX, ref minY, ref maxX, ref maxY);
UpdateMinMax(circle.Center.X + circle.Radius, circle.Center.Y + circle.Radius, ref minX, ref minY, ref maxX, ref maxY);
break;
case Arc arc:
UpdateMinMax(arc.Center.X - arc.Radius, arc.Center.Y - arc.Radius, ref minX, ref minY, ref maxX, ref maxY);
UpdateMinMax(arc.Center.X + arc.Radius, arc.Center.Y + arc.Radius, ref minX, ref minY, ref maxX, ref maxY);
break;
case Polyline2D polyline:
foreach (var vertex in polyline.Vertexes)
{
UpdateMinMax(vertex.Position.X, vertex.Position.Y, ref minX, ref minY, ref maxX, ref maxY);
}
break;
case Polyline3D polyline:
foreach (var vertex in polyline.Vertexes)
{
UpdateMinMax(vertex.X, vertex.Y, ref minX, ref minY, ref maxX, ref maxY);
}
break;
}
}
private void UpdateMinMax(double x, double y, ref double minX, ref double minY, ref double maxX, ref double maxY)
{
minX = Math.Min(minX, x);
minY = Math.Min(minY, y);
maxX = Math.Max(maxX, x);
maxY = Math.Max(maxY, y);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.Clear(Color.White);
e.Graphics.ResetTransform();
e.Graphics.TranslateTransform(pan.X, pan.Y);
if (Math.Abs(scale) < 0.0001f)
{
scale = 0.0001f * Math.Sign(scale);
}
e.Graphics.ScaleTransform(scale, -scale);
foreach (var entity in entities)
{
DrawEntity(entity, e.Graphics);
}
}
private void DrawEntity(EntityObject entity, Graphics g)
{
using (Pen pen = new Pen(Color.Black, 1 / scale))
{
switch (entity)
{
case Line line:
g.DrawLine(pen, (float)line.StartPoint.X, (float)line.StartPoint.Y, (float)line.EndPoint.X, (float)line.EndPoint.Y);
break;
case Circle circle:
float diameter = (float)(circle.Radius * 2);
g.DrawEllipse(pen, (float)(circle.Center.X - circle.Radius), (float)(circle.Center.Y - circle.Radius), diameter, diameter);
break;
case Arc arc:
RectangleF rect = new RectangleF((float)(arc.Center.X - arc.Radius), (float)(arc.Center.Y - arc.Radius), (float)(arc.Radius * 2), (float)(arc.Radius * 2));
g.DrawArc(pen, rect, (float)arc.StartAngle, (float)(arc.EndAngle - arc.StartAngle));
break;
case Polyline2D polyline:
DrawPolyline(g, pen, polyline.Vertexes.Select(v => new PointF((float)v.Position.X, (float)v.Position.Y)).ToArray());
break;
case Polyline3D polyline:
DrawPolyline(g, pen, polyline.Vertexes.Select(v => new PointF((float)v.X, (float)v.Y)).ToArray());
break;
}
}
}
private void DrawPolyline(Graphics g, Pen pen, PointF[] points)
{
if (points.Length > 1)
{
g.DrawLines(pen, points);
}
}
}
}