Skip to content

Prajuab Riabroy's Blog

Survey Application – GNSS – UAV – Programing – Python – Dart&Flutter – Rust

Menu
  • Home
  • About Us
  • Survey Application
    • Surveyor Pocket Tools
    • Traverse Pro
    • XSection Plot
    • Geoid Height Pro
    • Spot Fire
    • โปรแกรมงานสำรวจสำหรับเครื่องคิดเลข Casio fx-5800P
    • โปรแกรมงานสำรวจสำหรับเครื่องคิดเลข Casio fx-9860G II SD
  • Download
  • Privacy Policy
Menu

การเขียนโปรแกรมคำนวณแปลงพิกัดระหว่าง Datum ด้วยไลบรารี GDAL/OGR (ตอนที่ 2)

Posted on 17/01/2010
  • รูปด้านล่างแสดงตัว object ที่วางลงบนฟอร์มประกอบด้วย 2 combobox เก็บ datum ซึ่งผมจำกัดไว้แค่เท่าที่ประเทศไทยใช้กัน ส่วนตัวอื่นๆ ก็ไม่มีอะไรมาก มี Textbox จำนวน 4 ตัวสำหรับให้ผู้ใช้โปรแกรมกรอกค่าพิกัดที่ต้องการแปลง และ Label จำนวน 4 ตัวเพื่อแสดงค่าพิกัดที่แปลงแล้ว และสุดท้ายคือมี Button จำนวน 2 ตัวเอาไว้แสดงระบบพิกัดที่ดูแล้วเข้าใจง่าย และเรียกรูปแบบการแสดงผลนี้ว่า Well Known Text (WKT)
ส่วนประกอบของฟอร์ม

ระบบค่าพิกัดในรูปแบบ EPSG (Europian Petrolium Survey Group)

  • ระบบพิกัด (Coordinate Reference System) ที่ GDAL สนับสนุนนั้นมีหลายรูปแบบเช่นรูปแบบของ ESRI, EPSG และรูปแบบ Proj.4 รวมทั้งสามารถกำหนดเองได้ด้วยรูปแบบที่ผมกล่าวไปข้างต้นคือ Well Known Text แต่ในความรู้สึกของผมแล้วของ EPSG นั้นง่ายที่สุด
  • ก่อนจะไปต่อขอพูดถึง EPSG ว่าเป็นสมาคมที่ตั้งในปี 1985 นำโดย Jean-Patrick GIRBIG ด้วยบุคคลที่เกี่ยวข้องกับกลุ่มอุตสาหกรรมพลังงาน (oil & gas) แถวๆยุโรป ก่อนหน้านี้ระบบพิกัดที่ใช้กันทั่วโลกนั้นหลากหลายมาก ความแตกต่างระหว่างทรงรี ความแตกต่างของเส้นโครงแผนที่ (Map Projection) ทำให้ยากต่อการใช้งาน สมาคมนี้จึงได้กำหนดมาตรฐานขึ้นมาโดยใช้ตัวเลข (code) เป็นตัวอ้างอิง ด้านล่างเป็น EPSG ที่เกี่ยวข้องกับประเทศไทย ซึ่งผมจะนำมาใช้ในโปรแกรมนี้ด้วย ตัวที่สำคัญและใช้มากก็คือ 4326 ก็คือ WGS84 แและเป็นค่าพิกัด geographic (latitude/longitude)

4326  : WGS84 (Geographic)
32647 : WGS84 / UTM Zone 47 North
32648 : WGS84 / UTM Zone 48 North
4240  : INDIAN 1975 (Geographic)
24047 : INDIAN 1975 / UTM Zone 47 North
24048 : INDIAN 1975 / UTM Zone 48 North

  • แต่การใช้ EPSG ก็มีปัญหาเล็กน้อยถ้าเป็น Indian 1975 คือค่าพารามิเตอร์ที่ใช้ในการ transformation จะไม่ตรงกับที่เราใช้งานกันแต่ GDAL เปิดโอกาสให้เราแก้ไขได้ด้วยฟังก์ชั่นง่ายๆ

