VB代码(Delaunay.bas和Delaunay.frm如下)能根据Form上的Image中鼠标的点击形成三角网,并在Image中显示出来,谁能把该VB代码

  • 主题发起人 主题发起人 YL_YAN
  • 开始时间 开始时间
Y

YL_YAN

Unregistered / Unconfirmed
GUEST, unregistred user!
VB代码(Delaunay.bas和Delaunay.frm如下)能根据Form上的Image中鼠标的点击形成三角网,并在Image中显示出来,谁能把该VB代码翻译成Delphi代码? ( 积分: 200 )<br />VB代码(Delaunay.bas和Delaunay.frm如下)能根据Form上的Image中鼠标的点击形成三角网,并在Image中显示出来,谁能把该VB代码翻译成Delphi代码?

Delaunay.bas如下:
Attribute VB_Name = &quot;Module1&quot;

Option Explicit

'Points (Vertices)
Public Type dVertex
x As Long
y As Long
z As Long
End Type

'Created Triangles, vv# are the vertex pointers
Public Type dTriangle
vv0 As Long
vv1 As Long
vv2 As Long
End Type

'Set these as applicable
Public Const MaxVertices = 500
Public Const MaxTriangles = 1000

'Our points
Public Vertex(MaxVertices) As dVertex

'Our Created Triangles
Public Triangle(MaxTriangles) As dTriangle

Private Function InCircle(xp As Long, yp As Long, x1 As Long, y1 As Long, x2 As Long, y2 As Long, x3 As Long, y3 As Long, ByRef xc, ByRef yc, ByRef r) As Boolean
'Return TRUE if the point (xp,yp) lies inside the circumcircle
'made up by points (x1,y1) (x2,y2) (x3,y3)
'The circumcircle centre is returned in (xc,yc) and the radius r
'NOTE: A point on the edge is inside the circumcircle

Dim eps As Double
Dim m1 As Double
Dim m2 As Double
Dim mx1 As Double
Dim mx2 As Double
Dim my1 As Double
Dim my2 As Double
Dim dx As Double
Dim dy As Double
Dim rsqr As Double
Dim drsqr As Double

eps = 0.000001

InCircle = False

If Abs(y1 - y2) < eps And Abs(y2 - y3) < eps Then
MsgBox &quot;INCIRCUM - F - Points are coincident !!&quot;
Exit Function
End If

If Abs(y2 - y1) < eps Then
m2 = -(x3 - x2) / (y3 - y2)
mx2 = (x2 + x3) / 2
my2 = (y2 + y3) / 2
xc = (x2 + x1) / 2
yc = m2 * (xc - mx2) + my2
ElseIf Abs(y3 - y2) < eps Then
m1 = -(x2 - x1) / (y2 - y1)
mx1 = (x1 + x2) / 2
my1 = (y1 + y2) / 2
xc = (x3 + x2) / 2
yc = m1 * (xc - mx1) + my1
Else
m1 = -(x2 - x1) / (y2 - y1)
m2 = -(x3 - x2) / (y3 - y2)
mx1 = (x1 + x2) / 2
mx2 = (x2 + x3) / 2
my1 = (y1 + y2) / 2
my2 = (y2 + y3) / 2
xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2)
yc = m1 * (xc - mx1) + my1
End If

dx = x2 - xc
dy = y2 - yc
rsqr = dx * dx + dy * dy
r = Sqr(rsqr)
dx = xp - xc
dy = yp - yc
drsqr = dx * dx + dy * dy

If drsqr <= rsqr Then InCircle = True

End Function
Private Function WhichSide(xp As Long, yp As Long, x1 As Long, y1 As Long, x2 As Long, y2 As Long) As Integer
'Determines which side of a line the point (xp,yp) lies.
'The line goes from (x1,y1) to (x2,y2)
'Returns -1 for a point to the left
' 0 for a point on the line
' +1 for a point to the right

Dim equation As Double

equation = ((yp - y1) * (x2 - x1)) - ((y2 - y1) * (xp - x1))

If equation > 0 Then
WhichSide = -1
ElseIf equation = 0 Then
WhichSide = 0
Else
WhichSide = 1
End If

End Function

Public Function Triangulate(nvert As Integer) As Integer
'Takes as input NVERT vertices in arrays Vertex()
'Returned is a list of NTRI triangular faces in the array
'Triangle(). These triangles are arranged in clockwise order.

Dim Complete(MaxTriangles) As Boolean
Dim Edges(2, MaxTriangles * 3) As Long
Dim Nedge As Long

'For Super Triangle
Dim xmin As Long
Dim xmax As Long
Dim ymin As Long
Dim ymax As Long
Dim xmid As Long
Dim ymid As Long
Dim dx As Double
Dim dy As Double
Dim dmax As Double

'General Variables
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim ntri As Integer
Dim xc As Double
Dim yc As Double
Dim r As Double
Dim inc As Boolean

'Find the maximum and minimum vertex bounds.
'This is to allow calculation of the bounding triangle
xmin = Vertex(1).x
ymin = Vertex(1).y
xmax = xmin
ymax = ymin
For i = 2 To nvert
If Vertex(i).x < xmin Then xmin = Vertex(i).x
If Vertex(i).x > xmax Then xmax = Vertex(i).x
If Vertex(i).y < ymin Then ymin = Vertex(i).y
If Vertex(i).y > ymax Then ymax = Vertex(i).y
Next i
dx = xmax - xmin
dy = ymax - ymin
If dx > dy Then
dmax = dx
Else
dmax = dy
End If
xmid = (xmax + xmin) / 2
ymid = (ymax + ymin) / 2

'Set up the supertriangle
'This is a triangle which encompasses all the sample points.
'The supertriangle coordinates are added to the end of the
'vertex list. The supertriangle is the first triangle in
'the triangle list.

Vertex(nvert + 1).x = xmid - 2 * dmax
Vertex(nvert + 1).y = ymid - dmax
Vertex(nvert + 2).x = xmid
Vertex(nvert + 2).y = ymid + 2 * dmax
Vertex(nvert + 3).x = xmid + 2 * dmax
Vertex(nvert + 3).y = ymid - dmax
Triangle(1).vv0 = nvert + 1
Triangle(1).vv1 = nvert + 2
Triangle(1).vv2 = nvert + 3
Complete(1) = False
ntri = 1

