working on it ...

Filters

Explore Public Snippets

Sort by

Found 12 snippets matching: xe5

    public by FMXExpress modified Nov 12, 2014  7319  9  9  4

    Install A Shortcut On Android With Delphi XE5 Firemonkey

    http://www.fmxexpress.com/install-shortcuts-on-the-android-home-screen-with-delphi-xe5-firemonkey/
    //Android permission required:
    //<uses-permission android:name=”com.android.launcher.permission.INSTALL_SHORTCUT”/>
        
    Uses
    Androidapi.JNI.GraphicsContentViewText, FMX.Helpers.Android,
    Androidapi.JNI.JavaTypes, FMX.Platform.Android, AndroidApi.JniBridge, AndroidApi.Jni.App,
    AndroidAPI.jni.OS;
    
    {$IFDEF ANDROID}
    var
    ShortcutIntent: JIntent;
    addIntent: JIntent;
    wIconIdentifier : integer;
    wIconResource : JIntent_ShortcutIconResource;
    {$ENDIF}
    begin
    {$IFDEF ANDROID}
    
    ShortcutIntent := TJIntent.JavaClass.init(SharedActivityContext, SharedActivityContext.getClass);
    ShortcutIntent.setAction(TJIntent.JavaClass.ACTION_MAIN);
    
    addIntent := TJIntent.Create;
    addIntent.putExtra(TJIntent.JavaClass.EXTRA_SHORTCUT_INTENT, TJParcelable.Wrap((shortcutIntent as ILocalObject).GetObjectID));// here we need to cast the intent as it’s not done in delphi by default, not like java
    addIntent.putExtra(TJIntent.JavaClass.EXTRA_SHORTCUT_NAME, StringToJString(Application.Title));
    addIntent.setAction(StringToJString(‘com.android.launcher.action.INSTALL_SHORTCUT’));
    // get icon resource identifier
    wIconIdentifier := SharedActivity.getResources.getIdentifier(StringToJString(‘ic_launcher’), StringToJString(‘drawable’), StringToJString(‘com.embarcadero.HeaderFooterApplication’)); // if the app name change, you must change the package name
    wIconResource := TJIntent_ShortcutIconResource.JavaClass.fromContext(SharedActivityContext, wIconIdentifier);
    // set icon for shortcut
    addIntent.putExtra(TJIntent.JavaClass.EXTRA_SHORTCUT_ICON_RESOURCE, TJParcelable.Wrap((wIconResource as ILocalObject).GetObjectID));
    
    SharedActivityContext.sendBroadcast(addIntent);
    
    {$ENDIF}
     

    public by FMXExpress modified Nov 12, 2014  4331  20  6  1

    Decode GZIP Content From TRESTClient In Delphi XE7 Firemonkey

    RESTClient.AcceptEncoding := 'gzip, deflate';
    RESTClient.Execute;
    
    if RESTResponse.ContentEncoding=’gzip’ then
    DecodeGZIPContent(RESTResponse.RawBytes) // decode and do something with the content
    else
    RESTResponse.Content; // do something with the content
    
    function DecodeGZIPContent(RawBytes: System.TArray<System.Byte>): String;
    var
    MSI: TMemoryStream;
    MSO: TStringStream;
    begin
    MSI := TMemoryStream.Create;
    MSO := TStringStream.Create;
    MSI.WriteData(RawBytes,Length(RawBytes));
    MSI.Seek(0,0);
    // Zlib is a TIdCompressorZlib
    Zlib.DecompressGZipStream(MSI,MSO);
    MSI.DisposeOf;
    MSO.Seek(0,0);
    Result := MSO.DataString;
    MSO.Free;
    end;

    external by Github modified Feb 8, 2018  17  1  1  0

    Embarcadero Rad Studio Xe5 Architect Crack

    Embarcadero Rad Studio Xe5 Architect Crack: gistfile1.txt
    
    ********************
    Embarcadero Rad Studio Xe5 Architect Crack ->->->->
    ********************
    http://shurll.com/cq8r2
    (Copy & Paste link)
    ********************
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    Compiler Embarcadero RAD Studio XE5 Delphi dan C/C++ . Download Aktivasi Embarcadero RADStudio XE5 Crack/Keygen. Tweet.. Download Cracked RAD Studio XE5 Update2 HotFix 1 2 3, . FREE Download Rad Studio XE6 Update 1 + Crack. . Download Embarcadero RAD Studio Architect XE7 Update 1 .. Embarcadero RAD Studio XE7 Architect v21.0 . Embarcadero RAD Studio is the ultimate application .     Crack .. Search results for embarcadero . Embarcadero RAD Studio XE5 Architect [Crack Only] . Embarcadero RAD Studio XE Architect V.15.0.3953.35171 + With Keygen.rar. Embarcadero RAD Studio Tokyo Architect update 2 (10.2.2) version 25.0.28979.1978 Embarcadero Technologies, .. . Enjoy full ARCHITECT version of XE7 . . RAD Studio XE7 Full; RAD Studio XE8 .. Delphi XE5 Architect Update 2 Only Crack . Hotfix 2 for RAD Studio XE5, . Embarcadero RAD Studio Architect XE4 Update 1 18.0.4905.60485 Delphi;. RAD Studio is the fastest way to write, compile, package and deploy cross-platform native applications for Windows, Linux, macOS, iOS, and more.. Embarcadero rad studio xe5 update 1 crack. . they need and avoiding.embarcadero rad studio xe5 update 2 architect embarcadero rad studio xe5.download links .. Embarcadero RAD Studio XE5 FUll Version+Crack/Pacth Keygen And Serial Key. Menu. About; . install use this serial for architect HNFK-BCN8NN-78N53D-H4RS (not Tester .. Getting Started with RAD Studio. . and explicit step-by-step instructions for creating your first RAD Studio . Retrieved from " .. Visit us and download RAD Studio absolutely for free. . Embarcadero RAD Studio XE5 Architect [Crack Only] . Boutwell Studio Totally Rad Actions .. . RAD Studio XE5 Install from the Web - includes Update 2. . Web Installer for Embarcadero RAD Studio XE5 . RAD Studio XE5 Architect Named User Upgrade from .. RAD Studio XE5 Architect Named User Upgrade from RAD Studio XE4 . The HTML5 Builder .zip that can be burned to disc is available at .. Embarcadero RAD Studio XE5 es la mejor opcin para crear aplicaciones nativas para Android y iOS. Adems de permitir introducirlas en la tienda de .. Keygen for Embarcadero RAD Studio 10 Seattle Architect Update 1. . C Crack Oct Embarcadero rad studio xe5 architect 30 day trial Torrent files are with. .. Akll Telefon, Tablet, PC, Mac, IOS Platformlar iin ihtiyacnz olan tek Programlama Dili karnzda delphi xe5.jpg Embarcadero Rad Studio Xe5. ER/Studio Business Architect; . Embarcadero Developer . RAD Studio is the fastest way to develop cross-platform Native Apps with flexible Cloud services and .. Description Embarcadero RAD Studio 10 Seattle Architect Update1 + Crack [FU] Embarcadero Technologies, a leading provider of software solutions for application and .. Embarcadero Rad Studio Xe 5 Crack windows 8 enterprise free key photoshop app for macbook air solidworks 2014 torrent. RAD Studio - The Ultimate Application Development Platform for Windows 10, Mac, Mobile, and IoT Embarcadero rad studio xe5 architect crack.. Moved Permanently. The document has moved here.. About Embarcadero RAD Studio XE6 The complete app development suite for Windows, Mac, iOS and Android . Title: Embarcadero Rad Studio Delphi XE6 Fix Crack .. Embarcadero RAD Studio XE7 Architect 21 17017 3725 Ativador . Embarcadero RAD Studio XE5 Architect [Crack Only] .. Convert Embarcadero Rad Studio Xe Serial Number trail version to full software. . Embarcadero Rad Studio Xe5 Serial; . Embarcadero Rad Studio Xe3 Architect 16 .. embarcadero rad studio xe7 architect crack. embarcadero rad studio xe2. . download embarcadero rad studio xe5 architect. download embarcadero rad studio xe3 architect.. Embarcadero RAD Studio XE Architect Multilingual  37 Mb Embarcadero RAD Studio XE supports new features to improve application performance, optimize,.. . Download Cracked version of Embarcadero RAD Studio XE7 with CRACK . C++Builder XE Architect.delphi rad studio crack . DOWNLOAD EMBARCADERO RAD STUDIO XE5 .. Embarcadero RAD Studio XE5 Architect [Crack Only]. Reserve Online Visita The Embarcadero J. Tour e Bilhete ao Menor Preo! RAD Studio - Viso geral .. Download the Embarcadero RAD Studio XE5 crack only Torrent or choose other Embarcadero RAD Studio XE5 crack only torrent downloads.. Embarcadero Rad Studio Xe 5 Crack . and IoT Embarcadero rad studio xe5 architect crack. Embarcadero rad studio xe5 . and wearables.About Embarcadero RAD Studio .. Kali ini akan saya bagikan softwareRemo-xp.com  RAD Studio XE5 adalah app development . Download Embarcadero RAD Studio XE5 Delphi/C++ Crack Keygen.  520aad1ef5 
    
    

    external by Github modified Jun 19, 2017  6  0  1  0

    Android sdk для delphi xe5 скачать

    Android sdk для delphi xe5 скачать: Android sdk для delphi xe5 скачать.md
    Android sdk для delphi xe5 скачать
    ===================
    ———————————————————<br/>&#62;&#62;&#62;<a style="text-decoration:underline;" href="http://onyte.tdska6ll.ru/tds/?key=android+sdk+%D0%B4%D0%BB%D1%8F+delphi+xe5+%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C&mark=ghg" rel="nofollow" target="_blank">СКАЧАТЬ ФАЙЛ</a>&#60;&#60;&#60;<br/>———————————————————<br/>Проверено, вирусов нет!<br/>———————————————————<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>The installer gives you the option to not install the Android SDK and NDK. If you  opt. On the PC, download and run the JDK installer, which is available here. A software development kit (SDK) provides a set of files that are used to build  applications for a target platform. When you develop applications for Android, the. Для удобства разработчиков Android SDK можно скачать в двух. те или  иные инструменты разработчика мы будем уже с Delphi XE5. Для этого запускаем «Android SDK Manager» и нажимаем на кнопку. вашего  планшета, скачать и установить их самостоятельно. Возвращение к истокам Delphi XE5 я взял в руки по случаю.  Установленный до этого Андроид-SDK прицепить к Делфи не удалось,  поэтому. string =  /sdcard/Download/ ; filePrefix: string =  file:/ ; var  StrList. 16 Apr 2016. كيفية تثبيت Android sdk with RAD Studio Delphi/C++builder Install Platforms  SDKs in Rad Stdio XE5/XE6/XE7/XE8/10 seattle 1- JDK. 17 Sep 2013. RAD Studio XE5 - Setting Up Your Android Development Environment.  Embarcadero. Delphi will not connect EVER with a x64 DB. Even I ve. По вопросам скачивания -- тема в варезнике [?] (lite версии тут [?]).  Вопросы по компонентам для Delphi, C++ Builder разных версий [?]. SDK ( Android SDK/NDK можно подключить свои, т.е. скачанные ранее). По умолчанию, в Android SDK не установлено все необходимое для начала  разработки. Пакет SDK содержит инструменты. Android SDK, скачайте бесплатно Android SDK 24.4.1: Разработка  мобильных приложений для Android платформы от Google. При установки Delphi XE5 автоматически инсталлируются Android SDK и.  видео, скачать и поставить trial-версию Delphi XE5 и уже сегодня начать. 11 Sep 2013. You can also buy Delphi XE5 separately if you prefer. Embarcadero s  approach to Android development is distinctive. whether it did or did not (I  could not find it quickly), but it was easier to download the NDK manually. 10 анти-паттернов навигации в Android (разработка интерфейса. (ru)  Скачать бесплатную полнофункциональную 30-дневную пробную версию  RAD. Full Android SDK Interface Files In Object Pascal For Firemonkey &middot; (pt-BR ). Make sure you follow the instructions in Embarcadero s documentation:  Configuring. answer you re looking for? Browse other questions tagged android  delphi mobile delphi-xe5 android-sdk-tools or ask your own question. 13 Aug 2013. A juicy sneak peek of the Android support in the SDK Manager and Project  manager. where can ? download this delphi version. ya que no hace 6 meses  han sacado rad studio xe4 y ya estan anunciando xe5 no se vale. D.P.F Delphi iOS Native Components, iOS, Delphi XE4 / XE5 / XE6, Download &middot;  . Full Android SDK Interface Files In Object Pascal For Firemonkey. Скачать Android SDK. Android SDK   среда разработки приложений для  операционной системы Android, содержащий все. Embarcadero Delphi is a software development kit (SDK) for desktop, mobile,  web, and console applications. Delphi s compilers use their own Object Pascal  dialect of Pascal and generate native code for several platforms: Windows (x86  and x64), OS X (32-bit only), iOS (32 and 64-bit), Android and Linux (64-bit Intel). 2013 Embarcadero released RAD Studio XE5, which includes Delphi XE5. 16 May 2014. Some APIs in the Android SDK are not fully exposed to Delphi XE5 and XE6  Firemonkey (and AppMethod) by default. The Android SDK. 29 Sep 2014. If you install RAD Studio XE7 and then upgrade Android SDK to version 23, you  won t be able to. It will download and install the latest tools.
    
    

    external by Github modified Feb 14, 2018  5  0  1  0

    Delphi Xe5 Update 2 12

    Delphi Xe5 Update 2 12: gistfile1.txt
    
    ********************
    Delphi Xe5 Update 2 12 ->->->->
    ********************
    http://shurll.com/cwl46
    (Copy & Paste link)
    ********************
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    Updates news  Delphi Worlds
    If you haven't done so already, I suggest you download and install Update 2 for Delphi XE5.. If you apply Update 2 and you're already using any of my patches, make .
    delphiworlds.com/category/updates-news
    
    Update 2 for RAD Studio XE5, Delphi XE5 and C++Builder XE5
    Update 2 for RAD Studio XE5, Delphi XE5 and C++Builder XE5 is now available.. Download links.. You can obtain the update via the update notification the next time you .
    https://edn.embarcadero.com/article/43528
    
    delphi xe5 update 2 patch cracked - immenbo
    delphi xe5 update 2 patch cracked - immenbo
    https://abininkennessgobub.wixsite.com/immenbo/single-post/2017/05/...
    
    29667 Hotfix 1 for RAD Studio XE5 and Delphi XE5 Update 2
    Hotfix 1 for RAD Studio, Delphi XE5 Update 2.. Available to registered users of Delphi XE5, RAD Studio XE5, and Embarcadero All-Access XE This hotfix supplies the .
    cc.embarcadero.com/Item/29667
    
    Download CRACKED RAD Studio XE5 Update2 HotFix 1 2 3-
    Embarcadero RAD Studio XE5 Update 2 Hotfix 1-2-3  .. delphi xe5 android delphi xe5 update 2 delphi xe5 tutorial delphi xe5 feature .. 12 MONTH..  25% .
    https://www.irdevelopers.com/post/7211/Download-RAD-Studio-XE5...
    
    FireMonkey Mobile Preview in XE5 Update 2 - MarcoCantu
    December 12, 2013.. FireMonkey Mobile Preview in XE5 Update 2.. The first hidden gem in Delphi XE5 Update 2 is the Mobile Preview.
    blog.marcocantu.com/blog/fmx_mobile_preview_xe5upd2.html
    
    Hotfix 5 for RAD Studio, Delphi, C++Builder XE5 Update 2 .
    Hotfix 5 for RAD Studio, Delphi, C++Builder XE5 Update 2 is now available By: Tim DelChiaro .. Program FilesEmbarcaderoRAD Studio12.0biniteidew32190.jdbg.
    https://edn.embarcadero.com/article/43715
    
    Embarcadero Discussion Forums: Delphi XE5 on Windows 10?
    Yesterday I was able to compile the project on Windows 10.. However some windows update deleted the Visual J# 2.0.. .. 2017 12:59 PM .
    https://newsgroups.embarcadero.com/thread.jspa?messageID=883872
    
    29675 Hotfix 3 for RAD Studio, Delphi XE5, C++Builder Update 2
    Hotfix 3 for RAD Studio, Delphi, and C++Builder XE5 Update 2.
    cc.embarcadero.com/Item/29675
    
    Download Embarcadero RAD Studio XE5 Update 2 + Crack [WORK .
    Berikut tampilan Embarcadero RAD Studio XE5 Update 2 - Delphi nya ya (Ini penulis KULI Posting kedua yang jurusan kuliahnya beginian :D) .. April 12, 2014 .
    kuliposting.blogspot.com/.../download-embarcadero-rad-studio-xe5.html.  7286bcadf1 
    
    

    external by Github modified Sep 24, 2017  5  0  1  0

    Программа тест в delphi xe5 скачать

    Программа тест в delphi xe5 скачать: Программа тест в delphi xe5 скачать.md
    <h1>Программа тест в delphi xe5 скачать</h1><br><p><br>Ссылка на файл: &gt;&gt;&gt;&gt;&gt;&gt;   <a href="http://oooload.ru/54M9?charset=utf-8&keyword=Программа тест в delphi xe5 скачать"><b>http://file-portal.ru/Программа тест в delphi xe5 скачать/</b></a><br></p><br>Создание тестов в программе DELPHI<br>Видеокурс по Delphi<br>Тест производительности программы в Delphi XE3<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><p>Файлы Библиотека Ищу Обсуждения О сайте Топ Вопросы и ответы FAQ Заказать работу. По всему сайту В разделе Везде кроме раздела Search. Email Пароль Войти Зарегистрироваться Восстановить пароль FAQ по входу. Простая тест-программа созданная в Borland Delphi. В начале вводятся ФИО, группа. Результат тестирования записывается в файл базы данных. Базу вопросов можно легко поменять. Диплом защищён на оценку 5 в Самаре, СамГТУ. Объектом исследования является разработка системы автоматизированного контроля знаний специалистов по дефектоскопии. Актуальность использования дистанционного обучения в настоящее время уже не вызывает сомнений. Применение дистанционного обучения дает целый ряд преимуществ. Требования к системам дистанционного обучения. Обзор некоторых существующих решений. Разработка программы проверки знаний для тестирования студентов по программированию с кодом на языке Delphi. Проектирование визуального интерфейса и словесный алгоритм работы программы. Алгоритмы разработанных процедур и функций, инструкция пользователя. В данной курсовой работе рассмотрен метод разработки тестирующей программы для контроля знаний обучающихся. Программа имеет 2 варианта по пять вопросов с четырьмя вариантами ответа. Подобраны компоненты для реализации программы, а также расписаны их возможности. Дана схема работы программы. В работе детально расписан план отладки программы. Введение Основы теста Что такое тест Историческая справка Виды электронных тестов Аналитический обзор Анализ существующих программ и их функций Программа "Flash your brain" Программа "MyTest версия 2.</p>
    
    

    external by rickwheeler modified Feb 16, 2016  616  0  3  0

    Support for Delphi XE5-XE7

    Support for Delphi XE5-XE7: FMX.MeshObjects.pas
    unit FMX.MeshObjects;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, System.RTLConsts,
      System.Math, System.UIConsts, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Controls3D,
      FMX.Types3D, FMX.Objects3D, FMX.Layers3D, FMX.Objects, FMX.Menus, FMX.Edit, FMX.Colors, FMX.MaterialSources,
      System.StrUtils, System.Generics.Collections, FMX.Ani, FMX.Materials, System.Generics.Defaults;
    
    Type
      TSectionType = (sctNone, sctTop, sctBottom);
      TFrameType = (ftEllipse, ftRectangle);
      TPointArray = array of TPoint3d;
      TDummyPointLayer = class;
    
      TPoint3DHelper = record helper for TPoint3D
      public
        class function Zero: TPoint3D; static;
      end;
    
      TPointLayer = class(TObject)
      private
        FParent: TPointLayer;
        FChild: TPointLayer;
        FContent: TPointLayer;
        FPosition: TPosition3d;
        FLocalMatrix: TMatrix3D;
        FRotationAngle: TPosition3d;
        FQuaternion: TQuaternion3D;
        FScale: TPosition3d;
        FSavedAbsoluteMatrix: TMatrix3D;
        FAbsMatrixNeedRefresh: Boolean;
        FGapLayer: Boolean;
        function GetLength: Integer;
        procedure SetPointsLength(const Value: Integer);
        Procedure MatrixChanged(Sender: TObject);
        procedure RotationChanged(Sender: TObject); virtual;
        function GetAbsoluteMatrix: TMatrix3D;
        function GetRealParent: TPointLayer;
        function GetRealChild: TPointLayer;
        function GetLayerCount: Integer;
        function GetFirstParent: TPointLayer;
        function GetDummyChild: TPointLayer;
        function GeAbsoluteCenter: TPoint3d;
        function GetLayerH: Single;
      protected
        Procedure CreateDummies; virtual;
      public
        Points: TPointArray;
        Constructor Create;
        Destructor Destroy; override;
        Function CreateChildAtPosition(CPos: TPoint3d; RepeatNbr: Integer): TPointLayer;
        Procedure AddChild(CPointLayer: TPointLayer);
        Function LastChild: TPointLayer;
        Function RemoveFirstChild: TPointLayer;
        Function Index: Integer;
        Function GetLayer(LIndex: Integer): TPointLayer;
        Function AbsPoint(i: Integer): TPoint3d;
        Function GetTotalTurn: Single;
        Function Content: TPointLayer;
        Procedure InvalidateAbsoluteMatrix;
        Property FirstParent: TPointLayer read GetFirstParent;
        Property RealParent: TPointLayer read GetRealParent;
        Property RealChild: TPointLayer read GetRealChild;
        Property DummyChild: TPointLayer read GetDummyChild;
        Property Length: Integer read GetLength write SetPointsLength;
        Property Position: TPosition3d read FPosition write FPosition;
        property AbsoluteMatrix: TMatrix3D read GetAbsoluteMatrix;
        property LocalMatrix: TMatrix3D read FLocalMatrix;
        Property AbsoluteCenter: TPoint3d read GeAbsoluteCenter;
        Property LayerH: Single read GetLayerH;
        Property GapLayer: Boolean read FGapLayer write FGapLayer;
        property RotationAngle: TPosition3d read FRotationAngle write FRotationAngle;
        property Scale: TPosition3d read FScale write FScale;
        Property LayerCount: Integer read GetLayerCount;
      end;
    
      TDummyPointLayer = class(TPointLayer)
      protected
        Procedure CreateDummies; override;
      end;
    
      TLayerList = TList<TPointLayer>;
    
      TAnnulus = class(TCustomMesh)
      private
        FSectionType: TSectionType;
        FSectionDegree: Integer;
        FInnerFrameType: TFrameType;
        FOuterFrameType: TFrameType;
        FDrawBounds: Boolean;
        procedure SetThickness(const Value: Single);
        procedure SetSubdivisionsAxes(const Value: Integer);
        procedure SetSectionDegree(const Value: Integer);
        procedure SetSectionType(const Value: TSectionType);
        procedure setInnerFrameType(const Value: TFrameType);
        procedure setOuterFrameType(const Value: TFrameType);
        procedure SetDrawBounds(const Value: Boolean);
      protected
        FSubdivisionsAxes: Integer;
        FUnitWidth: Single;
        FUnitHeight: Single;
        FThickness: Single;
        FRenderScale: Single;
        FStartAngle: Single;
        FTotalAngle: Single;
        FDistAngle: Single;
        InnerPoints: TPointArray;
        OuterPoints: TPointArray;
        function ExtendPointToPlane(point, Plane, PlaneNormal: TPoint3D; var Distance: Single; var nPoint: TPoint3d): Boolean;
        Procedure CalcPoints; virtual;
        Procedure GetAnnulusPointsForPosY(PosY: Single; var IPoints, OPoints: TPointArray); virtual;
        procedure BuildAnnulus(IPoints, OPoints: TPointArray; Back: Boolean); virtual;
        procedure RebuildMesh; virtual;
        procedure Render; override;
        function FixHeight: Boolean; virtual;
        procedure SetHeight(const Value: Single); override;
        procedure SetWidth(const Value: Single); override;
        procedure SetDepth(const Value: Single); override;
      public
        constructor Create(AOwner: TComponent); override;
        property Data;
        Property Thickness: Single read FThickness write SetThickness;
        Property SubdivisionsAxes: Integer read FSubdivisionsAxes write SetSubdivisionsAxes;
        Property SectionType: TSectionType read FSectionType write SetSectionType;
        Property SectionDegree: Integer read FSectionDegree write SetSectionDegree;
        Property InnerFrameType: TFrameType read FInnerFrameType write setInnerFrameType;
        Property OuterFrameType: TFrameType read FOuterFrameType write setOuterFrameType;
        Property RenderScale: Single read FRenderScale;
        Property DrawBounds: Boolean read FDrawBounds write SetDrawBounds;
      end;
    
      TPipe = class;
    
      TPipeModifier = class(TFMXObject)
      private
        FPipe: TPipe;
        FStartPosition: Single;
        FEndPosition: Single;
        FSubdivisions: Integer;
        FUseGap: Boolean;
        FFirstCenter: TPoint3d;
        FLastCenter: TPoint3d;
        FModifyMargins: Boolean;
        procedure SetStartPosition(const Value: Single);
        procedure SetEndPosition(const Value: Single);
        procedure SetSubdivisions(const Value: Integer);
        function InsertPointLayer(StartLayer: TPointLayer; LayerH: Single; UseGap: Boolean = False): TPointLayer;
        procedure SetModifyMargins(const Value: Boolean);
      protected
        FStartMargin: Single;
        FEndMargin: Single;
        FLayerCount: Integer;
        StartLayer, EndLayer, StartMLayer, EndMLayer: TPointLayer;
        Procedure BeginModify(StartPoints: TPointLayer); virtual;
      public
        Constructor Create(aPipe: TPipe); virtual;
        Procedure ModifySubPoints(sPoints: TPointLayer; isInner: Boolean); virtual; abstract;
        Procedure DoModify(StartPoints: TPointLayer); virtual;
        Procedure EndModify; virtual;
      published
        Property StartPosition: Single read FStartPosition write SetStartPosition;
        Property EndPosition: Single read FEndPosition write SetEndPosition;
        Property Subdivisions: Integer read FSubdivisions write SetSubdivisions;
        Property UseGap: Boolean read FUseGap write FUseGap;
        Property FirstCenter: TPoint3d read FFirstCenter;
        Property LastCenter: TPoint3d read FLastCenter;
        Property ModifyMargins: Boolean read FModifyMargins write SetModifyMargins;
      end;
    
      TBendModifier = class(TPipeModifier)
      private
        FBendAngle: Single;
        FTurnAngle: Single;
        procedure SetBendAngle(const Value: Single);
        procedure SetTurnAngle(const Value: Single);
      public
        Constructor Create(aPipe: TPipe); override;
        Destructor Destroy; override;
        Procedure ModifySubPoints(sPoints: TPointLayer; isInner: Boolean); override;
      published
        Property BendAngle: Single read FBendAngle write SetBendAngle;
        Property TurnAngle: Single read FTurnAngle write SetTurnAngle;
      end;
    
      TBreakModifier = class(TBendModifier)
      private
        procedure SetEndMargin(const Value: Single);
        procedure SetStartMargin(const Value: Single);
      public
        Constructor Create(aPipe: TPipe); override;
        Procedure ModifySubPoints(sPoints: TPointLayer; isInner: Boolean); override;
        Property StartMargin: Single read FStartMargin write SetStartMargin;
        Property EndMargin: Single read FEndMargin write SetEndMargin;
      end;
    
      TTwistModifier = class(TPipeModifier)
      private
        FTotalRotation: Single;
        procedure SetTotalRotation(const Value: Single);
      public
        Constructor Create(aPipe: TPipe); override;
        Procedure ModifySubPoints(sPoints: TPointLayer; isInner: Boolean); override;
      published
        Property TotalRotation: Single read FTotalRotation write SetTotalRotation;
      end;
    
      TEmbossModifier = class(TPipeModifier)
      private
        FThicknessRatio: Single;
        procedure SetThicknessRatio(const Value: Single);
      public
        Constructor Create(aPipe: TPipe); override;
        Procedure ModifySubPoints(sPoints: TPointLayer; isInner: Boolean); override;
        Property ThicknessRatio: Single read FThicknessRatio write SetThicknessRatio;
      end;
    
      TPipe = class(TAnnulus)
      private
        FModifiers: TList<TPipeModifier>;
        FOnZAxis: Boolean;
        FFirstCenter: TPoint3d;
        FLastCenter: TPoint3d;
        FScaleBeforeRender: Boolean;
        Procedure SortModifiers;
        procedure SetOnZAxis(const Value: Boolean);
        procedure SetScaleBeforeRender(const Value: Boolean);
      protected
        function FixHeight: Boolean; override;
        procedure SetHeight(const Value: Single); override;
        Procedure GetAnnulusPointsForPosY(PosY: Single; var IPoints, OPoints: TPointArray); override;
        procedure BuildSectionSurfaces(OuterSectionPoints, InnerSectionPoints: TPointArray); virtual;
        procedure BuildCylinder(Points: TPointArray; Back: Boolean;
          var SectionPoints, FirstPoints, LastPoints: TPointArray); virtual;
        procedure RebuildMesh; override;
        Procedure Render; override;
        Procedure ModifiersNotify(Sender: TObject; Const Item: TPipeModifier; Action: TCollectionNotification);
      public
        constructor Create(AOwner: TComponent); override;
        Procedure ClearModifiers;
        destructor Destroy; override;
        Property Modifiers: TList<TPipeModifier> read FModifiers;
        Property OnZAxis: Boolean read FOnZAxis write SetOnZAxis;
        Property FirstCenter: TPoint3d Read FFirstCenter;
        Property LastCenter: TPoint3d read FLastCenter;
        Property ScaleBeforeRender: Boolean read FScaleBeforeRender write SetScaleBeforeRender;
      end;
    
    procedure Register;
    
    implementation
    
    procedure Register;
    begin
      RegisterComponents('3D Shapes', [TAnnulus, TPipe]);
    end;
    
    { TPoint3DHelper }
    
    class function TPoint3DHelper.Zero: TPoint3D;
    begin
      Result := Point3D(0,0,0);
    end;
    
    { TPipe }
    
    procedure TAnnulus.BuildAnnulus(IPoints, OPoints: TPointArray; Back: Boolean);
    var
      FData: TMeshData;
      i: Integer;
      vertexIdx: Integer;
      indexIdx: Integer;
    begin
    
      FData := Self.Data;
      vertexIdx := FData.VertexBuffer.Length;
      indexIdx := FData.IndexBuffer.Length;
      FData.VertexBuffer.Length := vertexIdx + FSubdivisionsAxes * 2;
    
      for i := 0 to FSubdivisionsAxes - 1 do begin
        FData.VertexBuffer.Vertices[vertexIdx + i] := IPoints[i];
        FData.VertexBuffer.TexCoord0[vertexIdx + i] := Pointf((IPoints[i].X + FUnitWidth / 2) / FUnitWidth,
          (IPoints[i].Z + FUnitHeight / 2) / FUnitHeight);
        FData.VertexBuffer.Vertices[vertexIdx + i + FSubdivisionsAxes] := OPoints[i];
        FData.VertexBuffer.TexCoord0[vertexIdx + i + FSubdivisionsAxes] :=
          Pointf((OPoints[i].X + FUnitWidth / 2) / FUnitWidth, (OPoints[i].Z + FUnitHeight / 2) / FUnitHeight);
      end;
    
      FData.IndexBuffer.Length := indexIdx + FSubdivisionsAxes * 6;
      if (FSectionType <> sctNone) then
        FData.IndexBuffer.Length := FData.IndexBuffer.Length - 6;
    
      for i := 0 to FSubdivisionsAxes - 1 do begin
        if (i = FSubdivisionsAxes - 1) then begin
          if (FSectionType = sctNone) then begin
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 0] := vertexIdx + i;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 1] := vertexIdx + 0;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 2] := vertexIdx + i + FSubdivisionsAxes;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 3] := vertexIdx + 0;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 4] := vertexIdx + FSubdivisionsAxes;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 5] := vertexIdx + i + FSubdivisionsAxes;
    
            if Back then begin
              FData.IndexBuffer.Indices[indexIdx + i * 6 + 2] := vertexIdx + i;
              FData.IndexBuffer.Indices[indexIdx + i * 6 + 1] := vertexIdx + 0;
              FData.IndexBuffer.Indices[indexIdx + i * 6 + 0] := vertexIdx + i + FSubdivisionsAxes;
              FData.IndexBuffer.Indices[indexIdx + i * 6 + 5] := vertexIdx + 0;
              FData.IndexBuffer.Indices[indexIdx + i * 6 + 4] := vertexIdx + FSubdivisionsAxes;
              FData.IndexBuffer.Indices[indexIdx + i * 6 + 3] := vertexIdx + i + FSubdivisionsAxes;
            end;
    
          end;
        end
        else begin
          FData.IndexBuffer.Indices[indexIdx + i * 6] := vertexIdx + i;
          FData.IndexBuffer.Indices[indexIdx + i * 6 + 1] := vertexIdx + i + 1;
          FData.IndexBuffer.Indices[indexIdx + i * 6 + 2] := vertexIdx + i + FSubdivisionsAxes;
          FData.IndexBuffer.Indices[indexIdx + i * 6 + 3] := vertexIdx + i + 1;
          FData.IndexBuffer.Indices[indexIdx + i * 6 + 4] := vertexIdx + i + FSubdivisionsAxes + 1;
          FData.IndexBuffer.Indices[indexIdx + i * 6 + 5] := vertexIdx + i + FSubdivisionsAxes;
          if Back then begin
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 2] := vertexIdx + i;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 1] := vertexIdx + i + 1;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 0] := vertexIdx + i + FSubdivisionsAxes;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 5] := vertexIdx + i + 1;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 4] := vertexIdx + i + FSubdivisionsAxes + 1;
            FData.IndexBuffer.Indices[indexIdx + i * 6 + 3] := vertexIdx + i + FSubdivisionsAxes;
          end;
        end;
      end;
    end;
    
    procedure TAnnulus.CalcPoints;
    var
      PhiSin, PhiCos: Extended;
      iWidth, iHeight: Single;
      rThickness: Single;
      A: Integer;
      Angle: Single;
      rPoint: TPoint3d;
      iPoint: TPoint3d;
      iDist: Single;
      uiWidth, uiHeight: Single;
    begin
      SetLength(OuterPoints, FSubdivisionsAxes);
      SetLength(InnerPoints, FSubdivisionsAxes);
      FUnitWidth := 1;
      FUnitHeight := 1;
      if Width > Depth then
        FUnitWidth := Width / Depth;
      if Depth > Width then
        FUnitHeight := Depth / Width;
      rThickness := FThickness * (FUnitWidth / Width);
      FRenderScale := Width / FUnitWidth;
    
      iWidth := 1;
      iHeight := 1;
      if (FThickness * 2 = Depth) or (FThickness * 2 = Width) then
        FThickness := FThickness - 0.1;
    
      if Width > Depth then
        iWidth := (Width - (FThickness * 2)) / (Depth - (FThickness * 2));
      if Depth > Width then
        iHeight := (Depth - (FThickness * 2)) / (Width - (FThickness * 2));
    
      FStartAngle := 0;
      FTotalAngle := 360;
      if FSectionType <> sctNone then
        FTotalAngle := 360 - FSectionDegree;
      if FSectionType = sctBottom then
        FStartAngle := -(180 - FSectionDegree) / 2;
      if FSectionType = sctTop then
        FStartAngle := 180 - (180 - FSectionDegree) / 2;
    
      FDistAngle := FTotalAngle / FSubdivisionsAxes;
      if FSectionType <> sctNone then
        FDistAngle := FTotalAngle / (FSubdivisionsAxes - 1);
    
      for A := 0 to FSubdivisionsAxes - 1 do begin
        Angle := DegToRad(FStartAngle) + DegToRad(FDistAngle) * A;
        SinCos(Angle, PhiSin, PhiCos);
    
        if FOuterFrameType = ftEllipse then begin
          OuterPoints[A] := Point3D(PhiCos * 0.5 * FUnitWidth, 0, PhiSin * 0.5 * FUnitHeight);
        end
        else begin
          rPoint := Point3D(PhiCos * 0.5 * FUnitWidth, 0, PhiSin * 0.5 * FUnitHeight);
          iDist := -1;
          iPoint := rPoint;
          Self.ExtendPointToPlane(rPoint, Point3D(FUnitWidth / 2, 0, 0), Point3D(-1, 0, 0), iDist, iPoint);
          Self.ExtendPointToPlane(rPoint, Point3D(0, 0, FUnitHeight / 2), Point3D(0, 0, -1), iDist, iPoint);
          Self.ExtendPointToPlane(rPoint, Point3D(-FUnitWidth / 2, 0, 0), Point3D(1, 0, 0), iDist, iPoint);
          Self.ExtendPointToPlane(rPoint, Point3D(0, 0, -FUnitHeight / 2), Point3D(0, 0, 1), iDist, iPoint);
          OuterPoints[A] := iPoint;
        end;
        if FInnerFrameType = ftEllipse then begin
          InnerPoints[A] := Point3D(PhiCos * (0.5 - rThickness) * iWidth, 0, PhiSin * (0.5 - rThickness) * iHeight);
        end
        else begin
          rPoint := Point3D(PhiCos * (0.5 - rThickness) * iWidth, 0, PhiSin * (0.5 - rThickness) * iHeight);
          uiWidth := (0.5 - rThickness) * iWidth;
          uiHeight := (0.5 - rThickness) * iHeight;
          iDist := -1;
          iPoint := rPoint;
          Self.ExtendPointToPlane(rPoint, Point3d(uiWidth, 0, 0), Point3d(-1, 0, 0), iDist, iPoint);
          Self.ExtendPointToPlane(rPoint, Point3d(0, 0, uiHeight), Point3d(0, 0, -1), iDist, iPoint);
          Self.ExtendPointToPlane(rPoint, Point3d(-uiWidth, 0, 0), Point3d(1, 0, 0), iDist, iPoint);
          Self.ExtendPointToPlane(rPoint, Point3d(0, 0, -uiHeight), Point3d(0, 0, 1), iDist, iPoint);
          InnerPoints[A] := iPoint;
        end;
      end;
    end;
    
    constructor TAnnulus.Create(AOwner: TComponent);
    begin
      inherited;
      FThickness := 0.2;
      FSubdivisionsAxes := 180;
      FSectionType := sctNone;
      FSectionDegree := 180;
      FOuterFrameType := ftEllipse;
      FInnerFrameType := ftEllipse;
      RebuildMesh;
    end;
    
    function TAnnulus.ExtendPointToPlane(point, Plane, PlaneNormal: TPoint3D; var Distance: Single; var nPoint: TPoint3d):
        Boolean;
    var
      iPoint: TVector3d;
      aDist: Single;
    begin
      Result := False;
      if RayCastPlaneIntersect(TPoint3D.Zero, point, Plane, PlaneNormal, iPoint) then begin
        aDist := Sqrt(iPoint.Distance(TPoint3D.Zero));
        if Distance = -1 then begin
          Distance := aDist;
          nPoint := iPoint.ToPoint3D;
          Result := True;
        end
        else if aDist < Distance then begin
          Distance := aDist;
          nPoint := iPoint.ToPoint3D;
          Result := True;
        end;
      end;
    
    end;
    
    function TAnnulus.FixHeight: Boolean;
    begin
      FHeight := 0.001;
      Result := True;
    end;
    
    procedure TAnnulus.GetAnnulusPointsForPosY(PosY: Single; var IPoints, OPoints: TPointArray);
    var
      i: Integer;
    begin
      SetLength(IPoints, Length(InnerPoints));
      SetLength(OPoints, Length(OuterPoints));
      for i := 0 to High(InnerPoints) do begin
        IPoints[i] := Point3D(InnerPoints[i].X, PosY, InnerPoints[i].Z);
        OPoints[i] := Point3D(OuterPoints[i].X, PosY, OuterPoints[i].Z);
      end;
    end;
    
    procedure TAnnulus.RebuildMesh;
    var
      IPoints, OPoints: TPointArray;
    begin
      CalcPoints;
      Data.VertexBuffer.Length := 0;
      Data.IndexBuffer.Length := 0;
      GetAnnulusPointsForPosY(-0.001, IPoints, OPoints);
      BuildAnnulus(IPoints, OPoints, True);
      GetAnnulusPointsForPosY(0.001, IPoints, OPoints);
      BuildAnnulus(IPoints, OPoints, False);
      Data.CalcFaceNormals;
    end;
    
    procedure TAnnulus.Render;
    begin
      Context.SetMatrix(TMatrix3D.CreateScaling(TPoint3D.Create(FRenderScale, Height, FRenderScale)) * AbsoluteMatrix);
      Context.DrawTriangles(Data.VertexBuffer, Data.IndexBuffer, TMaterialSource.ValidMaterial(MaterialSource),
        AbsoluteOpacity);
      if FDrawBounds then begin
        Context.SetMatrix(AbsoluteMatrix);
        Context.DrawCube(TPoint3D.Zero, Point3D(Width, 0, Depth), AbsoluteOpacity, TalphaColors.Red);
      end;
    end;
    
    procedure TAnnulus.SetDepth(const Value: Single);
    var
      FRefresh: Boolean;
    begin
      FRefresh := (Self.Depth <> Value);
      inherited;
      if FRefresh then
        RebuildMesh;
    end;
    
    procedure TAnnulus.SetDrawBounds(const Value: Boolean);
    begin
      FDrawBounds := Value;
      Render;
    end;
    
    procedure TAnnulus.SetHeight(const Value: Single);
    begin
      if not FixHeight then
        inherited;
    end;
    
    procedure TAnnulus.setInnerFrameType(const Value: TFrameType);
    begin
      FInnerFrameType := Value;
      RebuildMesh;
    end;
    
    procedure TAnnulus.setOuterFrameType(const Value: TFrameType);
    begin
      FOuterFrameType := Value;
      RebuildMesh;
    end;
    
    procedure TAnnulus.SetSectionDegree(const Value: Integer);
    begin
      FSectionDegree := Value;
      RebuildMesh;
    end;
    
    procedure TAnnulus.SetSectionType(const Value: TSectionType);
    begin
      FSectionType := Value;
      RebuildMesh;
    end;
    
    procedure TAnnulus.SetSubdivisionsAxes(const Value: Integer);
    begin
      FSubdivisionsAxes := Value;
      RebuildMesh;
    end;
    
    procedure TAnnulus.SetThickness(const Value: Single);
    begin
      FThickness := Value;
      RebuildMesh;
    end;
    
    procedure TAnnulus.SetWidth(const Value: Single);
    var
      FRefresh: Boolean;
    begin
      FRefresh := (Self.Width <> Value);
      inherited;
      if FRefresh then
        RebuildMesh;
    end;
    
    { TPipe }
    
    procedure TPipe.BuildCylinder(Points: TPointArray; Back: Boolean;
      var SectionPoints, FirstPoints, LastPoints: TPointArray);
    var
      FData: TMeshData;
      i, h, k: Integer;
      vertexIdx, pVertexIdx: Integer;
      indexIdx: Integer;
      hDist, hPos: Single;
      PhiSin, PhiCos: Extended;
      cntIndexInRow: Integer;
      cntVertexInRow: Integer;
      backM: Integer;
      Angle: Single;
      StartPoints: TPointLayer;
      EndPoints: TPointLayer;
      SubPoints: TPointArray;
      done: Boolean;
      PointsLen: Integer;
      pModifier: TPipeModifier;
      pLayer: TPointLayer;
      LayerCount: Integer;
      AbsStart: TPoint3d;
      sctIndex: Integer;
    begin
      FData := Self.Data;
      PointsLen := Length(Points);
      StartPoints := TPointLayer.Create;
      if FOnZAxis then
        StartPoints.RotationAngle.Point := Point3D(90, 90, 0);
      EndPoints := TPointLayer.Create;
      StartPoints.AddChild(EndPoints);
    
      StartPoints.Length := PointsLen;
      EndPoints.Length := PointsLen;
    
      StartPoints.Position.point := TPoint3D.Zero;
      EndPoints.Position.point := Point3D(0, Height, 0);
    
      for i := 0 to High(Points) do begin
        StartPoints.Points[i] := Point3D(Points[i].X, 0, Points[i].Z);
        EndPoints.Points[i] := Point3D(Points[i].X, 0, Points[i].Z);
      end;
    
      backM := 1;
      if Back then
        backM := -1;
    
      for pModifier in FModifiers do begin
        pModifier.DoModify(StartPoints);
      end;
    
      LayerCount := StartPoints.LayerCount;
    
      cntIndexInRow := PointsLen * 6;
      if FSectionType <> sctNone then begin
        cntIndexInRow := (PointsLen - 1) * 6;
      end;
    
      if FScaleBeforeRender then begin
        for i := 0 to LayerCount - 1 do begin
          pLayer := StartPoints.GetLayer(i);
          pLayer.Content.Scale.point := Point3D(pLayer.Content.Scale.point.X * FRenderScale, pLayer.Content.Scale.point.Y,
            pLayer.Content.Scale.point.Z * FRenderScale);
        end;
      end;
    
      AbsStart := Point3D(0, -Height / 2, 0);
      StartPoints.InvalidateAbsoluteMatrix;
      for i := 0 to LayerCount - 1 do begin
        vertexIdx := FData.VertexBuffer.Length;
        indexIdx := FData.IndexBuffer.Length;
        pLayer := StartPoints.GetLayer(i);
        FData.VertexBuffer.Length := vertexIdx + PointsLen;
        for k := 0 to PointsLen - 1 do begin
          FData.VertexBuffer.Vertices[vertexIdx + k] := pLayer.AbsPoint(k) + AbsStart;
          FData.VertexBuffer.TexCoord0[vertexIdx + k] := Pointf(k / (PointsLen - 1), pLayer.Position.Y / Height);
        end;
    
        if (FSectionType <> sctNone) and (not pLayer.GapLayer) then begin
          sctIndex := Length(SectionPoints);
          SetLength(SectionPoints, sctIndex + 2);
          SectionPoints[sctIndex] := pLayer.AbsPoint(PointsLen - 1) + AbsStart;
          SectionPoints[sctIndex + 1] := pLayer.AbsPoint(0) + AbsStart;
        end;
    
        if (i > 0) and (not pLayer.GapLayer) then begin
          FData.IndexBuffer.Length := indexIdx + cntIndexInRow;
          pVertexIdx := vertexIdx - PointsLen;
          for k := 0 to PointsLen - 1 do begin
            if k = PointsLen - 1 then begin
              if FSectionType = sctNone then begin
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 0] := vertexIdx;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 1] := vertexIdx + k;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 2] := pVertexIdx + k;
    
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 3] := vertexIdx;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 4] := pVertexIdx + k;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 5] := pVertexIdx;
                if Back then begin
                  FData.IndexBuffer.Indices[indexIdx + k * 6 + 2] := vertexIdx;
                  FData.IndexBuffer.Indices[indexIdx + k * 6 + 1] := vertexIdx + k;
                  FData.IndexBuffer.Indices[indexIdx + k * 6 + 0] := pVertexIdx + k;
                  FData.IndexBuffer.Indices[indexIdx + k * 6 + 5] := vertexIdx;
                  FData.IndexBuffer.Indices[indexIdx + k * 6 + 4] := pVertexIdx + k;
                  FData.IndexBuffer.Indices[indexIdx + k * 6 + 3] := pVertexIdx;
                end;
              end;
            end
            else begin
              FData.IndexBuffer.Indices[indexIdx + k * 6 + 0] := vertexIdx + k + 1;
              FData.IndexBuffer.Indices[indexIdx + k * 6 + 1] := vertexIdx + k;
              FData.IndexBuffer.Indices[indexIdx + k * 6 + 2] := pVertexIdx + k;
              FData.IndexBuffer.Indices[indexIdx + k * 6 + 3] := vertexIdx + k + 1;
              FData.IndexBuffer.Indices[indexIdx + k * 6 + 4] := pVertexIdx + k;
              FData.IndexBuffer.Indices[indexIdx + k * 6 + 5] := pVertexIdx + k + 1;
              if Back then begin
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 2] := vertexIdx + k + 1;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 1] := vertexIdx + k;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 0] := pVertexIdx + k;
    
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 5] := vertexIdx + k + 1;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 4] := pVertexIdx + k;
                FData.IndexBuffer.Indices[indexIdx + k * 6 + 3] := pVertexIdx + k + 1;
              end;
    
            end;
          end;
        end;
      end;
    
      SetLength(FirstPoints, PointsLen);
      SetLength(LastPoints, PointsLen);
      for i := 0 to StartPoints.Length - 1 do
        FirstPoints[i] := StartPoints.AbsPoint(i) + AbsStart;
      for i := 0 to EndPoints.Length - 1 do
        LastPoints[i] := EndPoints.AbsPoint(i) + AbsStart;
    
      FFirstCenter := StartPoints.AbsoluteCenter;
      FLastCenter := EndPoints.AbsoluteCenter;
    
      for pModifier in FModifiers do begin
        pModifier.EndModify;
      end;
    
      StartPoints.Free;
    end;
    
    procedure TPipe.BuildSectionSurfaces(OuterSectionPoints, InnerSectionPoints: TPointArray);
    var
      p1, p2: TPoint3d;
      i: Integer;
      FData: TMeshData;
      vertexIdx, indexIdx, vIdx: Integer;
      LevelCount: Integer;
    begin
    
      FData := Self.Data;
    
      LevelCount := System.Length(OuterSectionPoints) div 2;
    
      // left
      vertexIdx := FData.VertexBuffer.Length;
      FData.VertexBuffer.Length := vertexIdx + (LevelCount) * 2;
      for i := 0 to LevelCount - 1 do begin
        p1 := OuterSectionPoints[i * 2];
        p2 := InnerSectionPoints[i * 2];
        FData.VertexBuffer.Vertices[vertexIdx + i * 2 + 0] := p1;
        FData.VertexBuffer.Vertices[vertexIdx + i * 2 + 1] := p2;
      end;
    
      indexIdx := FData.IndexBuffer.Length;
      FData.IndexBuffer.Length := indexIdx + (LevelCount - 1) * 6;
      for i := 0 to LevelCount - 2 do begin
        vIdx := vertexIdx + i * 2 + 0;
        FData.IndexBuffer[indexIdx + i * 6 + 0] := vIdx + 1;
        FData.IndexBuffer[indexIdx + i * 6 + 1] := vIdx + 2;
        FData.IndexBuffer[indexIdx + i * 6 + 2] := vIdx + 0;
        FData.IndexBuffer[indexIdx + i * 6 + 3] := vIdx + 3;
        FData.IndexBuffer[indexIdx + i * 6 + 4] := vIdx + 2;
        FData.IndexBuffer[indexIdx + i * 6 + 5] := vIdx + 1;
      end;
    
      // right
      vertexIdx := FData.VertexBuffer.Length;
      FData.VertexBuffer.Length := vertexIdx + (LevelCount) * 2;
      for i := 0 to LevelCount - 1 do begin
        p1 := OuterSectionPoints[i * 2 + 1];
        p2 := InnerSectionPoints[i * 2 + 1];
        FData.VertexBuffer.Vertices[vertexIdx + i * 2 + 0] := p1;
        FData.VertexBuffer.Vertices[vertexIdx + i * 2 + 1] := p2;
      end;
    
      indexIdx := FData.IndexBuffer.Length;
      FData.IndexBuffer.Length := indexIdx + (LevelCount - 1) * 6;
      for i := 0 to LevelCount - 2 do begin
        vIdx := vertexIdx + i * 2 + 0;
        FData.IndexBuffer[indexIdx + i * 6 + 0] := vIdx + 0;
        FData.IndexBuffer[indexIdx + i * 6 + 1] := vIdx + 2;
        FData.IndexBuffer[indexIdx + i * 6 + 2] := vIdx + 1;
        FData.IndexBuffer[indexIdx + i * 6 + 3] := vIdx + 1;
        FData.IndexBuffer[indexIdx + i * 6 + 4] := vIdx + 2;
        FData.IndexBuffer[indexIdx + i * 6 + 5] := vIdx + 3;
      end;
    
    end;
    
    procedure TPipe.ClearModifiers;
    var
      pModifier: TPipeModifier;
    begin
      for pModifier in Self.FModifiers do
        pModifier.Free;
      FModifiers.Clear;
    end;
    
    constructor TPipe.Create(AOwner: TComponent);
    begin
      inherited;
      Self.TwoSide := True;
      FModifiers := TList<TPipeModifier>.Create;
      FModifiers.OnNotify := ModifiersNotify;
      FOnZAxis := False;
      FScaleBeforeRender := False;
      RebuildMesh;
    end;
    
    destructor TPipe.Destroy;
    begin
      ClearModifiers;
      FModifiers.Free;
      inherited;
    end;
    
    function TPipe.FixHeight: Boolean;
    begin
      Result := False;
    end;
    
    procedure TPipe.GetAnnulusPointsForPosY(PosY: Single; var IPoints, OPoints: TPointArray);
    var
      i: Integer;
    begin
      SetLength(IPoints, Length(InnerPoints));
      SetLength(OPoints, Length(OuterPoints));
      for i := 0 to High(InnerPoints) do begin
        IPoints[i] := Point3D(InnerPoints[i].X, PosY, InnerPoints[i].Z);
        OPoints[i] := Point3D(OuterPoints[i].X, PosY, OuterPoints[i].Z);
      end;
    end;
    
    procedure TPipe.ModifiersNotify(Sender: TObject; Const Item: TPipeModifier; Action: TCollectionNotification);
    begin
      SortModifiers;
      RebuildMesh;
    end;
    
    procedure TPipe.RebuildMesh;
    var
      OuterSectionPoints, InnerSectionPoints: TPointArray;
      InnerFirstPoints, InnerLastPoints, OuterFirstPoints, OuterLastPoints: TPointArray;
    begin
      if FModifiers = nil then
        exit;
      CalcPoints;
      Data.VertexBuffer.Length := 0;
      Data.IndexBuffer.Length := 0;
      BuildCylinder(InnerPoints, True, InnerSectionPoints, InnerFirstPoints, InnerLastPoints);
      BuildCylinder(OuterPoints, False, OuterSectionPoints, OuterFirstPoints, OuterLastPoints);
      if FSectionType <> sctNone then
        BuildSectionSurfaces(OuterSectionPoints, InnerSectionPoints);
      BuildAnnulus(InnerLastPoints, OuterLastPoints, True);
      BuildAnnulus(InnerFirstPoints, OuterFirstPoints, False);
      Data.CalcFaceNormals;
    end;
    
    procedure TPipe.Render;
    begin
      if not FScaleBeforeRender then
        Context.SetMatrix(TMatrix3D.CreateScaling(TPoint3D.Create(FRenderScale, 1, FRenderScale)) * AbsoluteMatrix);
      Context.DrawTriangles(Data.VertexBuffer, Data.IndexBuffer, TMaterialSource.ValidMaterial(MaterialSource),
        AbsoluteOpacity);
    end;
    
    procedure TPipe.SetHeight(const Value: Single);
    var
      FRefresh: Boolean;
    begin
      FRefresh := (Self.Height <> Value);
      inherited;
      if FRefresh then
        RebuildMesh;
    end;
    
    procedure TPipe.SetOnZAxis(const Value: Boolean);
    begin
      FOnZAxis := Value;
      RebuildMesh;
    end;
    
    procedure TPipe.SetScaleBeforeRender(const Value: Boolean);
    begin
      FScaleBeforeRender := Value;
      RebuildMesh;
    end;
    
    function CompareLevels(Item1, Item2: TPipeModifier): Integer;
    begin
      Result := 0;
      if TPipeModifier(Item1).StartPosition > TPipeModifier(Item2).StartPosition then begin
        Result := 1;
      end
      else if TPipeModifier(Item1).StartPosition < TPipeModifier(Item2).StartPosition then begin
        Result := -1;
      end;
    end;
    
    procedure TPipe.SortModifiers;
    var
      Comparer: IComparer<TPipeModifier>;
    begin
      Comparer := TDelegatedComparer<TPipeModifier>.Create(
    
        function(const Left, Right: TPipeModifier): Integer
        begin
          Result := Ceil(Left.StartPosition - Right.StartPosition);
          if (Result = 0) and (Left is TTwistModifier) then
            Result := 1;
        end);
    
      FModifiers.Sort(Comparer);
    end;
    
    { TPipeModifier }
    
    Function TPipeModifier.InsertPointLayer(StartLayer: TPointLayer; LayerH: Single; UseGap: Boolean = False): TPointLayer;
    var
      lParent: TPointLayer;
      FLayer: TPointLayer;
    begin
      Result := nil;
      FLayer := StartLayer;
      repeat
        if abs(LayerH - FLayer.LayerH) < 0.00001 then begin
          Result := FLayer;
          if UseGap then begin
            Result := Result.CreateChildAtPosition(TPoint3D.Zero, 1);
            Result.GapLayer := True;
          end;
        end
        else if (FLayer.LayerH > LayerH) then begin
          if assigned(FLayer.RealParent) then begin
            lParent := FLayer.RealParent;
            Result := lParent.CreateChildAtPosition(Point3D(0, LayerH - lParent.LayerH, 0), 1);
            if UseGap then begin
              Result := Result.CreateChildAtPosition(TPoint3D.Zero, 1);
              Result.GapLayer := True;
            end;
          end;
        end
        else if (Result = nil) and (FLayer.RealChild = nil) then begin
          Result := FLayer.CreateChildAtPosition(Point3D(0, LayerH - FLayer.LayerH, 0), 1);
          if UseGap then begin
            Result := Result.CreateChildAtPosition(TPoint3D.Zero, 1);
            Result.GapLayer := True;
          end;
        end;
        FLayer := FLayer.RealChild;
      until (Result <> nil) or (FLayer = nil);
    end;
    
    procedure TPipeModifier.BeginModify(StartPoints: TPointLayer);
    var
      i: Integer;
      FLayer: TPointLayer;
      mLen, dLen: Single;
      h1, h2, dh: Single;
      sCnt: Integer;
      tempList: TList<TPointLayer>;
      divCount: Integer;
    begin
    
      StartLayer := InsertPointLayer(StartPoints, FStartPosition, FUseGap);
      EndLayer := InsertPointLayer(StartPoints, FEndPosition, FUseGap);
    
      StartMLayer := nil;
      EndMLayer := nil;
    
      divCount := (FSubdivisions + 1);
      if (FStartMargin > 0) then begin
        StartMLayer := InsertPointLayer(StartPoints, FStartPosition + FStartMargin);
        divCount := divCount - 1;
      end;
      if (FEndMargin > 0) then begin
        EndMLayer := InsertPointLayer(StartPoints, FEndPosition - FEndMargin);
        divCount := divCount - 1;
      end;
    
      mLen := Self.EndPosition - Self.StartPosition - (FEndMargin + FStartMargin);
      dLen := mLen / divCount;
    
      if assigned(StartLayer) and assigned(EndLayer) then begin
        tempList := TList<TPointLayer>.Create;
        FLayer := StartLayer;
        if assigned(StartMLayer) then
          FLayer := StartMLayer;
        repeat
          tempList.Add(FLayer);
          FLayer := FLayer.RealChild;
        until (FLayer = EndLayer) or (FLayer = EndMLayer);
        if assigned(FLayer) then
          tempList.Add(FLayer);
        for i := 0 to tempList.Count - 2 do begin
          h1 := tempList[i].LayerH;
          h2 := tempList[i + 1].LayerH;
          sCnt := Round((h2 - h1) / dLen);
          if sCnt > 1 then begin
            dh := (h2 - h1) / sCnt;
            tempList[i].CreateChildAtPosition(Point3D(0, dh, 0), sCnt - 1);
          end;
        end;
        FLayerCount := EndLayer.Index - StartLayer.Index + 1;
        tempList.Free;
      end;
    end;
    
    constructor TPipeModifier.Create(aPipe: TPipe);
    begin
      inherited Create(aPipe);
      FPipe := aPipe;
      FSubdivisions := 10;
      FStartPosition := -FPipe.Height / 4;
      FEndPosition := FPipe.Height / 4;
      FStartMargin := 0;
      FEndMargin := 0;
      FModifyMargins := False;
    end;
    
    procedure TPipeModifier.DoModify(StartPoints: TPointLayer);
    var
      FLayer: TPointLayer;
    begin
      if (FStartPosition > FEndPosition) then
        exit;
      if (FStartPosition = FEndPosition) then
        exit;
      BeginModify(StartPoints);
      if (not assigned(StartLayer)) or (not assigned(EndLayer)) then
        raise Exception.Create('Modifier Position Indexes cant be arranged');
      FLayer := StartLayer;
      if (not FModifyMargins) and assigned(StartMLayer) then
        FLayer := StartMLayer;
      Self.ModifySubPoints(FLayer, False);
      repeat
        FLayer := FLayer.RealChild;
        if assigned(FLayer) then
          Self.ModifySubPoints(FLayer, False);
      until (FLayer = nil) or ((FLayer = EndMLayer) and (not FModifyMargins)) or (FLayer = EndLayer);
    end;
    
    procedure TPipeModifier.EndModify;
    begin
      if assigned(StartLayer) then
        FFirstCenter := StartLayer.AbsoluteCenter;
      if assigned(EndLayer) then
        FLastCenter := EndLayer.AbsoluteCenter;
    end;
    
    procedure TPipeModifier.SetEndPosition(const Value: Single);
    begin
      FEndPosition := Value;
      FPipe.RebuildMesh;
    end;
    
    procedure TPipeModifier.SetModifyMargins(const Value: Boolean);
    begin
      FModifyMargins := Value;
      FPipe.RebuildMesh;
    end;
    
    procedure TPipeModifier.SetStartPosition(const Value: Single);
    begin
      FStartPosition := Value;
      FPipe.RebuildMesh;
    end;
    
    procedure TPipeModifier.SetSubdivisions(const Value: Integer);
    begin
      FSubdivisions := Value;
      FPipe.RebuildMesh;
    end;
    
    { TBendModifier }
    
    constructor TBendModifier.Create(aPipe: TPipe);
    begin
      inherited;
      FEndPosition := FPipe.Height / 4;
      FBendAngle := 90;
      FTurnAngle := 0;
    end;
    
    destructor TBendModifier.Destroy;
    begin
    
      inherited;
    end;
    
    procedure TBendModifier.ModifySubPoints(sPoints: TPointLayer; isInner: Boolean);
    var
      Index: Integer;
      FCurrentBendAngle: Single;
    begin
      FCurrentBendAngle := (FBendAngle / (FLayerCount - 1));
      Index := sPoints.Index;
      if sPoints = StartLayer then begin
        sPoints.DummyChild.RotationAngle.Z := FCurrentBendAngle / 2;
        sPoints.RotationAngle.Y := FTurnAngle;
      end
      else if (Index > StartLayer.Index) and (Index <= EndLayer.Index) then begin
        sPoints.RotationAngle.Z := FCurrentBendAngle / 2;
        if sPoints <> EndLayer then begin
          sPoints.DummyChild.RotationAngle.Z := FCurrentBendAngle / 2;
        end;
      end;
    end;
    
    procedure TBendModifier.SetBendAngle(const Value: Single);
    begin
      FBendAngle := Value;
      FPipe.RebuildMesh;
    end;
    
    procedure TBendModifier.SetTurnAngle(const Value: Single);
    begin
      FTurnAngle := Value;
      FPipe.RebuildMesh;
    end;
    
    { TTwistModifier }
    
    constructor TTwistModifier.Create(aPipe: TPipe);
    begin
      inherited;
      FTotalRotation := 45;
    end;
    
    procedure TTwistModifier.ModifySubPoints(sPoints: TPointLayer; isInner: Boolean);
    var
      ya: Single;
      totalH, thisH: Single;
      cIndex, sIndex, eIndex: Integer;
    begin
      sIndex := StartLayer.Index;
      cIndex := sPoints.Index;
      eIndex := EndLayer.Index;
      if (cIndex > sIndex) and (cIndex <= eIndex) then begin
        totalH := FEndPosition - FStartPosition;
        thisH := sPoints.GetLayerH - FStartPosition;
        ya := (FTotalRotation / totalH) * thisH;
        sPoints.Content.RotationAngle.Y := ya;
      end;
    end;
    
    procedure TTwistModifier.SetTotalRotation(const Value: Single);
    begin
      FTotalRotation := Value;
      FPipe.RebuildMesh;
    end;
    
    { TPointLayer }
    function TPointLayer.AbsPoint(i: Integer): TPoint3d;
    var
      tTurn: Single;
    begin
      tTurn := GetTotalTurn;
      FContent.FContent.RotationAngle.Y := -tTurn;
      Result := Points[i] * FContent.FContent.AbsoluteMatrix;
    end;
    
    procedure TPointLayer.AddChild(CPointLayer: TPointLayer);
    var
      FOldChild: TPointLayer;
    begin
      FOldChild := FChild.FChild;
      Self.FChild.FChild := CPointLayer;
      CPointLayer.FParent := Self.FChild;
      if assigned(FOldChild) then begin
        CPointLayer.LastChild.AddChild(FOldChild);
      end;
    end;
    
    function TPointLayer.Content: TPointLayer;
    begin
      Result := FContent;
    end;
    
    constructor TPointLayer.Create;
    begin
      inherited;
      FLocalMatrix := TMatrix3D.Identity;
      FQuaternion := TQuaternion3D.Identity;
      FPosition := TPosition3d.Create(TPoint3D.Zero);
      FPosition.OnChange := MatrixChanged;
      FRotationAngle := TPosition3d.Create(TPoint3D.Zero);
      FRotationAngle.OnChange := RotationChanged;
      FScale := TPosition3d.Create(Point3D(1, 1, 1));
      FScale.OnChange := MatrixChanged;
      FAbsMatrixNeedRefresh := True;
      FGapLayer := False;
      CreateDummies;
    end;
    
    function TPointLayer.CreateChildAtPosition(CPos: TPoint3d; RepeatNbr: Integer): TPointLayer;
    var
      i: Integer;
    begin
      Result := TPointLayer.Create;
      Result.Length := Self.Length;
      for i := 0 to Length - 1 do
        Result.Points[i] := Self.Points[i];
      Result.Position.point := CPos;
      if assigned(FChild.FChild) then begin
        FChild.FChild.Position.point := FChild.FChild.Position.point - CPos;
      end;
      Self.AddChild(Result);
      RepeatNbr := RepeatNbr - 1;
      if RepeatNbr > 0 then
        Result := Result.CreateChildAtPosition(CPos, RepeatNbr);
    end;
    
    procedure TPointLayer.CreateDummies;
    var
      FContentContent: TPointLayer;
    begin
      FChild := TDummyPointLayer.Create;
      FChild.FParent := Self;
      FContent := TDummyPointLayer.Create;
      FContent.FParent := Self;
      FContentContent := TDummyPointLayer.Create;
      FContentContent.FParent := FContent;
      FContent.FContent := FContentContent;
    end;
    
    destructor TPointLayer.Destroy;
    begin
      FreeAndNil(FChild);
      FreeAndNil(FRotationAngle);
      FreeAndNil(FScale);
      FreeAndNil(FPosition);
      FreeAndNil(FContent);
      inherited;
    end;
    
    function TPointLayer.GeAbsoluteCenter: TPoint3d;
    var
      tTurn: Single;
    begin
      tTurn := GetTotalTurn;
      FContent.FContent.RotationAngle.Y := -tTurn;
      Result := TPoint3D.Zero * FContent.FContent.AbsoluteMatrix;
    end;
    
    function TPointLayer.GetAbsoluteMatrix: TMatrix3D;
    begin
      if not FAbsMatrixNeedRefresh then begin
        Result := FSavedAbsoluteMatrix;
      end
      else begin
        if assigned(FParent) and (FParent is TPointLayer) then
          Result := FLocalMatrix * TPointLayer(FParent).AbsoluteMatrix
        else
          Result := FLocalMatrix;
        FSavedAbsoluteMatrix := Result;
        FAbsMatrixNeedRefresh := False;
      end;
    end;
    
    function TPointLayer.GetDummyChild: TPointLayer;
    begin
      result := nil;
      if assigned(FChild) and (FChild is TDummyPointLayer) then
        Result := FChild;
    end;
    
    function TPointLayer.GetFirstParent: TPointLayer;
    begin
      Result := Self;
      if assigned(FParent.FParent) then begin
        Result := FParent.FParent.FirstParent;
      end;
    end;
    
    function TPointLayer.GetLayer(LIndex: Integer): TPointLayer;
    begin
      if LIndex = 0 then
        Result := Self
      else if assigned(FChild.FChild) and (LIndex > 0) then begin
        Result := FChild.FChild.GetLayer(LIndex - 1);
      end
      else
        Result := nil;
    end;
    
    function TPointLayer.GetLayerCount: Integer;
    begin
      Result := 1;
      if assigned(FChild.FChild) then
        Result := 1 + FChild.FChild.LayerCount;
    end;
    
    function TPointLayer.GetLayerH: Single;
    begin
      Result := Self.Position.Y;
      if assigned(RealParent) then
        Result := Result + RealParent.GetLayerH;
    end;
    
    function TPointLayer.GetLength: Integer;
    begin
      Result := System.Length(Points);
    end;
    
    function TPointLayer.GetRealChild: TPointLayer;
    begin
      Result := FChild.FChild;
    end;
    
    function TPointLayer.GetRealParent: TPointLayer;
    begin
      Result := nil;
      if assigned(FParent) then
        Result := FParent.FParent;
    end;
    
    function TPointLayer.GetTotalTurn: Single;
    begin
      Result := RotationAngle.Y;
      if assigned(FParent) then
        Result := Result + FParent.GetTotalTurn;
    end;
    
    function TPointLayer.Index: Integer;
    begin
      Result := 0;
      if assigned(FParent) and assigned(FParent.FParent) then
        Result := 1 + FParent.FParent.Index;
    end;
    
    procedure TPointLayer.InvalidateAbsoluteMatrix;
    begin
      FAbsMatrixNeedRefresh := True;
      if assigned(FChild) then
        FChild.InvalidateAbsoluteMatrix;
    end;
    
    function TPointLayer.LastChild: TPointLayer;
    begin
      Result := Self;
      if assigned(FChild.FChild) then
        Result := FChild.FChild.LastChild;
    end;
    
    procedure TPointLayer.MatrixChanged(Sender: TObject);
    var
      LeftVector, DirectionVector, UpVector: TPoint3d;
      RotMatrix: TMatrix3D;
    begin
      UpVector := Point3d(0, 1, 0);
      DirectionVector := Point3d(0, 0, 1);
      if (FRotationAngle.X <> 0) or (FRotationAngle.Y <> 0) or (FRotationAngle.Z <> 0) then begin
        RotMatrix := FQuaternion;
        UpVector := UpVector * RotMatrix;
        DirectionVector := DirectionVector * RotMatrix;
      end
      else begin
        FQuaternion := TQuaternion3D.Identity;
      end;
      LeftVector := UpVector.CrossProduct(DirectionVector);
      FLocalMatrix.M[0] := LeftVector * FScale.X;
      FLocalMatrix.m14 := 0;
      FLocalMatrix.M[1] := UpVector * FScale.Y;
      FLocalMatrix.m24 := 0;
      FLocalMatrix.M[2] := DirectionVector * FScale.Z;
      FLocalMatrix.m34 := 0;
      FLocalMatrix.m41 := FPosition.X;
      FLocalMatrix.m42 := FPosition.Y;
      FLocalMatrix.m43 := FPosition.Z;
      FAbsMatrixNeedRefresh := True;
    end;
    
    Function TPointLayer.RemoveFirstChild: TPointLayer;
    begin
      result := nil;
      if assigned(FChild.FChild) then begin
        Result := FChild.FChild;
        FChild.FChild := nil;
        if assigned(Result.FChild.FChild) then begin
          Self.AddChild(Result.FChild.FChild);
          Result.FChild.FChild := nil;
        end;
      end;
    end;
    
    procedure TPointLayer.RotationChanged(Sender: TObject);
    var
      q: TQuaternion3D;
      A: Single;
    begin
      FQuaternion := TQuaternion3D.Identity;
    
      A := DegToRad(DegNormalize(RotationAngle.X));
      if A <> 0 then begin
        { AbsoluteRight }
        q := TQuaternion3D.Create(Point3D(1, 0, 0), A);
        FQuaternion := FQuaternion * q;
      end;
      A := DegToRad(DegNormalize(RotationAngle.Y));
      if A <> 0 then begin
        { AbsoluteDirection }
        q := TQuaternion3D.Create(Point3D(0, 1, 0), A);
        FQuaternion := FQuaternion * q;
      end;
      A := DegToRad(DegNormalize(RotationAngle.Z));
      if A <> 0 then begin
        { AbsoluteUp }
        q := TQuaternion3D.Create(Point3D(0, 0, 1), A);
        FQuaternion := FQuaternion * q;
      end;
      MatrixChanged(Sender);
    end;
    
    procedure TPointLayer.SetPointsLength(const Value: Integer);
    begin
      SetLength(Points, Value);
    end;
    
    { TEmbossModifier }
    
    constructor TEmbossModifier.Create(aPipe: TPipe);
    begin
      inherited;
      FStartMargin := 0.02;
      FEndMargin := 0.02;
      FThicknessRatio := 0.1;
    end;
    
    procedure TEmbossModifier.ModifySubPoints(sPoints: TPointLayer; isInner: Boolean);
    begin
      sPoints.Content.Scale.point := Point3D(1 + FThicknessRatio, 0, 1 + FThicknessRatio);
    end;
    
    procedure TEmbossModifier.SetThicknessRatio(const Value: Single);
    begin
      FThicknessRatio := Value;
      FPipe.RebuildMesh;
    end;
    
    { TDummyPointLayer }
    
    procedure TDummyPointLayer.CreateDummies;
    begin
      // Do Nothing
    end;
    
    { TBreakModifier }
    
    constructor TBreakModifier.Create(aPipe: TPipe);
    begin
      inherited;
      FModifyMargins := True;
    end;
    
    procedure TBreakModifier.ModifySubPoints(sPoints: TPointLayer; isInner: Boolean);
    var
      Index: Integer;
      FCurrentBendAngle: Single;
      elpR: Single;
    begin
      FCurrentBendAngle := (FBendAngle / (FLayerCount - 2));
      FCurrentBendAngle := FCurrentBendAngle / 2;
      elpR := 1 / cos((FCurrentBendAngle) * (pi / 180));
      Index := sPoints.Index;
      if (Index > StartLayer.Index) and (Index < EndLayer.Index) then begin
        sPoints.RotationAngle.Z := FCurrentBendAngle;
        sPoints.Content.Scale.point := Point3D(elpR, 1, 1);
        sPoints.DummyChild.RotationAngle.Z := FCurrentBendAngle;
      end;
    end;
    
    procedure TBreakModifier.SetEndMargin(const Value: Single);
    begin
      FEndMargin := Value;
      FPipe.RebuildMesh;
    end;
    
    procedure TBreakModifier.SetStartMargin(const Value: Single);
    begin
      FStartMargin := Value;
      FPipe.RebuildMesh;
    end;
    
    initialization
    
    RegisterFmxClasses([TPipeModifier, TBendModifier, TTwistModifier, TEmbossModifier]);
    
    end.
    
    
    

    external by Github modified Dec 30, 2015  1  0  1  0

    Do you have any exams coming up? http://www.dgtresearch.com/ventolin-inhaler-price-in-pakistan-graph.pptx missionary ventolin price mercury drug rp101 thanks bank Republicans in the House and Senate made separate proposals to reopen the government and...

    Do you have any exams coming up? http://www.dgtresearch.com/ventolin-inhaler-price-in-pakistan-graph.pptx missionary ventolin price mercury drug rp101 thanks bank Republicans in the House and Senate made separate proposals to reopen the government and raise the $16.7 trillion debt limit — but only as part of broader approaches that cut the defic
    Do you have any exams coming up? http://www.dgtresearch.com/ventolin-inhaler-price-in-pakistan-graph.pptx missionary ventolin price mercury drug rp101 thanks bank  Republicans in the House and Senate made separate proposals to reopen the government and raise the $16.7 trillion debt limit — but only as part of broader approaches that cut the deficit, change the health care law known as Obamacare and ease the across-the-board spending cuts that the White House and Congress both dislike.
     http://www.pifpaf.com.br/abilify-20-mg-pill-high-dose.pptx wheat order abilify online pharmacies fund autobiography  XE4 and XE5 cut telephone cables used by various elements of Japan&#039;s military to communicate between Saigon, Hong Kong and Singapore. In July 1945, XE1 and XE3 sank the Japanese battle cruiser Takao.
     
    
    

    external by StackOverflow modified Oct 2, 2013  1  0  2  0

    Is PascalScript compatible with Delphi XE5 to create Android/iOS/Windows applications?

    I want to create an application that will draw simple forms based on JSON data. I need to have a script to put intelligence on that. Is Pascal Script from RemObjects a solution for that? Is is compatible to generate application with the same source code for Android, iOS and Windows? EDIT: Extending to better understand the need: I have a delph
    /* 
    If you want to draw shapes based on JSON data, then just interpret the data using Delphi code and have Delphi to draw the shapes or create the controls.  
    
    However I think it is a better idea to create some dummy code and ask RemObject support.
    See: http://www.remobjects.com/support/  
    
    You can write them an email with some source/pseudo code of what you're trying to do and see what they say.  
     */
    

    external by StackOverflow modified Jul 26, 2014  1  0  2  0

    Is DWScript compatible to create Delphi XE5 code for Android and IOs?

    Can I use DWScript classes in a Delphi XE5 program to run under Android and/or IOs and make the scripting works?
    /* 
    No, Android and iOS compilers are not supported.
    
    There are a few issues that prevent that at the moment
    
    
    I don't have access to those compilers
    There were some dropped Delphi features (like UTF8String) and there are some architectural changes (like ARC) which could make the adaptation non-trivial
    AFAIK the Apple licensing terms forbid use of 3rd party script engines in iOS, you're supposed to use the JavaScript one they provide, and only it.
     */
    
    • Public Snippets
    • Channels Snippets