Sourcecode ของเมนฟอร์ม

  • มาดูโค๊ดของฟอร์ม (mainform)
unit main;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, gdal, gdalcore, ogr, ogrcore;

type

  { TfrmMain }
  TCharSet = set of char;

  TfrmMain = class(TForm)
    cmdChkDatumFrom: TButton;
    cmdChkDatumTo: TButton;
    cmdCompute: TButton;
    cmbDatumFrom: TComboBox;
    cmbDatumTo: TComboBox;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    Label1: TLabel;
    Label10: TLabel;
    labNorthingTo: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    labEastingTo: TLabel;
    labLatitudeTo: TLabel;
    labLongitudeTo: TLabel;
    txtEastingFrom: TEdit;
    txtLatitudeFrom: TEdit;
    txtLongitudeFrom: TEdit;
    txtNorthingFrom: TEdit;
    procedure cmdChkDatumFromClick(Sender: TObject);
    procedure cmdChkDatumToClick(Sender: TObject);
    procedure cmbDatumFromChange(Sender: TObject);
    procedure cmbDatumToChange(Sender: TObject);
    procedure cmdComputeClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
    FEPSGFrom, FEPSGTo : longint;
    procedure Tokenize(tokens: TStrings; const sztarget: string; szdelims: TCharSet);
    procedure CheckDatum (epsgcode : longint);
  public
    { public declarations }
  end; 

var
  frmMain: TfrmMain;

implementation

procedure TfrmMain.Tokenize(tokens: TStrings; const sztarget: string; szdelims: TCharSet);
var
  Start: Integer;
  i: Integer;
  StrLength: Integer;
begin
  Start := 1;
  StrLength := Length(sztarget);
  for i := 1 to StrLength do
  begin
    if sztarget[i] in szdelims then
    begin
      if Start <= i - 1 then
        tokens.Add(Copy(sztarget, Start, i - start));

      Start := i + 1;
    end;
  end;

  if not (sztarget[strLength] in szdelims) then
  begin
    tokens.Add(Copy(sztarget, Start, strLength - start + 1));
  end;
end;

procedure TfrmMain.CheckDatum (epsgcode : longint);
var
  pszWKT : PCHAR;
  hSRS : TOGRSpatialReferenceH;
  err  : TOGRErr;
  i : longint;
  t1 : string;
  tokens : TStrings;