'Include each point one at a time into the existing mesh
For i = 1 To nvert
Nedge = 0
'Set up the edge buffer.
'If the point (Vertex(i).x,Vertex(i).y) lies inside the circumcircle then the
'three edges of that triangle are added to the edge buffer.
j = 0
Do
j = j + 1
If Complete(j) <> True Then
inc = InCircle(Vertex(i).x, Vertex(i).y, Vertex(Triangle(j).vv0).x, Vertex(Triangle(j).vv0).y, Vertex(Triangle(j).vv1).x, Vertex(Triangle(j).vv1).y, Vertex(Triangle(j).vv2).x, Vertex(Triangle(j).vv2).y, xc, yc, r)
'Include this if points are sorted by X
'If (xc + r) < Vertex(i).x Then
'complete(j) = True
'Else
If inc Then
Edges(1, Nedge + 1) = Triangle(j).vv0
Edges(2, Nedge + 1) = Triangle(j).vv1
Edges(1, Nedge + 2) = Triangle(j).vv1
Edges(2, Nedge + 2) = Triangle(j).vv2
Edges(1, Nedge + 3) = Triangle(j).vv2
Edges(2, Nedge + 3) = Triangle(j).vv0
Nedge = Nedge + 3
Triangle(j).vv0 = Triangle(ntri).vv0
Triangle(j).vv1 = Triangle(ntri).vv1
Triangle(j).vv2 = Triangle(ntri).vv2
Complete(j) = Complete(ntri)
j = j - 1
ntri = ntri - 1
End If
'End If
End If
Loop While j < ntri

'Tag multiple edges
'Note: if all triangles are specified anticlockwise then all
'interior edges are opposite pointing in direction.
For j = 1 To Nedge - 1
If Not Edges(1, j) = 0 And Not Edges(2, j) = 0 Then
For k = j + 1 To Nedge
If Not Edges(1, k) = 0 And Not Edges(2, k) = 0 Then
If Edges(1, j) = Edges(2, k) Then
If Edges(2, j) = Edges(1, k) Then
Edges(1, j) = 0
Edges(2, j) = 0
Edges(1, k) = 0
Edges(2, k) = 0
End If
End If
End If
Next k
End If
Next j

'Form new triangles for the current point
'Skipping over any tagged edges.
'All edges are arranged in clockwise order.
For j = 1 To Nedge
If Not Edges(1, j) = 0 And Not Edges(2, j) = 0 Then
ntri = ntri + 1
Triangle(ntri).vv0 = Edges(1, j)
Triangle(ntri).vv1 = Edges(2, j)
Triangle(ntri).vv2 = i
Complete(ntri) = False
End If
Next j
Next i

'Remove triangles with supertriangle vertices
'These are triangles which have a vertex number greater than NVERT
i = 0
Do
i = i + 1
If Triangle(i).vv0 > nvert Or Triangle(i).vv1 > nvert Or Triangle(i).vv2 > nvert Then
Triangle(i).vv0 = Triangle(ntri).vv0
Triangle(i).vv1 = Triangle(ntri).vv1
Triangle(i).vv2 = Triangle(ntri).vv2
i = i - 1
ntri = ntri - 1
End If
Loop While i < ntri

Triangulate = ntri
End Function



Delaunay.frm代码如下:

VERSION 5.00
Begin VB.Form frmAbout
BorderStyle = 3 'Fixed Dialog
Caption = &quot;About Triangulation&quot;
ClientHeight = 2850
ClientLeft = 2340
ClientTop = 1935
ClientWidth = 5730
ClipControls = 0 'False
LinkTopic = &quot;Form2&quot;
MaxButton = 0 'False
MinButton = 0 'False
ScaleHeight = 1967.121
ScaleMode = 0 'User
ScaleWidth = 5380.766
ShowInTaskbar = 0 'False
Begin VB.CommandButton cmdOK
Cancel = -1 'True
Caption = &quot;OK&quot;
Default = -1 'True
Height = 345
Left = 3240
TabIndex = 0
Top = 2280
Width = 1260
End
Begin VB.CommandButton cmdSysInfo
Caption = &quot;&amp;System Info...&quot;
Height = 345
Left = 1080
TabIndex = 1
Top = 2280
Width = 1245
End
Begin VB.Label Label1
Caption = &quot;VB Conversion by: EluZioN&quot;
ForeColor = &amp;H00000000&amp;
Height = 330
Left = 1050
TabIndex = 5
Top = 1560
Width = 3885
End
Begin VB.Line Line1
BorderColor = &amp;H00808080&amp;
BorderStyle = 6 'Inside Solid
Index = 1
X1 = 84.515
X2 = 5309.398
Y1 = 1408.045
Y2 = 1408.045
End
Begin VB.Label lblDescription
Caption = &quot;Original Fortran 77 Code by: Paul Bourke&quot;
ForeColor = &amp;H00000000&amp;
Height = 330
Left = 1050
TabIndex = 2
Top = 1200
Width = 3885
End
Begin VB.Label lblTitle
Caption = &quot;Delaunay Triangulation&quot;
ForeColor = &amp;H00000000&amp;
Height = 480
Left = 1050
TabIndex = 3
Top = 240
Width = 3885
End
Begin VB.Line Line1
BorderColor = &amp;H00FFFFFF&amp;
BorderWidth = 2
Index = 0
X1 = 112.686
X2 = 5323.484
Y1 = 1408.045
Y2 = 1408.045
End
Begin VB.Label lblVersion
Caption = &quot;Version: Non-Constrained&quot;
Height = 225
Left = 1050
TabIndex = 4
Top = 780
Width = 3885
End
End
Attribute VB_Name = &quot;frmAbout&quot;
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit

' Reg Key Security Options...
Const READ_CONTROL = &amp;H20000
Const KEY_QUERY_VALUE = &amp;H1
Const KEY_SET_VALUE = &amp;H2
Const KEY_CREATE_SUB_KEY = &amp;H4
Const KEY_ENUMERATE_SUB_KEYS = &amp;H8
Const KEY_NOTIFY = &amp;H10
Const KEY_CREATE_LINK = &amp;H20
Const KEY_ALL_ACCESS = KEY_QUERY_VALUE + KEY_SET_VALUE + _
KEY_CREATE_SUB_KEY + KEY_ENUMERATE_SUB_KEYS + _
KEY_NOTIFY + KEY_CREATE_LINK + READ_CONTROL

' Reg Key ROOT Types...
Const HKEY_LOCAL_MACHINE = &amp;H80000002
Const ERROR_SUCCESS = 0
Const REG_SZ = 1 ' Unicode nul terminated string
Const REG_DWORD = 4 ' 32-bit number

Const gREGKEYSYSINFOLOC = &quot;SOFTWARE/Microsoft/Shared Tools Location&quot;
Const gREGVALSYSINFOLOC = &quot;MSINFO&quot;
Const gREGKEYSYSINFO = &quot;SOFTWARE/Microsoft/Shared Tools/MSINFO&quot;
Const gREGVALSYSINFO = &quot;PATH&quot;

Private Declare Function RegOpenKeyEx Lib &quot;advapi32&quot; Alias &quot;RegOpenKeyExA&quot; (ByVal hKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long, ByRef phkResult As Long) As Long
Private Declare Function RegQueryValueEx Lib &quot;advapi32&quot; Alias &quot;RegQueryValueExA&quot; (ByVal hKey As Long, ByVal lpValueName As String, ByVal lpReserved As Long, ByRef lpType As Long, ByVal lpData As String, ByRef lpcbData As Long) As Long
Private Declare Function RegCloseKey Lib &quot;advapi32&quot; (ByVal hKey As Long) As Long


Private Sub cmdSysInfo_Click()
Call StartSysInfo
End Sub

Private Sub cmdOK_Click()
Unload Me
End Sub

Public Sub StartSysInfo()
On Error GoTo SysInfoErr

Dim rc As Long
Dim SysInfoPath As String

' Try To Get System Info Program Path/Name From Registry...
If GetKeyValue(HKEY_LOCAL_MACHINE, gREGKEYSYSINFO, gREGVALSYSINFO, SysInfoPath) Then
' Try To Get System Info Program Path Only From Registry...
ElseIf GetKeyValue(HKEY_LOCAL_MACHINE, gREGKEYSYSINFOLOC, gREGVALSYSINFOLOC, SysInfoPath) Then
' Validate Existance Of Known 32 Bit File Version
If (Dir(SysInfoPath &amp; &quot;/MSINFO32.EXE&quot;) <> &quot;&quot;) Then
SysInfoPath = SysInfoPath &amp; &quot;/MSINFO32.EXE&quot;

' Error - File Can Not Be Found...
Else
GoTo SysInfoErr
End If
' Error - Registry Entry Can Not Be Found...
Else
GoTo SysInfoErr
End If

Call Shell(SysInfoPath, vbNormalFocus)

Exit Sub
SysInfoErr:
MsgBox &quot;System Information Is Unavailable At This Time&quot;, vbOKOnly
End Sub

Public Function GetKeyValue(KeyRoot As Long, KeyName As String, SubKeyRef As String, ByRef KeyVal As String) As Boolean
Dim i As Long ' Loop Counter
Dim rc As Long ' Return Code
Dim hKey As Long ' Handle To An Open Registry Key
Dim hDepth As Long '
Dim KeyValType As Long ' Data Type Of A Registry Key
Dim tmpVal As String ' Tempory Storage For A Registry Key Value
Dim KeyValSize As Long ' Size Of Registry Key Variable
'------------------------------------------------------------
' Open RegKey Under KeyRoot {HKEY_LOCAL_MACHINE...}
'------------------------------------------------------------
rc = RegOpenKeyEx(KeyRoot, KeyName, 0, KEY_ALL_ACCESS, hKey) ' Open Registry Key

If (rc <> ERROR_SUCCESS) Then GoTo GetKeyError ' Handle Error...

tmpVal = String$(1024, 0) ' Allocate Variable Space
KeyValSize = 1024 ' Mark Variable Size

'------------------------------------------------------------
' Retrieve Registry Key Value...
'------------------------------------------------------------
rc = RegQueryValueEx(hKey, SubKeyRef, 0, _
KeyValType, tmpVal, KeyValSize) ' Get/Create Key Value

If (rc <> ERROR_SUCCESS) Then GoTo GetKeyError ' Handle Errors

If (Asc(Mid(tmpVal, KeyValSize, 1)) = 0) Then ' Win95 Adds Null Terminated String...
tmpVal = Left(tmpVal, KeyValSize - 1) ' Null Found, Extract From String
Else ' WinNT Does NOT Null Terminate String...
tmpVal = Left(tmpVal, KeyValSize) ' Null Not Found, Extract String Only
End If
'------------------------------------------------------------
' Determine Key Value Type For Conversion...
'------------------------------------------------------------
Select Case KeyValType ' Search Data Types...
Case REG_SZ ' String Registry Key Data Type
KeyVal = tmpVal ' Copy String Value
Case REG_DWORD ' Double Word Registry Key Data Type
For i = Len(tmpVal) To 1 Step -1 ' Convert Each Bit
KeyVal = KeyVal + Hex(Asc(Mid(tmpVal, i, 1))) ' Build Value Char. By Char.
Next
KeyVal = Format$(&quot;&amp;h&quot; + KeyVal) ' Convert Double Word To String
End Select

GetKeyValue = True ' Return Success
rc = RegCloseKey(hKey) ' Close Registry Key
Exit Function ' Exit

GetKeyError: ' Cleanup After An Error Has Occured...
KeyVal = &quot;&quot; ' Set Return Val To Empty String
GetKeyValue = False ' Return Failure
rc = RegCloseKey(hKey) ' Close Registry Key
End Function
 
