Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 11.08.2016, 16:48
-=#PupaJr#=- -=#PupaJr#=- вне форума
Новичок
 
Регистрация: 17.08.2010
Сообщения: 74
Репутация: 518
Печаль Запись и чтение разно-типизированного файла

Доброго всем.
Есть стандартный файл литографии STL - дока в сети есть но всёже приведу
Его структура:
80 первых байт текст - комменты
4 байта число элементов (треугольников) (тип Dword)
4 по 4 Real32 - нормаль XYZ и координаты ХYZ вершин треугольника
2 байта вспомогательная инфа.
и того 80 + 4 + 50 + 50 +50 +.....+50(раз элементов).
составляю типы:
Код:
type triangle=record
 nv:single
 tx:single
 ty:single
 tz:single
 tc:word
end
type mstl=record
 comm:string  // 80 
 numt:dword  // 4
 ztrian:triangle // 50
end
Программа компилится, запускается но при какой либо попытке чтения вылетает I/O error и всё стоп.
К тому же не ясно, как перебирать в таком типе все треугольники (50 байт 4х4 +2)
при чтении указывать как массив(максючисло треуг.допустим 6000000): ztrian:array [0..6000000] of triangle .
А как писать обратно в такой файл? и если писать массив то запишется весь??? (6000000???) а мне надо скажем 10000 всего?
Что не делаю то I/O error или вместо данных (достоверно прочтёных в фирменной программе) получаю не координаты и сумашедшие числа...
ХЕЛП...
Ответить с цитированием
  #2  
Старый 12.08.2016, 03:43
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,053
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

1. Читать через TFileStream
2. Перед чтением надо память выделять
Как-то так:
Код:
type
  TSTLItem = record
    nv:single
    tx:single
    ty:single
    tz:single
    tc:word
  end;

  TSTLStruct = record
    Comm : AnsiString;
    Count : DWORD;
    Items : Array Of TSTLItem;
  end;

procedure ReadSTLFile(FileName : String; var Data : TSTLStruct);
var
  I : Integer;
  F : TFileStream;
begin
  F := TFileStream.Create(FileName, fmOpenRead);
  Try
    SetLength(Data.Comm,80);
    F.ReadBuffer(Data.Comm[1],80);
    F.ReadBuffer(Data.Count,sizeOf(DWORD));
    SetLength(Data.Items,Data.Count);
    For I := 0 To Data.Count-1 Do
      Begin
        F.ReadBuffer(Data.Items[i].nv,SizeOf(Single));
        // Здесь читаем остальные поля текущего треугольника
      End;
  Finally
    F.Free;
  end;
end;
Ответить с цитированием
  #3  
Старый 12.08.2016, 07:46
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

ТС похоже немного заблуждается, если судить по описанию бинарной версии данного формата, то структура записей должна быть слегка другой, с чтением из буфера не дружу, но вот такой вариант загрузил координаты треугольников тестового чайника из teapot.stl
Код:
type
  TSTLItem = record
    ni: single;
    nj: single;
    nk: single;
    x1: single;
    y1: single;
    z1: single;
    x2: single;
    y2: single;
    z2: single;
    x3: single;
    y3: single;
    z3: single;
    tc: word;
  end;

   TSTLStruct = record
    Comm : String[80];
    Count : DWORD;
    Items : Array Of TSTLItem;
  end;

var
 Data : TSTLStruct;
 StlFile: TFileStream;
 b: dword;
begin
  StlFile:= TFileStream.Create(FileName, fmOpenRead);
  StlFile.Seek(0, soFromBeginning);
  StlFile.Read(Data.comm,80);
  StlFile.Read(Data.Count,4);
  SetLength(Data.Items,Data.Count);
  for b:= 0 to Data.Count-1 do
   begin
    StlFile.Read(Data.Items[b].ni,4);
    StlFile.Read(Data.Items[b].nj,4);
    StlFile.Read(Data.Items[b].nk,4);
    StlFile.Read(Data.Items[b].x1,4);
    StlFile.Read(Data.Items[b].y1,4);
    StlFile.Read(Data.Items[b].z1,4);
    StlFile.Read(Data.Items[b].x2,4);
    StlFile.Read(Data.Items[b].y2,4);
    StlFile.Read(Data.Items[b].z2,4);
    StlFile.Read(Data.Items[b].x3,4);
    StlFile.Read(Data.Items[b].y3,4);
    StlFile.Read(Data.Items[b].z3,4);
    StlFile.Read(Data.Items[b].tc,2);
   end;
 StlFile.Free;
  end;
Ответить с цитированием
  #4  
Старый 12.08.2016, 07:47
-=#PupaJr#=- -=#PupaJr#=- вне форума
Новичок
 
Регистрация: 17.08.2010
Сообщения: 74
Репутация: 518
По умолчанию

Прочитать могу только < примерно 40000 треугольников и а если ставлю больше то Stack Overflow, если не ставлю размер - то вообще не компилит.
Вот моя полная процедура:
Код:
procedure TForm1.Button1Click(Sender: TObject);  // загрузить файл точек/бинарник/треугольники
type
  striangle=packed record           // 50_и байтная запись 1 треугольника
  trnormx:single;       // 4
  trnormy:single;       // 4
  trnormz:single;       // 4
  tr3dx1: Single;       // 4
  tr3dy1: Single;       // 4
  tr3dz1: Single;       // 4
  tr3dx2: Single;       // 4
  tr3dy2: Single;       // 4
  tr3dz2: Single;       // 4
  tr3dx3: Single;       // 4
  tr3dy3: Single;       // 4
  tr3dz3: Single;       // 4
  trattr: word;         // 2