begin
  pszWKT := NIL;
  hSRS := ogrcore.OSRNewSpatialReference(NIL);
  err := ogrcore.OSRImportFromEPSG(hSRS, epsgcode);
  if (err = OGRERR_NONE) then
  begin
    err := ogrcore.OSRExportToPrettyWkt(hSRS, @pszWKT, 0);
    try
      tokens := TStringList.Create;
      tokenize(tokens, pszWKT, [#10]);
      t1 := '';
      for i := 0 to tokens.Count - 1 do
        t1 := t1 + tokens.Strings[i] + #10;
      ShowMessage (t1);
    finally
      tokens.Free;
    end;
    OGRFree(pszWKT);
  end;
  ogrcore.OSRDestroySpatialReference(hSRS);
end;

procedure TfrmMain.cmdChkDatumFromClick(Sender: TObject);
begin
  CheckDatum(FEPSGFrom);
end;

procedure TfrmMain.cmdChkDatumToClick(Sender: TObject);
begin
  CheckDatum(FEPSGTo);
end;

procedure TfrmMain.cmbDatumFromChange(Sender: TObject);
begin
  if (cmbDatumFrom.ItemIndex = 0) then
  begin
    txtNorthingFrom.Text := '';
    txtEastingFrom.Text := '';
    labLatitudeTo.Caption := '';
    labLongitudeTo.Caption := '';
  end;

  //Set EPSG Code to match with Combobox of datums.
  case cmbDatumFrom.ItemIndex of
    0 : FEPSGFrom := 4326;  //WGS84 (Geographic)
    1 : FEPSGFrom := 32647; //WGS84 / UTM Zone 47 North
    2 : FEPSGFrom := 32648; //WGS84 / UTM Zone 48 North
    3 : FEPSGTo := 4240;  //INDIAN 1975 (Geographic)
    4 : FEPSGFrom := 24047; //INDIAN 1975 / UTM Zone 47 North
    5 : FEPSGFrom := 24048; //INDIAN 1975 / UTM Zone 48 North
  end;

end;

procedure TfrmMain.cmbDatumToChange(Sender: TObject);
begin
  if (cmbDatumTo.ItemIndex = 0) then
  begin
    labNorthingTo.Caption := '';
    labEastingTo.Caption := '';
    txtLatitudeFrom.Text := '';
    txtLongitudeFrom.Text := '';
  end;

  case cmbDatumTo.ItemIndex of
    0 : FEPSGTo := 4326;
    1 : FEPSGTo := 32647;
    2 : FEPSGTo := 32648;
    3 : FEPSGTo := 4240;
    4 : FEPSGTo := 24047;
    5 : FEPSGTo := 24048;
  end;

end;

procedure TfrmMain.cmdComputeClick(Sender: TObject);
var
  hSrc, hTarget : TOGRSpatialReferenceH;
  hCT : TOGRCoordinateTransformationH;
  dX, dY, dZ : double;
  err : TOGRErr;
  //EPSGFrom, EPSGTo : longint;
  success : longint;
  retval : longint;
  wkt : PCHAR;
  //adCoeffs : TDoubleArray7;
begin
  if (FEPSGFrom = FEPSGTo) then
  begin
    Showmessage('Can not convert coordinates at the same datum.');
    exit;
  end;
  try
    hSrc := ogrcore.OSRNewSpatialReference(NIL);
    try
      hTarget := ogrcore.OSRNewSpatialReference(NIL);

      err := ogrcore.OSRImportFromEPSG(hSrc, FEPSGFrom);
      err := ogrcore.OSRImportFromEPSG(hTarget, FEPSGTo);

      //For Thailand we change transformation parameters to Royai Thai Survey Department (RTSD).
      //Indian 1975 to WGS84 => TX=206, TY=837, TZ=295
      if (ogrcore.OSRIsProjected(hSrc) = 1) then
        err := ogrcore.OSRSetTOWGS84(hSrc, 206, 837, 295, 0, 0, 0, 0);
      if (ogrcore.OSRIsProjected(hTarget) = 1) then
        err := ogrcore.OSRSetTOWGS84(hTarget, 206, 837, 295, 0, 0, 0, 0);
      //We can check the transformation parameters by this function.
      //err := ogrcore.OSRGetTOWGS84(hSrc, @adCoeffs, 7);

      success := 0;
      try
        hCT := ogrcore.OCTNewCoordinateTransformation(hSrc, hTarget);
        if (ogrcore.OSRIsGeographic(hSrc) = 1) then
        begin
          dY := strtofloat(txtLatitudeFrom.Text);
          dX := strtofloat(txtLongitudeFrom.Text);
          dZ := 0;
        end
        else
        begin
          dY := strtofloat(txtNorthingFrom.Text);
          dX := strtofloat(txtEastingFrom.Text);
          dZ := 0;
        end;
        retval := ogrcore.OCTTransformEx(hCT, 1, @dX, @dy, @dZ, @success );
        if( hCT = NIL)  or  ( retval = 0) then
          Showmessage('Computation failed.\n')
        else
        begin
          if (ogrcore.OSRIsGeographic(hTarget) = 1) then
          begin
            labLatitudeTo.Caption := format('%10.6f', [dY]);
            labLongitudeTo.Caption := format('%10.6f', [dX]);
          end
          else
          begin
            labNorthingTo.Caption := format('%10.3f', [dY]);
            labEastingTo.Caption := format('%10.3f', [dX]);
          end;
        end;

      finally
        ogrcore.OCTDestroyCoordinateTransformation(hCT);
      end;
    finally
      ogrcore.OSRDestroySpatialReference(hTarget);
    end;
  finally
    ogrcore.OSRDestroySpatialReference(hSrc);
  end;
end;

procedure TfrmMain.FormActivate(Sender: TObject);
begin
  cmbDatumFromChange(Sender);
  cmbDatumToChange(Sender);
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  gdalcore.AllRegister;
  //Set the path to GDAL Library.
  //If the path is not correct. We can't use EPSG database.
  gdalcore.SetConfigOption('GDAL_DATA', 'C:\gdalwin32-1.6\data');

end;

initialization
  {$I main.lrs}


end.
  • ผมจะอธิบายโค๊ดพอสังเขป เริ่มจากตรง uses clause ในโปรแกรมนี้จะใช้ไฟล์ pascal 4 ไฟล์คือ gdal.pas, gdalcore.pas, ogr.pas และ ogrcore.pas และประกาศตัวแปรตรง private section ได้แก่ตัวแปร FEPSGFrom และ FEPSGTo ไว้เก็บตัวเลข EPSG ส่วนโปรซีเจอร์ Tokenize เอาไว้แยกสตริงที่ใช้ตัวคั่น (ตัวอย่างไฟล์ csv ที่ใช้เครื่องหมายคอมม่าคั่น) ส่วนฟังก์ชั่น CheckDatum เอาไว้แสดงระบบพิกัดเมื่อส่งตัวเลข EPSG มาให้
  private
    { private declarations }
    FEPSGFrom, FEPSGTo : longint;
    procedure Tokenize(tokens: TStrings; const sztarget: string; szdelims: TCharSet);
    procedure CheckDatum (epsgcode : longint);
  • เมื่อเริ่มสร้างฟอร์มเราจะตั้งค่าให้ GDAL ได้ทราบ path ที่ติดตั้งไว้ โดยไปดักที่อีเวนต์ FromCreate ผมสังเกตว่าในวินโดส์ต้องกำหนดให้ผ่านฟังก์ชั่น SetConfigOption ส่วนบรรทัดแรกนั้นสั่งให้ไลบรารีทำการ register ทุกฟอร์แม็ตที่สนับสนุน
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  gdalcore.AllRegister;
  //Set the path to GDAL Library.
  //If the path is not correct. We can't use EPSG database.
  gdalcore.SetConfigOption('GDAL_DATA', 'C:\gdalwin32-1.6\data');

end;

ฟังก์ชั่นคำนวณ

  • การคำนวณจะเรียกใช้ไฟล์ฟังก์ชั่นที่อยู่ใน ogrcore.pas (ส่วน gdalcore.pas จะเกีียวข้องกับ raster) มาดูโค๊ด
procedure TfrmMain.cmdComputeClick(Sender: TObject);
var
  hSrc, hTarget : TOGRSpatialReferenceH;
  hCT : TOGRCoordinateTransformationH;
  dX, dY, dZ : double;
  err : TOGRErr;
  //EPSGFrom, EPSGTo : longint;
  success : longint;
  retval : longint;
  wkt : PCHAR;
  //adCoeffs : TDoubleArray7;
begin
  if (FEPSGFrom = FEPSGTo) then
  begin
    Showmessage('Can not convert coordinates at the same datum.');
    exit;
  end;
  try
    hSrc := ogrcore.OSRNewSpatialReference(NIL);
    try
      hTarget := ogrcore.OSRNewSpatialReference(NIL);

      err := ogrcore.OSRImportFromEPSG(hSrc, FEPSGFrom);
      err := ogrcore.OSRImportFromEPSG(hTarget, FEPSGTo);

      //For Thailand we change transformation parameters to Royai Thai Survey Department (RTSD).
      //Indian 1975 to WGS84 => TX=206, TY=837, TZ=295
      if (ogrcore.OSRIsProjected(hSrc) = 1) then
        err := ogrcore.OSRSetTOWGS84(hSrc, 206, 837, 295, 0, 0, 0, 0);
      if (ogrcore.OSRIsProjected(hTarget) = 1) then
        err := ogrcore.OSRSetTOWGS84(hTarget, 206, 837, 295, 0, 0, 0, 0);
      //We can check the transformation parameters by this function.
      //err := ogrcore.OSRGetTOWGS84(hSrc, @adCoeffs, 7);

      success := 0;
      try
        hCT := ogrcore.OCTNewCoordinateTransformation(hSrc, hTarget);
        if (ogrcore.OSRIsGeographic(hSrc) = 1) then
        begin
          dY := strtofloat(txtLatitudeFrom.Text);
          dX := strtofloat(txtLongitudeFrom.Text);
          dZ := 0;
        end
        else
        begin
          dY := strtofloat(txtNorthingFrom.Text);
          dX := strtofloat(txtEastingFrom.Text);
          dZ := 0;
        end;
        retval := ogrcore.OCTTransformEx(hCT, 1, @dX, @dy, @dZ, @success );
        if( hCT = NIL)  or  ( retval = 0) then
          Showmessage('Computation failed.\n')
        else
        begin
          if (ogrcore.OSRIsGeographic(hTarget) = 1) then
          begin
            labLatitudeTo.Caption := format('%10.6f', [dY]);
            labLongitudeTo.Caption := format('%10.6f', [dX]);
          end
          else
          begin
            labNorthingTo.Caption := format('%10.3f', [dY]);
            labEastingTo.Caption := format('%10.3f', [dX]);
          end;
        end;

      finally
        ogrcore.OCTDestroyCoordinateTransformation(hCT);
      end;
    finally
      ogrcore.OSRDestroySpatialReference(hTarget);
    end;
  finally
    ogrcore.OSRDestroySpatialReference(hSrc);
  end;
end;
  • จะเห็นว่าเมื่อผู้ใช้โปรแกรมคลิกที่ปุ่มคำนวณจะเรียกอีเวนต์นี้ ต้นฟังก์ชั่นผมประกาศตัวแปรสำหรับการแปลงค่าพิกัดคือ ซึ่งทั้งหมดเป็น pointer หรือเรียกอีกนัยหนึ่งว่า handle
hSrc, hTarget : TOGRSpatialReferenceH;   hCT : TOGRCoordinateTransformationH;
  • ซึ่ง hSrc และ hTarget จะได้ค่า handle จากการเรียกฟังก์ชั่น OGR คือ OSRNewSpatialReference(NIL) เมื่อได้ค่า handle แล้วระบบพิกัดต้นทางและปลายทางมีตัวตนขึ้นมาแล้ว ต่อไปจะกำหนดค่าตัวเลข EPSG ให้ผ่านฟังก์ชั่น OSRImportFromEPSG(handle, EPSGcode) ซึ่งตัวแปร FEPSGFrom และ FEPSGTo จะได้ตัวเลขจากการ map ค่ากับ combobox ที่แสดง datum
  • ที่ผมกล่าวไปแล้วว่าค่าพารามิเตอร์ที่ใช้ในการแปลงค่าพิกัดไม่ตรงกับที่เราใช้กัน ผม assign ค่าให้ใหม่ด้วย OSRSetTOWGS84(hSrc, 206, 837, 295, 0, 0, 0, 0) และกำหนดให้ hTarget เช่นเดียวกัน
  • handle ตัว hSrc และ hTarget เก็บระบบพิกัดเท่านั้นจะคำนวณแปลงค่าพิกัดด้วยตัวเองไม่ได้ การคำนวณจะใช้ handle อีกตัวคือ hCT โดยการเรียกฟังก์ชั่น hCT := ogrcore.OCTNewCoordinateTransformation(hSrc, hTarget) เพื่อสร้าง handle ขึ้นมา ต่อไปใช้ฟังก์ชั่น OSRIsGeographic(hSrc) เพื่อตรวจสอบว่าระบบพิกัดที่ผู้ใช้เลือกว่าเป็น geographic หรือเป็น projection (UTM) จะได้เลือกเก็บค่าพิกัดที่ผู้ใช้ป้อนได้ถูกที่ (ผมไม่ได้เขียนดัก error ที่อาจจะเกิดจากการป้อนตัวอักษรแทนตัวเลข ถ้าจะเขียนโปรแกรมไปใช้เป็นเรื่องเป็นราวต้องเขียนดัก)
  • ทำการคำนวณการแปลงพิกัดด้วยฟังก์ชั่น retval := ogrcore.OCTTransformEx(hCT, 1, @dX, @dy, @dZ, @success ) ด้วยการส่ง pointer ค่าพิกัด ตรวจสอบผลลัพธ์การคำนวณด้วย retval หรือ success ว่าเท่ากับ 1 หรือไม่ ฟังก์ชั่นตัวนี้สามารถคำนวณค่าพิกัดได้มากกว่า 1 จุด ด้วยการส่ง array of double ไปแทน dX, dY, dZ ถ้าดูในฟังก์ชั่นจะเห็นพารามิเตอร์ที่สอง จะเป็น 1 คือจำนวนจุดนั่นเอง ถ้ามีสัก 10 จุดที่ต้องการแปลงต้องส่งเลข 10 ไปให้ และอาร์เรย์จะต้องประกาศเป็น array[0..9] of double ส่งไปให้

ทอสอบโปรแกรมบน windows

  • พร้อมแล้วก็กดคีย์ F9 เพื่อรันโปรแกรมได้เลย ผมลองแปลงพิกัดจาก WGS84 /UTM Zone 47N ไปยัง Indian 1975/UTM Zone 47N ดังรูปด้านล่าง
แปลงพิกัดจาก WGS84 ไปยัง Indian 1975

ทดสอบโปรแกรมบน Ubuntu linux

  • รัน lazarus แล้วเปิดโครงการที่จำเพาะกับ linux มาลองรันดูแล้วป้อนค่าพิกัดเข้าไป
แปลงค่าพิกัดทดสอบใน linux
  • เพื่อยืนยันว่าการแปลงพิกัดได้ถูกต้อง ถ้าผู้อ่านมี Geocalc บนวินโดส์ก็สามารถทดสอบได้ค่าจะได้เท่ากันครับ ต่อไปลองคลิกที่ปุ่ม Coordinate System Information ดูเพื่อดูระบบพิกัดในรูปแบบ Well Known Text
แสดงระบบพิกัดแบบ WKT
  • เป็นอย่างไรบ้างครับ ความสามารถของ GDAL ไม่ธรรมดาเลยและยัง cross-platform ด้วย ผมดูแล้วถ้ามานั่งเขียนให้ support ทุกๆ datum ก็ไม่น่ายากเกินไปเพราะไลบรารีเตรียมมาให้หมดแล้ว ลองศึกษาที่ website ของ GDAL ดู ผมเองยังดูได้ไม่หมดเลยเพราะไลบรารีค่อนข้างใหญ่ แต่ก็ไม่ยากจนเกินไปครับ

Related

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

October 2026
M T W T F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
« Sep    

Blog Stats

There was an issue retrieving stats. Please try again later.

Recent Posts

  • เร็วแรงทะลุนรกกับ POCUT (POint Cloud UTils)
  • อัพเดทแอพ “SurveyStar LDP Thailand” เพื่อรับกับยกร่างมาตรฐาน “TH-LDP”
  • ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 2
  • ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 1
  • โปรแกรมอรรถประโยชน์ Pocut (POint Cloud Utils)
  • โปรแกรมแปลงไฟล์แคดข้ามระบบพิกัด (Drawing Transformer)
  • มาตรฐานระบบพิกัดแผนที่แบบแอลดีพีของประเทศไทยสำหรับงานวิศวกรรมและการก่อสร้าง (Thailand Low Distortion Map Coordinate System for Engineering and Construction)
  • ประสบการณ์ใช้งาน Kimi K3 Code เขมือบแบบสยอง
  • สร้างแพลตฟอร์มดู Point Cloud บนเว็บด้วย Potree + CesiumJS — เรื่องเล่าจากสนามบินอู่ตะเภา
  • เมื่อวิศวกรสำรวจคำนวณเรื่องน้ำ – วิเคราะห์ระบบระบายน้ำบริเวณ RESA
  • แนะนำหนังสือ “จีออเดซี” ที่ยอดเยี่ยมของดร.พุทธิพล
  • ESPrtk ทำให้ ESP32 ใช้ไม่ได้? วิธีกู้คืน
  • กรณีศึกษา – คืนชีพ SDL30 ปี 2000 ด้วย ESP32 และแอพทำเอง SDL30 Collector
  • DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
  • รีวิวกูปรี (CoPre2) โปรแกรมประมวลผลไลดาร์จากค่าย CHCNav
  • DIY RTK Base Station (survey-grade) รุ่น V3.2 ด้วย Orange Pi 3 Zero + UM980 ตอนที่ 3
  • DIY RTK Base Station (survey-grade) รุ่น V3 ด้วย Orange Pi 3 Zero + UM980 ตอนที่ 2
  • เส้นทางและไทม์ไลน์ของใบรับรองความรู้ความชำนาญในการประกอบอาชีพวิศวกรรม(สำรวจ)ระดับวิศวกรวิชาชีพ
  • มัดแหนมรวมสามโปรแกรมไปใช้บนสโตร์ Snap ฝั่งลีนุกซ์
  • ปัดฝุ่น Traverse Pro เพิ่มรายละเอียดรายการคำนวณใหม่แบบแนวนอน (Landscape) และธีมมืด
  • DIY RTK Base Station (Survey-Grade) ด้วยชิป UM980 และบอร์ด ESP32 ตอนที่ 1
  • สร้าง NTRIP Caster ด้วย BNC บนคลาวด์แบบ DIY สำหรับ RTK Base Station ใช้ CHCNav P5
  • จับ AI มาไตรกรีฬา สร้างตัวติดตั้ง Snap สำหรับ Surveyor Pocket Tools กับประเด็นแฝงเร้นความเป็นส่วนตัวของผู้ใช้
  • ทดสอบรีด QGIS แบบโหดสัสด้วยชุดข้อมูล Open Building V3 โพลีกอน 74 ล้านหลัง
  • เมื่อ AI เป็นพิษชักจูงผู้ใช้ด้วยข้อมูลผิดๆ

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 122 other subscribers

Archives

  • October 2026
  • September 2026
  • August 2026
  • July 2026
  • May 2026
  • April 2026
  • March 2026
  • January 2026
  • December 2025
  • November 2025
  • September 2025
  • August 2025
  • July 2025
  • June 2025
  • May 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • July 2024
  • May 2024
  • April 2024
  • January 2024
  • November 2023
  • October 2023
  • September 2023
  • July 2023
  • June 2023
  • May 2023
  • March 2023
  • February 2023
  • January 2023
  • November 2022
  • October 2022
  • September 2022
  • July 2022
  • May 2022
  • December 2021
  • October 2021
  • September 2021
  • August 2021
  • May 2021
  • February 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • September 2019
  • August 2019
  • July 2019
  • May 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • January 2018
  • November 2017
  • July 2017
  • June 2017
  • May 2017
  • April 2017
  • March 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
  • October 2016
  • August 2016
  • November 2015
  • March 2015
  • August 2014
  • March 2014
  • January 2014
  • December 2013
  • February 2012
  • January 2012
  • November 2011
  • October 2011
  • August 2011
  • April 2011
  • February 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • June 2010
  • April 2010
  • March 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009

Recent Comments

  • priabroy on ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 1
  • Konexana Yomleuangsa on ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 1
  • เฟือง เถา on DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
  • priabroy on DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
  • ตรันฟองนาม on DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
©2026 Prajuab Riabroy's Blog | Design: Newspaperly WordPress Theme