How to display an element at the center of the view

Hi, There, 

I am trying to display an element (could be a complex one) with the view centered around the element. The elements were prescanned and stored in a internal data structure, not interactively selected by the user. Any suggestions how to achieve this go?

Best Regards,

Ken

  • Unknown said:
    I am trying to display an element (could be a complex one) with the view centered around the element

    1. Get the range of the element
    2. Calculate the view parameters from the range
    3. Update the view

     
    Regards, Jon Summers
    LA Solutions

  • Hi, Jon,

    Thanks for your suggestions. Follow your advise, I coded as follows but It did not work properly:

    Private void showElement

    (

       ULong filePos // element file position

    {

       MSElementDescr  *edP;

       Dpoint3d wOrigin;

       DPoint3d    minP;

       DPoint3d    maxP;

       Dpoint3d pointArray[101];

       int numVerts;

       // Read the element into a descriptor.

       if (mdlElmdscr_readToMaster (&edP, filePos, mdlModelRef_getActive(), FALSE, NULL))

       {    //

           mdlElmdscr_computeRange( &minP, &maxP, edP, NULL);

           switch (  mdlElement_getType(&edP->el) )

           {

               case LINE_STRING_ELM:

               case LINE_ELM:

               {

                   mdlLinear_extract (pointArray, &numVerts, &edP->el, mdlModelRef_getActive());

                   wOrigin = pointArray[0];

                   windowElment(&wOrigin, &minP, &maxP);

                   mdlElement_display (&edP->el, HILITE);

               }

               break;

               case ARC_ELM:

               {

                   double           start;

                   double           sweep;

                   double           primary;

                   double           secondary;

                   RotMatrix        rMatrix;          

                   Dpoint3d         center;   /* Start and End for Arc */

                   mdlArc_extract(&pointArray[0], &start, &sweep, &primary, &secondary, &rMatrix, &center, &edP->el);

                   windowElment(&center, &minP, &maxP);

                   mdlElement_display (&edP->el, HILITE);

               }

               break;

               case CMPLX_SHAPE_ELM:

               case CMPLX_STRING_ELM:

                   windowElment(&minP, &minP, &maxP, rFactor);

                   mdlElmdscr_display (edP, ACTIVEMODEL, HILITE);                

               break;

               default:

                   //CES_TODO: what to do: rs = ERROR;

               break;

           }

           mdlElmdscr_freeAll (&edP);

       }

    }   // end of showElement()

    The function windowElment is as follows:

    Public void windowElment

    (

       Dpoint3d *origin,    /* => window origin */

       Dpoint3d *minP, // => element range minP

       Dpoint3d *maxP,    // => element range maxP

    )

    {

       double viewExtent;

       Dpoint3d viewCenter, viewRange[2];

       /* calculate view center */

       viewCenter.x = origin->x;

       viewCenter.y = origin->y;

       viewCenter.z = 0;

       /* change view area to focus on element */

    viewExtent = mdlVec_distance(maxP, minP);    

       viewRange[0].x = viewCenter.x - viewExtent / 2;

       viewRange[0].y = viewCenter.y - viewExtent / 2;

       viewRange[1].x = viewCenter.x + viewExtent / 2;

       viewRange[1].y = viewCenter.y + viewExtent / 2;

       viewRange[0].z = viewRange[1].z = 0;

       /* now change the view */

       mdlView_setArea (0, viewRange, NULL, 10.0, 1.0, NULL);

       mdlView_zoom (0, 0, &viewCenter, .90);

       mdlView_updateSingle (0);

    }   // end of windowElment()

    It works ok for lines. But for arc it did not work at all (I could not figure out how the view was resized!)

    Your advise would be greatly appreciated.

    Ken

  • Rather than switch on element type, why not use the centre of the range as the view centre?

     
    Regards, Jon Summers
    LA Solutions

  • Hi, Jon,

    Thanks for the suggestion. I will give it a try.

    Ken

  • two hints

    1. if you really only need to center to a specific point you might use the following sequence (center is a DPoint3d):

        mdlView_newWindowCenter(view, &center);

        mdlView_updateSingle(view);

    2. if you really want to use range, don't forget that this range needs to be multiplied by the views rotation (if not in top-view) i.e.

    void cDwViewFunctions::zoomRange(int view, Dpoint3d *minPoint, Dpoint3d *maxPoint)
    {
        Dpoint3d    center, origin, delta;
        RotMatrix    rmat;
        double        activeZ=0.0;
        Dpoint3d    viewpt[2];
        FitViewOptions    options;

        options.expandClippingPlanes = 1;
        options.forceActiveZToCenter = 0;
        options.optionPadding = 0;
        options.optionPadding2 = 0;
        mdlView_getParameters(&origin, &center, &delta, &rmat, &activeZ, view);
        // do not change given points, save calculated range for further calls
        viewpt[0] = *minPoint;
        viewpt[1] = *maxPoint;
        mdlRMatrix_multiplyRange(&viewpt[0], &viewpt[1], &rmat);
        mdlView_fitViewToRange(&viewpt[0], &viewpt[1], &options, view);
        mdlView_updateSingle(view);
    }



  • Hi, Michael,

    Thanks for your help. The zoomRange function worked perfectly. I made a small change to make the view range scalable, please advise if this is the right way to do it:

    Private void zoomRange(int view, Dpoint3d *minPoint, Dpoint3d *maxPoint, double viewScale)

    {

       Dpoint3d    center, origin, delta;

       RotMatrix   rmat;

       double      activeZ=0.0;

       Dpoint3d    viewpt[2];

       FitViewOptions    options;

       options.expandClippingPlanes = 1;

       options.forceActiveZToCenter = 0;

       options.optionPadding = 0;

       options.optionPadding2 = 0;

       mdlView_getParameters(&origin, &center, &delta, &rmat, &activeZ, view);

       // do not change given points, save calculated range for further calls

       mdlVec_scale (&viewpt[0], minPoint, viewScale);

       mdlVec_scale (&viewpt[1], maxPoint, viewScale);

       mdlRMatrix_multiplyRange(&viewpt[0], &viewpt[1], &rmat);

       mdlView_fitViewToRange(&viewpt[0], &viewpt[1], &options, view);

       mdlView_updateSingle(view);

    }   // zoomRange

    Thanks again.

    Ken

  • Its a personal preference, you can do it this way, which would lead to a single function with one additional parameter. I think I would split this in two functions, one for the scaled zoom  and one without scale (where the first is only scaling and calling the second). But this is really a personal preference.

    What is the scale designed for in your case ? I never had a need to do so. Range calculation is done at my side for single elements or selection sets. If you need some extra space, I don't think scaling points is the correct approach, scaling the range (i.e. by 1.1) might work, but adding/subtracting the extra space to minpoint/maxpoint would show the intention better (i.e. minpoint.x = maxpoint.x - factor*(maxpoint.x-minpoint.x)). There are a number of different possibilities to enlarge the range to be shown, but all of them should be outside the basic zoom function (imho).