Gui: determine the bounding box of an SoDatumLabel outside its GLRender() method
This commit is contained in:
@@ -140,7 +140,298 @@ void SoDatumLabel::drawImage()
|
||||
Gui::BitmapFactory().convert(image, this->image);
|
||||
}
|
||||
|
||||
void SoDatumLabel::computeBBox(SoAction * /*action*/, SbBox3f &box, SbVec3f ¢er)
|
||||
namespace {
|
||||
// Helper class to determine the bounding box of a datum label
|
||||
class DatumLabelBox
|
||||
{
|
||||
public:
|
||||
DatumLabelBox(float scale, SoDatumLabel* label)
|
||||
: scale{scale}
|
||||
, label{label}
|
||||
{
|
||||
|
||||
}
|
||||
void computeBBox(SbBox3f& box, SbVec3f& center) const
|
||||
{
|
||||
std::vector<SbVec3f> corners;
|
||||
if (label->datumtype.getValue() == SoDatumLabel::DISTANCE ||
|
||||
label->datumtype.getValue() == SoDatumLabel::DISTANCEX ||
|
||||
label->datumtype.getValue() == SoDatumLabel::DISTANCEY ) {
|
||||
corners = computeDistanceBBox();
|
||||
}
|
||||
else if (label->datumtype.getValue() == SoDatumLabel::RADIUS ||
|
||||
label->datumtype.getValue() == SoDatumLabel::DIAMETER) {
|
||||
corners = computeRadiusDiameterBBox();
|
||||
}
|
||||
else if (label->datumtype.getValue() == SoDatumLabel::ANGLE) {
|
||||
corners = computeAngleBBox();
|
||||
}
|
||||
else if (label->datumtype.getValue() == SoDatumLabel::SYMMETRIC) {
|
||||
corners = computeSymmetricBBox();
|
||||
}
|
||||
|
||||
getBBox(corners, box, center);
|
||||
}
|
||||
|
||||
private:
|
||||
void getBBox(const std::vector<SbVec3f>& corners, SbBox3f& box, SbVec3f& center) const
|
||||
{
|
||||
if (corners.size() > 1) {
|
||||
float minX = FLT_MAX;
|
||||
float minY = FLT_MAX;
|
||||
float maxX = -FLT_MAX;
|
||||
float maxY = -FLT_MAX;
|
||||
for (SbVec3f it : corners) {
|
||||
minX = (it[0] < minX) ? it[0] : minX;
|
||||
minY = (it[1] < minY) ? it[1] : minY;
|
||||
maxX = (it[0] > maxX) ? it[0] : maxX;
|
||||
maxY = (it[1] > maxY) ? it[1] : maxY;
|
||||
}
|
||||
|
||||
// Store the bounding box
|
||||
box.setBounds(SbVec3f(minX, minY, 0.0F), SbVec3f (maxX, maxY, 0.0F));
|
||||
center = box.getCenter();
|
||||
}
|
||||
}
|
||||
std::vector<SbVec3f> computeDistanceBBox() const
|
||||
{
|
||||
SbVec2s imgsize;
|
||||
int nc;
|
||||
int srcw = 1;
|
||||
int srch = 1;
|
||||
|
||||
const unsigned char * dataptr = label->image.getValue(imgsize, nc);
|
||||
if (dataptr) {
|
||||
srcw = imgsize[0];
|
||||
srch = imgsize[1];
|
||||
}
|
||||
|
||||
float aspectRatio = (float) srcw / (float) srch;
|
||||
float imgHeight = scale * (float) (srch);
|
||||
float imgWidth = aspectRatio * imgHeight;
|
||||
|
||||
// Get the points stored in the pnt field
|
||||
const SbVec3f *points = label->pnts.getValues(0);
|
||||
if (label->pnts.getNum() < 2) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SbVec3f textOffset;
|
||||
|
||||
float length = label->param1.getValue();
|
||||
float length2 = label->param2.getValue();
|
||||
|
||||
SbVec3f p1 = points[0];
|
||||
SbVec3f p2 = points[1];
|
||||
|
||||
SbVec3f dir;
|
||||
SbVec3f normal;
|
||||
if (label->datumtype.getValue() == SoDatumLabel::DISTANCE) {
|
||||
dir = (p2-p1);
|
||||
}
|
||||
else if (label->datumtype.getValue() == SoDatumLabel::DISTANCEX) {
|
||||
dir = SbVec3f( (p2[0] - p1[0] >= FLT_EPSILON) ? 1 : -1, 0, 0);
|
||||
}
|
||||
else if (label->datumtype.getValue() == SoDatumLabel::DISTANCEY) {
|
||||
dir = SbVec3f(0, (p2[1] - p1[1] >= FLT_EPSILON) ? 1 : -1, 0);
|
||||
}
|
||||
|
||||
dir.normalize();
|
||||
normal = SbVec3f (-dir[1], dir[0], 0);
|
||||
|
||||
// when the datum line is not parallel to p1-p2 the projection of
|
||||
// p1-p2 on normal is not zero, p2 is considered as reference and p1
|
||||
// is replaced by its projection p1_
|
||||
float normproj12 = (p2 - p1).dot(normal);
|
||||
SbVec3f p1_ = p1 + normproj12 * normal;
|
||||
|
||||
SbVec3f midpos = (p1_ + p2)/2;
|
||||
|
||||
float offset1 = ((length + normproj12 < 0.0F) ? -1.0F : 1.0F) * float(srch);
|
||||
float offset2 = ((length < 0.0F) ? -1.0F : 1.0F) * float(srch);
|
||||
|
||||
textOffset = midpos + normal * length + dir * length2;
|
||||
float margin = imgHeight / 4.0F;
|
||||
|
||||
SbVec3f perp1 = p1_ + normal * (length + offset1 * scale);
|
||||
SbVec3f perp2 = p2 + normal * (length + offset2 * scale);
|
||||
|
||||
// Finds the mins and maxes
|
||||
std::vector<SbVec3f> corners;
|
||||
corners.push_back(p1);
|
||||
corners.push_back(p2);
|
||||
corners.push_back(perp1);
|
||||
corners.push_back(perp2);
|
||||
|
||||
// Make sure that the label is inside the bounding box
|
||||
corners.push_back(textOffset + dir * (imgWidth / 2.0F + margin) + normal * (srch + margin));
|
||||
corners.push_back(textOffset - dir * (imgWidth / 2.0F + margin) + normal * (srch + margin));
|
||||
corners.push_back(textOffset + dir * (imgWidth / 2.0F + margin) - normal * margin);
|
||||
corners.push_back(textOffset - dir * (imgWidth / 2.0F + margin) - normal * margin);
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
std::vector<SbVec3f> computeRadiusDiameterBBox() const
|
||||
{
|
||||
SbVec2s imgsize;
|
||||
int nc;
|
||||
int srcw = 1;
|
||||
int srch = 1;
|
||||
|
||||
const unsigned char * dataptr = label->image.getValue(imgsize, nc);
|
||||
if (dataptr) {
|
||||
srcw = imgsize[0];
|
||||
srch = imgsize[1];
|
||||
}
|
||||
|
||||
float aspectRatio = (float) srcw / (float) srch;
|
||||
float imgHeight = scale * (float) (srch);
|
||||
float imgWidth = aspectRatio * imgHeight;
|
||||
|
||||
// Get the points stored in the pnt field
|
||||
const SbVec3f *points = label->pnts.getValues(0);
|
||||
if (label->pnts.getNum() < 2) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the Points
|
||||
SbVec3f p1 = points[0];
|
||||
SbVec3f p2 = points[1];
|
||||
|
||||
SbVec3f dir = p2 - p1;
|
||||
dir.normalize();
|
||||
SbVec3f normal (-dir[1], dir[0], 0);
|
||||
|
||||
float length = label->param1.getValue();
|
||||
SbVec3f pos = p2 + length*dir;
|
||||
|
||||
float margin = imgHeight / 4.0F;
|
||||
|
||||
SbVec3f p3 = pos + dir * (imgWidth / 2.0F + margin);
|
||||
if ((p3-p1).length() > (p2-p1).length()) {
|
||||
p2 = p3;
|
||||
}
|
||||
|
||||
// Calculate the points
|
||||
SbVec3f pnt1 = pos - dir * (margin + imgWidth / 2.0F);
|
||||
SbVec3f pnt2 = pos + dir * (margin + imgWidth / 2.0F);
|
||||
|
||||
// Finds the mins and maxes
|
||||
std::vector<SbVec3f> corners;
|
||||
corners.push_back(p1);
|
||||
corners.push_back(p2);
|
||||
corners.push_back(pnt1);
|
||||
corners.push_back(pnt2);
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
std::vector<SbVec3f> computeAngleBBox() const
|
||||
{
|
||||
SbVec2s imgsize;
|
||||
int nc;
|
||||
int srcw = 1;
|
||||
int srch = 1;
|
||||
|
||||
const unsigned char * dataptr = label->image.getValue(imgsize, nc);
|
||||
if (dataptr) {
|
||||
srcw = imgsize[0];
|
||||
srch = imgsize[1];
|
||||
}
|
||||
|
||||
float aspectRatio = (float) srcw / (float) srch;
|
||||
float imgHeight = scale * (float) (srch);
|
||||
float imgWidth = aspectRatio * imgHeight;
|
||||
|
||||
// Get the points stored in the pnt field
|
||||
const SbVec3f *points = label->pnts.getValues(0);
|
||||
if (label->pnts.getNum() < 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Only the angle intersection point is needed
|
||||
SbVec3f p0 = points[0];
|
||||
|
||||
// Load the Parameters
|
||||
float length = label->param1.getValue();
|
||||
float startangle = label->param2.getValue();
|
||||
float range = label->param3.getValue();
|
||||
float endangle = startangle + range;
|
||||
|
||||
|
||||
float len2 = 2.0F * length;
|
||||
|
||||
// Useful Information
|
||||
// v0 - vector for text position
|
||||
// p0 - vector for angle intersect
|
||||
SbVec3f v0(cos(startangle+range/2), sin(startangle+range/2), 0);
|
||||
|
||||
SbVec3f textOffset = p0 + v0 * len2;
|
||||
|
||||
float margin = imgHeight / 4.0F;
|
||||
|
||||
// Direction vectors for start and end lines
|
||||
SbVec3f v1(cos(startangle), sin(startangle), 0);
|
||||
SbVec3f v2(cos(endangle), sin(endangle), 0);
|
||||
|
||||
SbVec3f pnt1 = p0+(len2-margin)*v1;
|
||||
SbVec3f pnt2 = p0+(len2+margin)*v1;
|
||||
SbVec3f pnt3 = p0+(len2-margin)*v2;
|
||||
SbVec3f pnt4 = p0+(len2+margin)*v2;
|
||||
|
||||
// Finds the mins and maxes
|
||||
// We may need to include the text position too
|
||||
|
||||
SbVec3f img1 = SbVec3f(-imgWidth / 2.0F, -imgHeight / 2, 0.0F);
|
||||
SbVec3f img2 = SbVec3f(-imgWidth / 2.0F, imgHeight / 2, 0.0F);
|
||||
SbVec3f img3 = SbVec3f( imgWidth / 2.0F, -imgHeight / 2, 0.0F);
|
||||
SbVec3f img4 = SbVec3f( imgWidth / 2.0F, imgHeight / 2, 0.0F);
|
||||
|
||||
img1 += textOffset;
|
||||
img2 += textOffset;
|
||||
img3 += textOffset;
|
||||
img4 += textOffset;
|
||||
|
||||
std::vector<SbVec3f> corners;
|
||||
corners.push_back(pnt1);
|
||||
corners.push_back(pnt2);
|
||||
corners.push_back(pnt3);
|
||||
corners.push_back(pnt4);
|
||||
corners.push_back(img1);
|
||||
corners.push_back(img2);
|
||||
corners.push_back(img3);
|
||||
corners.push_back(img4);
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
std::vector<SbVec3f> computeSymmetricBBox() const
|
||||
{
|
||||
// Get the points stored in the pnt field
|
||||
const SbVec3f *points = label->pnts.getValues(0);
|
||||
if (label->pnts.getNum() < 2) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SbVec3f p1 = points[0];
|
||||
SbVec3f p2 = points[1];
|
||||
|
||||
// Finds the mins and maxes
|
||||
std::vector<SbVec3f> corners;
|
||||
corners.push_back(p1);
|
||||
corners.push_back(p2);
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
private:
|
||||
float scale;
|
||||
SoDatumLabel* label;
|
||||
};
|
||||
}
|
||||
|
||||
void SoDatumLabel::computeBBox(SoAction * action, SbBox3f &box, SbVec3f ¢er)
|
||||
{
|
||||
if (!this->bbox.isEmpty()) {
|
||||
// Set the bounding box using stored parameters
|
||||
@@ -148,6 +439,13 @@ void SoDatumLabel::computeBBox(SoAction * /*action*/, SbBox3f &box, SbVec3f &cen
|
||||
SbVec3f bbcenter = this->bbox.getCenter();
|
||||
center.setValue(bbcenter[0], bbcenter[1], bbcenter[2]);
|
||||
}
|
||||
else {
|
||||
SoState *state = action->getState();
|
||||
float scale = getScaleFactor(state);
|
||||
|
||||
DatumLabelBox datumBox(scale, this);
|
||||
datumBox.computeBBox(box, center);
|
||||
}
|
||||
}
|
||||
|
||||
void SoDatumLabel::generateDistancePrimitives(SoAction * action, const SbVec3f& p1, const SbVec3f& p2)
|
||||
|
||||
Reference in New Issue
Block a user