How to get bounding rectangle of an ArcGIS TextSymbol? - c++

I'm using the Qt C++ ArcGIS Runtime SDK v100.9 and I have various shapes and labels being drawn on a map.
I want to be able to find out the area (bounding rectangle) of Graphic (which is a text label (TextSymbol) at a given point (SpatialReference::wgs84) on the map) so I can determine if the width of the label is more or less than another Graphic (lets say it has a Polygon for its Geometry which is being used to draw a circle) in order to decide if the label should be set to visible or not.
Within a class derived from Esri::ArcGISRuntime::MapGraphicsView the circle and the text label are created along the lines of:
Point centerWgs84(0.0, 0.0, SpatialReference::wgs84());
Graphic* circleGraphic_p = new Graphic(GeometryEngine::bufferGeodetic(centerWgs84, 1000.0, LinearUnit::meters(), 0.5, GeodeticCurveType::Geodesic));
this->graphicsOverlays()->at(0)->graphics()->append(circleGraphic_p);
circleGraphic_p->setSymbol(new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor(Qt::blue), 1.0));
circleGraphic_p->setVisible(true);
TextSymbol* textMarker_p = new TextSymbol("Some Label", Qt::black, 12.0, HorizontalAlignment::Center, VerticalAlignment::Bottom);
Graphic* labelGraphic_p = new Graphic(centerWgs84, textMarker_p);
this->graphicsOverlays()->at(0)->graphics()->append(labelGraphic_p);
labelGraphic_p->setVisible(true);
Rather than always setting the label visibility to true, I thought I would be able to take the Geometry of each Graphic and use it to construct an Envelope which would allow me to then get the width of each envelope that could then be compared:
Envelope circleEnvelope(circleGraphic_p->geometry());
Envelope labelEnvelope(labelGraphic_p->geometry());
labelGraphic_p->setVisible(circleEnvelope.width() >= labelEnvelope.width());
but when I try and do this, the width of each envelope is always a very small negative value (such as -2.25017... e-98)
Any suggestions on what I am doing wrong or if there is a better way to get the size on the map (or in device independent units) of the text label and a Graphic described by the Geometry of a Polyline or Polygon?
EDIT: I've discovered that the Geometry object has an extent() method from which I can get the width of the circle but the Geometry of the Graphic being used for the text label results in a width of zero from its extent() method. I expect this is because the Geometry is just a Point which has no width or height. So the question still stands of how to get the bounding rectangle of a TextSymbol?

You are correct, the extent is being returned of the underlying geometry, not the TextSymbol. I don't think you will be able to achieve what you are wanting in the way you are going about it, as there isn't a way to get the bounding box or screen coordinates of the symbol itself. Instead, have you considered using LabelDefinitions and setting the various deconfliction options? This sample shows labels on layers, but can be applied to graphics as well. There are many labeling options you can apply, and this would allow the internal labeling engine to deconflict for you.

Related

High-DPI scaling of QQuickItem-derived class

I use QtQuickControls 2 together with QQuickItem-derived class in my app. After I set AA_EnableHighDpiScaling attribute and all QQuickControls 2 components look correctly on my smartphone but object of my custom class is scaled incorrectly. Here is the app without HighDpi scaling with minimum zoom(the way it is meant to work):
And here is the one with scaling with minimum zoom:
It seems that on the second screen the object is scaled too much and I can see square pixels of all textures that I draw with QPixmap or QImage. However, the images that I load from external memory and nodes like QSGGeometryNode look correct. Can I switch off scaling for just one particular QQuickItem? If no, what should I set to render it correctly?
Also, when I try to set opacity on QQuickItem with a lot of QSGOpacityNodes in scene graph node tree I get segmentation fault. What can cause this?
So I solved this problem by dividing the size of QSGTexture by QQuickWindow::effectiveDevicePixelRatio() and also multiplying the size of the image from which texture is created by this ratio.
If you are drawing the text using on QImage you should also multiply your font's size by this ratio. The same thing should be done with geometrical shapes and QPixmap::scaled().

Qt: Scale polygons but not children

