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
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, ¢er, &edP->el);
windowElment(¢er, &minP, &maxP);
case CMPLX_SHAPE_ELM:
case CMPLX_STRING_ELM:
windowElment(&minP, &minP, &maxP, rFactor);
mdlElmdscr_display (edP, ACTIVEMODEL, HILITE);
default:
//CES_TODO: what to do: rs = ERROR;
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.
Rather than switch on element type, why not use the centre of the range as the view centre?
Thanks for the suggestion. I will give it a try.
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, ¢er);
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, ¢er, &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, ¢er, &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);
} // zoomRange
Thanks again.
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).