Menu

TGLMultipolygon help

Help
bobmc
2020-03-23
2023-09-10
  • bobmc

    bobmc - 2020-03-23

    Hi,

    This issue could be summed up like this: how to turn a TGLPolygon into a TGLMultiPolygon?

    Now the details:

    I’m using GLscene to render a 3D representation of buildings. A building is made of construction elements (wall, roof, etc.). Each element is represented by a polygon, for which 3D coordinates are known.

    Up to now, I’ve been using TGLPolygon to render these construction elements. Here’s what a sample building it looks like:

    Now I’d like to take into account openings for doors and windows and display “holes” in those areas. I think using TGLMultipolygon instead of TGLPolygon is the right way to do this, as it allows to define an outer contour as well as various inner contours for the “holes”.

    But I’m having trouble using TGLMultiPolygon. As I understand it, the contours must be defined in the XY plane, or otherwise they’re projected onto it.

    So I project each of my 3D polygons onto their own plane in order to get a 2D polygon and build the outer contours. Here’s what the building walls looks like using TGLMultiPolygon. Everything is on the XY plane, as expected. I set up the positions of the TGLMultiPolygon at the original polygons’centers so placement should be OK.

    Now I think I need to modify the “Direction” and “Up” vectors or the “rollangle”, “pitchAngle” and “turnAngle” properties of the TGLPolygons in order to orientate them properly. And that’s where I’m having trouble. If I had a single building, I could do it manually for each element. But here I need to be able to display any building. So I need a function that does it automatically for any element of any building. I already spend a lot of time playing with those parameters and whenever I fix the orientation of something, something else gets messed up. For example, here’s what it looks like after setting up the “direction” vector according to the normal vector of the original polygons:

    Then some polygons should be rotated. But I cannot automatically find which ones and by which angle. In that particular case, it’s either by 90° or -90°.

    So I’m stuck. Anyone could help?

     
  • Jerome.D (BeanzMaster)

    Hi can you provide you're sample code please.

    Cheers

     
  • bobmc

    bobmc - 2020-03-26

    Hi Jerome,

    Here's a extact from my code:

    First some types definition: a building is made of polygons, which are made of XYZ points.

    type
       T2Dpoint = record
           x: Extended;
           y: Extended;
       end;
      T3DPoint = array [0..2] of extended; // Point 0=x, 1=y, 2=z
      T3DVector = T3DPoint;
      T3DPolyPoint = array of T3DPoint;    // Polygon
      T3DBuilding = array of T3DPolyPoint; // Building
    

    Then the global function which is called to daw a building:

    function DrawBuilding(bld: T3DBuilding);
    var
      i,j : Integer;
      poly3D : T3DPolyPoint;
      poly : TGLPolygon;
      mpoly : TGLMultiPolygon;
    begin
      // for each construction element (wall, roof, etc..)
      for i := Low(bld) to High(bld) do begin
        poly3D := bld[i];
    
        // using TGLPolygon, which is working
        {poly := TGLPolygon.Create(nil);
        for j := 0 to Length(D3Poly)-1
        do poly.AddNode(poly3D[j][0],poly3D[j][1],poly3D[j][2]);
        GLScene.Objects.AddChild(poly);}
    
        // using TGLMultiPolygon, which is not working
        AddMultiGLPolygon(GLScene,poly3D);
      end;
    end;
    

    and finally, the function that I cannot get to work properly, which is supposed to return a TGLMultiPolygon:

    procedure AddGLMultiPolygon(GLScene: TGLScene; poly3D: T3DPolypoint);
    const
          xVector : T3DPoint = (1,0,0);
          yVector : T3DPoint = (0,1,0);
          zVector : T3DPoint = (0,0,1);
    var
      Polycenter : T3DPoint;
      u,v,n,w : T3DVector;
      poly2D : TPolygon;
      mpoly : TGLMultiPolygon;
      contour : TGLContour;
      j : Integer;
      fact : Double;
    begin
      if Length(poly3D)<3 then exit;
    
      // vector normal to the 3D polygon plane
      n := D3Normalize(D3VectorCrossProductPoints(poly3D[0],poly3D[1],poly3D[0],poly3D[2]));
    
      // one of the world axis will be used a U vector
      if not D3VectorsAreColinear(xVector,n)
      then w := xVector
      else if not D3VectorsAreColinear(yVector,n)
      then w := yVector
      else w := zVector;
    
      // project u onto plane
      fact := ( D3VectorDotProduct(w,n) / Sqr(D3VectorLen(n)));
      u[0] := w[0]-fact*n[0];
      u[1] := w[1]-fact*n[1];
      u[2] := w[2]-fact*n[2];
      u := D3Normalize(u);
    
      v := D3Normalize(D3VectorCrossProduct(u,n)); // deduce v from u and plane
    
      polyCenter := D3polyPointCenter(poly3D);  // this is the center point of the original 3D polygon
    
      // project the 3D polygon onto its own plane, the result is a 2D polygon
      poly2D := D23PolypointToPolygon(poly3D,polyCenter,u,v);
    
      // Create external contour.
      mpoly := TGLMultiPolygon.create(GLScene);
      contour := mpoly.Contours.Add;
      for j := Length(poly3D)-1 downto 0
      do contour.Nodes.AddNode(poly2D[j].x,poly2D[j].y,0);
    
      mpoly.visible := true;
    
      mpoly.position.x := polycenter[0];
      mpoly.position.y := polycenter[1];
      mpoly.position.z := polycenter[2];
    
      mpoly.direction.x := n[0];
      mpoly.direction.y := n[1];
      mpoly.direction.z := n[2];
    
      mpoly.Material.FrontProperties.Diffuse.Red := GetRValue(clRed)/255;
      mpoly.Material.FrontProperties.Diffuse.Green := GetGValue(clRed)/255;
      mpoly.Material.FrontProperties.Diffuse.Blue := GetBValue(clRed)/255;
      mpoly.Material.PolygonMode := pmFill;
      mpoly.Material.FrontProperties.Diffuse.Alpha := 0.5;
    
      GLScene.Objects.AddChild(mpoly);
    end;
    

    The problem is when I project the polygon onto its on plane, in order to build the contour, I lose its orientation.

    Thanks for your help.

     

    Last edit: bobmc 2020-03-26
  • Jerome.D (BeanzMaster)

    Hi can you provide me your full project in a zip. It's to hard to tell you what's wrong with just this code.
    Why you don't use methods in GLGeometry for vectors ?
    It's not a good idea to use extend because it's not compatible with 64 bits use Double instead

    Thanks
    Cheers

     
  • bobmc

    bobmc - 2020-03-31

    Hi,

    I extracted the relevant code and made a sample application. Please see attached zip.

    Currently, the app uses our own library to represent and manipulate 2D and 3D objects. I might update to GLgeometry if I manage to display what I want using GLscene.

    The function I'm having trouble with is called "AddGLMultiPolygon". It transforms a standard 3D polygon (array of 3D points) into a TGLMultiPolygon. That is done by projecting the 3D polygon onto its own plate in order to build the contour. However, by doing that I lose information about the polygone orientation.

    Thanks in advance!

    PS: There is a problem with sample app crashing when moving the camera around but I cannot figure out what's wrong. It doesn't happen in the original app.

     

    Last edit: bobmc 2020-03-31
  • Jerome.D (BeanzMaster)

    Hi Bob i converted your sample to Lazarus, and take a look it seems the problem is in your D23PolypointToPolygon method. For me is wrong, this method dosen't project a point on a SPECIFIC plane so. You can see if you render only the first fourth polygons,
    I've also a doubt with your "n" value ;)

    Please try to use the methods in GLVectorGeometry unit you have all you need for making what you want and all methods are approved and deeply tested ;)
    AffineVectorMake
    VectorSubstract
    VectorAdd
    VectorNormalize
    VectorCrossProduct
    VectorDotProduct
    VectorLength
    PointPlaneProjection
    IsColinear

    etc....

    Ca ne sert à rien de réinventer la roue. Par exemple pour D3VectorsAreColinear il y a plus simple ;) regardes IsColinear

    A+

    Jérôme

     

    Last edit: Jerome.D (BeanzMaster) 2020-04-06
  • bobmc

    bobmc - 2020-05-14

    Hi,

    Thanks for trying to help. I let this problem rest for a while bu I'm back at it trying to find a solution. Regarding your last comment, I'm not trying to reinvent the wheel, just using some code that dates from way back, maybe even before GLScene came around. But I'll look into the GLVectorGeometry as you suggested, and update my code accordingly.

    Regarding the issue, I don't think the problem comes from the projection function. I tested it on a few polygons and it gives me what I expect. I think the problem probably rather comes from me. From what I am expecting, what I give this function to eat or from what I do with the result. So I need some help figuring that out.

    Let's take a simple example:

    1) A 3D polygon defined by the 4 following points: P1(0,0,0), P2(0,0,3), P3(6,6,3), P4(6,6,0). In the following picture, it’s represented by a TGLPolygon.

    2) I’m trying to use a TGLMultiPolygon to represent it. So I need to create a contour on the XY plane representing the polygon. In order to do that, I project these 4 points onto the plane on which they all are. That plane is defined by:
    - the point P0=(3,3,1.5), which corresponds to the center of the polygon
    - the vector U=(0.707,0.707,0), which is on the XY plane
    - the vector V=(0,0,1), along the Z axis.
    The resulting 2D polygon, according to the new referential (p0,u,v), has the following 4 points (rounded coordinates) : a1(-4.24,-1.5), a2(-4.24,1.5), a3(4.24,1.5), a4(4.24,-1.5)

    So this 2D polygon has the right dimensions, 8.48x3, which is what I was expecting.
    Now when I create a contour, I use these 4 points to create nodes on the XY plane, just adding zero as Z coordinate. The 4 nodes are: (-4.24,-1.5,0), (-4.24,1.5,0), (4.24,1.5,0), (4.24,-1.5,0)

    3) Then I set the position the TGLMultipolygon at the center point P0 (3,3,1.5) and setup the direction as vector n = (-0.707,0.707,0), which was the vector perpendicular to the original polygon. The result is this:

    The position and the direction are correct. However, the GLMultipolygon is rotated. This could be corrected this by changing the rollangle but I have no idea how to evaluate the angle.

    Does all this make sense or do I go at it all wrong? There might be something I haven’t understood about how to create the contour.

    Thanks.

     

    Last edit: bobmc 2020-05-14
  • Everton Teles

    Everton Teles - 2021-01-28

    Hello bobmc,
    I am facing the same difficulty that you had, did you find any solution?

     
  • bobmc

    bobmc - 2021-08-03

    Hi Everton,
    Sorry I only see your post now. Unfortunately, despite spending many hours on this last year, I was never able to figure out how to use the TGLMultipolygon properly. I think my latest post above sums it up well so if anyone has an idea how to solve this, your help is welcome!

     
  • Michael Läßig

    Michael Läßig - 2023-09-10

    Hello,
    I know this is an "cold case" but i faced it yesterday.
    Your polygon coordinates are absolute 3d coordinates.
    there ist currently no information about rotations and translations.
    You can see it if you turn polyGL.ShowAxes on. All Polygons have the same positions and angles.

    This ist not the way GLScene works. All Polygons should be defined in x/y plane around the centerpoint at 0/0 and then using Translation and Rotation to set it in the right places.

    We can determine the needed informations as the position is the centerpoint. For the angles we can create a plane using 3 points and calculate the angles using vectoranglecosine.

    I have made that in your procedure DisplayBuilding.
    I am sure that it can be done more effectively.

    procedure TForm4.DisplayBuilding(aResetCamera: Boolean = false);
    const
       cSteps = 16;
       cFactWorld = 1.5;
    var
      i,j : Integer;
      center : T3DPoint;
      polyGrd: TGLPolygon;
      polyGL : TGLPolygon;
      mPolyGL : TGLMultiPolygon;
      obj : TGLBaseSceneObject;
      poly3D : T3DPolyPoint;
      dMatrix, uMatrix : TMatrix;
      cp : T3DPoint;
      vcp : TAffineVector;
      Plane : THmgPlane;
      p1, p2, p3 : TAffineVector;   // to create the plane
    
    begin
      // remove existing polygons
      i := 0;
    
      while i < GLScene.Objects.Count  do begin
        obj := GLScene.Objects[i];
        if (obj is TGLExtrusionSolid) or (obj is TGLPolygon) or (obj is TGLMultiPolygon)
        or (obj is TGLLines) then begin
          GLScene.Objects.Remove(obj,false);
          obj.Free;
        end
        else Inc(i);
      end;
    
      // world extent in x and y coordinates
      FdX := Abs(FExtentP0[0])+Abs(FExtentP1[0]);
      FdY := Abs(FExtentP0[1])+Abs(FExtentP1[1]);
    
      // center of building on XY plane
      center[0] := (FExtentP0[0]+FExtentP1[0])/2;
      center[1] := (FExtentP0[1]+FExtentP1[1])/2;
      center[2] :=  0;
    
      // draw ground rectangle
      if ckShowGround.Checked then begin
        polyGrd := TGLPolygon.Create(nil);
        with polyGrd do begin
          Material.MaterialLibrary := GLMaterialLibrary;
          Material.LibMaterialName := 'Ground';
          AddNode(center[0]-cFactWorld*FdX  , center[1]-cFactWorld*FdY , 0);
          AddNode(center[0]+cFactWorld*FdX  , center[1]-cFactWorld*FdY , 0);
          AddNode(center[0]+cFactWorld*FdX  , center[1]+cFactWorld*FdY  , 0);
          AddNode(center[0]-cFactWorld*FdX  , center[1]+cFactWorld*FdY  , 0);
        end;
        GLScene.Objects.AddChild(polyGrd);
      end;
    
      GLDummyCube.Position.X := center[0];
      GLDummyCube.Position.Y := center[1];
      GLDummyCube.Position.Z := center[2];
      GLDummyCube.CubeSize := Max(FdX,FdY);
      GLDummyCube.Visible := true;
    
      if aResetCamera
      then GLSCameraReset;
    
      for i:=0 to Length(FBld)-1 do begin
        poly3D := FBLD[i];
        cp := D3PolyPointCenter(poly3D);
        vcp := AffineVectorMake(-cp[0], -cp[1], -cp[2]);
        Assert(Length(poly3D) > 2);
        p1 := AffineVectorMake(poly3D[0][0], poly3D[0][1], poly3D[0][2]);
        p2 := AffineVectorMake(poly3D[1][0], poly3D[1][1], poly3D[1][2]);
        p3 := AffineVectorMake(poly3D[2][0], poly3D[2][1], poly3D[2][2]);
        Plane := PlaneMake(p1, p2, p3);
        dMatrix := CreateTranslationMatrix(vcp);
        dMatrix := MatrixMultiPly(dMatrix, CreateRotationMatrix(ZVector, ArcCos(VectorAngleCosine(XHmgVector, Plane))));
        dMatrix := MatrixMultiply(dMatrix, CreateRotationMatrix(YVector, ArcCos(VectorAngleCosine(ZHmgVector, Plane))));
        uMatrix := dMatrix;
        InvertMatrix(uMatrix);
    
        // TGLPOLYGON
        if RadioGroup1.ItemIndex = 0 then
        begin
          polyGL := TGLPolygon.Create(nil);
          for j := 0 to Length(poly3D)-1 do begin
            p1 := VectorTransform(AffineVectorMake(poly3D[j][0],poly3D[j][1],poly3D[j][2]), dMatrix);
            polyGL.AddNode(p1);
          end;
          polyGL.Matrix := uMatrix;
          GLScene.Objects.AddChild(polyGL);
        end else
        begin
          mpolyGL := TGLMultiPolygon.Create(nil);
          for j := 0 to Length(poly3D)-1 do
          begin
            p1 := VectorTransform(AffineVectorMake(poly3D[j][0],poly3D[j][1],poly3D[j][2]), dMatrix);
            mpolyGL.AddNode(0, p1);
          end;
          mpolyGL.Matrix := uMatrix;
          GLScene.Objects.AddChild(mpolyGL);
        end;
       end;
    end;
    

    Michael

     
  • Michael Läßig

    Michael Läßig - 2023-09-10

    Hello,

    after playing around with your building i see that there are some wrong polygons.
    Within the code above i stupidly used the 3 first points to create a plane.
    Unfortunatily are some polygons where the first 3 points lay on a straight line that cannot build an plane.

    Michael

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.