I use graphics, which you suggested. I had the impression that some of the processing results are not displayed. But though I can not say. Pascal was a prototype. It works well. In Alaska I made a complete similar. Well, something else added, interfaces, saving all the results in a database. But works like something is wrong. I do not understand what was going on. That thought may need to somehow make that new team did not start until the early completion fulfilled. I have noticed that when you insert variables in view triangulation cycle, it is usually not worked all right. For when the program runs quickly without a pause - then the results are not always correct.
Still, I wanted to use in conjunction with Roger graphics command: GraGradient(oPS, {X1,Y1}, {{X2,Y2}, {X3,Y3}}, aClrs, GRA_GRADIENT_TRIANGLE) to display color triangles.
Code: Select all
/*
*Обращаться очень просто - там есть массив Points в который записывать точки, переменная PointsCount в 
*которую записывать количество точек. Вам нужно заполнить точками этот массив перед вызовом функции и 
*присвоить соответствующее значение переменной PointsCount. Затем нужно вызвать одну единственную 
*функцию - Triangulation. В функцию не передаются никакие параметры. И после того как функция отработает - 
*получаем заполненный массив рёбер Ribs и заполненный массив треугольников Triangles - которые вы 
*можете прочитать после выполнения функции Triangulation. Количества рёбер и треугольников так же можно 
*прочитать в соответствующих переменных RibsCount и TrianglesCount. В массиве Triangles треугольники 
*описаны тремя целыми числами - это номера точек в массиве Points. То есть допустим если треугольник 
*описан числами 1,2,3 это значит что координаты точек нужно брать из ячеек points[1], points[2] и points[3] 
*соответственно. 
Ribs - это массив ребер. Он заполняется в процессе работы функции триангуляции, нужен для работы самой процедуры 
но может затем использовать и для любых других нужд. В этом массиве просто записан список ребер которые обнаруживаются 
в ходе триангуляции. Каждое ребро описано двумя целыми числами - это номера 2-х точек задающих ребро. Номера точек 
- это их индексы в массиве points.
Triangles - это массив треугольников. Он заполняется в процессе работы функции триангуляции, используется для работы 
самой функции а так же является результатом работы функции. В этом массиве просто записан список треугольников в порядке 
как они обнаруживались в ходе работы функции. Каждый треугольник описан тремя целыми числами. Каждое из этих чисел имеет 
тот же смысл что и в массиве Ribs - это номера точек задающих вершины треугольника. Номера точек - это их индексы в массиве points.
Кстати, из глобальных переменных у меня там только 6 - три массива и три целочисленных переменных. 
Это массив Triangles, массив Ribs, массив Points, переменная TrianglesCount, перменная RibsCount, переменная PointsCount. 
Всё - на этом список исчерпан. ВСЕ остальные переменные у меня там локальные.
*/
#include "appevent.ch"
#include "axcdxcmx.ch"
#include "collat.ch"
#include "common.ch"
#include "dbedit.ch"
#include "dbfdbe.ch"
#include "dcapp.ch"
#include "dcbitmap.ch"
#include "dccargo.ch"
#include "dccursor.ch"
#include "dcdialog.ch"
#include "dcdir.ch"
#include "dcfiles.ch"
#include "dcgra.ch"
#include "dcgraph.ch"        // графика
#include "BdColors.Ch"       // графика
#include "dccolors.ch"       // графика
#include "dcprint.ch"        // графика
*#INCLUDE "rmchart.CH"       // графика
#include "dcicon.ch"
#include "dcmsg.ch"
#include "dcpick.ch"
#include "deldbe.ch"
#include "directry.ch"
#include "dmlb.ch"
#include "express.ch"
#include "fileio.ch"
#include "font.ch"
#include "gra.ch"
#include "inkey.ch"
#include "memvar.ch"
#include "natmsg.ch"
#include "prompt.ch"
#include '_dcdbfil.ch'
*#INCLUDE "dcads.CH"
#include "set.ch"
#include "std.ch"
#include "xbp.ch"
#include '_dcappe.ch'
#include 'dcscope.ch'
#include '_dcstru.ch'
#include 'dcfields.ch'
#include 'dccolor.ch'
#INCLUDE "dll.CH"
#pragma library( "ascom10.lib" )
#pragma library( "dclip1.lib" )
#pragma library( "dclip2.lib" )
#pragma library( "dclipx.lib" )
#pragma library( "xbtbase1.lib" )
#pragma library( "xbtbase2.lib" )
#pragma library( "xppui2.lib" )
#INCLUDE "dll.CH"
#INCLUDE "dcdialog.CH"
#DEFINE SRCCOPY  0xCC0020
STATIC snHdll
PROCEDURE AppSys
// Рабочий стол остается окном приложения
RETURN
*****************************************************************************
FUNCTION Main()
PUBLIC GetList[0], GetOptions, oSay, hDC1, hDC2, oStatic1, oStatic2, aPixel
PUBLIC nColorB := AutomationTranslateColor(GraMakeRGBColor({0,0,0}),.f.)          // Черные пиксели
PUBLIC nColorG := AutomationTranslateColor(GraMakeRGBColor({200,200,200}),.f.)    // Серые  пиксели
PUBLIC nColorR := AutomationTranslateColor(GraMakeRGBColor({255,050,039}),.f.)    // Ярко-красный пиксель
DC_IconDefault(1000)
*********** Формирование массива точек
PUBLIC X := {}, Y := {}, Z := {}, mFlagCircle := .T.                              // Координаты X,Y,Z точек облак
PUBLIC TrianglesP1:= {}, TrianglesP2:= {}, TrianglesP3:= {}                       // Массивы номеров точек вершин треугольников
PUBLIC RibsP1:= {}, RibsP2:= {}, Points:= {}                                      // Массивы номеров точек ребер
PUBLIC TrianglesCount:=0, RibsCount:=0, PointsCount:=20                           // Кол-во треугольников, ребер, точек
PUBLIC X_MaxW := 1300, Y_MaxW := 700                                              // Размер графического окна для самого графика в пикселях
PUBLIC nXSize := X_MaxW
PUBLIC nYSize := Y_MaxW
** Максимальные значения x,y,z
maxX = nXSize-10
maxY = nYSize-10
maxZ = 1000
** Имя графического файла для рисования
mFileName = 'Delone.jpg'
H = 20  // Высота кнопки
W =  8  // Ширина кнопки
D =  5  // Расстояние между кнопками
@ 0,0 DCSTATIC TYPE XBPSTATIC_TYPE_BITMAP ;
      CAPTION mFileName ;
      OBJECT oStatic1 ;
      PREEVAL {|o|o:autoSize := .t.} ;
      EVAL {|o|hDC1 := GetWindowDC(o:getHWnd()), ;
               o:motion := {|a,b,o|ShowColor( hDC1, a, oSay, o )}, ;
               aPixel := Array(o:caption:xSize,o:caption:ySize)}
@ 0,0 DCSTATIC TYPE XBPSTATIC_TYPE_BITMAP;
      CAPTION mFileName ;
      PREEVAL {|o|o:autoSize := .t.} ;
      OBJECT oStatic2 ;
      EVAL {|o|hDC2 := GetWindowDC(o:getHWnd())}
@  40,2 DCSAY '' SAYSIZE 350,20 FONT '10.Lucida Console' OBJECT oSay
@  40,2 DCPUSHBUTTON                    CAPTION 'Очистка'                SIZE 100, H ACTION {||ClearImage(hDC2,aPixel)}
@ DCGUI_ROW, DCGUI_COL + D DCPUSHBUTTON CAPTION 'Генерация облака точек' SIZE 200, H ACTION {||GenPoints(hDC2,PointsCount,.T.)}
@ DCGUI_ROW, DCGUI_COL + D DCPUSHBUTTON CAPTION 'Триангуляция (сетка)'   SIZE 150, H ACTION {||Triangulation(hDC2)}
@ DCGUI_ROW, DCGUI_COL + D DCPUSHBUTTON CAPTION 'Триангуляция (цвет)'    SIZE 150, H ACTION {||Shading(hDC2)}
@ DCGUI_ROW, DCGUI_COL + D DCPUSHBUTTON CAPTION 'Поиск 1-го ребра'       SIZE 100, H ACTION {||FindFirstRib(hDC2)}
@ DCGUI_ROW, DCGUI_COL + 80*D DCCHECKBOX mFlagCircle PROMPT  'Рисовать окружности?'
DCGETOPTIONS PIXEL
DCREAD GUI FIT TITLE 'Триангуляция Делоне' OPTIONS GetOptions ;
   EVAL {||GenPoints(hDC2,PointsCount,.F.)} SETAPPWINDOW