该代码的原理是用Delaunay不规则三角格网组建地面模型,Delaunay三角网是俄国数学家B.Delaunay于1934年发现的。Delaunay三角网构建的具有数据量大的特征。Delaunay三角网有一个特性,每个三角网形成的外接圆都不包含其他参考点。利用这一个性质,可以直接构成Delaunay三角网。
我不懂VB!
 
该Form如下:

File About

Points: 4 Trianlges:1 Click The Pic Box to add points
_______________________________________________________________
| |
| |
| |
| |
| |/ |
| |_/ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
_______________________________________________________________


说明:4=1(初始值)+3(鼠标点3下)表示鼠标有在Image上点3下,每多点
一下,该值加1;
1:表示组成一个三角形,该值随着点击的增加而增加
 
数据结构可如下:
struct Pixel //脚点数据
{
double x,y,z,g;
bool flag;
};
struct List //数据链表
{
Pixel *pixel;
List *next;
};
struct Line //三角形边
{
Pixel *pixel1; //三角形边一端点
Pixel *pixel2; //三角形边另一端点
Pixel *pixel3; //三角形边所对顶点
bool flag;
};
struct Linelist //三角形边表
{
Line *line;
Linelist *next;
};
struct Triangle //三角形表
{
Line *line1;
Line *line2;
Line *line3;
Triangle *next;
};
 
看来我自己解决这个问题,Steve Evans把VB翻译成Pascal,已从网上下载下来。
 
以下unit1.pas和Delaunay.pas代码编译通过,但是运行时不能在Form1上靠鼠标的点击形成三角网,并显示出来三角网,要怎样改?

unit1.pas代码如下:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public

{ Public declarations }
end;

var
Form1: TForm1;

implementation
uses Delaunay;

{$R *.DFM}



procedure TForm1.FormCreate(Sender: TObject);
begin
TDelaunay.Create;

end;

end.



Delaunay.pas代码如下:
unit Delaunay;

interface

uses Math,Windows,SysUtils,CommDlg,CommCtrl,Penwin, WinTypes, WinProcs,
Messages, Classes, Graphics, Controls, Forms, Dialogs, Chart, Series,
ExtCtrls, Teengine, StdCtrls, Buttons, TeeProcs;

//Set these as applicable
Const
MaxVertices = 500000;
MaxTriangles = 1000000;
ExPtTolerance = 0.000001; //小于这个被认为是同一点


Type
TCastArray = Array [0..2,0..2,0..2] of Integer;
TVectorL3D = Array [0..2] of Double;
TVectorL3I = Array [0..2] of Integer;

PPointPair = ^TPointPair;
TPointPair = record
x1,y1,
x2,y2: Double
end;
//单条等值线
TLever = record
FZ: Double;
Points: TList;
end;

//Points (Vertices)
dVertex = record
X ,
Y ,
Z: Double;
end;

//Created Triangles, vv# are the vertex pointers(点的索引)
dTriangle = record
vv0: LongInt;
vv1: LongInt;
vv2: LongInt;
PreCalc: Integer;
xc,yc,r: Double; //三角形外接圆圆心坐标和半径
end;

TDVertexs = array[0..MaxVertices] of dVertex;
PVertexs = ^TDVertexs;

TDTriangles = array[0..MaxTriangles] of dTriangle;
PTriangles = ^TDTriangles;

TDCompletes = array [0..MaxTriangles] of Boolean;
PCompletes = ^TDCompletes;

TDEdges = array[0..2,0..MaxTriangles * 3] of LongInt;
PEdges = ^TDEdges;

TDelaunay = class
private
{ Private declarations }
FzLow,
FzHigh: Double;

FVertexs: PVertexs;
FTriangles: PTriangles;
FTriangleCount: Integer;
FPointCount: Integer; //Variable for total number of points (vertices)
procedure QuickSort(var aVertexs: PVertexs; Low,High: Integer);
function GetPointCount: integer;
function InCircle(xp, yp, x1, y1, x2, y2, x3, y3: Double;
var xc: Double; var yc: Double; var r: Double; j: Integer): Boolean;
Function WhichSide(xp, yp, x1, y1, x2, y2: Double): Integer;
Function Triangulate(nVert: Integer): Integer;

public
{ Public declarations }
FLevers: Array of TLever;
TempBuffer: TBitmap;
TargetForm: TForm;
constructor Create;
destructor Destroy; override;
procedure Mesh;
procedure Draw;
procedure ScatterContour(ZCount: Integer; Z: Array of Single);
procedure AddPoint(x,y,z: Single);
procedure ClearBackPage;
procedure FlipBackPage;
property zLow: Double read FzLow write FzLow;
property zHigh: Double read FzHigh write FzHigh;
property Vertexs: PVertexs read FVertexs;
property Triangles: PTriangles read FTriangles;
property TriangleCount: Integer read FTriangleCount;
property PointCount: Integer read GetPointCount;
end;

implementation
//uses unit1;

constructor TDelaunay.Create;
begin
//Initiate total points to 1, using base 0 causes problems in the functions
FPointCount := 1;
FTriangleCount:=0;
FzLow:= 0;
FzHigh:= 0;
// TempBuffer:=TBitmap.Create;
TempBuffer:=TBitmap.Create;

//Allocate memory for arrays
GetMem(FVertexs, sizeof(FVertexs^));
GetMem(FTriangles, sizeof(FTriangles^));
end;

destructor TDelaunay.Destroy;
begin
//Free memory for arrays
FreeMem(FVertexs, sizeof(FVertexs^));
FreeMem(FTriangles, sizeof(FTriangles^));
end;

//加入点到FVertexs数组里
procedure TDelaunay.AddPoint(x,y,z: Single);
var
i: Integer;
SamePoint: Boolean;
begin
//Check for duplicate points 检查是否有完全相同的点,
//如果有则,该点不被加入
SamePoint := false;
i := 1;
while i < FPointCount do
begin
If (Abs(x-FVertexs^.X) < ExPtTolerance) and
(Abs(y-FVertexs^.Y) < ExPtTolerance) Then
SamePoint:= true;
Inc(i);
end;

