Mercurial > hg > orthanc-stone
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 } |