CLOSE ALL
RETURN NIL
*****************************************************************************
*--------------------
FUNCTION FRND(mMax)
RETURN(1 + INT(RANDOM() / 65535 * mMax))
*--------------------
FUNCTION LB_Warning( message, ctitle )
  LOCAL aMsg := {}
  DEFAULT cTitle TO ''
  IF VALTYPE(message) # 'A'
    aadd(aMsg,message)
  ELSE
    aMsg := message
  ENDIF
  IF LEN(ALLTRIM(cTitle)) > 0
     DC_MsgBox( ,,aMsg,cTitle)
  ELSE
     DC_MsgBox( ,,aMsg,'Универсальная когнитивная аналитическая система "Эйдос-Х++"')
  ENDIF
RETURN NIL
*--------------------
******** Задание количества точек
FUNCTION NPoints(oStatic)
LOCAL GetList[0], GetOptions, oSay
@10,10 DCGROUP oGroup1 CAPTION 'Задайте количество точек:' SIZE 23.0, 2.5
@ 1, 1 DCSAY "" GET PointsCount PICTURE "##########" PARENT oGroup1
   DCGETOPTIONS TABSTOP
   DCREAD GUI ;
      TO lExit ;
      FIT ;
      OPTIONS GetOptions ;
      ADDBUTTONS;
      MODAL ;
      TITLE 'Триангуляция Делоне'
      ********************************************************************
      IF lExit
         ** Button Ok
      ELSE
         QUIT
      ENDIF
      ********************************************************************
RETURN(PointsCount)
* ---------
******** Генерация и отображение облака точек
FUNCTION GenPoints(hDC,PointsCount,mClear)
LOCAL GetList[0], GetOptions, oSay, oDevice
LOCAL hMemoryDC := hDC      // CreateMemoryDC( hDC, nXSize, nYSize )
PUBLIC X := {}, Y := {}, Z := {}                                                  // Координаты X,Y,Z точек облак
PUBLIC TrianglesP1:= {}, TrianglesP2:= {}, TrianglesP3:= {}                       // Массивы номеров точек вершин треугольников
PUBLIC RibsP1:= {}, RibsP2:= {}, Points:= {}                                      // Массивы номеров точек ребер
*PUBLIC TrianglesCount:=0, RibsCount:=0, PointsCount:=20                          // Кол-во треугольников, ребер, точек
PointsCount = NPoints()     // Задание количества точек
IF mClear
   ClearImage(hDC,aPixel)
ENDIF
**** Создать БД для облака точек X,Y,Z
aStructure := { { "Num", "N",  15, 0 }, ;
                { "pX" , "N",  15, 0 }, ;
                { "pY" , "N",  15, 0 }, ;
                { "pZ" , "N",  15, 0 }  }
DbCreate( 'Points_XYZ', aStructure )
CLOSE ALL
USE Points_XYZ EXCLUSIVE NEW
SELECT Points_XYZ
** Максимальные значения x,y,z
maxX = nXSize-10
maxY = nYSize-10
maxZ = 1000
FOR p=1 TO PointsCount
    
    mX = FRND(maxX)
    mY = FRND(maxY)
    mZ = FRND(maxZ)
    AADD(X, mX)
    AADD(Y, mY)
    AADD(Z, mZ)
    APPEND BLANK
    REPLACE Num WITH p
    REPLACE pX  WITH X[p]
    REPLACE pY  WITH Y[p]
    REPLACE pZ  WITH Z[p]
    Circle(hDC,mX,mY,1,nColorR)          // Маленький кружочек (r=1)
    Circle(hDC,mX,mY,2,nColorR)          // Маленький кружочек (r=2)
    Circle(hDC,mX,mY,3,nColorB)          // Маленький кружочек (r=3)
    Circle(hDC,mX,mY,4,nColorG)          // Маленький кружочек (r=4)