if FzLow > z then
FzLow:= z
else if FzHigh < z then
FzHigh:= z;

if not SamePoint then
begin
//Set Vertex coordinates
FVertexs^[FPointCount].X := x;
FVertexs^[FPointCount].Y := y;
FVertexs^[FPointCount].Z := z;
//Increment the total number of points
//最后得到的点的数目会比实际数目多一个
FPointCount := FPointCount + 1;
end;
end;

//构建三角网
procedure TDelaunay.Mesh;
begin
QuickSort(FVertexs,1,FPointCount-1);
If FPointCount > 3 Then
FTriangleCount := Triangulate(FPointCount-1); //'Returns number of triangles created.
end;

//点按X坐标从小到大排序
procedure TDelaunay.QuickSort(var aVertexs: PVertexs; Low,High: Integer);
//Sort all points by x
procedure DoQuickSort(var aVertexs: PVertexs; iLo, iHi: Integer);
var
Lo, Hi: Integer;
Mid: Double;
T: dVertex;
begin
Lo := iLo;
Hi := iHi;
Mid := aVertexs^[(Lo + Hi) div 2].X;
repeat
while aVertexs^[Lo].x < Mid do Inc(Lo);
while aVertexs^[Hi].x > Mid do Dec(Hi);
if Lo <= Hi then
begin
T := aVertexs^[Lo];
aVertexs^[Lo] := aVertexs^[Hi];
aVertexs^[Hi] := T;
Inc(Lo);
Dec(Hi);
end;
until Lo > Hi;
if Hi > iLo then DoQuickSort(aVertexs, iLo, Hi);
if Lo < iHi then DoQuickSort(aVertexs, Lo, iHi);
end;
begin
DoQuickSort(aVertexs, Low, High);
end;


//真正构建三角网(nVert:点的个数)
Function TDelaunay.Triangulate(nVert: Integer): Integer;
//Takes as input NVERT vertices in arrays Vertex()
//Returned is a list of NTRI triangular faces in the array
//Triangle(). These triangles are arranged in clockwise order.
var
Completes: PCompletes;
Edges: PEdges;
Nedge: LongInt;

//For Super Triangle 一个包括所有点的外包三角形
xmin: Double;
xmax: Double;
ymin: Double;
ymax: Double;
xmid: Double;
ymid: Double;
dx: Double;
dy: Double;
dmax: Double;

//General Variables
i : Integer;
j : Integer;
k : Integer;
ntri : Integer;
xc : Double;
yc : Double;
r : Double;
inc : Boolean; //是否在外接圆中
begin
//Allocate memory
GetMem(Completes, sizeof(Completes^));
GetMem(Edges, sizeof(Edges^));

//Find the maximum and minimum vertex bounds.
//This is to allow calculation of the bounding triangle
xmin := FVertexs^[1].x;
ymin := FVertexs^[1].y;
xmax := xmin;
ymax := ymin;
For i := 2 To nvert do
begin
If FVertexs^.x < xmin Then xmin := FVertexs^.x;
If FVertexs^.x > xmax Then xmax := FVertexs^.x;
If FVertexs^.y < ymin Then ymin := FVertexs^.y;
If FVertexs^.y > ymax Then ymax := FVertexs^.y;
end;

dx := xmax - xmin;
dy := ymax - ymin;
If dx > dy Then
dmax := dx
Else
dmax := dy;

xmid := Trunc((xmax + xmin) / 2);
ymid := Trunc((ymax + ymin) / 2);

//Set up the supertriangle
//This is a triangle which encompasses all the sample points.
//The supertriangle coordinates are added to the end of the
//vertex list. 注意:The supertriangle is the first triangle in
//the triangle list.

FVertexs^[nvert + 1].x := (xmid - 2 * dmax);
FVertexs^[nvert + 1].y := (ymid - dmax);
FVertexs^[nvert + 2].x := xmid;
FVertexs^[nvert + 2].y := (ymid + 2 * dmax);
FVertexs^[nvert + 3].x := (xmid + 2 * dmax);
FVertexs^[nvert + 3].y := (ymid - dmax);
FTriangles^[1].vv0 := nvert + 1;
FTriangles^[1].vv1 := nvert + 2;
FTriangles^[1].vv2 := nvert + 3;
FTriangles^[1].Precalc := 0;

Completes[1] := False;
ntri := 1;

//Include each point one at a time into the existing mesh
For i := 1 To nvert do
begin
Nedge := 0;
//Set up the edge buffer.
//If the point (Vertex(i).x,Vertex(i).y) lies inside the circumcircle then the
//three edges of that triangle are added to the edge buffer.
j := 0;
repeat
j := j + 1;
If Completes^[j] <> True Then
begin
inc := InCircle(FVertexs^.x, FVertexs^.y, FVertexs^[FTriangles^[j].vv0].x,
FVertexs^[FTriangles^[j].vv0].y, FVertexs^[FTriangles^[j].vv1].x,
FVertexs^[FTriangles^[j].vv1].y, FVertexs^[FTriangles^[j].vv2].x,
FVertexs^[FTriangles^[j].vv2].y, xc, yc, r,j);
//Include this if points are sorted by X
If (xc + r) < FVertexs.x Then //
completes[j] := True //
Else If inc Then
begin
Edges^[1, Nedge + 1] := FTriangles^[j].vv0;
Edges^[2, Nedge + 1] := FTriangles^[j].vv1;
Edges^[1, Nedge + 2] := FTriangles^[j].vv1;
Edges^[2, Nedge + 2] := FTriangles^[j].vv2;
Edges^[1, Nedge + 3] := FTriangles^[j].vv2;
Edges^[2, Nedge + 3] := FTriangles^[j].vv0;
Nedge := Nedge + 3;
FTriangles^[j].vv0 := FTriangles^[ntri].vv0;
FTriangles^[j].vv1 := FTriangles^[ntri].vv1;
FTriangles^[j].vv2 := FTriangles^[ntri].vv2;
FTriangles^[j].PreCalc:=FTriangles^[ntri].PreCalc;
FTriangles^[j].xc:=FTriangles^[ntri].xc;
FTriangles^[j].yc:=FTriangles^[ntri].yc;
FTriangles^[j].r:=FTriangles^[ntri].r;
FTriangles^[ntri].PreCalc:=0;
Completes^[j] := Completes^[ntri];
j := j - 1;
ntri := ntri - 1;
End;//else
End; //if
until j>=ntri; //repeat

