vec Plane::ClosestPoint(const LineSegment &lineSegment) const { /* ///@todo Output parametric d as well. float d; if (lineSegment.Intersects(*this, &d)) return lineSegment.GetPoint(d); else if (Distance(lineSegment.a) < Distance(lineSegment.b)) return Project(lineSegment.a); else return Project(lineSegment.b); */ assume(lineSegment.IsFinite()); assume(!IsDegenerate()); float aDist = Dot(normal, lineSegment.a); float bDist = Dot(normal, lineSegment.b); float denom = bDist - aDist; if (EqualAbs(denom, 0.f)) return Project(Abs(aDist) < Abs(bDist) ? lineSegment.a : lineSegment.b); // Project()ing the result here is not strictly necessary, // but done for numerical stability, so that Plane::Contains() // will return true for the returned point. else { ///@todo Output parametric t along the ray as well. float t = (d - Dot(normal, lineSegment.a)) / (bDist - aDist); t = Clamp01(t); // Project()ing the result here is necessary only if we clamped, but done for numerical stability, so that Plane::Contains() will // return true for the returned point. return Project(lineSegment.GetPoint(t)); } }
static Float _ModifyHairShadowTransparencyFn(HairVideoPost* vp, Int32 oindex, HairMaterialData* mat, RayObject* ro, HairObject* op, HairGuides* guides, BaseList2D* bl, Float32* thk, VolumeData* vd, Int32 cpu, Int32 lid, Int32 seg, Int32 p, Float lined, const Vector& linep, const Vector& n, const Vector& lp, const Vector& huv, const RayHitID& ply_id, RayLight* light, Float trans) { HairRenderingTag* hrt = (HairRenderingTag*)bl->GetNodeData(); if (light) // shadow call trans = (Float) 1.0 - Clamp01(((Float) 1.0 - Clamp01(trans)) * hrt->m_Shadow); else trans = (Float) 1.0 - Clamp01(((Float) 1.0 - Clamp01(trans)) * hrt->m_Trans); if (hrt->m_Depth > 1) { Float depth = Float(1 + (seg % hrt->m_Depth)) / Float(hrt->m_Depth); trans = 1.0 - ((1.0 - trans) * depth); } return trans; }
void SaveSummary(const std::string &fname, Result &result, Config &config) { const float fnorm = 2.f / sqrtf(result.npoints); const float rnorm = 1.f / sqrtf(2.f / (SQRT3 * result.npoints)); const int csize = 512; // Composition cell size const double dashes[] = { 6.0, 3.0 }; cairo_surface_t *surface = cairo_pdf_surface_create(fname.c_str(), 2*csize, 1.5*csize); cairo_pdf_surface_restrict_to_version(surface, CAIRO_PDF_VERSION_1_4); cairo_t *cr = cairo_create(surface); unsigned char *imgdata = NULL; cairo_surface_t *image = NULL; // Draw points const float radius = 2.0; cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); for (int i = 0; i < result.points.size(); ++i) { float x = result.points[i].x * csize; float y = (1.f - result.points[i].y) * csize; cairo_arc(cr, x, y, radius, 0, TWOPI); cairo_fill(cr); } // Draw radial power reference level cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, dashes, 2, 0); const float rpref = 1.f - (1.f - config.fymin) / (config.fymax - config.fymin); cairo_move_to(cr, csize, csize + rpref*csize/2); cairo_line_to(cr, 2*csize, csize + rpref*csize/2); cairo_stroke(cr); // Draw radial power cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, NULL, 0, 0); for (int i = 0; i < result.rp.size(); ++i) { float x = i / (float) result.rp.size(); float y = 1.f - (result.rp[i] - config.fymin) / (config.fymax - config.fymin); Clamp01(y); if (i == 0) cairo_move_to(cr, csize + x*csize, csize + y*csize/2); else cairo_line_to(cr, csize + x*csize, csize + y*csize/2); } cairo_stroke(cr); // Draw spectrum int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, result.spectrum.width); result.spectrum.GetRGBA(imgdata); image = cairo_image_surface_create_for_data(imgdata, CAIRO_FORMAT_RGB24, result.spectrum.width, result.spectrum.height, stride); cairo_identity_matrix(cr); cairo_translate(cr, csize, 0); cairo_scale(cr, csize / (float) result.spectrum.width, csize / (float) result.spectrum.height); cairo_set_source_surface(cr, image, 0, 0); cairo_paint(cr); // Draw RDF reference level cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, dashes, 2, 0); const float rdfref = 1.f - (1.f - config.rymin) / (config.rymax - config.rymin); cairo_move_to(cr, 0, csize + rdfref*csize/2); cairo_line_to(cr, csize, csize + rdfref*csize/2); cairo_stroke(cr); // Draw RDF cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, NULL, 0, 0); for (int i = 0; i < result.rdf.size(); ++i) { float x = i / (float) result.rdf.size(); float y = 1.f - (result.rdf[i] - config.rymin) / (config.rymax - config.rymin); Clamp01(y); if (i == 0) cairo_move_to(cr, x*csize, csize + y*csize/2); else cairo_line_to(cr, x*csize, csize + y*csize/2); } cairo_stroke(cr); // Draw separators cairo_identity_matrix(cr); cairo_set_line_width(cr, 1.0); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_move_to(cr, 0, csize); cairo_line_to(cr, 2*csize, csize); cairo_stroke(cr); cairo_move_to(cr, csize, 0); cairo_line_to(cr, csize, 1.5*csize); cairo_stroke(cr); // Draw labels cairo_identity_matrix(cr); cairo_set_font_size(cr, 12.0); cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_move_to(cr, 0.0125 * csize, 1.025 * csize); cairo_show_text(cr, "RDF"); cairo_stroke(cr); cairo_move_to(cr, 1.0125 * csize, 1.025 * csize); cairo_show_text(cr, "Power Spectrum"); cairo_stroke(cr); // Draw stats box #ifdef PSA_HAS_CGAL int nlines = 5; #else int nlines = 4; #endif nlines += (result.nsets > 1); double offset = 0.03; double bsize[] = { 0.33 * csize, (nlines * offset + 0.01) * csize }; double banchor = 0.0125 * csize; cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.7); cairo_rectangle(cr, banchor, banchor, bsize[0], bsize[1]); cairo_fill(cr); // Draw stats and corresponding labels cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); cairo_set_font_size(cr, 12.0); cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); const int len = 128; char label[len]; double tanchor[2] = { 1.75 * banchor, 0.9 * banchor }; int i = 1; if (result.nsets > 1) { snprintf(label, len, "Averaged over %d sets", result.nsets); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); cairo_show_text(cr, label); ++i; } snprintf(label, len, "Gbl. Mindist %.5f", result.stats.mindist * rnorm); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); snprintf(label, len, "Avg. Mindist %.5f", result.stats.avgmindist * rnorm); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); #ifdef PSA_HAS_CGAL snprintf(label, len, "Orient. order %.5f", result.stats.orientorder); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); #endif snprintf(label, len, "Eff. Nyquist %.5f", result.stats.effnyquist * fnorm); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); snprintf(label, len, "Oscillations %.5f", result.stats.oscillations); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); cairo_stroke(cr); // Save and clean up cairo_show_page(cr); cairo_surface_destroy(image); if (imgdata) delete[] imgdata; cairo_destroy(cr); cairo_surface_destroy(surface); }
///\todo Enable this codepath. This if rom Geometric Tools for Computer Graphics, /// but the algorithm in the book is broken and does not take into account the /// direction of the gradient to determine the proper region of intersection. /// Instead using a slower code path above. /// [groupSyntax] float3 Triangle::ClosestPoint(const LineSegment &lineSegment, float3 *otherPt) const { float3 e0 = b - a; float3 e1 = c - a; float3 v_p = a - lineSegment.a; float3 d = lineSegment.b - lineSegment.a; // Q(u,v) = a + u*e0 + v*e1 // L(t) = ls.a + t*d // Minimize the distance |Q(u,v) - L(t)|^2 under u >= 0, v >= 0, u+v <= 1, t >= 0, t <= 1. float v_p_dot_e0 = Dot(v_p, e0); float v_p_dot_e1 = Dot(v_p, e1); float v_p_dot_d = Dot(v_p, d); float3x3 m; m[0][0] = Dot(e0, e0); m[0][1] = Dot(e0, e1); m[0][2] = -Dot(e0, d); m[1][0] = m[0][1]; m[1][1] = Dot(e1, e1); m[1][2] = -Dot(e1, d); m[2][0] = m[0][2]; m[2][1] = m[1][2]; m[2][2] = Dot(d, d); float3 B(-v_p_dot_e0, -v_p_dot_e1, v_p_dot_d); float3 uvt; bool success = m.SolveAxb(B, uvt); if (!success) { float t1, t2, t3; float s1, s2, s3; LineSegment e1 = Edge(0); LineSegment e2 = Edge(1); LineSegment e3 = Edge(2); float d1 = e1.Distance(lineSegment, &t1, &s1); float d2 = e2.Distance(lineSegment, &t2, &s2); float d3 = e3.Distance(lineSegment, &t3, &s3); if (d1 < d2 && d1 < d3) { if (otherPt) *otherPt = lineSegment.GetPoint(s1); return e1.GetPoint(t1); } else if (d2 < d3) { if (otherPt) *otherPt = lineSegment.GetPoint(s2); return e2.GetPoint(t2); } else { if (otherPt) *otherPt = lineSegment.GetPoint(s3); return e3.GetPoint(t3); } } if (uvt.x < 0.f) { // Clamp to u == 0 and solve again. float m_00 = m[2][2]; float m_01 = -m[1][2]; float m_10 = -m[2][1]; float m_11 = m[1][1]; float det = m_00 * m_11 - m_01 * m_10; float v = m_00 * B[1] + m_01 * B[2]; float t = m_10 * B[1] + m_11 * B[2]; v /= det; t /= det; if (v < 0.f) { // Clamp to v == 0 and solve for t. t = B[2] / m[2][2]; t = Clamp01(t); // The solution for t must also be in the range [0,1]. // The solution is (u,v,t)=(0,0,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a; } else if (v > 1.f) { // Clamp to v == 1 and solve for t. t = (B[2] - m[2][1]) / m[2][2]; t = Clamp01(t); // The solution is (u,v,t)=(0,1,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return c; // == a + v*e1 } else if (t < 0.f) { // Clamp to t == 0 and solve for v. v = B[1] / m[1][1]; // mathassert(EqualAbs(v, Clamp01(v))); v = Clamp01(v); // The solution for v must also be in the range [0,1]. TODO: Is this guaranteed by the above? // The solution is (u,v,t)=(0,v,0). if (otherPt) *otherPt = lineSegment.a; return a + v * e1; } else if (t > 1.f) { // Clamp to t == 1 and solve for v. v = (B[1] - m[1][2]) / m[1][1]; // mathassert(EqualAbs(v, Clamp01(v))); v = Clamp01(v); // The solution for v must also be in the range [0,1]. TODO: Is this guaranteed by the above? // The solution is (u,v,t)=(0,v,1). if (otherPt) *otherPt = lineSegment.b; return a + v * e1; } else { // The solution is (u,v,t)=(0,v,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a + v * e1; } } else if (uvt.y < 0.f) { // Clamp to v == 0 and solve again. float m_00 = m[2][2]; float m_01 = -m[0][2]; float m_10 = -m[2][0]; float m_11 = m[0][0]; float det = m_00 * m_11 - m_01 * m_10; float u = m_00 * B[0] + m_01 * B[2]; float t = m_10 * B[0] + m_11 * B[2]; u /= det; t /= det; if (u < 0.f) { // Clamp to u == 0 and solve for t. t = B[2] / m[2][2]; t = Clamp01(t); // The solution for t must also be in the range [0,1]. // The solution is (u,v,t)=(0,0,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a; } else if (u > 1.f) { // Clamp to u == 1 and solve for t. t = (B[2] - m[2][0]) / m[2][2]; t = Clamp01(t); // The solution for t must also be in the range [0,1]. // The solution is (u,v,t)=(1,0,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return b; } else if (t < 0.f) { // Clamp to t == 0 and solve for u. u = B[0] / m[0][0]; // mathassert(EqualAbs(u, Clamp01(u))); u = Clamp01(u); // The solution for u must also be in the range [0,1]. if (otherPt) *otherPt = lineSegment.a; return a + u * e0; } else if (t > 1.f) { // Clamp to t == 1 and solve for u. u = (B[0] - m[0][2]) / m[0][0]; // mathassert(EqualAbs(u, Clamp01(u))); u = Clamp01(u); // The solution for u must also be in the range [0,1]. if (otherPt) *otherPt = lineSegment.b; return a + u * e0; } else { // The solution is (u, 0, t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a + u * e0; } } else if (uvt.z < 0.f) { if (otherPt) *otherPt = lineSegment.a; // Clamp to t == 0 and solve again. float m_00 = m[1][1]; float m_01 = -m[0][1]; float m_10 = -m[1][0]; float m_11 = m[0][0]; float det = m_00 * m_11 - m_01 * m_10; float u = m_00 * B[0] + m_01 * B[1]; float v = m_10 * B[0] + m_11 * B[1]; u /= det; v /= det; if (u < 0.f) { // Clamp to u == 0 and solve for v. v = B[1] / m[1][1]; v = Clamp01(v); return a + v*e1; } else if (v < 0.f) { // Clamp to v == 0 and solve for u. u = B[0] / m[0][0]; u = Clamp01(u); return a + u*e0; } else if (u+v > 1.f) { // Set v = 1-u and solve again. // u = (B[0] - m[0][0]) / (m[0][0] - m[0][1]); // mathassert(EqualAbs(u, Clamp01(u))); // u = Clamp01(u); // The solution for u must also be in the range [0,1]. // return a + u*e0; // Clamp to v = 1-u and solve again. float m_00 = m[2][2]; float m_01 = m[1][2] - m[0][2]; float m_10 = m_01; float m_11 = m[0][0] + m[1][1] - 2.f * m[0][1]; float det = m_00 * m_11 - m_01 * m_10; float b0 = m[1][1] - m[0][1] + v_p_dot_e1 - v_p_dot_e0; float b1 = -m[1][2] + v_p_dot_d; float u = m_00 * b0 + m_01 * b1; u /= det; u = Clamp01(u); float t = m_10 * b0 + m_11 * b1; t /= det; t = Clamp01(t); if (otherPt) *otherPt = lineSegment.GetPoint(t); return a + u*e0 + (1.f-u)*e1; } else { // The solution is (u, v, 0) return a + u * e0 + v * e1; } } else if (uvt.z > 1.f) { if (otherPt) *otherPt = lineSegment.b; // Clamp to t == 1 and solve again. float m_00 = m[1][1]; float m_01 = -m[0][1]; float m_10 = -m[1][0]; float m_11 = m[0][0]; float det = m_00 * m_11 - m_01 * m_10; float u = m_00 * (B[0]-m[0][2]) + m_01 * (B[1]-m[1][2]); float v = m_10 * (B[0]-m[0][2]) + m_11 * (B[1]-m[1][2]); u /= det; v /= det; if (u < 0.f) { // Clamp to u == 0 and solve again. v = (B[1] - m[1][2]) / m[1][1]; v = Clamp01(v); return a + v*e1; } else if (u > 1.f) { // Clamp to u == 1 and solve again. v = (B[1] - m[1][0] - m[1][2]) / m[1][1]; v = Clamp01(v); // The solution for v must also be in the range [0,1]. TODO: Is this guaranteed by the above? // The solution is (u,v,t)=(1,v,1). return a + e0 + v*e1; } else if (u+v > 1.f) { // Set v = 1-u and solve again. // Q(u,1-u) = a + u*e0 + e1 - u*e1 = a+e1 + u*(e0-e1) // L(1) = ls.a + t*d = ls.b // Minimize the distance |Q(u,1-u) - L(1)| = |a+e1+ls.b + u*(e0-e1)| // |K + u*(e0-e1)|^2 = (K,K) + 2*u(K,e0-e1) + u^2 * (e0-e1,e0-e1) // grad = 2*(K,e0-e1) + 2*u*(e0-e1,e0-e1) == 0 // u == (K,e1-e0) / (e0-e1,e0-e1) u = (B[0] - m[0][1] - m[0][2]) / (m[0][0] - m[0][1]); // u = Dot(a + e1 + lineSegment.b, e1 - e0) / Dot(e0-e1, e0-e1); // mathassert(EqualAbs(u, Clamp01(u))); u = Clamp01(u); return a + u*e0 + (1-u)*e1; } else { // The solution is (u, v, 1) return a + u*e0 + v*e1; } } else if (uvt.x + uvt.y > 1.f) { // Clamp to v = 1-u and solve again. float m_00 = m[2][2]; float m_01 = m[1][2] - m[0][2]; float m_10 = m_01; float m_11 = m[0][0] + m[1][1] - 2.f * m[0][1]; float det = m_00 * m_11 - m_01 * m_10; float b0 = m[1][1] - m[0][1] + v_p_dot_e1 - v_p_dot_e0; float b1 = -m[1][2] + v_p_dot_d; float u = m_00 * b0 + m_01 * b1; float t = m_10 * b0 + m_11 * b1; u /= det; t /= det; t = Clamp01(t); if (otherPt) *otherPt = lineSegment.GetPoint(t); if (u < 0.f) { // The solution is (u,v,t)=(0,1,t) return c; } if (u > 1.f) { // The solution is (u,v,t)=(1,0,t) return b; } mathassert(t >= 0.f); mathassert(t <= 1.f); return a + u*e0 + (1.f-u)*e1; } else // All parameters are within range, so the triangle and the line segment intersect, and the intersection point is the closest point. { if (otherPt) *otherPt = lineSegment.GetPoint(uvt.z); return a + uvt.x * e0 + uvt.y * e1; } }