NEXT
LB_Warning( 'Построение точек завершено','Триангуляция Делоне' )
CLOSE ALL
RETURN nil
* ---------
******** Градиентная заливка
FUNCTION Shading(oStatic)
RETURN nil
* ---------
*************************************************
function Side(hDC,i,j,k)
LOCAL x1,y1,x2,y2,xo,yo,dx,dy,a,b,v
x1:=X[i]
y1:=Y[i]
x2:=X[j]
y2:=Y[j]
xo:=X[k]
yo:=Y[k]
dx:=x2-x1
dy:=y2-y1
if abs(dx)>abs(dy)
   a:=dy/dx
   b:=y1-a*x1
   v:=a*xo+b
   result = if(yo>v,0,1)
else
   a:=dx/dy
   b:=x1-a*y1
   v:=a*yo+b
   result = if(xo>v,0,1)
endif
*Circle(hDC,xo,yo,5,IF(result=1,nColorB,nColorR))          // Сделать отображение окружности, если это задано
*Line(hDC,x1,y1,x2,y2,nColorR)
RETURN(result)
*--------------------
function TriangleExists(p1,p2,p3)
LOCAL i
IF TrianglesCount = 0
   RETURN(.F.)
ELSE
   for i:=TrianglesCount to 1 STEP -1
       f1=.F.;if p1=trianglesP1[i] .or. p1=trianglesP2[i] .or. p1=trianglesP3[i];f1=.T.;endif
       f2=.F.;if p2=trianglesP1[i] .or. p2=trianglesP2[i] .or. p2=trianglesP3[i];f2=.T.;endif
       f3=.F.;if p3=trianglesP1[i] .or. p3=trianglesP2[i] .or. p3=trianglesP3[i];f3=.T.;endif
       IF f1 .and. f2 .and. f3
          RETURN(.T.)
       ENDIF
   NEXT
ENDIF
RETURN(.F.)
*--------------------
function SolveCircle(hDC,x1,y1,x2,y2,x3,y3)
LOCAL ma,mb,dx1,dy1,dx2,dy2,dm
*MsgBox("SolveCircle: x1,y1=("+str(x1)+","+str(y1)+"),  x2,y2=("+str(x2)+","+str(y2)+") , x3,y3=("+str(x3)+","+str(y3)+")")
dx1:=x2-x1;dy1:=y2-y1
dx2:=x3-x2;dy2:=y3-y2
if abs(dx1)<0.01;x1:=x1-0.1;dx1:=x2-x1;endif
if abs(dx2)<0.01;x3:=x3+0.1;dx2:=x3-x2;endif
if abs(dy1)<0.01;y1:=y1-0.1;dy1:=y2-y1;endif
if abs(dy2)<0.01;y3:=y3+0.1;dy2:=y3-y2;endif
ma:=dy1/dx1
mb:=dy2/dx2
dm:=mb-ma
if abs(dm)<0.0000001;y3:=y3+0.1;dy2:=y3-y2;mb:=dy2/dx2;dm:=mb-ma;endif
xo:=(ma*mb*(y1-y3)+mb*(x1+x2)-ma*(x2+x3))*0.5/dm
yo:=-1/mb*(xo-(x2+x3)*0.5)+(y2+y3)*0.5
dx1:=x1-xo
dy1:=y1-yo
R:=sqrt(dx1*dx1+dy1*dy1)
IF mFlagCircle
   Circle(hDC,xo,yo,R,nColorB)          // Сделать отображение окружности, если это задано
ENDIF
cr := {}
AADD(cr,xo)
AADD(cr,yo)
AADD(cr,R )
RETURN(cr)
*--------------------
function FindPoint(hDC,r1,r2)
LOCAL i,j,cr,b,x2,y2,v,xo,yo,R
for i:=1 to pointsCount
    if .not. TriangleExists(r1,r2,i)
       if i<>r1 .and. i<>r2