end;
type
  StlRec= packed record
    SName: array[1..80] of Char;//string[80];      // array of char  сработал правильно
    Snum: dword;
    msstri: array [0..60000]of striangle;         // множество записей треугольничных записей - 60000 уже не берёт 
end;
var
i,ii,jj,sl:integer;
sss,stru:string;
Buf: array[1..127] of Char;
mash:single;
NumRead: integer;
Infl: file of Single;
//stlf: file;
stlperm: StlRec;
stlf: file of StlRec;
begin
 mash:=strtofloat(Edit1.text);
 if OpenDialog1.Execute then
   begin
      if OpenDialog1.FilterIndex=3 then   //  STL bin file
        begin
          AssignFile(stlf,OpenDialog1.FileName);
          Reset(stlf);
          DlnStr:=80;
        //  BlockRead(stlf,,DlnStr,NumRead);                //читаем файл в массив
          read(stlf,stlperm);
       //   SetLength(stlperm.msstri, stlperm.Snum);    // попытка дать размер массиву треугольников
          DlnStr:=1;
         // ntri:=FilePos(stlf);// - возвращает текущую позицию чтения/записи в файл
      //    BlockRead(stlf,ntri,DlnStr,NumRead);
          DlnStr:=NumRead;                          //получили реальную длину файла
          CloseFile(stlf);
          ii:=21;
          i:=0;
         // ntri:=Fbind[20];    // запоминаем число треугольников для процедуры вывода графики
    //      memo1.Clear;
   //       SendMessage(memo1.Handle, WM_SETREDRAW, 0, 0) ;   // запрещаем перерисовку для ускорения вывода
          jlc:=stlperm.Snum;
        //  while i<(stlperm.Snum-1) do
          while i<(19999) do
            begin
//              ii:=ii+1;
//              stlperm.msstri[]                                 // перепрыгиваем направление нормали треугольника
              triangle3dx1[i]:= stlperm.msstri[i].tr3dx1;         // заполняем массив точками
              triangle3dy1[i]:= stlperm.msstri[i].tr3dy1;         // заполняем массив точками
              triangle3dz1[i]:= stlperm.msstri[i].tr3dz1;         // заполняем массив точками
              triangle3dx2[i]:= stlperm.msstri[i].tr3dx2;         // заполняем массив точками
              triangle3dy2[i]:= stlperm.msstri[i].tr3dy2;         // заполняем массив точками
              triangle3dz2[i]:= stlperm.msstri[i].tr3dz2;         // заполняем массив точками
              triangle3dx3[i]:= stlperm.msstri[i].tr3dx3;         // заполняем массив точками
              triangle3dy3[i]:= stlperm.msstri[i].tr3dy3;         // заполняем массив точками
              triangle3dz3[i]:= stlperm.msstri[i].tr3dz3;         // заполняем массив точками
              i:=i+1;
              ii:=i;
      //        memo1.Lines.Add(floattostrf(points3dx[i],fffixed,6,3)+' '+floattostrf(points3dy[i],fffixed,6,3)+' '+floattostrf(points3dz[i],fffixed,6,3));
       //       i:=i+1;
            end;  
      //    SendMessage(memo1.Handle, WM_SETREDRAW, 1, 0);     // разрешаем перерисовку
      //    RedrawWindow(memo1.Handle, nil, 0,RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN);
        end; // open STL
   end;// open file
 l_point:=true;

label1.Tag:=ii;
end;

В принципе работает он но на малое число - 20000 точно берёт.
Видел примеры что делают через Read/Seek по записям - но там нет заголовочной инфы и какие-то примеры не полноценные...

Спасибо, попробую.
Ответить с цитированием
  #5  
Старый 12.08.2016, 14:09
-=#PupaJr#=- -=#PupaJr#=- вне форума
Новичок
 
Регистрация: 17.08.2010
Сообщения: 74
Репутация: 518
По умолчанию

Alegun Ваш код работает, спасибо, только число переменных больше и Data надо объявить (о, Вы уже дописали код ))), и в принципе я читал потом не в переменную файла а в массив типа single - всё нормально прочиталось и массив заполнился.
С этого массива сразу читал точки и в OpenGl строил треугольники - всё чётко.
Всем спасибо ))
Ответить с цитированием
  #6  
Старый 12.08.2016, 18:02
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Способом копипасты довёл число треугольников в текстовом варианте больше чем 160000 штук, затем первёл в бинарный формат - прекрасно под D7 полученный файл и открывается и грузится в структуру, наверное с типами у вас неразбериха, отсюда и преполнение

З.Ы. Есть менее затратный вариант - подключить к проекту assimp32.dll, порт объявы под делфи в сетке вроде на неё есть, а это умеет работать со многими форматами, в том числе и с двумя вариантами *.stl
Ответить с цитированием
Этот пользователь сказал Спасибо Alegun за это полезное сообщение:
-=#PupaJr#=- (22.08.2016)
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 07:11.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter