diff --git a/src/Icon/diameter.png b/src/Icon/diameter.png
new file mode 100644
index 0000000..2fc1f35
Binary files /dev/null and b/src/Icon/diameter.png differ
diff --git a/src/QDicomViewer.qrc b/src/QDicomViewer.qrc
index b8a387b..f8bbca3 100644
--- a/src/QDicomViewer.qrc
+++ b/src/QDicomViewer.qrc
@@ -57,6 +57,7 @@
Icon/Reset.png
Icon/Settings.png
Icon/preset.png
+ Icon/diameter.png
Icon/pq/pqBold24.png
diff --git a/src/src/Common/QGlobals.h b/src/src/Common/QGlobals.h
index fffa3b0..80e3efc 100644
--- a/src/src/Common/QGlobals.h
+++ b/src/src/Common/QGlobals.h
@@ -81,6 +81,7 @@ enum AnnotationActorType
OpenPolygonAnn,
ArrowAnn,
EllipseAnn,
+ DiameterAnn,
TextAnn,
};
enum AnnotationDeleteType{
diff --git a/src/src/Rendering/Core/ControlPointActor.cpp b/src/src/Rendering/Core/ControlPointActor.cpp
index d4784f6..b9419b8 100644
--- a/src/src/Rendering/Core/ControlPointActor.cpp
+++ b/src/src/Rendering/Core/ControlPointActor.cpp
@@ -70,6 +70,11 @@ void ControlPointActor::SetWorldPosition(double x, double y, double z) {
BaseDataPoints->Reset();
BaseDataPoints->SetNumberOfPoints(1);
BaseDataPoints->SetPoint(0, x, y, z);
+}
+
+double *ControlPointActor::GetRenderPosition()
+{
+ return renderPoints->GetPoint(0);
};
double *ControlPointActor::GetWorldPosition() {
diff --git a/src/src/Rendering/Core/ControlPointActor.h b/src/src/Rendering/Core/ControlPointActor.h
index 6ab9c2f..a5dd561 100644
--- a/src/src/Rendering/Core/ControlPointActor.h
+++ b/src/src/Rendering/Core/ControlPointActor.h
@@ -24,6 +24,8 @@ public:
void SetWorldPosition(double x, double y, double z);
+ double *GetRenderPosition();
+
void SetWorldPosition(double *pos) {
SetWorldPosition(pos[0], pos[1], pos[2]);
}
diff --git a/src/src/Rendering/Measure/EllipseAnnotationActor.cpp b/src/src/Rendering/Measure/EllipseAnnotationActor.cpp
index 5a8135b..09449c5 100644
--- a/src/src/Rendering/Measure/EllipseAnnotationActor.cpp
+++ b/src/src/Rendering/Measure/EllipseAnnotationActor.cpp
@@ -13,7 +13,21 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#include
+#include
+
+
+#include "omp.h"
+
+#include "Interaction/ActorDraggableInteractorStyle.h"
#include "Rendering/Core/ControlPointActor.h"
#include "Common/QGlobals.h"
@@ -26,30 +40,30 @@ namespace {
void EllipseAnnotationActor::BuildShape() {
if (!BaseDataPoints->GetNumberOfPoints()) return;
+ QString stamp = QString("%1-%2").arg(BaseDataPoints->GetMTime())
+ .arg(Renderer->GetActiveCamera()->GetMTime());
+ if (mRenderTime == stamp) return;
+ QStringList stamps = stamp.split("-");
+ QStringList renderTimes = mRenderTime.split("-");
+ mRenderTime = stamp;
RebuildRenderPoint();
-
- double *p_lt = controlP_lt->GetWorldPosition();
- double *p_rb = controlP_rb->GetWorldPosition();
- if (!transforming)
- {
- double area = abs((p_lt[0] - p_rb[0]) * (p_lt[1] - p_rb[1])) * vtkMath::Pi() * 0.25;
- bool unitFlag2 = area>1000;
- QString num = QString::number(area, 'f', 2);
- QString textValue = QString("%1: %2 %3")
- .arg(mAreaName)
- .arg(unitFlag2?area/100:area,0,'f',2).arg(unitFlag2?mUnitcm2:mUnitmm2);
- vtkTextMapper::SafeDownCast(text->GetMapper())->SetInput(textValue.toUtf8().constData());
-
+ //base data change change message
+ if (stamps[0] != renderTimes[0])
+ { double p_lt[3] = {0, 0, 0};
+ double* disp_lt = controlP_lt->GetRenderPosition();
+ MapScreenPointToWorld(disp_lt[0], disp_lt[1], this->Renderer, p_lt);
+ double p_rb[3] = {0, 0, 0};
+ double* disp_rb = controlP_rb->GetRenderPosition();
+ MapScreenPointToWorld(disp_rb[0], disp_rb[1], this->Renderer, p_rb);
+ analyzePixel(p_lt,p_rb);
}
double *rp = renderPoints->GetPoint(0);
text->SetDisplayPosition(rp[0] + 10, rp[1] - 20);
-
vtkNew source;
source->SetPoints(renderPoints);
source->Update();
-
renderData->DeepCopy(source->GetOutput());
if (Measure::Hidden) {
@@ -83,8 +97,8 @@ EllipseAnnotationActor::EllipseAnnotationActor() {
//BaseDataPoints->SetPoint(0, 0, 0, 0);
//BaseDataPoints->SetPoint(1, 512, 512, 0);
-
renderPoints->SetNumberOfPoints(GRANULARITY + 1);
+ BaseDataPoints->Modified();
controlP_lt->AddObserver(DraggableActorEvents::DragEvent, this, &EllipseAnnotationActor::controlPointCb);
controlP_rt->AddObserver(DraggableActorEvents::DragEvent, this, &EllipseAnnotationActor::controlPointCb);
controlP_lb->AddObserver(DraggableActorEvents::DragEvent, this, &EllipseAnnotationActor::controlPointCb);
@@ -95,10 +109,8 @@ EllipseAnnotationActor::EllipseAnnotationActor() {
controlP_lb->SetcontrolledActor(this);
controlP_rb->SetcontrolledActor(this);
-
//this->AddObserver(DraggableActorEvents::DragEvent, this, &EllipseAnnotationActor::selfDragCb);
-
text = vtkActor2D::New();
vtkNew textMapper;
textMapper->SetInput("0");
@@ -147,72 +159,378 @@ void EllipseAnnotationActor::SetRenderer(vtkRenderer *ren) {
}
void EllipseAnnotationActor::controlPointCb(vtkObject *sender, unsigned long event, void *data) {
-
-
+ if (transforming) return;
vtkPoints *pts = static_cast(data);
double *pos = pts->GetPoint(0);
-
+ double displayP[3] = {pos[0], pos[1], 0};
double result[3] = {0, 0, 0};
- MapScreenPointToWorld(pos[0], pos[1], this->Renderer, result);
-
- //BaseDataPoints->SetPoint(index, result);
-
+ MapScreenPointToWorld(pos[0]+0.5, pos[1]+0.5, this->Renderer, result);
+ double * dp = Renderer->GetActiveCamera()->GetDirectionOfProjection();
+ int nIndex[2] = {0,1};
+ if (abs(dp[1])>0.0){
+ nIndex[1] = 2;
+ }
+ if (abs(dp[0])>0.0){
+ nIndex[0] = 1;
+ nIndex[1] = 2;
+ }
double *p1;
double *p2;
+ double displaypos[3]={0};
- if (sender == controlP_lt) {
+ if (sender == controlP_lt ) {
p1 = result;
p2 = controlP_rb->GetWorldPosition();
-
- double p_rt[3] = {p2[0], p1[1], 0};
- double p_lb[3] = {p1[0], p2[1], 0};
+ Renderer->SetWorldPoint(p2);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayp_rb = displaypos;
+ double p_rt[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayp_rb[0], displayP[1], Renderer,p_rt);
+ double p_lb[3] = {0, 0, 0};
+ MapScreenPointToWorld( displayP[0], displayp_rb[1], Renderer,p_lb);
controlP_rt->SetWorldPosition(p_rt);
controlP_lb->SetWorldPosition(p_lb);
- } else if (sender == controlP_rt) {
+ drawCircle(p1, p2);
+ } else if (sender == controlP_rt ) {
p1 = result;
p2 = controlP_lb->GetWorldPosition();
-
- double p_lt[3] = {p2[0], p1[1], 0};
- double p_rb[3] = {p1[0], p2[1], 0};
+ Renderer->SetWorldPoint(p2);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayp_lb = displaypos;
+ double p_lt[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayp_lb[0], displayP[1], Renderer,p_lt);
+ double p_rb[3] = {0, 0, 0};
+ MapScreenPointToWorld( displayP[0], displayp_lb[1], Renderer,p_rb);
controlP_lt->SetWorldPosition(p_lt);
controlP_rb->SetWorldPosition(p_rb);
+ drawCircle(p_lt, p_rb);
- } else if (sender == controlP_lb) {
- p1 = result;
- p2 = controlP_rt->GetWorldPosition();
-
- double p_lt[3] = {p1[0], p2[1], 0};
- double p_rb[3] = {p2[0], p1[1], 0};
+ } else if (sender == controlP_lb ) {
+ p2 = result;
+ p1 = controlP_rt->GetWorldPosition();
+ Renderer->SetWorldPoint(p1);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayp_rt = displaypos;
+ double p_lt[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayP[0],displayp_rt[1], Renderer,p_lt);
+ double p_rb[3] = {0, 0, 0};
+ MapScreenPointToWorld( displayp_rt[0], displayP[1], Renderer,p_rb);
controlP_lt->SetWorldPosition(p_lt);
controlP_rb->SetWorldPosition(p_rb);
- } else if (sender == controlP_rb) {
- p1 = result;
- p2 = controlP_lt->GetWorldPosition();
-
- double p_rt[3] = {p1[0], p2[1], 0};
- double p_lb[3] = {p2[0], p1[1], 0};
+ drawCircle(p_lt, p_rb);
+ } else if (sender == controlP_rb ) {
+ p2 = result;
+ p1 = controlP_lt->GetWorldPosition();
+ Renderer->SetWorldPoint(p1);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayp_lt = displaypos;
+ double p_rt[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayP[0], displayp_lt[1], Renderer,p_rt);
+ double p_lb[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayp_lt[0], displayP[1], Renderer,p_lb);
controlP_rt->SetWorldPosition(p_rt);
controlP_lb->SetWorldPosition(p_lb);
+ drawCircle(p1, p2);
} else {
+
}
- drawCircle(p1, p2);
+
}
void EllipseAnnotationActor::drawCircle(double *p1, double *p2) {
- int CenterX = (p1[0] + p2[0]) / 2.0;
- int CenterY = (p1[1] + p2[1]) / 2.0;
- double r1 = abs(p1[0] - p2[0]) / 2.0;
- double r2 = abs(p1[1] - p2[1]) / 2.0;
+ double * dp = Renderer->GetActiveCamera()->GetDirectionOfProjection();
+
+ int nIndex[2] = {0,1};
+ if (abs(dp[1])>0.0){
+ nIndex[1] = 2;
+ }
+ if (abs(dp[0])>0.0){
+ nIndex[0] = 1;
+ nIndex[1] = 2;
+ }
+ int CenterX = (p1[nIndex[0]] + p2[nIndex[0]] ) / 2.0;
+ int CenterY = (p1[nIndex[1]] + p2[nIndex[1]] ) / 2.0;
+ double r1 = round(abs(p1[nIndex[0]] - p2[nIndex[0]]) / 2.0*100.0)/100;
+ double r2 = round(abs(p1[nIndex[1]]- p2[nIndex[1]]) / 2.0*100.0)/100;
double angle = 0;
int id = 0;
while (angle <= 2.0 * vtkMath::Pi() + (2.0 * vtkMath::Pi() / (GRANULARITY * 1.0))) {
- BaseDataPoints->SetPoint(id, r1 * cos(angle) + CenterX, r2 * sin(angle) + CenterY, 0);
+ double p[3]={0};
+ p[0] = p1[0];
+ p[1] = p1[1];
+ p[2] = p1[2];
+ p[nIndex[0]] = r1 * cos(angle) + CenterX;
+ p[nIndex[1]] = r2 * sin(angle) + CenterY;
+
+ BaseDataPoints->SetPoint(id, p);
angle = angle + (2.0 * vtkMath::Pi() / (GRANULARITY * 1.0));
id++;
}
+ BaseDataPoints->Modified();
+}
+
+template
+void makeMessage(int count[4], double avg[4], double sq2[4], T max[4], T min[4], QString &message, double area, const QString& aAreaUnitName)
+{
+ long totalCount = count[0];
+ double avgV = avg[0];
+ double sq2V = sq2[0];
+ bool hasValue = false;
+ for (size_t i = 1; i < 4; i++)
+ {
+ long lastCount = totalCount;
+ if (totalCount == 0)
+ {
+ totalCount = count[i];
+ avgV = avg[i];
+ sq2V = sq2[i];
+ continue;
+ }
+ hasValue = true;
+ totalCount += count[i];
+ double delta = avg[i] - avgV;
+ avgV = (lastCount * avgV + count[i] * avg[i]) / totalCount;
+ sq2V += sq2[i] + delta * delta * lastCount * count[i] / totalCount;
+ }
+ if (!hasValue)
+ {
+ double maxV = std::max({max[0], max[1], max[2], max[3]});
+ double minV = std::min({min[0], min[1], min[2], min[3]});
+ double sd = std::sqrt(sq2V / totalCount);
+ message = message
+ .arg(area)
+ .arg(0)
+ .arg(0)
+ .arg(0)
+ .arg(0)
+ .arg(0)
+ .arg(aAreaUnitName);
+ }
+ else{
+ double maxV = std::max({max[0], max[1], max[2], max[3]});
+ double minV = std::min({min[0], min[1], min[2], min[3]});
+ double sd = std::sqrt(sq2V / totalCount);
+ message = message
+ .arg(area, 0, 'f', 0)
+ .arg(totalCount)
+ .arg(maxV, 0, 'f', 0)
+ .arg(minV, 0, 'f', 0)
+ .arg(avgV, 0, 'f', 0)
+ .arg(sd, 0, 'f', 0)
+ .arg(aAreaUnitName);
+ }
+}
+
+template
+void calcLoopContent(int count[4], T *row_pointer, size_t j, int pixelStride, T max[4], T min[4], double avg[4], double sq2[4])
+{
+ count[omp_get_thread_num()]++;
+ T value = row_pointer[j * pixelStride];
+ max[omp_get_thread_num()] = std::max(value, max[omp_get_thread_num()]);
+ min[omp_get_thread_num()] = std::min(value, min[omp_get_thread_num()]);
+ double lastavg = avg[omp_get_thread_num()];
+ avg[omp_get_thread_num()] = (count[omp_get_thread_num()] - 1) * avg[omp_get_thread_num()] / ((double)count[omp_get_thread_num()]) + ((double)value) / ((double)count[omp_get_thread_num()]);
+ sq2[omp_get_thread_num()] = sq2[omp_get_thread_num()] + ((double)value - avg[omp_get_thread_num()]) * ((double)value - lastavg);
+}
+
+template
+void EllipseAnnotationActor::vtkValueCalcTemplate(vtkImageData *image, int sliceNumber, double *pt1, double *pt2, double *normals, QString &message)
+{
+ double spacings[3] ={0};
+ int dims[3] = {0};
+ image->GetSpacing(spacings);
+ image->GetDimensions(dims);
+ T *pointer = (T *)image->GetScalarPointer();
+ if (!pointer) {
+ return;
+ }
+ int count[4] = {0, 0, 0, 0};
+ T max[4] = {std::numeric_limits::min(),std::numeric_limits::min(),std::numeric_limits::min(),std::numeric_limits::min()};
+ T min[4] = {std::numeric_limits::max(),std::numeric_limits::max(),std::numeric_limits::max(),std::numeric_limits::max()};
+ double avg[4] = {0, 0, 0, 0};
+ double sq2[4] = {0, 0, 0, 0};
+
+ if (abs(normals[2])>0.5)
+ {
+ int CenterX = (pt1[0] + pt2[0]) / 2.0;
+ int CenterY = (pt1[1] + pt2[1]) / 2.0;
+
+ double r1= abs((pt1[0] - pt2[0]) / 2.0);
+ double r2= abs((pt1[1] - pt2[1]) / 2.0);
+
+ double r2_1 = pow(r1, 2.0);
+ double r2_2 = pow(r2, 2.0);
+ long long sliceStride = dims[0] * dims[1];
+ int pixelStride = 1;
+ int rowStride = dims[0];
+
+ pointer += sliceStride * (sliceNumber);
+
+ double maxX = std::max({pt1[0], pt2[0]});
+ double minX = std::min({pt1[0], pt2[0]});
+ double maxY = std::max({pt1[1], pt2[1]});
+ double minY = std::min({pt1[1], pt2[1]});
+ double maxZ = 0.5;
+ double minZ = 0.5;
+
+ #pragma omp parallel for num_threads(4)
+ for (int i = 0; i < dims[1]; i++)
+ {
+ T *row_pointer = pointer + i * rowStride;
+ double posY = i * spacings[1];
+ if (posY < minY)
+ continue;
+ if (posY > maxY)
+ break;
+ for (size_t j = 0; j < dims[0]; j++)
+ {
+ double posX = j * spacings[0];
+ if (posX < minX)
+ continue;
+ if (posX > maxX)
+ break;
+ if (pow((posX - CenterX), 2.0) / r2_1 + pow((posY - CenterY), 2.0) / r2_2 <= 1)
+ {
+ calcLoopContent(count, row_pointer, j, pixelStride, max, min, avg, sq2);
+ }
+ }
+ }
+ double area = vtkMath::Pi()*r1*r2;
+
+ makeMessage(count, avg, sq2, max, min, message, area>1000?area/100:area,area>100?mUnitcm2:mUnitmm2);
+ }
+ else if (abs(normals[1])>0.5)
+ {
+ int CenterX = (pt1[0] + pt2[0]) / 2.0;
+ int CenterZ = (pt1[2] + pt2[2]) / 2.0;
+
+ double r1= abs((pt1[0] - pt2[0]) / 2.0);
+ double r2= abs((pt1[2] - pt2[2]) / 2.0);
+
+ double r2_1 = pow(r1, 2.0);
+ double r2_2 = pow(r2, 2.0);
+
+ long long sliceStride = dims[0];
+ int pixelStride = 1;
+ int rowStride = dims[0] * dims[1];
+ pointer += sliceStride * (sliceNumber);
+
+ double maxX = std::max({pt1[0], pt2[0]});
+ double minX = std::min({pt1[0], pt2[0]});
+ double maxY = 0.5;
+ double minY = 0.5;
+ double maxZ = std::max({pt1[2], pt2[2]});
+ double minZ = std::min({pt1[2], pt2[2]});
+
+ #pragma omp parallel for num_threads(4)
+ for (int i = 0; i < dims[2]; i++)
+ {
+ T* row_pointer = pointer + i * rowStride;
+ double posZ = i * spacings[2];
+ if (posZ < minZ)
+ continue;
+ if (posZ > maxZ)
+ break;
+ for (size_t j = 0; j < dims[0]; j++)
+ {
+ double posX = j * spacings[0];
+ if (posX < minX)
+ continue;
+ if (posX > maxX)
+ break;
+ if (pow((posX - CenterX), 2.0) / r2_1 + pow((posZ - CenterZ), 2.0) / r2_2 <= 1)
+ {
+ calcLoopContent(count, row_pointer, j, pixelStride, max, min, avg, sq2);
+ }
+ }
+ }
+ double area = vtkMath::Pi()*r1*r2;
+ makeMessage(count, avg, sq2, max, min, message, area>1000?area/100:area,area>100?mUnitcm2:mUnitmm2);
+ }
+ else{
+ int CenterY = (pt1[1] + pt2[1]) / 2.0;
+ int CenterZ = (pt1[2] + pt2[2]) / 2.0;
+
+ double r1= abs((pt1[1] - pt2[1]) / 2.0);
+ double r2= abs((pt1[2] - pt2[2]) / 2.0);
+
+ double r2_1 = pow((pt1[1] - pt2[1]) / 2.0,2.0);
+ double r2_2 = pow((pt1[2] - pt2[2]) / 2.0, 2.0);
+ long long sliceStride = 1;
+ int pixelStride = dims[0];
+ int rowStride = dims[0]*dims[1];
+
+ pointer += sliceStride*(sliceNumber);
+
+ double maxY = std::max({pt1[1], pt2[1]});
+ double minY = std::min({pt1[1], pt2[1]});
+ double maxZ = std::max({pt1[2], pt2[2]});
+ double minZ = std::min({pt1[2], pt2[2]});
+
+ #pragma omp parallel for num_threads(4)
+ for (int i = 0; i < dims[2]; i++)
+ {
+ T *row_pointer = pointer + i * rowStride;
+ double posZ = i * spacings[2];
+ if (posZ < minZ)
+ continue;
+ if (posZ > maxZ)
+ break;
+ for (size_t j = 0; j < dims[1]; j++)
+ {
+ double posY = j * spacings[1];
+ if (posY < minY)
+ continue;
+ if (posY > maxY)
+ break;
+ if (pow((posY - CenterY), 2.0) / r2_1 + pow((posZ - CenterZ), 2.0) / r2_2 <= 1)
+ {
+ calcLoopContent(count, row_pointer, j, pixelStride, max, min, avg, sq2);
+ }
+ }
+ }
+ double area = vtkMath::Pi()*r1*r2;
+ makeMessage(count, avg, sq2, max, min, message, area>1000?area/100:area,area>100?mUnitcm2:mUnitmm2);
+ }
+}
+
+
+void EllipseAnnotationActor::analyzePixel(double *p1, double *p2)
+{
+ if (!Renderer) return;
+ auto renderWin = Renderer->GetRenderWindow();
+ if (!renderWin)return;
+ auto interactor = renderWin->GetInteractor();
+ if (!interactor)return;
+ auto style = interactor->GetInteractorStyle();
+ if (!style) return;
+ auto castedStyle = ActorDraggableInteractorStyle::SafeDownCast(style);
+ if (!castedStyle) return;
+
+ auto imageSlice = castedStyle->GetCurrentImageSlice();
+ if (!imageSlice) return;
+ auto sliceMapper = vtkImageSliceMapper::SafeDownCast(imageSlice->GetMapper());
+ if (!sliceMapper) return;
+ int sliceNumber = sliceMapper->GetSliceNumber();
+ vtkImageData* data = imageSlice->GetMapper()->GetInput();
+ if (!data) return;
+ double normals[3]={0};
+ Renderer->GetActiveCamera()->GetDirectionOfProjection(normals);
+ QString message = QCoreApplication::translate("EllipseAnnotationActor","Area:%1 %7, Pixel:%2,\nMax:%3, Min:%4,\nAvg:%5, SD:%6");
+ switch (data->GetScalarType())
+ {
+ vtkTemplateMacro(vtkValueCalcTemplate(data, sliceNumber, p1, p2, normals, message));
+ default:
+ break;
+ }
+ vtkTextMapper::SafeDownCast(text->GetMapper())->SetInput(message.toUtf8().constData());
}
void EllipseAnnotationActor::selfDragCb(vtkObject *, unsigned long, void *data) {
@@ -220,12 +538,12 @@ void EllipseAnnotationActor::selfDragCb(vtkObject *, unsigned long, void *data)
}
void EllipseAnnotationActor::controlPointsTransform(float x, float y) {
-
//no need to trigger renderpoint repaint
DraggableActor::SafeDownCast(controlP_lt)->Transform(x, y);
DraggableActor::SafeDownCast(controlP_rt)->Transform(x, y);
DraggableActor::SafeDownCast(controlP_lb)->Transform(x, y);
DraggableActor::SafeDownCast(controlP_rb)->Transform(x, y);
+ BaseDataPoints->Modified();
}
void EllipseAnnotationActor::controlPointsApplyTransform() {
@@ -242,34 +560,37 @@ void EllipseAnnotationActor::onMeasureMouseMove(vtkRenderWindowInteractor *iren)
int y = iren->GetEventPosition()[1];
vtkRenderer *renderer = iren->FindPokedRenderer(x, y);
if (!renderer) return;
- renderer->SetDisplayPoint(x, y, 0.0);
- renderer->DisplayToWorld();
-
- double *p_lt = controlP_lt->GetWorldPosition();
- double *p_rb = renderer->GetWorldPoint();
-
+ double p_rb[3] = {0, 0, 0};
+ double displayp_rb[3] = {x+0.5, y+0.5, 0};
+ double* p_lt = controlP_lt->GetWorldPosition();
+ MapScreenPointToWorld(x+0.5, y+0.5, renderer, p_rb);
+ renderer->SetWorldPoint(p_lt);
+ renderer->WorldToDisplay();
+ double displayp_lt[3] ={0};
+ renderer->GetDisplayPoint(displayp_lt);
//if ctrl key is pressed ,draw a standard circle
if (iren->GetControlKey()) {
- double xlen = p_rb[0] - p_lt[0];
- double ylen = p_rb[1] - p_lt[1];
+ double xlen = x - displayp_lt[0];
+ double ylen = y - displayp_lt[1];
if (abs(ylen) < abs(xlen)) {
- if (xlen > 0) { p_rb[0] = p_lt[0] + abs(ylen); }
- if (xlen < 0) { p_rb[0] = p_lt[0] - abs(ylen); }
+ if (xlen > 0) { displayp_rb[0] = displayp_lt[0] + abs(ylen); }
+ if (xlen < 0) { displayp_rb[0] = displayp_lt[0] - abs(ylen); }
} else {
- if (ylen > 0) { p_rb[1] = p_lt[1] + abs(xlen); }
- if (ylen < 0) { p_rb[1] = p_lt[1] - abs(xlen); }
+ if (ylen > 0) { displayp_rb[1] = displayp_lt[1] + abs(xlen); }
+ if (ylen < 0) { displayp_rb[1] = displayp_lt[1] - abs(xlen); }
}
-
+ MapScreenPointToWorld(displayp_rb[0], displayp_rb[1], renderer, p_rb);
}
- double p_rt[3] = {p_rb[0], p_lt[1], 0};
- double p_lb[3] = {p_lt[0], p_rb[1], 0};
+ double p_rt[3] = {0};
+ MapScreenPointToWorld(displayp_rb[0], displayp_lt[1], renderer, p_rt);
+ double p_lb[3] = {0};
+ MapScreenPointToWorld(displayp_lt[0], displayp_rb[1], renderer, p_lb);
controlP_rt->SetWorldPosition(p_rt);
controlP_lb->SetWorldPosition(p_lb);
controlP_rb->SetWorldPosition(p_rb);
-
drawCircle(p_lt, p_rb);
//this->SetWorldPosition2(p);
iren->Render();
@@ -278,20 +599,21 @@ void EllipseAnnotationActor::onMeasureMouseMove(vtkRenderWindowInteractor *iren)
bool EllipseAnnotationActor::onMeasureLeftButtonDown(vtkRenderWindowInteractor *iren) {
int x = iren->GetEventPosition()[0];
int y = iren->GetEventPosition()[1];
+
vtkRenderer *renderer = iren->FindPokedRenderer(x, y);
if (!renderer) return false;
- renderer->SetDisplayPoint(x, y, 0.0);
- renderer->DisplayToWorld();
- double *p = renderer->GetWorldPoint();
- controlP_lt->SetWorldPosition(p);
+ double result[3] = {0, 0, 0};
+ MapScreenPointToWorld(x+0.5, y+0.5, renderer, result);
+ printf("lt:%d,%d,world lt:%f.2,%f.2,%f.2\r\n", x,y, result[0], result[1], result[2]);
+ controlP_lt->SetWorldPosition(result);
controlP_lt->Highlight(0);
- controlP_rt->SetWorldPosition(p);
- controlP_lb->SetWorldPosition(p);
- controlP_rb->SetWorldPosition(p);
+ controlP_rt->SetWorldPosition(result);
+ controlP_lb->SetWorldPosition(result);
+ controlP_rb->SetWorldPosition(result);
for (int id = 0; id <= GRANULARITY; id++) {
- BaseDataPoints->SetPoint(id, p[0], p[1], p[2]);
+ BaseDataPoints->SetPoint(id, result[0], result[1], result[2]);
}
this->SetRenderer(renderer);
iren->Render();
@@ -312,19 +634,3 @@ void EllipseAnnotationActor::ApplyTransform() {
this->controlPointsApplyTransform();
}
-//void EllipseAnnotationActor::TransformOnly(float x, float y) {
-// if (!tempStorePoints) {
-// tempStorePoints = vtkPoints::New();
-// tempStorePoints->DeepCopy(renderPoints);
-// transforming = true;
-// }
-// vtkNew trans;
-// trans->Translate(x, y, 0);
-// vtkNew filter;
-// filter->SetTransform(trans);
-// vtkNew poly;
-// poly->SetPoints(tempStorePoints);
-// filter->SetInputData(poly);
-// filter->Update();
-// renderPoints->DeepCopy(filter->GetPolyDataOutput()->GetPoints());
-//}
diff --git a/src/src/Rendering/Measure/EllipseAnnotationActor.h b/src/src/Rendering/Measure/EllipseAnnotationActor.h
index 7e41f9f..f6d6da8 100644
--- a/src/src/Rendering/Measure/EllipseAnnotationActor.h
+++ b/src/src/Rendering/Measure/EllipseAnnotationActor.h
@@ -9,6 +9,8 @@ class vtkTextProperty;
class ControlPointActor;
+class vtkImageData;
+
class EllipseAnnotationActor : public DraggableActor, public Measure {
public:
//@{
@@ -56,11 +58,17 @@ private:
void drawCircle(double *p1, double *p2);
+ void analyzePixel(double *p1, double *p2);
+
vtkTextProperty *textProperty;
QString mUnitmm2 ;
QString mUnitcm2 ;
QString mAreaName;
+
+ QString mRenderTime;
+
+ template
+ void vtkValueCalcTemplate(vtkImageData *image, int sliceNumber, double *pt1, double *pt2, double *normals, QString &message);
};
-
#endif //OMEGAV_EllipseANNOTATIONACTOR_H
diff --git a/src/src/Rendering/Measure/MeasureFactory.cpp b/src/src/Rendering/Measure/MeasureFactory.cpp
index 6375e1f..4a6ec7f 100644
--- a/src/src/Rendering/Measure/MeasureFactory.cpp
+++ b/src/src/Rendering/Measure/MeasureFactory.cpp
@@ -7,6 +7,8 @@
#include "TextAnnotationActor.h"
#include "ArrowAnnotationActor.h"
#include "EllipseAnnotationActor.h"
+#include "RoundAnnotationActor.h"
+
Measure *MeasureFactory::getMeasure(AnnotationActorType type) {
switch (type) {
@@ -25,6 +27,8 @@ Measure *MeasureFactory::getMeasure(AnnotationActorType type) {
return ArrowAnnotationActor::New();
case AnnotationActorType::EllipseAnn:
return EllipseAnnotationActor::New();
+ case AnnotationActorType::DiameterAnn:
+ return RoundAnnotationActor::New();
case AnnotationActorType::TextAnn:
return TextAnnotationActor::New();
default:
diff --git a/src/src/Rendering/Measure/OpenPolyAnnotationActor.cpp b/src/src/Rendering/Measure/OpenPolyAnnotationActor.cpp
index b6dccf5..11ff37b 100644
--- a/src/src/Rendering/Measure/OpenPolyAnnotationActor.cpp
+++ b/src/src/Rendering/Measure/OpenPolyAnnotationActor.cpp
@@ -192,7 +192,7 @@ void OpenPolyAnnotationActor::UpdatePerimeterAndAreaText()
if(!Closed)
{
bool unitFlag = distance>100;
- QString textValue = QString("%1: %2 %3").arg(mDistanceName)
+ QString textValue = QString("%1: %2%3").arg(mDistanceName)
.arg(unitFlag?distance/10:distance,0,'f',2).arg(unitFlag?mUnitcm:mUnitmm);
vtkTextMapper::SafeDownCast(text->GetMapper())->SetInput(textValue.toUtf8().constData());
text->SetVisibility(1);
@@ -206,7 +206,7 @@ void OpenPolyAnnotationActor::UpdatePerimeterAndAreaText()
bool unitFlag1 = distance>100;
bool unitFlag2 = area>1000;
- QString textValue = QString("%1: %2 %3, %4: %5 %6").arg(mDistanceName)
+ QString textValue = QString("%1: %2%3, %4: %5%6").arg(mDistanceName)
.arg(unitFlag1?distance/10:distance,0,'f',2).arg(unitFlag1?mUnitcm:mUnitmm)
.arg(mAreaName)
.arg(unitFlag2?area/100:area,0,'f',2).arg(unitFlag2?mUnitcm2:mUnitmm2);
@@ -220,3 +220,7 @@ void OpenPolyAnnotationActor::UpdatePerimeterAndAreaText()
bool OpenPolyAnnotationActor::Valid() {
return Closed == 0 ? BaseDataPoints->GetNumberOfPoints() > 1 : BaseDataPoints->GetNumberOfPoints() > 2;
}
+
+void OpenPolyAnnotationActor::onTerminate(vtkRenderWindowInteractor *){
+
+}
diff --git a/src/src/Rendering/Measure/OpenPolyAnnotationActor.h b/src/src/Rendering/Measure/OpenPolyAnnotationActor.h
index a960cab..fdaa261 100644
--- a/src/src/Rendering/Measure/OpenPolyAnnotationActor.h
+++ b/src/src/Rendering/Measure/OpenPolyAnnotationActor.h
@@ -38,6 +38,8 @@ public:
bool onMeasureLeftButtonUp(vtkRenderWindowInteractor *) override;
+ void onTerminate(vtkRenderWindowInteractor *) override;
+
Measure *GetNextMeasure()
override {
auto m = OpenPolyAnnotationActor::New();
diff --git a/src/src/Rendering/Measure/RoundAnnotationActor.cpp b/src/src/Rendering/Measure/RoundAnnotationActor.cpp
new file mode 100644
index 0000000..e404611
--- /dev/null
+++ b/src/src/Rendering/Measure/RoundAnnotationActor.cpp
@@ -0,0 +1,411 @@
+
+#include "RoundAnnotationActor.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+
+#include "omp.h"
+
+#include "Interaction/ActorDraggableInteractorStyle.h"
+#include "Rendering/Core/ControlPointActor.h"
+#include "Common/QGlobals.h"
+
+
+vtkStandardNewMacro(RoundAnnotationActor)
+
+namespace {
+ const int GRANULARITY = 60;
+}
+
+void RoundAnnotationActor::BuildShape() {
+ if (!BaseDataPoints->GetNumberOfPoints()) return;
+ QString stamp = QString("%1-%2").arg(BaseDataPoints->GetMTime())
+ .arg(Renderer->GetActiveCamera()->GetMTime());
+ if (mRenderTime == stamp) return;
+ QStringList stamps = stamp.split("-");
+ QStringList renderTimes = mRenderTime.split("-");
+ mRenderTime = stamp;
+ RebuildRenderPoint();
+ //base data change change message
+ if (stamps[0] != renderTimes[0])
+ { double p_lt[3] = {0, 0, 0};
+ double* disp_lt = controlP_lt->GetRenderPosition();
+ MapScreenPointToWorld(disp_lt[0], disp_lt[1], this->Renderer, p_lt);
+ double p_rb[3] = {0, 0, 0};
+ double* disp_rb = controlP_rb->GetRenderPosition();
+ MapScreenPointToWorld(disp_rb[0], disp_rb[1], this->Renderer, p_rb);
+ // analyzePixel(p_lt,p_rb);
+ }
+ double *rp = renderPoints->GetPoint(0);
+
+ text->SetDisplayPosition(rp[0] + 10, rp[1] - 20);
+
+ vtkNew source;
+ source->SetPoints(renderPoints);
+ source->Update();
+ renderData->DeepCopy(source->GetOutput());
+
+ if (Measure::Hidden) {
+ this->Hide();
+ controlP_rt->Hide();
+ controlP_lb->Hide();
+ controlP_rb->Hide();
+ controlP_lt->Hide();
+
+ } else {
+ this->Show();
+ controlP_rt->Show();
+ controlP_lb->Show();
+ controlP_rb->Show();
+ controlP_lt->Show();
+ }
+}
+
+RoundAnnotationActor::RoundAnnotationActor() {
+ controlP_rt = ControlPointActor::New();
+ controlP_lb = ControlPointActor::New();
+ controlP_rb = ControlPointActor::New();
+ controlP_lt = ControlPointActor::New();
+
+ controlP_lt->SetWorldPosition(0, 0, 0);
+ controlP_rt->SetWorldPosition(512, 0, 0);
+ controlP_lb->SetWorldPosition(0, 512, 0);
+ controlP_rb->SetWorldPosition(512, 512, 0);
+
+ BaseDataPoints->SetNumberOfPoints(GRANULARITY + 1);
+ //BaseDataPoints->SetPoint(0, 0, 0, 0);
+ //BaseDataPoints->SetPoint(1, 512, 512, 0);
+
+ renderPoints->SetNumberOfPoints(GRANULARITY + 1);
+ BaseDataPoints->Modified();
+ controlP_lt->AddObserver(DraggableActorEvents::DragEvent, this, &RoundAnnotationActor::controlPointCb);
+ controlP_rt->AddObserver(DraggableActorEvents::DragEvent, this, &RoundAnnotationActor::controlPointCb);
+ controlP_lb->AddObserver(DraggableActorEvents::DragEvent, this, &RoundAnnotationActor::controlPointCb);
+ controlP_rb->AddObserver(DraggableActorEvents::DragEvent, this, &RoundAnnotationActor::controlPointCb);
+
+ controlP_lt->SetcontrolledActor(this);
+ controlP_rt->SetcontrolledActor(this);
+ controlP_lb->SetcontrolledActor(this);
+ controlP_rb->SetcontrolledActor(this);
+
+ //this->AddObserver(DraggableActorEvents::DragEvent, this, &RoundAnnotationActor::selfDragCb);
+
+ text = vtkActor2D::New();
+ vtkNew textMapper;
+ textMapper->SetInput("0");
+ text->SetMapper(textMapper);
+ textProperty = textMapper->GetTextProperty();
+ if (LanguageHelper::getLanguage() == ChineseSimple && QFile::exists(FONT_FILE_PATH))
+ {
+ textProperty->SetFontFamily(VTK_FONT_FILE);
+ textProperty->SetFontFile(FONT_FILE_PATH);
+ }
+ else{
+ textProperty->SetFontFamilyToArial();
+ textProperty->SetBold(1);
+ }
+ textProperty->SetFontSize(16);
+ textProperty->SetColor(0.8, 0.8, 0.0);
+ textProperty->SetOpacity(0.75);
+ textProperty->SetFrame(false);
+ //textProperty->SetFrameColor(1.0,0.0,0.0);
+ textProperty->SetBackgroundColor(1.0, 0.0, 0.0);
+ textProperty->SetBackgroundOpacity(0.3);
+
+ mUnitmm2 = QCoreApplication::translate("RoundAnnotationActor","mm²");
+ mUnitcm2 = QCoreApplication::translate("RoundAnnotationActor","cm²");
+ mAreaName = QCoreApplication::translate("RoundAnnotationActor", "Area");
+ mUnitcm3 = QCoreApplication::translate("RoundAnnotationActor","cm³");
+ mUnitmm3 = QCoreApplication::translate("RoundAnnotationActor","mm³");
+ mVolumeName = QCoreApplication::translate("RoundAnnotationActor", "Volume");
+}
+
+RoundAnnotationActor::~RoundAnnotationActor() {
+ controlP_lt->Delete();
+ controlP_rt->Delete();
+ controlP_lb->Delete();
+ controlP_rb->Delete();
+
+ controlP_lt = nullptr;
+ controlP_rt = nullptr;
+ controlP_lb = nullptr;
+ controlP_rb = nullptr;
+}
+
+void RoundAnnotationActor::SetRenderer(vtkRenderer *ren) {
+ DraggableActor::SetRenderer(ren);
+ controlP_lt->SetRenderer(ren);
+ controlP_rt->SetRenderer(ren);
+ controlP_lb->SetRenderer(ren);
+ controlP_rb->SetRenderer(ren);
+}
+
+void RoundAnnotationActor::controlPointCb(vtkObject *sender, unsigned long event, void *data) {
+ if (transforming) return;
+ vtkPoints *pts = static_cast(data);
+ double *pos = pts->GetPoint(0);
+ double displayP[3] = {pos[0], pos[1], 0};
+ double result[3] = {0, 0, 0};
+ MapScreenPointToWorld(pos[0]+0.5, pos[1]+0.5, this->Renderer, result);
+ double * dp = Renderer->GetActiveCamera()->GetDirectionOfProjection();
+
+ int nIndex[2] = {0,1};
+ if (abs(dp[1])>0.0){
+ nIndex[1] = 2;
+ }
+ if (abs(dp[0])>0.0){
+ nIndex[0] = 1;
+ nIndex[1] = 2;
+ }
+ double *p1;
+ double *p2;
+ double displaypos[3]={0};
+
+ if (sender == controlP_lt ) {
+ p1 = result;
+ p2 = controlP_rb->GetWorldPosition();
+ Renderer->SetWorldPoint(p2);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayP2 = displaypos;
+ drawCircle(p1, p2);
+ double d = std::min({abs(displayP[0] - displayP2[0]), abs(displayP[1] - displayP2[1])});
+ pos[0] = displayP[0]>displayP2[0]?displayP2[0]+d:displayP2[0]-d;
+ pos[1] = displayP[1]>displayP2[1]?displayP2[1]+d:displayP2[1]-d;
+ pts->SetPoint(0, pos);
+ double p_rt[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayP2[0], pos[1], Renderer,p_rt);
+ double p_lb[3] = {0, 0, 0};
+ MapScreenPointToWorld(pos[0], displayP2[1], Renderer,p_lb);
+ controlP_rt->SetWorldPosition(p_rt);
+ controlP_lb->SetWorldPosition(p_lb);
+ } else if (sender == controlP_rt ) {
+ p1 = result;
+ p2 = controlP_lb->GetWorldPosition();
+ Renderer->SetWorldPoint(p2);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayP2 = displaypos;
+ drawCircle(p1, p2);
+ double d = std::min({abs(displayP[0] - displayP2[0]), abs(displayP[1] - displayP2[1])});
+ pos[0] = displayP[0]>displayP2[0]?displayP2[0]+d:displayP2[0]-d;
+ pos[1] = displayP[1]>displayP2[1]?displayP2[1]+d:displayP2[1]-d;
+ pts->SetPoint(0, pos);
+ double p_lt[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayP2[0], pos[1], Renderer,p_lt);
+ double p_rb[3] = {0, 0, 0};
+ MapScreenPointToWorld( pos[0], displayP2[1], Renderer,p_rb);
+ controlP_lt->SetWorldPosition(p_lt);
+ controlP_rb->SetWorldPosition(p_rb);
+ } else if (sender == controlP_lb ) {
+ p1 = result;
+ p2 = controlP_rt->GetWorldPosition();
+ Renderer->SetWorldPoint(p2);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayP2 = displaypos;
+ drawCircle(p1, p2);
+ double d = std::min({abs(displayP[0] - displayP2[0]), abs(displayP[1] - displayP2[1])});
+ pos[0] = displayP[0]>displayP2[0]?displayP2[0]+d:displayP2[0]-d;
+ pos[1] = displayP[1]>displayP2[1]?displayP2[1]+d:displayP2[1]-d;
+ pts->SetPoint(0, pos);
+
+ double p_lt[3] = {0, 0, 0};
+ MapScreenPointToWorld(pos[0],displayP2[1], Renderer,p_lt);
+ double p_rb[3] = {0, 0, 0};
+ MapScreenPointToWorld( displayP2[0], pos[1], Renderer,p_rb);
+ controlP_lt->SetWorldPosition(p_lt);
+ controlP_rb->SetWorldPosition(p_rb);
+ } else if (sender == controlP_rb ) {
+ p1 = result;
+ p2 = controlP_lt->GetWorldPosition();
+ Renderer->SetWorldPoint(p2);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displaypos);
+ double *displayP2 = displaypos;
+ drawCircle(p1, p2);
+ double d = std::min({abs(displayP[0] - displayP2[0]), abs(displayP[1] - displayP2[1])});
+ pos[0] = displayP[0]>displayP2[0]?displayP2[0]+d:displayP2[0]-d;
+ pos[1] = displayP[1]>displayP2[1]?displayP2[1]+d:displayP2[1]-d;
+ pts->SetPoint(0, pos);
+ double p_rt[3] = {0, 0, 0};
+ MapScreenPointToWorld(pos[0], displayP2[1], Renderer,p_rt);
+ double p_lb[3] = {0, 0, 0};
+ MapScreenPointToWorld(displayP2[0], pos[1], Renderer,p_lb);
+ controlP_rt->SetWorldPosition(p_rt);
+ controlP_lb->SetWorldPosition(p_lb);
+ } else {
+
+ }
+
+}
+
+
+void RoundAnnotationActor::drawCircle(double *p1, double *p2) {
+ double * dp = Renderer->GetActiveCamera()->GetDirectionOfProjection();
+
+ int nIndex[2] = {0,1};
+ if (abs(dp[1])>0.0){
+ nIndex[1] = 2;
+ }
+ if (abs(dp[0])>0.0){
+ nIndex[0] = 1;
+ nIndex[1] = 2;
+ }
+ double r1 = round(abs(p1[nIndex[0]] - p2[nIndex[0]]) / 2.0*100.0)/100;
+ double r2 = round(abs(p1[nIndex[1]]- p2[nIndex[1]]) / 2.0*100.0)/100;
+ double r = r1r){
+ CenterX = CenterX > p2[nIndex[0]]?(r+p2[nIndex[0]]):(p2[nIndex[0]]-r);
+ }
+ int CenterY = (p1[nIndex[1]] + p2[nIndex[1]] ) / 2.0;
+ if (abs(CenterY-p2[nIndex[1]])>r){
+ CenterY = CenterY > p2[nIndex[1]]?(r+p2[nIndex[1]]):(p2[nIndex[1]]-r);
+ }
+
+ double angle = 0;
+ int id = 0;
+ while (angle <= 2.0 * vtkMath::Pi() + (2.0 * vtkMath::Pi() / (GRANULARITY * 1.0))) {
+ double p[3]={0};
+ p[0] = p1[0];
+ p[1] = p1[1];
+ p[2] = p1[2];
+ p[nIndex[0]] = r * cos(angle) + CenterX;
+ p[nIndex[1]] = r * sin(angle) + CenterY;
+
+ BaseDataPoints->SetPoint(id, p);
+ angle = angle + (2.0 * vtkMath::Pi() / (GRANULARITY * 1.0));
+ id++;
+ }
+ BaseDataPoints->Modified();
+ double area = vtkMath::Pi()*r*r;
+ double volume = area*3*r/4;
+ QString textValue = QString("%1: %2%3\r\n%4: %5%6").arg(mAreaName)
+ .arg(area>1000?area/100:area,0,'f',2).arg(area>1000?mUnitcm2:mUnitmm2)
+ .arg(mVolumeName)
+ .arg(volume>10000?volume/1000:volume,0,'f',2).arg(volume>10000?mUnitcm3:mUnitmm3);
+ vtkTextMapper::SafeDownCast(text->GetMapper())->SetInput(textValue.toUtf8().constData());
+}
+
+void RoundAnnotationActor::selfDragCb(vtkObject *, unsigned long, void *data) {
+//control point drag realized by father
+}
+
+void RoundAnnotationActor::controlPointsTransform(float x, float y) {
+ //no need to trigger renderpoint repaint
+ DraggableActor::SafeDownCast(controlP_lt)->Transform(x, y);
+ DraggableActor::SafeDownCast(controlP_rt)->Transform(x, y);
+ DraggableActor::SafeDownCast(controlP_lb)->Transform(x, y);
+ DraggableActor::SafeDownCast(controlP_rb)->Transform(x, y);
+ BaseDataPoints->Modified();
+}
+
+void RoundAnnotationActor::controlPointsApplyTransform() {
+ //restore base point
+ DraggableActor::SafeDownCast(controlP_lt)->ApplyTransform();
+ DraggableActor::SafeDownCast(controlP_rt)->ApplyTransform();
+ DraggableActor::SafeDownCast(controlP_lb)->ApplyTransform();
+ DraggableActor::SafeDownCast(controlP_rb)->ApplyTransform();
+}
+
+
+void RoundAnnotationActor::onMeasureMouseMove(vtkRenderWindowInteractor *iren) {
+ int x = iren->GetEventPosition()[0];
+ int y = iren->GetEventPosition()[1];
+ vtkRenderer *renderer = iren->FindPokedRenderer(x, y);
+ if (!renderer) return;
+ double p_rb[3] = {0, 0, 0};
+ double displayp_rb[3] = {x+0.5, y+0.5, 0};
+ double* p_lt = controlP_lt->GetWorldPosition();
+ MapScreenPointToWorld(x+0.5, y+0.5, renderer, p_rb);
+ renderer->SetWorldPoint(p_lt);
+ renderer->WorldToDisplay();
+ double displayp_lt[3] ={0};
+ renderer->GetDisplayPoint(displayp_lt);
+
+ double xlen = x - displayp_lt[0];
+ double ylen = y - displayp_lt[1];
+ if (abs(ylen) < abs(xlen)) {
+ if (xlen > 0) { displayp_rb[0] = displayp_lt[0] + abs(ylen); }
+ if (xlen < 0) { displayp_rb[0] = displayp_lt[0] - abs(ylen); }
+ } else {
+ if (ylen > 0) { displayp_rb[1] = displayp_lt[1] + abs(xlen); }
+ if (ylen < 0) { displayp_rb[1] = displayp_lt[1] - abs(xlen); }
+ }
+ MapScreenPointToWorld(displayp_rb[0], displayp_rb[1], renderer, p_rb);
+
+ double p_rt[3] = {0};
+ MapScreenPointToWorld(displayp_rb[0], displayp_lt[1], renderer, p_rt);
+ double p_lb[3] = {0};
+ MapScreenPointToWorld(displayp_lt[0], displayp_rb[1], renderer, p_lb);
+
+ controlP_rt->SetWorldPosition(p_rt);
+ controlP_lb->SetWorldPosition(p_lb);
+ controlP_rb->SetWorldPosition(p_rb);
+
+ drawCircle(p_lt, p_rb);
+ //this->SetWorldPosition2(p);
+ iren->Render();
+}
+
+bool RoundAnnotationActor::onMeasureLeftButtonDown(vtkRenderWindowInteractor *iren) {
+ int x = iren->GetEventPosition()[0];
+ int y = iren->GetEventPosition()[1];
+
+ vtkRenderer *renderer = iren->FindPokedRenderer(x, y);
+ if (!renderer) return false;
+ double result[3] = {0, 0, 0};
+ MapScreenPointToWorld(x+0.5, y+0.5, renderer, result);
+ printf("lt:%d,%d,world lt:%f.2,%f.2,%f.2\r\n", x,y, result[0], result[1], result[2]);
+ controlP_lt->SetWorldPosition(result);
+ controlP_lt->Highlight(0);
+
+ controlP_rt->SetWorldPosition(result);
+ controlP_lb->SetWorldPosition(result);
+ controlP_rb->SetWorldPosition(result);
+
+ for (int id = 0; id <= GRANULARITY; id++) {
+ BaseDataPoints->SetPoint(id, result[0], result[1], result[2]);
+ }
+ this->SetRenderer(renderer);
+ iren->Render();
+ return true;
+}
+
+bool RoundAnnotationActor::onMeasureLeftButtonUp(vtkRenderWindowInteractor *iren) {
+ return false;
+}
+
+void RoundAnnotationActor::Transform(float x, float y) {
+ DraggableActor::Transform(x, y);
+ this->controlPointsTransform(x, y);
+}
+
+void RoundAnnotationActor::ApplyTransform() {
+ DraggableActor::ApplyTransform();
+ this->controlPointsApplyTransform();
+}
+
diff --git a/src/src/Rendering/Measure/RoundAnnotationActor.h b/src/src/Rendering/Measure/RoundAnnotationActor.h
new file mode 100644
index 0000000..e95e3e3
--- /dev/null
+++ b/src/src/Rendering/Measure/RoundAnnotationActor.h
@@ -0,0 +1,70 @@
+#ifndef OMEGAV_ROUNDANNOTATIONACTOR_H
+#define OMEGAV_ROUNDANNOTATIONACTOR_H
+
+#include "Rendering/Core/DraggableActor.h"
+#include "Rendering/Measure/Measure.h"
+
+class vtkTextProperty;
+
+class ControlPointActor;
+
+class RoundAnnotationActor : public DraggableActor, public Measure {
+public:
+ //@{
+ /**
+ * Standard methods for instances of this class.
+ */
+ static RoundAnnotationActor *New();
+
+ vtkTypeMacro(RoundAnnotationActor, DraggableActor);
+
+ //@}
+ void controlPointsTransform(float x, float y);
+
+ void controlPointsApplyTransform();
+
+ void SetRenderer(vtkRenderer *ren) override;
+
+ void BuildShape() override;
+
+ void Transform(float x, float y) override;
+
+ void ApplyTransform() override;
+
+ bool onMeasureLeftButtonDown(vtkRenderWindowInteractor *) override;
+
+ void onMeasureMouseMove(vtkRenderWindowInteractor *) override;
+
+ bool onMeasureLeftButtonUp(vtkRenderWindowInteractor *) override;
+
+ NextMeasureMacro(RoundAnnotationActor);
+protected:
+ RoundAnnotationActor();
+
+ ~RoundAnnotationActor() override;
+
+private:
+ ControlPointActor *controlP_rt = nullptr;
+ ControlPointActor *controlP_lb = nullptr;
+ ControlPointActor *controlP_rb = nullptr;
+ ControlPointActor *controlP_lt = nullptr;
+
+ void selfDragCb(vtkObject *, unsigned long event, void *data);
+
+ void controlPointCb(vtkObject *sender, unsigned long event, void *data);
+
+ void drawCircle(double *p1, double *p2);
+
+ // void analyzePixel(double *p1, double *p2);
+
+ vtkTextProperty *textProperty;
+ QString mUnitmm2 ;
+ QString mUnitcm2 ;
+ QString mUnitmm3 ;
+ QString mUnitcm3 ;
+ QString mAreaName;
+ QString mVolumeName;
+ QString mRenderTime;
+};
+
+#endif /* OMEGAV_ROUNDANNOTATIONACTOR_H */
diff --git a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp
index 7fd9fff..38b065e 100644
--- a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp
+++ b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp
@@ -17,7 +17,7 @@ namespace {
const char *SYNC_MANUAL_URL = ":/InfiniteViewer/Icon/sync/sync_manual.png";
const char *SYNC_AUTO_URL = ":/InfiniteViewer/Icon/sync/sync_auto.png";
const char *SYNC_DIS_URL = ":/InfiniteViewer/Icon/sync/sync_dis.png";
- const int ACTION_COUNT = 7;
+ const int ACTION_COUNT = 8;
const ActionProperty MEASURE_ACTIIONS[ACTION_COUNT] = {
{ ":/InfiniteViewer/Icon/distance.png", AnnotationActorType::RulerAnn},
{ ":/InfiniteViewer/Icon/angle.png", AnnotationActorType::AngleAnn},
@@ -25,6 +25,7 @@ namespace {
{ ":/InfiniteViewer/Icon/polyline.png", AnnotationActorType::OpenPolygonAnn},
{ ":/InfiniteViewer/Icon/arrow.png", AnnotationActorType::ArrowAnn},
{ ":/InfiniteViewer/Icon/ellipse.png", AnnotationActorType::EllipseAnn},
+ { ":/InfiniteViewer/Icon/diameter.png", AnnotationActorType::DiameterAnn},
{ ":/InfiniteViewer/Icon/text.png", AnnotationActorType::TextAnn}
};
}
diff --git a/src/translations/zh_CN.ts b/src/translations/zh_CN.ts
index 8af9618..15e0617 100644
--- a/src/translations/zh_CN.ts
+++ b/src/translations/zh_CN.ts
@@ -500,6 +500,15 @@
Area
面积
+
+
+ Area:%1 %7, Pixel:%2,
+Max:%3, Min:%4,
+Avg:%5, SD:%6
+ 面积:%1 %7, 像素:%2,
+最大值:%3, 最小值:%4,
+平均值:%5, 标准差:%6
+
ExportDialog
@@ -1037,6 +1046,21 @@
Area
面积
+
+
+ cm³
+ 立方厘米
+
+
+
+ mm³
+ 立方毫米
+
+
+
+ Volume
+ 体积
+
RulerAnnotationActor