*         MsgBox("FindPoint: x1,y1=("+str(X[r1])+","+str(Y[r1])+"),  x2,y2=("+str(X[r2])+","+str(Y[r2])+") , x3,y3=("+str(X[i])+","+str(Y[i])+")")
          cr = SolveCircle(hDC,X[r1],Y[r1],X[r2],Y[r2],X[i],Y[i])
          xo=cr[1]
          yo=cr[2]
          R =cr[3]
          b:=.T.
          for j:=1 to pointsCount
              if j<>r1 .and. j<>r2 .and. j<>i
                 x2:=X[j]-xo
                 y2:=Y[j]-yo
                 v:=sqrt(x2*x2+y2*y2)
*                 Circle(hDC,xo,yo,R,nColorB)          // Сделать отображение окружности, если это задано
*                 Circle(hDC,X[j],Y[j],10,nColorR)     // Сделать отображение окружности, если это задано
*                 MsgBox('STOP')
                 if v<R
                    b:=.F.
                    EXIT
                 endif
              endif
          NEXT
          if b
             RETURN(i)
          endif
       endif
    endif
NEXT
RETURN(-1)
*--------------------
function FindFirstRib(hDC)
LOCAL i,j,k,n,st_1,st_0
for i:=1 to pointsCount-1
    for j:=i+1 to pointsCount
   	st_1:=.F.
  	st_0:=.F.
  	for k:=1 to pointsCount
   	    if k<>i .and. k<>j
  	       n:=Side(hDC,i,j,k)
	       if n=1;st_1:=.T.;endif
  	       if n=0;st_0:=.T.;endif
	    endif
        NEXT
	if st_1 <> st_0
           AADD(RibsP1, i)
           AADD(RibsP2, j)
           RibsCount:=1
           Line(hDC,X[i],Y[i],X[j],Y[j],nColorR)
           CLOSE ALL
           **** Создать БД для координат концов ребер
           aStructure := { { "Num" , "N",  15, 0 }, ;
                           { "pX1" , "N",  15, 0 }, ;
                           { "pY1" , "N",  15, 0 }, ;
                           { "pX2" , "N",  15, 0 }, ;
                           { "pY2" , "N",  15, 0 }, ;
                           { "pID" , "C",  20, 0 }  }
           DbCreate( 'Ribs_XY', aStructure )
           ar := {}
           AADD(ar, i)
           AADD(ar, j)
           ASORT(ar)
           mRibsID = STRTRAN(STR(ar[1])+STR(ar[2]),' ','_')
           CLOSE ALL
           USE Ribs_XY EXCLUSIVE NEW
           SELECT Ribs_XY
           APPEND BLANK
           REPLACE Num WITH i
           REPLACE pX1 WITH X[i]
           REPLACE pY1 WITH Y[i]
           REPLACE pX2 WITH X[j]
           REPLACE pY2 WITH Y[j]
           REPLACE pID WITH mRibsID
           CLOSE ALL
           RETURN NIL
	endif
*       MsgBox('STOP '+STR(j))
    NEXT
NEXT
RETURN NIL
*--------------------
FUNCTION Triangulation(hDC)
LOCAL i,p1,p2,n
FindFirstRib(hDC)
**** Создать БД для координат вершин треугольников
aStructure := { { "Num" , "N",  15, 0 }, ;
                { "pX1" , "N",  15, 0 }, ;
                { "pY1" , "N",  15, 0 }, ;
                { "pZ1" , "N",  15, 0 }, ;
                { "pX2" , "N",  15, 0 }, ;
                { "pY2" , "N",  15, 0 }, ;
                { "pZ2" , "N",  15, 0 }, ;
                { "pX3" , "N",  15, 0 }, ;
                { "pY3" , "N",  15, 0 }, ;
                { "pZ3" , "N",  15, 0 }, ;
                { "pID" , "C",  30, 0 }  }
DbCreate( 'Triang_XYZ', aStructure )
CLOSE ALL
USE Ribs_XY    EXCLUSIVE NEW
USE Triang_XYZ EXCLUSIVE NEW
TrianglesCount:=0
*MsgBox("Кол-во ребер: "+STR(RibsCount))
aRibsID   := {}
aTriangID := {}
TrianglesCount:=0
i:=1
DO WHILE i < RibsCount+1
   p1:=RibsP1[i]
   p2:=RibsP2[i]
   n:=FindPoint(hDC,p1,p2)          // Не происходит обход цикла и выход из цикла