// Tag multiple edges
// Note: if all triangles are specified anticlockwise then all
// interior edges are opposite pointing in direction.
For j := 1 To Nedge - 1 do
If Not (Edges^[1, j] = 0) And Not (Edges^[2, j] = 0) Then
For k := j + 1 To Nedge do
If Not (Edges^[1, k] = 0) And Not (Edges^[2, k] = 0) Then
If Edges^[1, j] = Edges^[2, k] Then
If Edges^[2, j] = Edges^[1, k] Then
begin
Edges^[1, j] := 0;
Edges^[2, j] := 0;
Edges^[1, k] := 0;
Edges^[2, k] := 0;
End;

// Form new triangles for the current point
// Skipping over any tagged edges.
// All edges are arranged in clockwise order.
For j := 1 To Nedge do
If Not (Edges^[1, j] = 0) And Not (Edges^[2, j] = 0) Then
begin
ntri := ntri + 1;
FTriangles^[ntri].vv0 := Edges^[1, j];
FTriangles^[ntri].vv1 := Edges^[2, j];
FTriangles^[ntri].vv2 := i;
FTriangles^[ntri].PreCalc:=0;
Completes^[ntri] := False;
End;

end; //the first for

//Remove triangles with supertriangle vertices
//These are triangles which have a vertex number greater than NVERT
i:= 0;
repeat
i := i + 1;
If (FTriangles^.vv0 > nvert) Or (FTriangles^.vv1 > nvert) Or (FTriangles^.vv2 > nvert) Then
begin
FTriangles^.vv0 := FTriangles^[ntri].vv0;
FTriangles^.vv1 := FTriangles^[ntri].vv1;
FTriangles^.vv2 := FTriangles^[ntri].vv2;
i := i - 1;
ntri := ntri - 1;
End;
until i>=ntri;

Triangulate := ntri;

//Free memory
FreeMem(Completes, sizeof(Completes^));
FreeMem(Edges, sizeof(Edges^));
End;



function TDelaunay.InCircle(xp, yp, x1, y1, x2, y2, x3, y3: Double;
var xc: Double; var yc: Double; var r: Double; j: Integer): Boolean;
//Return TRUE if the point (xp,yp) lies inside the circumcircle
//made up by points (x1,y1) (x2,y2) (x3,y3)
//The circumcircle centre is returned in (xc,yc) and the radius r
//NOTE: A point on the edge is inside the circumcircle
var
eps: Double;
m1: Double;
m2: Double;
mx1: Double;
mx2: Double;
my1: Double;
my2: Double;
dx: Double;
dy: Double;
rsqr: Double;
drsqr: Double;
begin
eps:= 0.000001;
InCircle := False;

//Check if xc,yc and r have already been calculated
if FTriangles^[j].PreCalc=1 then
begin
xc := FTriangles^[j].xc;
yc := FTriangles^[j].yc;
r := FTriangles^[j].r;
rsqr := r*r;
dx := xp - xc;
dy := yp - yc;
drsqr := dx * dx + dy * dy;
end
else
begin
If (Abs(y1 - y2) < eps) And (Abs(y2 - y3) < eps) Then
begin
ShowMessage('INCIRCUM - F - Points are coincident !!');
Exit;
end;