I am new to Qt. I am representing events from my application as polygons in my scene, using a custom class that inherits QGraphicsPolygomItem. The polygon dimensions are (event duration, fixed height), using 1s : 1px. Event duration can be as low as 1E-6, so I simply scale my view so that the smaller polygon is scaled up to MIN_POLY_WIDTH (10px):
view->scale(qreal(MIN_POLY_WIDTH/min_event_duration), qreal(1.0));
So far so good. However, I have a QGraphicsTextItem child for each polygon, which get stretched by the scale operation to a point they get way outside the polygon boundaries:
The text item is created as follows:
void EventPolygon::setId(QString id) {
if (!this->id) {
this->id = new QGraphicsTextItem(id, this);
} else {
this->id->setPlainText(id);
}
this->id->setPos(0, this->polygon().boundingRect().height() / 2 - this->id->boundingRect().height() / 2);
}
That function is usually called by EventPolygon constructor. I though that was the issue, since scale is done after all items are added to the scene, so it would affect the text items. So I tried calling setId after the scale operation, by iterating over all items in the scene. That way I though only the polygons would be stretched. That was not the case, and the text remained stretched.
I also tried using the following instead of scale:
QTransform t = QTransform();
t.scale(qreal(MIN_POLY_WIDTH/min_event_duration), qreal(1.0));
view->setTransform(t, false);
I thought "false" would avoid the transformation being applied to the polygons children, however it seems that is not the case. Is there any way I can scale the polygons to 10px width min and have a readable text inside them?
The QGraphicsScene forms a scenegraph hierarchy based upon the parent-child relationships, transformations are inherited down this hierarchy - there is no way round this (see the Transformations section here).
So to fix your issue, you will need to make the child QGraphicsTextItem invert the scaling transformation of the parent multiplied by the scaling of your view.
In fact I really recommend that you never set view transformations that are not for simulating a camera operation (pan, zoom, etc.) for this reason. I would simply allow for the seconds per pixel ratio to vary and allow the child items to be able to query this from the view - in other words have the progress items take care of their own size on screen.
That was not the case, and the text remained stretched.
Changing the transformation stack will cause a redraw, that's why it doesn't matter when you set the scale.
I thought "false" would avoid the transformation being applied to the
polygons children
No, the combine argument when false just overrides the existing transformation matrix with the one you are providing.

How to set bounds for 3d map in vtk by c++?

I have a lot of lines and planes which are around, for example, (0.5, 0.5, 0.5) point. Also I have area where they have importance, it's a cube. And lines, planes have possibility to intersect this area, and be outside of it. Can I hide part of all elements, and parts of elements, which are not included in my area? Does Vtk have opportunity to do it very simple? Or I need to do it by myself? I want to write, for example SetBounds(bounds), and after that all what isn't included in cube dissapear.
Try using vtkClipDataSet with the clip-function set to vtkBox. Finally, render the output from the vtkClipDataSet filter.
vtkNew<vtkBox> box;
box->SetBounds(.....); // set the bounds of interest.
vtkNew<vtkClipDataSet> clipper;
clipper->SetInputConnection(....); // set to your data producer
clipper->SetClipFunction(box.GetPointer());
// since clipper will produce an unstructured grid, apply the following to
// extract a polydata from it.
vtkNew<vtkGeometryFilter> geomFilter;
geomFilter->SetInputConnection(clipper->GetOutputPort());
// now, this can be connected to the mapper.
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(geomFilter->GetOutputPort());

QT Graph plotting, how to change coordinate system/geometry of QGraphicsView

I am using QT and try to plot a graph with QGraphicsView and QGraphicsScene..i dont want any additional dependencies, thats why i dont use QWT. When i plot my data, at the moment i use
scene->drawLine(x1,y1,x2,y2,pen);
then this draws a line between the 2 points in the QGraphicScene. But this uses a top left x=0 y=0 system... i would like to use my own system like in the picture below. Another problem is that i have double values from -3 to +3..has anyone some experience with QGraphicScene and QGraphicsView and can tell me how i can accomplish this?
Try looking into QGraphicsView::setTransform. This matrix defines how "scene coordinates" are translated to "view coordinates", it's a common concept in graphics programming.
There are also convenience functions scale(), rotate(), translate() and shear() which modify the view's current transformation matrix.
So you could do something like this:
scale(1.0, -1.0); // invert Y axis
// translate to account for fact that Y coordinates start at -3
translate(0.0, 3.0);
// scale Y coordinates to height of widget
scale(1.0, (qreal)viewport()->size().height()/6.0);
And since this is dependent on the size of the widget, you'd also want to catch any resize events and reset the transformation matrix again there. Assuming you want "3" to represent the top of the viewport and "-3" the bottom.

