# How to draw lines in VTK so they can be displayed in paraview

**URL:** https://discourse.vtk.org/t/how-to-draw-lines-in-vtk-so-they-can-be-displayed-in-paraview/9200
**Category:** Support
**Created:** [August 23, 2022, 5:26pm UTC](https://discourse.vtk.org/t/how-to-draw-lines-in-vtk-so-they-can-be-displayed-in-paraview/9200 "2022-08-23T17:26:27Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![anirudh\_puligandla](https://discourse.vtk.org/user_avatar/discourse.vtk.org/anirudh_puligandla/32/5055_2.png) [@anirudh\_puligandla](https://discourse.vtk.org/u/anirudh_puligandla)
#### Post date: [August 23, 2022, 5:26pm UTC](https://discourse.vtk.org/t/how-to-draw-lines-in-vtk-so-they-can-be-displayed-in-paraview/9200/1 "2022-08-23T17:26:27Z")

</div>

I am trying draw a primitive scene with multiple polyData objects, write them into .ply file and view it using paraview. So far I am able to display an ellipsoid source, two sets of arrow sources showing axes of cameras placed on the ellipsoid. I display points as spheres using a glyph filter. I want to draw lines representing camera FoV originating from the sets of arrows (see attached images). I create different objects as separate polyData objects and combine them into one polyData using append filter before writing to .ply file. I am struggling with drawing lines that can be visualized in paraview. I must have tried all the VTK examples related to lines. When using vtkLineSource or vtkLine as cells, I can see some geometry at the ends of the lines when viewed on paraview as ‘points gaussian’ (second attached image). But in ‘surface’, I do not see the lines at all. How to draw lines so they can be seen in paraview with the rest of my polyData objects?

edit:  
vtk - 9.2  
Qt 6.3, Qt creator 8.0  
C++  
Paraview 5.10.1

 ![eg1](https://discourse.vtk.org/uploads/default/original/2X/2/256b8b44aa68c084c36a9797202a09a63a456a04.jpeg)  
 ![eg2](https://discourse.vtk.org/uploads/default/original/2X/2/20738048aacf30ae37f8f0022aa52eee475f19cb.jpeg)

```auto
//----------------------------- Ellipsoid -----------------------------------------------------------
    vtkSmartPointer<vtkParametricEllipsoid> ellipsoid = vtkSmartPointer<vtkParametricEllipsoid>::New();
    // set ellipsoid parameters
    ellipsoid->SetXRadius(ellipseParams[0]);
    ellipsoid->SetYRadius(ellipseParams[1]);
    ellipsoid->SetZRadius(ellipseParams[2]);
    ellipsoid->SetMaximumV(M_PI/2);
    // set ellipsoid center
    vtkSmartPointer<vtkParametricFunctionSource> ellipsoidSource = vtkSmartPointer<vtkParametricFunctionSource>::New();
    ellipsoidSource->SetParametricFunction(ellipsoid);
    ellipsoidSource->SetUResolution(50);
    ellipsoidSource->SetVResolution(50);
    ellipsoidSource->SetWResolution(50);
    ellipsoidSource->Update();
    vtkSmartPointer<vtkPolyData> scene = vtkSmartPointer<vtkPolyData>::New();
    scene->ShallowCopy(ellipsoidSource->GetOutput());
// -----------------------------------Create another polydata with control points-----------------------------------
    auto pointSet = vtkSmartPointer<vtkPoints>::New();
    int numControl = controlp.size();
    pointSet->SetNumberOfPoints(numControl);
    for(vtkIdType i = 0; i < numControl; i++)
    {
        double point[3];
        point[0] = controlp[i][0];
        point[1] = controlp[i][1];
        point[2] = controlp[i][2];
        pointSet->SetPoint(i,point);
    }
    auto sceneControl = vtkSmartPointer<vtkPolyData>::New();
    sceneControl->SetPoints(pointSet);
    // pass through glyph3d filter to render points as small spheres and save into new polydata
    auto glyphFilter = vtkSmartPointer<vtkGlyph3D>::New();
    auto sphereSource = vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetRadius(0.08);
    //sphereSource->SetThetaResolution(21);
    //sphereSource->SetPhiResolution(21);
    glyphFilter->SetSourceConnection(sphereSource->GetOutputPort());
    glyphFilter->SetInputData(sceneControl);
    glyphFilter->Update();
    auto scenePoints = vtkSmartPointer<vtkPolyData>::New();
    scenePoints->ShallowCopy(glyphFilter->GetOutput());
// -------------------------------------Display camera axes----------------------------------------------------------
    std::vector<std::vector<vtkSmartPointer<vtkPolyData>>> arrowDatVec(nCam);
    std::vector<vtkSmartPointer<vtkPolyData>> linesDatVec(nCam);
    for(int camCount = 0; camCount < nCam; camCount++)
    {
        std::vector<double> optSol = optSolVecs[camCount];
        double x = ellipseParams[0] * cos(optSol[0]) * sin(optSol[1]);
        double y = ellipseParams[1] * sin(optSol[0]) * sin(optSol[1]);
        double z = ellipseParams[2] * cos(optSol[1]);
        std::vector<double> camPos({x,y,z});
        std::vector<std::vector<double>> camDirs(3);
        // camera direction vector from the optimized solution
        std::vector<double> camDir = normVec(std::vector<double>({optSol[2],optSol[3],optSol[4]}));
        camDirs[2] = camDir;
        // camera right vector as a cross product of direction and world up vectors
        std::vector<double> worldUp({0.0,0.0,1.0});
        std::vector<double> camRight = normVec(crossVec(camDir,worldUp));
        camDirs[0] = camRight;
        std::vector<double> camUp = normVec(crossVec(camRight,camDir));
        camDirs[1] = camUp;
        std::vector<vtkSmartPointer<vtkPolyData>> arrowDat(3);
        for(int i = 0 ; i < 3; i++)
        {
            // Create an arrow.
            vtkNew<vtkArrowSource> arrowSource;
            arrowSource->SetShaftRadius(.01);
            arrowSource->SetShaftResolution(20);
            arrowSource->SetTipLength(.1);
            arrowSource->SetTipRadius(.05);
            arrowSource->SetTipResolution(20);
            //vtkMath::Normalize(camDirs[i].data());
            auto rng = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
            rng->SetSeed(8775070);
            std::vector<double> arbitrary(3);
            for(int j = 0; j < 3; j++)
            {
                rng->Next();
                arbitrary[i] = rng->GetRangeValue(-10, 10);
            }
            std::vector<double> zTemp(3), yTemp(3);
            vtkMath::Cross(camDirs[i].data(), arbitrary.data(), zTemp.data());
            vtkMath::Normalize(zTemp.data());
            vtkMath::Cross(zTemp.data(), camDirs[i].data(), yTemp.data());
            vtkNew<vtkMatrix4x4> matrix;
            // Create the direction cosine matrix
            matrix->Identity();
            for (auto j = 0; j < 3; j++)
            {
                matrix->SetElement(j, 0, camDirs[i][j]);
                matrix->SetElement(j, 1, yTemp[j]);
                matrix->SetElement(j, 2, zTemp[j]);
            }
            // Apply the transforms
            auto transform = vtkSmartPointer<vtkTransform>::New();
            transform->Translate(camPos.data());
            transform->Concatenate(matrix);
            double length = vtkMath::Norm(camDirs[i].data());
            transform->Scale(length, length, length);
            // Transform the polydata
            auto transformPD = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
            transformPD->SetTransform(transform);
            transformPD->SetInputConnection(arrowSource->GetOutputPort());
            transformPD->Update();
            arrowDat[i] = transformPD->GetOutput();
        }
        arrowDatVec[camCount] = arrowDat;
        // --------------------Draw camera FoV----------------------------------
        intrinsics intParams;
        double hFov = 2 * atan(intParams.h/(2*intParams.f_x));
        double vFov = 2 * atan(intParams.v/(2*intParams.f_y));
        double halfH = intParams.depth * tan(hFov/2);
        double halfV = intParams.depth * tan(vFov/2);
        double fovCent[3] = {x+(intParams.depth * camDir[0]), y+(intParams.depth * camDir[1]), z+(intParams.depth * camDir[2])};
        double fovTL[3] = {fovCent[0]+(camUp[0]*halfV)+(-camRight[0]*halfH), fovCent[1]+(camUp[1]*halfV)+(-camRight[1]*halfH), fovCent[2]+(camUp[2]*halfV)+(-camRight[2]*halfH)};
        double fovBL[3] = {fovTL[0]+(-camUp[0]*2*halfV), fovTL[1]+(-camUp[1]*2*halfV), fovCent[2]+(-camUp[2]*2*halfV)};
        double fovBR[3] = {fovBL[0]+(camRight[0]*2*halfH), fovCent[1]+(camRight[1]*2*halfH), fovCent[2]+(camRight[2]*2*halfH)};
        double fovTR[3] = {fovBR[0]+(camUp[0]*2*halfV), fovBR[1]+(camUp[1]*2*halfV), fovBR[2]+(camUp[2]*2*halfV)};
        // Insert the 5 points defining fov
        vtkSmartPointer<vtkPoints> fovPoints = vtkSmartPointer<vtkPoints>::New();
        fovPoints->InsertNextPoint(x,y,z);
        fovPoints->InsertNextPoint(fovTL);
        fovPoints->InsertNextPoint(fovBL);
        fovPoints->InsertNextPoint(fovBR);
        fovPoints->InsertNextPoint(fovTR);
        vtkSmartPointer<vtkPolyData> linesDat = vtkSmartPointer<vtkPolyData>::New();
        linesDat->SetPoints(fovPoints);
        std::vector<vtkSmartPointer<vtkLine>> lineVec(8);
        for(int i = 0; i < 8; i++)
            lineVec[i] = vtkSmartPointer<vtkLine>::New();
        // Draw 8 lines defining camera fov
        lineVec[0]->GetPointIds()->SetId(0,0); // origin to TL
        lineVec[0]->GetPointIds()->SetId(1,1);
        lineVec[1]->GetPointIds()->SetId(0,0); // origin to BL
        lineVec[1]->GetPointIds()->SetId(1,2);
        lineVec[2]->GetPointIds()->SetId(0,0); // origin to BR
        lineVec[2]->GetPointIds()->SetId(1,3);
        lineVec[3]->GetPointIds()->SetId(0,0); // origin to TR
        lineVec[3]->GetPointIds()->SetId(1,4);
        lineVec[4]->GetPointIds()->SetId(0,1); // TL to BL
        lineVec[4]->GetPointIds()->SetId(1,2);
        lineVec[5]->GetPointIds()->SetId(0,2); // BL to BR
        lineVec[5]->GetPointIds()->SetId(1,3);
        lineVec[6]->GetPointIds()->SetId(0,3); // BR to TR
        lineVec[6]->GetPointIds()->SetId(1,4);
        lineVec[7]->GetPointIds()->SetId(0,4); // TR to TL
        lineVec[7]->GetPointIds()->SetId(1,1);
        // create cell array and set it to polydata
        auto lineCell = vtkSmartPointer<vtkCellArray>::New();
        for(int i = 0; i < 8; i++)
            lineCell->InsertNextCell(lineVec[i]);
        linesDat->SetLines(lineCell);
        // Draw lines as tubes
        vtkSmartPointer<vtkTubeFilter> tubeFilt = vtkSmartPointer<vtkTubeFilter>::New();
        tubeFilt->SetInputData(linesDat);
        tubeFilt->SetRadius(5);
        tubeFilt->SetNumberOfSides(6);
        tubeFilt->Update();
        // add poly data into array
        linesDatVec[camCount] = tubeFilt->GetOutput();
    }
    //-------------------------------- Combine all polyData-----------------------------------------------------------------
    vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
    appendFilter->AddInputData(scene);
    appendFilter->AddInputData(scenePoints);
    for(int i = 0; i < nCam; i++)
    {
        appendFilter->AddInputData(linesDatVec[i]);
        for(int j = 0; j < 3; j++)
            appendFilter->AddInputData(arrowDatVec[i][j]);
    }
    //appendFilter->Update();
    auto cleanFilter = vtkSmartPointer<vtkCleanPolyData>::New();
    cleanFilter->SetInputConnection(appendFilter->GetOutputPort());
    cleanFilter->Update();
    // --------------------------------write to file-------------------------------------------------------------------------
    vtkSmartPointer<vtkPLYWriter> outWrite = vtkSmartPointer<vtkPLYWriter>::New();
    std::string fileName = folderPath+"ellipse_test.ply";
    outWrite->SetFileName(fileName.c_str());
    //outWrite->SetInputData(scenePoints);
    outWrite->SetInputConnection(cleanFilter->GetOutputPort());
    outWrite->Write();

```

---

<div class="post-metadata">

### Author: ![mwestphal](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mwestphal/32/19_2.png) [@mwestphal](https://discourse.vtk.org/u/mwestphal)
#### Post date: [August 29, 2022, 1:44am UTC](https://discourse.vtk.org/t/how-to-draw-lines-in-vtk-so-they-can-be-displayed-in-paraview/9200/2 "2022-08-29T01:44:06Z")

</div>

Please share your .ply data.

---

<div class="post-metadata">

### Author: ![anirudh\_puligandla](https://discourse.vtk.org/user_avatar/discourse.vtk.org/anirudh_puligandla/32/5055_2.png) [@anirudh\_puligandla](https://discourse.vtk.org/u/anirudh_puligandla)
#### Post date: [August 29, 2022, 6:45am UTC](https://discourse.vtk.org/t/how-to-draw-lines-in-vtk-so-they-can-be-displayed-in-paraview/9200/3 "2022-08-29T06:45:31Z")

</div>

> **[ellipse\_test.ply](https://drive.google.com/file/d/1WPIepgFTl3mQxwughGx2VFsGknxOhd36/view?usp=sharing)**
>
> Google Drive file.

Here is the link to the ,ply file uploaded to google drive.

---

<div class="post-metadata">

### Author: ![mwestphal](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mwestphal/32/19_2.png) [@mwestphal](https://discourse.vtk.org/u/mwestphal)
#### Post date: [August 29, 2022, 6:58am UTC](https://discourse.vtk.org/t/how-to-draw-lines-in-vtk-so-they-can-be-displayed-in-paraview/9200/4 "2022-08-29T06:58:10Z")

</div>

> [@anirudh\_puligandla](#):
>
> `vtkPLYWriter`

It looks like the vtkPLYWriter only write polys, not lines. This is an issue, however you can just use another writer, vtkXMLPolyDataWriter would work.

---

<div class="post-metadata">

### Author: ![anirudh\_puligandla](https://discourse.vtk.org/user_avatar/discourse.vtk.org/anirudh_puligandla/32/5055_2.png) [@anirudh\_puligandla](https://discourse.vtk.org/u/anirudh_puligandla)
#### Post date: [August 29, 2022, 8:14am UTC](https://discourse.vtk.org/t/how-to-draw-lines-in-vtk-so-they-can-be-displayed-in-paraview/9200/5 "2022-08-29T08:14:27Z")

</div>

Thanks a lot. That works.