If Abs(y2 - y1) < eps Then
begin
m2 := -(x3 - x2) / (y3 - y2);
mx2 := (x2 + x3) / 2;
my2 := (y2 + y3) / 2;
xc := (x2 + x1) / 2;
yc := m2 * (xc - mx2) + my2;
end
Else If Abs(y3 - y2) < eps Then
begin
m1 := -(x2 - x1) / (y2 - y1);
mx1 := (x1 + x2) / 2;
my1 := (y1 + y2) / 2;
xc := (x3 + x2) / 2;
yc := m1 * (xc - mx1) + my1;
end
Else
begin
m1 := -(x2 - x1) / (y2 - y1);
m2 := -(x3 - x2) / (y3 - y2);
mx1 := (x1 + x2) / 2;
mx2 := (x2 + x3) / 2;
my1 := (y1 + y2) / 2;
my2 := (y2 + y3) / 2;
if (m1-m2)<>0 then //se
begin
xc := (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
yc := m1 * (xc - mx1) + my1;
end
else
begin
xc:= (x1+x2+x3)/3;
yc:= (y1+y2+y3)/3;
end;
end;//else

dx := x2 - xc;
dy := y2 - yc;
rsqr := dx * dx + dy * dy;
r := Sqrt(rsqr);
dx := xp - xc;
dy := yp - yc;
drsqr := dx * dx + dy * dy;

//store the xc,yc and r for later use
FTriangles^[j].PreCalc:=1;
FTriangles^[j].xc:=xc;
FTriangles^[j].yc:=yc;
FTriangles^[j].r:=r;
end; //the big else

If drsqr <= rsqr Then InCircle := True;
end;



Function TDelaunay.WhichSide(xp, yp, x1, y1, x2, y2: Double): Integer;
//Determines which side of a line the point (xp,yp) lies.
//The line goes from (x1,y1) to (x2,y2)
//Returns -1 for a point to the left
// 0 for a point on the line
// +1 for a point to the right
var
equation: Double;
begin
equation := ((yp - y1) * (x2 - x1)) - ((y2 - y1) * (xp - x1));

If equation > 0 Then
WhichSide := -1
Else If equation = 0 Then
WhichSide := 0
Else
WhichSide := 1;
End;



procedure TDelaunay.Draw;
var
i: Integer;
begin
// Clear the form canvas
ClearBackPage;

TempBuffer.Canvas.Brush.Color := clwhite;
//Draw the created triangles
if (FTriangleCount > 0) then
For i:= 1 To FTriangleCount do
begin
TempBuffer.Canvas.Polygon([Point(Trunc(FVertexs^[FTriangles^.vv0].x), Trunc(FVertexs^[FTriangles^.vv0].y)),
Point(Trunc(FVertexs^[FTriangles^.vv1].x), Trunc(FVertexs^[FTriangles^.vv1].y)),
Point(Trunc(FVertexs^[FTriangles^.vv2].x), Trunc(FVertexs^[FTriangles^.vv2].y))]);
end;
FlipBackPage;
end;



procedure TDelaunay.ClearBackPage;
begin
TempBuffer.Height:=TargetForm.Height;
TempBuffer.Width:=TargetForm.Width;
TempBuffer.Canvas.Brush.Color := clBlack;
TempBuffer.Canvas.FillRect(Rect(0,0,TargetForm.Width,TargetForm.Height));
end;

procedure TDelaunay.FlipBackPage;
var
ARect : TRect;
begin
ARect := Rect(0,0,TargetForm.Width,TargetForm.Height);
TargetForm.Canvas.CopyRect(ARect, TempBuffer.Canvas, ARect);
end;



function TDelaunay.GetPointCount: integer;
begin
Result:= FPointCount-1;
end;


procedure TDelaunay.ScatterContour(ZCount: Integer; Z: Array of Single);
var
i,j,m: Integer;
Deside: Integer;
CastTab : TCastArray;

sH : TVectorL3I;
H,xH,yH : TVectorL3D;

TempD1,TempD2,dMin,dMax: Double ;
x1,x2,y1,y2: Double; //等值点坐标

ARecord: PPointPair; //记录点对

//插值计算
Function xSec(p1,p2:Integer): Double;
Begin
result:= (H[p2]*xH[p1]-H[p1]*xH[p2])/(H[p2]-H[p1]);
End;

Function ySec(p1,p2:Integer): Double;
Begin
result:= (H[p2]*yH[p1]-H[p1]*yH[p2])/(H[p2]-H[p1]);
End;

begin
//分配记录等值线的数组
for i:= 0 to Length(FLevers)-1 do
if Assigned(FLevers.Points) then
FLevers.Points.Free;
SetLength(FLevers,ZCount);
for i:= 0 to ZCount-1 do
begin
FLevers.FZ:= Z;
FLevers.Points:= TList.Create;
end;

//每个三角行内出现等值点的情况映射,有27种情况
//这27种情况是根据三角形的三个顶点高程与等值点
//的大小比较得来得,每个点有三种情况:大、小、等
//0..19 为 对各种情况的处理方法,有20种
CastTab[0,0,0]:= 0; CastTab[0,0,1]:= 0; CastTab[0,0,2]:= 1;
CastTab[0,1,0]:= 0; CastTab[0,1,1]:= 2; CastTab[0,1,2]:= 3;
CastTab[0,2,0]:= 4; CastTab[0,2,1]:= 5; CastTab[0,2,2]:= 6;

CastTab[1,0,0]:= 0; CastTab[1,0,1]:= 7; CastTab[1,0,2]:= 8;
CastTab[1,1,0]:= 9; CastTab[1,1,1]:= 10; CastTab[1,1,2]:= 9;
CastTab[1,2,0]:= 8; CastTab[1,2,1]:= 7; CastTab[1,2,2]:= 0;

CastTab[2,0,0]:= 6; CastTab[2,0,1]:= 5; CastTab[2,0,2]:= 4;
CastTab[2,1,0]:= 3; CastTab[2,1,1]:= 2; CastTab[2,1,2]:= 0;
CastTab[2,2,0]:= 1; CastTab[2,2,1]:= 0; CastTab[2,2,2]:= 0;

for i:= 1 to TriangleCount do
begin

//获得三角形三个顶点中的最小值和最大值
TempD1:= min(FVertexs^[FTriangles^.vv0].Z,FVertexs^[FTriangles^.vv1].Z);
TempD2:= min(FVertexs^[FTriangles^.vv1].Z,FVertexs^[FTriangles^.vv2].Z);
dMin:= min(TempD1,TempD2);
TempD1:= max(FVertexs^[FTriangles^.vv0].Z,FVertexs^[FTriangles^.vv1].Z);
TempD2:= max(FVertexs^[FTriangles^.vv1].Z,FVertexs^[FTriangles^.vv2].Z);
dMax:= max(TempD1,TempD2);

for j:= 0 to ZCount-1 do
if (Z[j] >= dMin) And (Z[j] <= dMax) Then
begin

H[0] := FVertexs^[FTriangles^.vv0].Z-Z[j];
xH[0]:= FVertexs^[FTriangles^.vv0].X;
yH[0]:= FVertexs^[FTriangles^.vv0].Y;
H[1] := FVertexs^[FTriangles^.vv1].Z-Z[j];
xH[1]:= FVertexs^[FTriangles^.vv1].X;
yH[1]:= FVertexs^[FTriangles^.vv1].Y;
H[2] := FVertexs^[FTriangles^.vv2].Z-Z[j];
xH[2]:= FVertexs^[FTriangles^.vv2].X;
yH[2]:= FVertexs^[FTriangles^.vv2].Y;

for m:= 0 to 2 do
If H[m] > 0 Then
sH[m]:= 1
Else If H[m]<0 Then
sH[m]:= -1
Else
sH[m]:= 0;

Deside := CastTab[sH[0]+1 ,sH[1]+1, sH[2]+1];

If NOT(deside = 0) Then // 0的情况不处理
begin
Case deside Of
1: begin
x1:= xSec(0,2);
y1:= ySec(0,2);
x2:= xSec(1,2);
y2:= ySec(1,2);
end;
2: begin
x1:= xH[1];
y1:= yH[1];
x2:= xH[2];
y2:= yH[2];
end;
3: begin
x1:= xH[1];
y1:= yH[1];
x2:= xSec(0,2);
y2:= ySec(0,2);
end;
4: begin
x1:= xSec(0,1);
y1:= ySec(0,1);
x2:= xSec(1,2);
y2:= ySec(1,2);
end;
5: Begin
x1:= xH[2];
y1:= yH[2];
x2:= xSec(0,1);
y2:= ySec(0,1);
End;
6: Begin
x1:= xSec(0,1);
y1:= ySec(0,1);
x2:= xSec(0,2);
y2:= ySec(0,2);
End;
7: Begin
x1:= xH[0];
y1:= yH[0];
x2:= xH[2];
y2:= yH[2];
End;
8: Begin
x1:= xH[0];
y1:= yH[0];
x2:= xSec(1,2);
y2:= ySec(1,2);
End;
9: Begin
x1:= xH[0];
y1:= yH[0];
x2:= xH[1];
y2:= yH[1];
End;
10: begin //there is some argument here
x1:= xH[0];
y1:= yH[0];
x2:= xH[2];
y2:= yH[2];
end;
end;//----case

//此处获得该三角形内的等值点
New(ARecord);
ARecord^.x1:= x1;
ARecord^.y1:= y1;
ARecord^.x2:= x2;
ARecord^.y2:= y2;
FLevers[j].Points.Add(ARecord);
end; //if not(deside)
end;// if Z[]
end;
end;

end.
 
再提个问题,还是200分,程序一运行,先读入d.txt(内容如下,第一列序号,第二列X,第三列Y),后就在Form上的Image显示响应的三角网,怎样写?

d.txt内容如下:
1 10 10
2 10 100
3 50 100
4 40 200
5 100 50
 
用Delphi做类似VB的Form,即靠鼠标的点击来形成三角网,代码(如下)编译出错:“invalid typecast”, 该行为 dVertex(tPoints).x:=mousex; 如何改?

unit Main;
interface
uses Math,Windows, SysUtils, WinTypes,Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, Menus, ComCtrls,
ShellApi,WinProcs,TeeProcs, TeEngine, chart,Series,delaunay;

type
TMainForm = class(TForm)
MainMenu: TMainMenu;
FileExitItem: TMenuItem;
StatusLine: TStatusBar;
OpenDialog: TOpenDialog;
SaveDialog: TSaveDialog;
PrintDialog: TPrintDialog;
PrintSetupDialog: TPrinterSetupDialog;
SpeedBar: TPanel;
Image1: TImage;
Timer1: TTimer;
Button1: TButton;
procedure FileExit(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
procedure d;
{ Private declarations }
public
procedure ClearCanvas;
{ Public declarations }
end;
var
MainForm : TMainForm;
StrA : String;
mhook1 :HHOOK;
x4,y4 : real;
x,y,x2,y2 : integer;
x0,x1,y1,xj0,yj0 : real;
sc2,z1,z2,z3,r : real;
mousex,mousey,mousex0,mousey0 : integer;
pnumber,mode :integer;
ch : char;
i,j,l,col : byte;
ok : boolean;
ix,iy :integer;

implementation
{$R *.DFM}

procedure TMainForm.ClearCanvas;
begin
with MainForm.Image1,Canvas do
begin
Brush.Style:=bsSolid;
Brush.Color:=clWhite;
FillRect(ClipRect);
end;
end;

procedure TMainForm.FileExit(Sender: TObject);
begin
Close;
end;

procedure TMainForm.d;
procedure xy_to_xy(x0,y0:real;var x1,y1:integer);
begin
x1 :=80+round(sc2*x0);
y1 :=440-round(sc2*y0);
end;
procedure line1(x0,y0,x1,y1:real);
begin
xy_to_xy(x0,y0,x,y);
xy_to_xy(x1,y1,x2,y2);
With MainForm.Image1,Canvas do
begin
moveto(x-ix,y-iy);
lineto(x2-ix,y2-iy);
end;
end;

function MouseHookProc1(iCode: Integer; wParam: WPARAM; lParam: LPARAM):LRESULT;stdcall;export;
var
CurPoint:TPoint;
i,j :integer;
howmany :integer;
tPoints :integer;
begin
if (wParam=WM_LButtonDown) then
begin
if pnumber<>99 then pnumber:=pnumber+1;
GetCursorPos(CurPoint);
mousex:=CurPoint.x;
mousey:=CurPoint.y;
dVertex(tPoints).x:=mousex;
dVertex(tPoints).y:=mousey;

if tPoints >2 then
begin
mainform.ClearCanvas;
howmany :=Triangulate(tPoints);
end

tPoints :=tPonts +1;
for i=1 to howmany do
begin
line1(Vertex(dTriangle(i).vv0).x, dVertex(dTriangle(i).vv0).y,dVertex(Triangle(i).vv1).x, dVertex(dTriangle(i).vv1).y);
Line1(Vertex(dTriangle(i).vv1).x, dVertex(dTriangle(i).vv1).y,dVertex(Triangle(i).vv2).x, dVertex(dTriangle(i).vv2).y);
Line1(Vertex(dTriangle(i).vv0).x, dVertex(dTriangle(i).vv0).y,dVertex(Triangle(i).vv2).x, dVertex(dTriangle(i).vv2).y);

end;

with MainForm.Image1,Canvas do Textout(50,460,'请再点:');
UnhookWindowsHookEx(mHook1);
setCursorpos(mousex,mousey);
mhook1:=SetWindowsHookEx(WH_MOUSE, @mouseHookProc1, 0, GetCurrentThreadID);
end; //pnumber down

end; //if (wParam=WM_LButtonDown) then
Result := CallNextHookEx(mHook1, iCode, wParam, lParam); //调用下一个函数
end;

begin
with MainForm.Image1,Canvas do Textout(50,460,'点入点位置');
mhook1:=SetWindowsHookEx(WH_MOUSE, @mouseHookProc1, 0, GetCurrentThreadID);
pnumber:=0;
ix:=image1.left;
iy:=25+21+SpeedBar.height; //bar=25 MainMenu=21
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
MainForm.d;
end;

end.
 
在dVertex(tPoints).x:=mousex之前应申请内存,即De:=TDelaunay.Create; 而要
申请内存,就先得定义De,即De:TDelaunay
 
接受答案了.
 
后退
顶部