| 2122 | ImPlot3DRay PixelsToPlotRay(double x, double y) { return PixelsToPlotRay(ImVec2((float)x, (float)y)); } |
| 2123 | |
| 2124 | ImPlot3DPoint PixelsToPlotPlane(const ImVec2& pix, ImPlane3D plane, bool mask) { |
| 2125 | ImPlot3DContext& gp = *GImPlot3D; |
| 2126 | IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PixelsToPlotPlane() needs to be called between BeginPlot() and EndPlot()!"); |
| 2127 | |
| 2128 | ImPlot3DPlot& plot = *gp.CurrentPlot; |
| 2129 | ImPlot3DRay ray = PixelsToNDCRay(pix); |
| 2130 | const ImPlot3DPoint& O = ray.Origin; |
| 2131 | const ImPlot3DPoint& D = ray.Direction; |
| 2132 | |
| 2133 | // Helper lambda to check intersection with a given coordinate and return intersection point if valid. |
| 2134 | auto IntersectPlane = [&](double coord) -> ImPlot3DPoint { |
| 2135 | // Solve for t in O[axis] + D[axis]*t = coord |
| 2136 | double denom = 0.0; |
| 2137 | double numer = 0.0; |
| 2138 | if (plane == ImPlane3D_YZ) { |
| 2139 | denom = D.x; |
| 2140 | numer = coord - O.x; |
| 2141 | } else if (plane == ImPlane3D_XZ) { |
| 2142 | denom = D.y; |
| 2143 | numer = coord - O.y; |
| 2144 | } else if (plane == ImPlane3D_XY) { |
| 2145 | denom = D.z; |
| 2146 | numer = coord - O.z; |
| 2147 | } |
| 2148 | |
| 2149 | if (ImAbs(denom) < 1e-12f) { |
| 2150 | // Ray is parallel or nearly parallel to the plane |
| 2151 | return ImPlot3DPoint(NAN, NAN, NAN); |
| 2152 | } |
| 2153 | |
| 2154 | double t = numer / denom; |
| 2155 | if (t < 0.0f) { |
| 2156 | // Intersection behind the ray origin |
| 2157 | return ImPlot3DPoint(NAN, NAN, NAN); |
| 2158 | } |
| 2159 | |
| 2160 | return O + D * t; |
| 2161 | }; |
| 2162 | |
| 2163 | // Compute which plane to intersect with |
| 2164 | bool active_faces[3]; |
| 2165 | ComputeActiveFaces(active_faces, plot.Rotation, plot.Axes); |
| 2166 | |
| 2167 | // Calculate intersection point with the planes |
| 2168 | ImPlot3DPoint P = IntersectPlane(active_faces[plane] ? 0.5f * plot.Axes[plane].NDCScale : -0.5f * plot.Axes[plane].NDCScale); |
| 2169 | if (P.IsNaN()) |
| 2170 | return P; |
| 2171 | |
| 2172 | // Helper lambda to check if point P is within the plot box |
| 2173 | auto InRange = [&](const ImPlot3DPoint& P) { |
| 2174 | ImPlot3DPoint box_scale = plot.GetBoxScale(); |
| 2175 | return P.x >= -0.5f * box_scale.x && P.x <= 0.5f * box_scale.x && P.y >= -0.5f * box_scale.y && P.y <= 0.5f * box_scale.y && |
| 2176 | P.z >= -0.5f * box_scale.z && P.z <= 0.5f * box_scale.z; |
| 2177 | }; |
| 2178 | |
| 2179 | // Handle mask (if one of the intersections is out of range, set it to NAN) |
| 2180 | if (mask) { |
| 2181 | switch (plane) { |
no test coverage detected