Positioning Circle Shapes within a Body in Box2D Web

I've had to completely revamp this question as I don't think I was explicit enough about my problem.
I'm attempting to learn the ropes of Box2D Web. I started having problems when I wanted to learn how to put multiple shapes in one rigid body (to form responsive concave bodies). One of the assumptions I made was that this kind of feature would only really be useful if I could change the positions of the shapes (so that I can be in control of what the overall rigid body looked like). An example would be creating an 'L' body with two rectangle shapes, one of which was positioned below and to-the-right of the first shape.
I've gotten that far in so-far-as I've found the SetAsOrientedBox method where you can pass the box its position in the 3rd argument (center).
All well and good. But when I tried to create two circle shapes in one rigid body, I found undesirable behaviour. My instinct was to use the SetLocalPosition method (found in the b2CircleShape class). This seems to work to an extent. In the debug draw, the body responds physically as it should do, but visually (within the debug) it doesn't seem to be drawing the shapes in their position. It simply draws the circle shapes at the centre position. I'm aware that this is probably a problem with Box2D's debug draw logic - but it seems strange to me that there is no online-patter regarding this issue. One would think that creating two circle shapes at different positions in the body's coordinate space would be a popular and well-documented phenomina. Clearly not.
Below is the code I'm using to create the bodies. Assume that the world has been passed to this scope effectively:
// first circle shape and def
var fix_def1 = new b2FixtureDef;
fix_def1.density = 1.0;
fix_def1.friction = 0.5;
fix_def1.restitution = .65;
fix_def1.bullet = false;
var shape1 = new b2CircleShape();
fix_def1.shape = shape1;
fix_def1.shape.SetLocalPosition(new b2Vec2(-.5, -.5));
fix_def1.shape.SetRadius(.3);
// second circle def and shape
var fix_def2 = new b2FixtureDef;
fix_def2.density = 1.0;
fix_def2.friction = 0.5;
fix_def2.restitution = .65;
fix_def2.bullet = false;
var shape2 = new b2CircleShape();
fix_def2.shape = shape2;
fix_def2.shape.SetLocalPosition(new b2Vec2(.5, .5));
fix_def2.shape.SetRadius(.3);
// creating the body
var body_def = new b2BodyDef();
body_def.type = b2Body.b2_dynamicBody;
body_def.position.Set(5, 1);
var b = world.CreateBody( body_def );
b.CreateFixture(fix_def1);
b.CreateFixture(fix_def2);
Please note that I'm using Box2D Web ( http://code.google.com/p/box2dweb/ ) with the HTML5 canvas.
It looks like you are not actually using the standard debug draw at all, but a function that you have written yourself - which explains the lack of online-patter about it (pastebin for posterity).
Take a look in the box2dweb source and look at these functions for a working reference:
b2World.prototype.DrawDebugData
b2World.prototype.DrawShape
b2DebugDraw.prototype.DrawSolidCircle
You can use the canvas context 'arc' function to avoid the need for calculating points with sin/cos and then drawing individual lines to make a circle. It also lets the browser use the most efficient way it knows of to render the curve, eg. hardware support on some browsers.
Since it seems like you want to do custom rendering, another pitfall to watch out for is the different call signatures for DrawCircle and DrawSolidCircle. The second of these takes a parameter for the axis direction, so if you mistakenly use the three parameter version Javascript will silently use the color parameter for the axis, leaving you with an undefined color parameter. Hours of fun!
DrawCircle(center, radius, color)
DrawSolidCircle(center, radius, axis, color)