*  MsgBox('p1='+STR(p1)+',  p2='+STR(p2)+',  n='+STR(n))
*  MsgBox("Номер найденной точки: "+STR(n)+", номер текущего ребра: "+STR(i))
   IF n > 0                         // Не происходит обход цикла и выход из цикла
      ********* Формирование ID ребер и тругольников и обход, если они уже есть
      SELECT Ribs_XY
      AADD(RibsP1, p1);AADD(RibsP2, n);RibsCount++
      ar := {}
      AADD(ar, p1)
      AADD(ar, n )
      ASORT(ar)
      mRibsID = STRTRAN(STR(ar[1])+STR(ar[2]),' ','_')
      APPEND BLANK
      REPLACE Num WITH i
      REPLACE pX1 WITH X[p1]
      REPLACE pY1 WITH Y[p1]
      REPLACE pX2 WITH X[n ]
      REPLACE pY2 WITH Y[n ]
      REPLACE pID WITH mRibsID
      Line(hDC,X[p1],Y[p1],X[n],Y[n],nColorR)
      ar := {}
      AADD(ar, p2)
      AADD(ar, n )
      ASORT(ar)
      mRibsID = STRTRAN(STR(ar[1])+STR(ar[2]),' ','_')
      AADD(RibsP1, p2);AADD(RibsP2, n);RibsCount++
      APPEND BLANK
      REPLACE Num WITH i
      REPLACE pX1 WITH X[p2]
      REPLACE pY1 WITH Y[p2]
      REPLACE pX2 WITH X[n ]
      REPLACE pY2 WITH Y[n ]
      REPLACE pID WITH mRibsID
      Line(hDC,X[p2],Y[p2],X[n],Y[n],nColorR)
      SELECT Triang_XYZ
      ar := {}
      AADD(ar, p1)
      AADD(ar, p2)
      AADD(ar, n )
      ASORT(ar)
      mTriangID = STRTRAN(STR(ar[1])+STR(ar[2])+STR(ar[3]),' ','_')
      AADD (aTriangID, mTriangID)
      AADD(trianglesP1, p1)
      AADD(trianglesP2, p2)
      AADD(trianglesP3, n )
      TrianglesCount++
      APPEND BLANK
      REPLACE Num WITH i
      REPLACE pX1 WITH X[p1]
      REPLACE pY1 WITH Y[p1]
      REPLACE pZ1 WITH Z[p1]
      REPLACE pX2 WITH X[p2]
      REPLACE pY2 WITH Y[p2]
      REPLACE pZ2 WITH Z[p2]
      REPLACE pX3 WITH X[n ]
      REPLACE pY3 WITH Y[n ]
      REPLACE pZ3 WITH Z[n ]
      REPLACE pID WITH mTriangID
      Line(hDC,X[p1],Y[p1],X[n ],Y[n ],nColorB)
      Line(hDC,X[p2],Y[p2],X[n ],Y[n ],nColorB)
      Line(hDC,X[p1],Y[p1],X[p2],Y[p2],nColorB)
   ENDIF
   i++
ENDDO
IF mFlagCircle
*  SELECT Ribs_XY
*  DBGOTOP()
*  DO WHILE .NOT. EOF()
*     Line(hDC,pX1,pY1,pX2,pY2,nColorR)
*     DBSKIP(1)
*  ENDDO
*   SELECT Triang_XYZ
*   DBGOTOP()
*   DO WHILE .NOT. EOF()
*      Line(hDC,pX1,pY1,pX2,pY2,nColorR)
*      Line(hDC,pX1,pY1,pX3,pY3,nColorR)
*      Line(hDC,pX2,pY2,pX3,pY3,nColorR)
*      DBSKIP(1)
*   ENDDO
    FOR j=1 TO LEN(trianglesP1)
        X1 = X[trianglesP1[j]]
        Y1 = Y[trianglesP1[j]]
        X2 = X[trianglesP2[j]]
        Y2 = Y[trianglesP2[j]]
        X3 = X[trianglesP3[j]]
        Y3 = Y[trianglesP3[j]]
        Line(hDC,X1,Y1,X2,Y2,nColorR)
        Line(hDC,X1,Y1,X3,Y3,nColorR)
        Line(hDC,X2,Y2,X3,Y3,nColorR)
    NEXT
