* \brief Parse and validate a camera patch body for a given window kind. * * On success, fills `patch` and returns nullopt. On failure, returns the * HTTP 400 error payload (the caller already knows the status). * * Rules: * - Unknown top-level fields -> 400. * - position/focal_point/view_up: array of 3 numbers if present. * - parallel_scale: number > 0, only for 2D windows
| 727 | * - Empty body (no recognised field) -> 400. |
| 728 | */ |
| 729 | std::optional<std::string> ParseCameraPatch( |
| 730 | const nlohmann::json& body, bool is3d, mitk::CameraPatch& patch) |
| 731 | { |
| 732 | static const std::set<std::string> knownFields = { |
| 733 | "position", "focal_point", "view_up", |
| 734 | "parallel_scale", "perspective_angle", "standard_view" |
| 735 | }; |
| 736 | |
| 737 | if (!body.is_object()) |
| 738 | return "Request body must be a JSON object."; |
| 739 | |
| 740 | for (auto it = body.begin(); it != body.end(); ++it) |
| 741 | { |
| 742 | if (!knownFields.count(it.key())) |
| 743 | return "Unknown field '" + it.key() + "'."; |
| 744 | } |
| 745 | |
| 746 | if (body.contains("position")) |
| 747 | { |
| 748 | mitk::Point3D p; |
| 749 | if (const auto err = ReadPoint3D(body["position"], p)) |
| 750 | return "'position' " + *err + "."; |
| 751 | patch.position = p; |
| 752 | } |
| 753 | if (body.contains("focal_point")) |
| 754 | { |
| 755 | mitk::Point3D p; |
| 756 | if (const auto err = ReadPoint3D(body["focal_point"], p)) |
| 757 | return "'focal_point' " + *err + "."; |
| 758 | patch.focalPoint = p; |
| 759 | } |
| 760 | if (body.contains("view_up")) |
| 761 | { |
| 762 | mitk::Vector3D v; |
| 763 | if (const auto err = ReadVector3D(body["view_up"], v)) |
| 764 | return "'view_up' " + *err + "."; |
| 765 | patch.viewUp = v; |
| 766 | } |
| 767 | if (body.contains("parallel_scale")) |
| 768 | { |
| 769 | if (is3d) |
| 770 | return "'parallel_scale' is not applicable to the 3D window."; |
| 771 | if (!body["parallel_scale"].is_number()) |
| 772 | return "'parallel_scale' must be a positive number."; |
| 773 | const double s = body["parallel_scale"].get<double>(); |
| 774 | if (!(s > 0.0)) |
| 775 | return "'parallel_scale' must be a positive number."; |
| 776 | patch.parallelScale = s; |
| 777 | } |
| 778 | if (body.contains("perspective_angle")) |
| 779 | { |
| 780 | if (!is3d) |
| 781 | return "'perspective_angle' is only applicable to the 3D window."; |
| 782 | if (!body["perspective_angle"].is_number()) |
| 783 | return "'perspective_angle' must be a number in (0, 180)."; |
| 784 | const double a = body["perspective_angle"].get<double>(); |
| 785 | if (!(a > 0.0 && a < 180.0)) |
| 786 | return "'perspective_angle' must be a number in (0, 180)."; |
no test coverage detected