| 667 | } |
| 668 | |
| 669 | double Measurement::angle(const Base::Vector3d& /*param*/) const |
| 670 | { |
| 671 | // TODO: do these references arrive as obj+sub pairs or as a struct of obj + [subs]? |
| 672 | const std::vector<App::DocumentObject*>& objects = References3D.getValues(); |
| 673 | const std::vector<std::string>& subElements = References3D.getSubValues(); |
| 674 | int numRefs = objects.size(); |
| 675 | if (numRefs == 0) { |
| 676 | throw Base::RuntimeError("No references available for angle measurement"); |
| 677 | } |
| 678 | else if (measureType == MeasureType::Invalid) { |
| 679 | throw Base::RuntimeError("MeasureType is Invalid for angle measurement"); |
| 680 | } |
| 681 | else if (measureType == MeasureType::TwoLines) { |
| 682 | // Only case that is supported is edge to edge |
| 683 | // The angle between two skew lines is measured by the angle between one line (A) |
| 684 | // and a line (B) with the direction of the second through a point on the first line. |
| 685 | // Since we don't know if the directions of the lines point in the same general direction |
| 686 | // we could get the angle we want or the supplementary angle. |
| 687 | if (numRefs == 2) { |
| 688 | TopoDS_Shape shape1 = getShape(objects.at(0), subElements.at(0).c_str(), TopAbs_EDGE); |
| 689 | TopoDS_Shape shape2 = getShape(objects.at(1), subElements.at(1).c_str(), TopAbs_EDGE); |
| 690 | |
| 691 | BRepAdaptor_Curve curve1(TopoDS::Edge(shape1)); |
| 692 | BRepAdaptor_Curve curve2(TopoDS::Edge(shape2)); |
| 693 | |
| 694 | if (curve1.GetType() == GeomAbs_Line && curve2.GetType() == GeomAbs_Line) { |
| 695 | |
| 696 | gp_Pnt pnt1First = curve1.Value(curve1.FirstParameter()); |
| 697 | gp_Dir dir1 = curve1.Line().Direction(); |
| 698 | gp_Dir dir2 = curve2.Line().Direction(); |
| 699 | gp_Dir dir2r = curve2.Line().Direction().Reversed(); |
| 700 | |
| 701 | gp_Lin l1 = gp_Lin(pnt1First, dir1); // (A) |
| 702 | gp_Lin l2 = gp_Lin(pnt1First, dir2); // (B) |
| 703 | gp_Lin l2r = gp_Lin(pnt1First, dir2r); // (B') |
| 704 | Standard_Real aRad = l1.Angle(l2); |
| 705 | double aRadr = l1.Angle(l2r); |
| 706 | return Base::toDegrees<double>(std::min(aRad, aRadr)); |
| 707 | } |
| 708 | else { |
| 709 | throw Base::RuntimeError("Measurement references must both be lines"); |
| 710 | } |
| 711 | } |
| 712 | else { |
| 713 | throw Base::RuntimeError("Can not compute angle measurement - too many references"); |
| 714 | } |
| 715 | } |
| 716 | else if (measureType == MeasureType::Points) { |
| 717 | // NOTE: we are calculating the 3d angle here, not the projected angle |
| 718 | // ASSUMPTION: the references are in end-apex-end order |
| 719 | if (numRefs == 3) { |
| 720 | TopoDS_Shape shape0 = getShape(objects.at(0), subElements.at(0).c_str(), TopAbs_VERTEX); |
| 721 | TopoDS_Shape shape1 = getShape(objects.at(1), subElements.at(1).c_str(), TopAbs_VERTEX); |
| 722 | TopoDS_Shape shape2 = getShape(objects.at(1), subElements.at(2).c_str(), TopAbs_VERTEX); |
| 723 | if (shape0.ShapeType() != TopAbs_VERTEX || shape1.ShapeType() != TopAbs_VERTEX |
| 724 | || shape2.ShapeType() != TopAbs_VERTEX) { |
| 725 | throw Base::RuntimeError("Measurement references for 3 point angle are not Vertex"); |
| 726 | } |