comparison OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp @ 1999:709b90ae0f89

starting text annotations
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 02 Nov 2022 13:44:13 +0100
parents 1fa3f484008e
children 3e9ced39cd1b
comparison
equal deleted inserted replaced
1998:1fa3f484008e 1999:709b90ae0f89
40 static const double ARROW_LENGTH = 1.5 * HANDLE_SIZE; 40 static const double ARROW_LENGTH = 1.5 * HANDLE_SIZE;
41 static const double ARROW_ANGLE = 20.0 * PI / 180.0; 41 static const double ARROW_ANGLE = 20.0 * PI / 180.0;
42 42
43 static const char* const KEY_ANNOTATIONS = "annotations"; 43 static const char* const KEY_ANNOTATIONS = "annotations";
44 static const char* const KEY_TYPE = "type"; 44 static const char* const KEY_TYPE = "type";
45 static const char* const KEY_TEXT = "text";
46 static const char* const KEY_X = "x"; 45 static const char* const KEY_X = "x";
47 static const char* const KEY_Y = "y"; 46 static const char* const KEY_Y = "y";
48 static const char* const KEY_X1 = "x1"; 47 static const char* const KEY_X1 = "x1";
49 static const char* const KEY_Y1 = "y1"; 48 static const char* const KEY_Y1 = "y1";
50 static const char* const KEY_X2 = "x2"; 49 static const char* const KEY_X2 = "x2";
51 static const char* const KEY_Y2 = "y2"; 50 static const char* const KEY_Y2 = "y2";
52 static const char* const KEY_X3 = "x3"; 51 static const char* const KEY_X3 = "x3";
53 static const char* const KEY_Y3 = "y3"; 52 static const char* const KEY_Y3 = "y3";
54 static const char* const KEY_UNITS = "units"; 53 static const char* const KEY_UNITS = "units";
54 static const char* const KEY_LABEL = "label";
55 55
56 static const char* const VALUE_ANGLE = "angle"; 56 static const char* const VALUE_ANGLE = "angle";
57 static const char* const VALUE_CIRCLE = "circle"; 57 static const char* const VALUE_CIRCLE = "circle";
58 static const char* const VALUE_LENGTH = "length"; 58 static const char* const VALUE_LENGTH = "length";
59 static const char* const VALUE_MILLIMETERS = "millimeters"; 59 static const char* const VALUE_MILLIMETERS = "millimeters";
258 public: 258 public:
259 enum Shape { 259 enum Shape {
260 Shape_Square, 260 Shape_Square,
261 Shape_CrossedSquare, 261 Shape_CrossedSquare,
262 Shape_Circle, 262 Shape_Circle,
263 Shape_CrossedCircle 263 Shape_CrossedCircle,
264 Shape_Invisible /* to use in conjunction with arrows */
264 }; 265 };
265 266
266 private: 267 private:
267 Shape shape_; 268 Shape shape_;
268 ScenePoint2D center_; 269 ScenePoint2D center_;
360 case Shape_CrossedCircle: 361 case Shape_CrossedCircle:
361 polyline.AddCircle(x, y, unzoomedHandleSize, GetActiveColor(), NUM_SEGMENTS); 362 polyline.AddCircle(x, y, unzoomedHandleSize, GetActiveColor(), NUM_SEGMENTS);
362 AddCross(polyline, x1, y1, x2, y2); 363 AddCross(polyline, x1, y1, x2, y2);
363 break; 364 break;
364 365
366 case Shape_Invisible:
367 break;
368
365 default: 369 default:
366 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 370 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
367 } 371 }
368 } 372 }
369 373
793 SetModified(true); 797 SetModified(true);
794 content_->SetText(text); 798 content_->SetText(text);
795 } 799 }
796 } 800 }
797 801
802 std::string GetText() const
803 {
804 return content_->GetText();
805 }
806
798 void SetPosition(double x, 807 void SetPosition(double x,
799 double y) 808 double y)
800 { 809 {
801 if (content_.get() == NULL) 810 if (content_.get() == NULL)
802 { 811 {
1056 primitive_.MoveDone(sceneClick_, scene); // TODO Check this 1065 primitive_.MoveDone(sceneClick_, scene); // TODO Check this
1057 } 1066 }
1058 }; 1067 };
1059 1068
1060 1069
1061 class AnnotationsSceneLayer::LengthAnnotation : public Annotation 1070 class AnnotationsSceneLayer::SegmentAnnotation : public Annotation
1062 { 1071 {
1063 private: 1072 private:
1064 bool showLabel_;
1065 Handle& handle1_; 1073 Handle& handle1_;
1066 Handle& handle2_; 1074 Handle& handle2_;
1067 Segment& segment_; 1075 Segment& segment_;
1068 Text& label_; 1076 Text& label_;
1069 1077
1078 protected:
1079 void SetLabelContent(const TextSceneLayer& content)
1080 {
1081 label_.SetContent(content);
1082 }
1083
1084 std::string GetCurrentLabel() const
1085 {
1086 return label_.GetText();
1087 }
1088
1089 const Handle& GetHandle1() const
1090 {
1091 return handle1_;
1092 }
1093
1094 const Handle& GetHandle2() const
1095 {
1096 return handle2_;
1097 }
1098
1099 void SetStartArrow(bool enabled)
1100 {
1101 segment_.SetStartArrow(enabled);
1102 }
1103
1104 void SetEndArrow(bool enabled)
1105 {
1106 segment_.SetEndArrow(enabled);
1107 }
1108
1109 public:
1110 SegmentAnnotation(AnnotationsSceneLayer& that,
1111 Units units,
1112 Handle::Shape shape1,
1113 const ScenePoint2D& p1,
1114 Handle::Shape shape2,
1115 const ScenePoint2D& p2) :
1116 Annotation(that, units),
1117 handle1_(AddTypedPrimitive<Handle>(new Handle(*this, shape1, p1))),
1118 handle2_(AddTypedPrimitive<Handle>(new Handle(*this, shape2, p2))),
1119 segment_(AddTypedPrimitive<Segment>(new Segment(*this, p1, p2))),
1120 label_(AddTypedPrimitive<Text>(new Text(that, *this)))
1121 {
1122 label_.SetColor(COLOR_TEXT);
1123 }
1124
1125 virtual unsigned int GetHandlesCount() const ORTHANC_OVERRIDE
1126 {
1127 return 2;
1128 }
1129
1130 virtual Handle& GetHandle(unsigned int index) const ORTHANC_OVERRIDE
1131 {
1132 switch (index)
1133 {
1134 case 0:
1135 return handle1_;
1136
1137 case 1:
1138 return handle2_;
1139
1140 default:
1141 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
1142 }
1143 }
1144
1145 virtual void SignalMove(GeometricPrimitive& primitive,
1146 const Scene2D& scene) ORTHANC_OVERRIDE
1147 {
1148 if (&primitive == &handle1_ ||
1149 &primitive == &handle2_)
1150 {
1151 segment_.SetPosition(handle1_.GetCenter(), handle2_.GetCenter());
1152 }
1153 else if (&primitive == &segment_)
1154 {
1155 handle1_.SetCenter(segment_.GetPosition1());
1156 handle2_.SetCenter(segment_.GetPosition2());
1157 }
1158 else
1159 {
1160 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1161 }
1162 }
1163
1164 virtual void UpdateProbe(const Scene2D& scene) ORTHANC_OVERRIDE
1165 {
1166 }
1167 };
1168
1169
1170 class AnnotationsSceneLayer::LengthAnnotation : public SegmentAnnotation
1171 {
1172 private:
1173 bool showLabel_;
1174
1070 void UpdateLabel() 1175 void UpdateLabel()
1071 { 1176 {
1072 if (showLabel_) 1177 if (showLabel_)
1073 { 1178 {
1074 TextSceneLayer content; 1179 TextSceneLayer content;
1075 1180
1076 double x1 = handle1_.GetCenter().GetX(); 1181 double x1 = GetHandle1().GetCenter().GetX();
1077 double y1 = handle1_.GetCenter().GetY(); 1182 double y1 = GetHandle1().GetCenter().GetY();
1078 double x2 = handle2_.GetCenter().GetX(); 1183 double x2 = GetHandle2().GetCenter().GetX();
1079 double y2 = handle2_.GetCenter().GetY(); 1184 double y2 = GetHandle2().GetCenter().GetY();
1080 1185
1081 // Put the label to the right of the right-most handle 1186 // Put the label to the right of the right-most handle
1082 if (x1 < x2) 1187 if (x1 < x2)
1083 { 1188 {
1084 content.SetPosition(x2, y2); 1189 content.SetPosition(x2, y2);
1109 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1214 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1110 } 1215 }
1111 1216
1112 content.SetText(buf); 1217 content.SetText(buf);
1113 1218
1114 label_.SetContent(content); 1219 SetLabelContent(content);
1115 } 1220 }
1116 } 1221 }
1117 1222
1118 public: 1223 public:
1119 LengthAnnotation(AnnotationsSceneLayer& that, 1224 LengthAnnotation(AnnotationsSceneLayer& that,
1120 Units units, 1225 Units units,
1121 bool showLabel, 1226 bool showLabel,
1122 const ScenePoint2D& p1, 1227 const ScenePoint2D& p1,
1123 const ScenePoint2D& p2) : 1228 const ScenePoint2D& p2) :
1124 Annotation(that, units), 1229 SegmentAnnotation(that, units, Handle::Shape_Square, p1, Handle::Shape_Square, p2),
1125 showLabel_(showLabel), 1230 showLabel_(showLabel)
1126 handle1_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, p1))), 1231 {
1127 handle2_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, p2))),
1128 segment_(AddTypedPrimitive<Segment>(new Segment(*this, p1, p2))),
1129 label_(AddTypedPrimitive<Text>(new Text(that, *this)))
1130 {
1131 label_.SetColor(COLOR_TEXT);
1132 UpdateLabel(); 1232 UpdateLabel();
1133 }
1134
1135 virtual unsigned int GetHandlesCount() const ORTHANC_OVERRIDE
1136 {
1137 return 2;
1138 }
1139
1140 virtual Handle& GetHandle(unsigned int index) const ORTHANC_OVERRIDE
1141 {
1142 switch (index)
1143 {
1144 case 0:
1145 return handle1_;
1146
1147 case 1:
1148 return handle2_;
1149
1150 default:
1151 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
1152 }
1153 } 1233 }
1154 1234
1155 virtual void SignalMove(GeometricPrimitive& primitive, 1235 virtual void SignalMove(GeometricPrimitive& primitive,
1156 const Scene2D& scene) ORTHANC_OVERRIDE 1236 const Scene2D& scene) ORTHANC_OVERRIDE
1157 { 1237 {
1158 if (&primitive == &handle1_ || 1238 SegmentAnnotation::SignalMove(primitive, scene);
1159 &primitive == &handle2_)
1160 {
1161 segment_.SetPosition(handle1_.GetCenter(), handle2_.GetCenter());
1162 }
1163 else if (&primitive == &segment_)
1164 {
1165 handle1_.SetCenter(segment_.GetPosition1());
1166 handle2_.SetCenter(segment_.GetPosition2());
1167 }
1168 else
1169 {
1170 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1171 }
1172
1173 UpdateLabel(); 1239 UpdateLabel();
1174 }
1175
1176 virtual void UpdateProbe(const Scene2D& scene) ORTHANC_OVERRIDE
1177 {
1178 } 1240 }
1179 1241
1180 virtual void Serialize(Json::Value& target) ORTHANC_OVERRIDE 1242 virtual void Serialize(Json::Value& target) ORTHANC_OVERRIDE
1181 { 1243 {
1182 target = Json::objectValue; 1244 target = Json::objectValue;
1183 target[KEY_TYPE] = VALUE_LENGTH; 1245 target[KEY_TYPE] = VALUE_LENGTH;
1184 target[KEY_X1] = handle1_.GetCenter().GetX(); 1246 target[KEY_X1] = GetHandle1().GetCenter().GetX();
1185 target[KEY_Y1] = handle1_.GetCenter().GetY(); 1247 target[KEY_Y1] = GetHandle1().GetCenter().GetY();
1186 target[KEY_X2] = handle2_.GetCenter().GetX(); 1248 target[KEY_X2] = GetHandle2().GetCenter().GetX();
1187 target[KEY_Y2] = handle2_.GetCenter().GetY(); 1249 target[KEY_Y2] = GetHandle2().GetCenter().GetY();
1188 } 1250 }
1189 1251
1190 static void Unserialize(AnnotationsSceneLayer& target, 1252 static void Unserialize(AnnotationsSceneLayer& target,
1191 Units units, 1253 Units units,
1192 const Json::Value& source) 1254 const Json::Value& source)
1205 ScenePoint2D(source[KEY_X2].asDouble(), source[KEY_Y2].asDouble())); 1267 ScenePoint2D(source[KEY_X2].asDouble(), source[KEY_Y2].asDouble()));
1206 } 1268 }
1207 else 1269 else
1208 { 1270 {
1209 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot unserialize a length annotation"); 1271 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot unserialize a length annotation");
1272 }
1273 }
1274 };
1275
1276
1277 class AnnotationsSceneLayer::TextAnnotation : public SegmentAnnotation
1278 {
1279 public:
1280 TextAnnotation(AnnotationsSceneLayer& that,
1281 Units units,
1282 const std::string& label,
1283 const ScenePoint2D& p1,
1284 const ScenePoint2D& p2) :
1285 SegmentAnnotation(that, units, Handle::Shape_Invisible, p1, Handle::Shape_Square, p2)
1286 {
1287 SetStartArrow(true);
1288 UpdateLabel(label);
1289 }
1290
1291 void UpdateLabel(const std::string& label)
1292 {
1293 TextSceneLayer content;
1294
1295 double x1 = GetHandle1().GetCenter().GetX();
1296 double x2 = GetHandle2().GetCenter().GetX();
1297 double y2 = GetHandle2().GetCenter().GetY();
1298
1299 if (x1 < x2)
1300 {
1301 content.SetAnchor(BitmapAnchor_CenterLeft);
1302 }
1303 else
1304 {
1305 content.SetAnchor(BitmapAnchor_CenterRight);
1306 }
1307
1308 content.SetPosition(x2, y2);
1309 content.SetBorder(10);
1310 content.SetText(label);
1311
1312 SetLabelContent(content);
1313 }
1314
1315 void UpdateLabel()
1316 {
1317 UpdateLabel(GetCurrentLabel());
1318 }
1319
1320 virtual void SignalMove(GeometricPrimitive& primitive,
1321 const Scene2D& scene) ORTHANC_OVERRIDE
1322 {
1323 SegmentAnnotation::SignalMove(primitive, scene);
1324 UpdateLabel();
1325 }
1326
1327 virtual void Serialize(Json::Value& target) ORTHANC_OVERRIDE
1328 {
1329 target = Json::objectValue;
1330 target[KEY_TYPE] = VALUE_TEXT_ANNOTATION;
1331 target[KEY_X1] = GetHandle1().GetCenter().GetX();
1332 target[KEY_Y1] = GetHandle1().GetCenter().GetY();
1333 target[KEY_X2] = GetHandle2().GetCenter().GetX();
1334 target[KEY_Y2] = GetHandle2().GetCenter().GetY();
1335 target[KEY_LABEL] = GetCurrentLabel();
1336 }
1337
1338 static void Unserialize(AnnotationsSceneLayer& target,
1339 Units units,
1340 const Json::Value& source)
1341 {
1342 if (source.isMember(KEY_X1) &&
1343 source.isMember(KEY_Y1) &&
1344 source.isMember(KEY_X2) &&
1345 source.isMember(KEY_Y2) &&
1346 source.isMember(KEY_LABEL) &&
1347 source[KEY_X1].isNumeric() &&
1348 source[KEY_Y1].isNumeric() &&
1349 source[KEY_X2].isNumeric() &&
1350 source[KEY_Y2].isNumeric() &&
1351 source[KEY_LABEL].isString())
1352 {
1353 new TextAnnotation(target, units, source[KEY_LABEL].asString(),
1354 ScenePoint2D(source[KEY_X1].asDouble(), source[KEY_Y1].asDouble()),
1355 ScenePoint2D(source[KEY_X2].asDouble(), source[KEY_Y2].asDouble()));
1356 }
1357 else
1358 {
1359 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot unserialize a text annotation");
1210 } 1360 }
1211 } 1361 }
1212 }; 1362 };
1213 1363
1214 1364
2668 { 2818 {
2669 Annotation* annotation = new EllipseProbeAnnotation(*this, units_, s, s); 2819 Annotation* annotation = new EllipseProbeAnnotation(*this, units_, s, s);
2670 return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform()); 2820 return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform());
2671 } 2821 }
2672 2822
2673 /*case Tool_TextAnnotation: 2823 case Tool_TextAnnotation:
2674 { 2824 {
2675 Annotation* annotation = new TextAnnotation(*this, units_, true show label, s, s); 2825 Annotation* annotation = new TextAnnotation(*this, units_, "" /* empty label */, s, s);
2676 return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform()); 2826 return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform());
2677 }*/ 2827 }
2678 2828
2679 default: 2829 default:
2680 return NULL; 2830 return NULL;
2681 } 2831 }
2682 } 2832 }
2779 } 2929 }
2780 else if (type == VALUE_ELLIPSE_PROBE) 2930 else if (type == VALUE_ELLIPSE_PROBE)
2781 { 2931 {
2782 EllipseProbeAnnotation::Unserialize(*this, units_, annotations[i]); 2932 EllipseProbeAnnotation::Unserialize(*this, units_, annotations[i]);
2783 } 2933 }
2784 /*else if (type == VALUE_TEXT_ANNOTATION) 2934 else if (type == VALUE_TEXT_ANNOTATION)
2785 { 2935 {
2786 TextAnnotation::Unserialize(*this, units_, annotations[i]); 2936 TextAnnotation::Unserialize(*this, units_, annotations[i]);
2787 }*/ 2937 }
2788 else 2938 else
2789 { 2939 {
2790 LOG(ERROR) << "Cannot unserialize unknown type of annotation: " << type; 2940 LOG(ERROR) << "Cannot unserialize unknown type of annotation: " << type;
2791 } 2941 }
2792 } 2942 }