ENDIF
CLOSE ALL
LB_Warning( 'Триангуляция завершена','Триангуляция Делоне' )
RETURN NIL
******************************************************************************************
******************************************************************************************
******************************************************************************************
* --------- Графика Роджера ---------------------------
FUNCTION LoadArray( hDC1, aPixel )
LOCAL hMemoryDC
LOCAL i, j, oScrn, nXSize := Len(aPixel), nYSize := Len(aPixel[1])
LOCAL nSeconds := Seconds()
/*
IF !aPixel[1,1] == nil
  DCMSGBOX 'Array is already loaded!'
  RETURN nil
ENDIF
*/
hMemoryDC := CreateMemoryDC( hDC1, nXSize, nYSize)
FOR i := 1 TO nXSize
  FOR j := 1 TO nYSize
    aPixel[i,j] := GetPixel(hMemoryDC,i-1,j-1)
  NEXT
NEXT
MsgBox(Alltrim(Str(Seconds()-nSeconds)) + ' Seconds to load Array')
DC_ClearEvents()
RETURN aPixel
* ---------
FUNCTION ClearImage( hDC2, aPixel )
LOCAL i, j, nXSize := Len(aPixel), nYSize := Len(aPixel[1])
LOCAL nColor := AutomationTranslateColor(GraMakeRGBColor({255,255,255}),.f.)
LOCAL hMemoryDC := hDC2 // CreateMemoryDC( hDC2, nXSize, nYSize )   // Для ускорения работы GetPixel() примерно в 50 раз
PUBLIC X := {}, Y := {}, Z := {}, mFlagCircle := .T.                              // Координаты X,Y,Z точек облак
PUBLIC TrianglesP1:= {}, TrianglesP2:= {}, TrianglesP3:= {}                       // Массивы номеров точек вершин треугольников
PUBLIC RibsP1:= {}, RibsP2:= {}, Points:= {}                                      // Массивы номеров точек ребер
PUBLIC TrianglesCount:=0, RibsCount:=0, PointsCount:=20                           // Кол-во треугольников, ребер, точек
FOR i := 0 TO nXSize
    FOR j := 0 TO nYSize
*       SetPixel(hMemoryDC, i, j, nColor)
        SetPixel(hDC2, i, j, nColor)
    NEXT
NEXT
LB_Warning( 'Очистка изображения завершена','Триангуляция Делоне' )
RETURN nil
* ----------
FUNCTION TransferImage( hDC1, hDC2, aPixel )
LOCAL i, j, nColor, lEmptyArray := aPixel[1,1] == nil, ;
      nXSize := Len(aPixel), nYSize := Len(aPixel[1])
LOCAL hMemoryDC := CreateMemoryDC( hDC1, nXSize, nYSize )
FOR i := 0 TO nXSize-1
  FOR j := 0 TO nYSize-1
    IF lEmptyArray
      SetPixel(hDC2,i,j,GetPixel(hMemoryDC,i,j))
    ELSE
      SetPixel(hDC2,i,j,aPixel[i+1,j+1])
    ENDIF
  NEXT
NEXT
RETURN nil
* ----------
FUNCTION FlipImage( hDC1, hDC2, aPixel )
LOCAL i, j, lEmptyArray := aPixel[1,1] == nil, ;
      nXSize := Len(aPixel), nYSize := Len(aPixel[1])
LOCAL hMemoryDC := CreateMemoryDC( hDC1, nXSize, nYSize )
FOR i := 0 TO nXSize-1
  FOR j := 0 TO nYSize-1
    IF lEmptyArray
      SetPixel(hDC2,j,i,GetPixel(hMemoryDC,j,nXSize-i))
    ELSE
      SetPixel(hDC2,j,i,aPixel[i+1,j+1])
    ENDIF
  NEXT
NEXT
RETURN nil
* -----------
FUNCTION RotateImage( hDC1, hDC2, aPixel )
LOCAL i, j, lEmptyArray := aPixel[1,1] == nil, ;
      nXSize := Len(aPixel), nYSize := Len(aPixel[1])
LOCAL hMemoryDC := CreateMemoryDC( hDC1, nXSize, nYSize )
FOR i := 0 TO nXSize-1
  FOR j := 0 TO nYSize-1
    IF lEmptyArray
      SetPixel(hDC2,i,j,GetPixel(hMemoryDC,j,nXSize-i))
    ELSE
      SetPixel(hDC2,i,j,aPixel[j+1,nXSize-i])
    ENDIF
  NEXT
NEXT
RETURN nil
* ---------
FUNCTION CreateMemoryDC( hDC, nXSize, nYSize )
LOCAL hMemoryDC, hBMP
hMemoryDC := CreateCompatibleDC(hDC)    // create compatible memory DC
hBMP      := CreateCompatibleBitmap(hDC,nXSize,nYSize) // create DDB
SelectObject(hMemoryDC,hBMP)                    // put hBMP into memory DC
BitBlt( hMemoryDC,0,0,nXSize,nYSize,hDC,0,0,SRCCOPY ) // copy desktop DC into memory DC
RETURN hMemoryDC
* ---------
STATIC FUNCTION ShowColor( hDC, aCoords, oSay, oStatic )
LOCAL nColor
aCoords[2] := oStatic:currentSize()[2] - aCoords[2]
nColor := GetPixel(hDC,aCoords[1],aCoords[2])
oSay:setCaption('Color: ' + DC_Array2String(GraGetRGBIntensity(AutomationTranslateColor(nColor,.T.))) + ;
   ' Coords: ' + DC_Array2String(aCoords))
RETURN nil
* ----------
#command  GDIFUNCTION <Func>([<x,...>]) ;
       => ;
FUNCTION <Func>([<x>]);;
STATIC scHCall := nil ;;
IF scHCall == nil ;;
  IF snHdll == nil ;;
    snHDll := DllLoad('GDI32.DLL') ;;
  ENDIF ;;
  scHCall := DllPrepareCall(snHDll,DLL_STDCALL,<(Func)>) ;;
ENDIF ;;
RETURN DllExecuteCall(scHCall,<x>)
GDIFUNCTION GetPixel( nHDC, x, y)
GDIFUNCTION SetPixel( nHDC, x, y, n )
DLLFUNCTION GetWindowDC( hwnd ) USING STDCALL FROM USER32.DLL
DLLFUNCTION CreateCompatibleDC( nHDC ) USING STDCALL FROM GDI32.DLL
DLLFUNCTION CreateCompatibleBitmap( nHDC, dw, dh ) USING STDCALL FROM GDI32.DLL
DLLFUNCTION SelectObject(hMemoryDC,hBMP) USING STDCALL FROM GDI32.DLL
DLLFUNCTION BitBlt( hDC,nXDest,nYDest,nXSize,nYSize,hDCSrc,nXSrc,nYSrc,dwROP ) USING STDCALL FROM GDI32.DLL
**********************************************************************************************
FUNCTION Circle(hDC,X0,Y0,R0,nColor)
FOR j = 1 TO 360 STEP 1
    nX = X0 + R0 * COS( j * 3.14159265358979323846 / 180 )
    nY = Y0 - R0 * SIN( j * 3.14159265358979323846 / 180 )
    SetPixel(hDC, nX, nY, nColor)
NEXT
RETURN nil
*--------------
FUNCTION Line(hDC,X1,Y1,X2,Y2,nColor)
FOR nX = X1 TO X2 STEP 0.01
    nY=Y1+(Y2-Y1)/(X2-X1)*(nX-X1)
    SetPixel(hDC, nX, nY, nColor)
NEXT
FOR nY = Y1 TO Y2 STEP 0.01
    nX=X1+(X2-X1)/(Y2-Y1)*(nY-Y1)
    SetPixel(hDC, nX, nY, nColor)
NEXT
RETURN nil