23
#include "PreCompiled.h"
25
# include <BRep_Tool.hxx>
26
# include <BRepAdaptor_Curve.hxx>
27
# include <BRepAdaptor_Surface.hxx>
28
# include <BRepBuilderAPI_MakeEdge.hxx>
29
# include <BRepBuilderAPI_MakeFace.hxx>
30
# include <BRepExtrema_DistShapeShape.hxx>
31
# include <BRepGProp.hxx>
32
# include <BRepIntCurveSurface_Inter.hxx>
33
# include <BRepLProp_SLProps.hxx>
34
# include <Geom_Line.hxx>
35
# include <Geom_Plane.hxx>
36
# include <GeomAdaptor.hxx>
37
# include <GeomAPI.hxx>
38
# include <GeomAPI_ProjectPointOnCurve.hxx>
39
# include <GeomAPI_ProjectPointOnSurf.hxx>
40
# include <GeomAPI_IntSS.hxx>
41
# include <GeomLib_IsPlanarSurface.hxx>
44
# include <gp_Elips.hxx>
45
# include <gp_Hypr.hxx>
46
# include <gp_Parab.hxx>
49
# include <GProp_GProps.hxx>
50
# include <GProp_PGProps.hxx>
51
# include <GProp_PrincipalProps.hxx>
52
# include <ShapeExtend_Explorer.hxx>
54
# include <TopoDS_Edge.hxx>
55
# include <TopoDS_Face.hxx>
56
# include <TopoDS_Iterator.hxx>
57
# include <TopoDS_Shape.hxx>
58
# include <TopoDS_Vertex.hxx>
59
# include <TopTools_HSequenceOfShape.hxx>
62
#include <App/Application.h>
63
#include <App/Document.h>
64
#include <App/OriginFeature.h>
65
#include <Base/Console.h>
68
#include "AttachExtension.h"
73
using namespace Attacher;
76
const char* AttachEngine::eMapModeStrings[]= {
89
"SectionOfRevolution",
143
const char* AttachEngine::eRefTypeStrings[]= {
174
TYPESYSTEM_SOURCE_ABSTRACT(Attacher::AttachEngine, Base::BaseClass)
176
AttachEngine::AttachEngine() = default;
178
void AttachEngine::setReferences(const App::PropertyLinkSubList& references)
181
std::vector<std::string> names;
182
for (auto obj : references.getValues()) {
183
if (!obj->getNameInDocument()) {
184
throw AttachEngineException("AttachEngine::invalid object");
186
if (docname.empty()) {
187
docname = obj->getDocument()->getName();
189
else if (docname != obj->getDocument()->getName()) {
190
throw AttachEngineException("AttachEngine::object from multiple document");
192
names.emplace_back(obj->getNameInDocument());
194
this->docName = docname;
195
this->objNames = std::move(names);
196
this->subnames.clear();
197
this->subnames.reserve(this->objNames.size());
198
this->shadowSubs.clear();
199
this->shadowSubs.reserve(this->objNames.size());
200
for (auto& shadow : references.getShadowSubs()) {
201
this->shadowSubs.push_back(shadow.newName);
202
this->subnames.push_back(shadow.oldName);
204
assert(this->objNames.size() == this->subnames.size());
207
void AttachEngine::setReferences(const std::vector<App::SubObjectT>& references)
210
std::vector<std::string> names;
211
std::vector<std::string> subnames;
212
std::vector<std::string> shadowSubs;
213
for (auto& ref : references) {
214
if (!ref.getSubObject()) {
215
FC_THROWM(AttachEngineException,
216
"AttachEngine::invalid object " << ref.getSubObjectFullName());
218
if (docname.empty()) {
219
docname = ref.getDocumentName();
221
else if (docname != ref.getDocumentName()) {
222
throw AttachEngineException("AttachEngine::object from multiple document");
224
names.push_back(ref.getObjectName());
225
subnames.push_back(ref.getSubNameNoElement() + ref.getOldElementName());
226
shadowSubs.push_back(ref.getSubNameNoElement() + ref.getNewElementName());
228
this->docName = docname;
229
this->objNames = std::move(names);
230
this->subnames = std::move(subnames);
231
this->shadowSubs = std::move(shadowSubs);
234
void AttachEngine::setUp(const App::PropertyLinkSubList &references,
235
eMapMode mapMode, bool mapReverse,
236
double attachParameter,
237
double surfU, double surfV,
238
const Base::Placement &attachmentOffset)
240
setReferences(references);
241
this->mapMode = mapMode;
242
this->mapReverse = mapReverse;
243
this->attachParameter = attachParameter;
246
this->attachmentOffset = attachmentOffset;
249
void AttachEngine::setUp(const AttachEngine &another)
251
this->docName = another.docName;
252
this->objNames = another.objNames;
253
this->subnames = another.subnames;
254
this->shadowSubs = another.shadowSubs;
255
this->mapMode = another.mapMode;
256
this->mapReverse = another.mapReverse;
257
this->attachParameter = another.attachParameter;
258
this->surfU = another.surfU;
259
this->surfV = another.surfV;
260
this->attachmentOffset = another.attachmentOffset;
263
void AttachEngine::setOffset(const Base::Placement &offset)
265
this->attachmentOffset = offset;
268
Base::Placement AttachEngine::placementFactory(const gp_Dir &ZAxis,
273
bool useRefOrg_Plane,
275
bool makeLegacyFlatFaceOrientation,
276
Base::Placement* placeOfRef) const
280
gp_Vec refOrgV = gp_Vec(refOrg.XYZ());
281
gp_Vec OriginV = gp_Vec(Origin.XYZ());
282
gp_Vec ZAxisV = gp_Vec(ZAxis);
284
OriginV + ZAxisV*ZAxisV.Dot(refOrgV-OriginV)
289
gp_Vec refOrgV = gp_Vec(refOrg.XYZ());
290
gp_Vec OriginV = gp_Vec(Origin.XYZ());
291
gp_Vec ZAxisV = gp_Vec(ZAxis);
293
refOrgV + ZAxisV*ZAxisV.Dot(OriginV-refOrgV)
297
if (XAxis.Magnitude() < Precision::Confusion())
298
makeYVertical = true;
301
if (!makeYVertical) {
302
ax3 = gp_Ax3(Origin, ZAxis, XAxis);
303
} else if (!makeLegacyFlatFaceOrientation) {
305
gp_Vec YAxis(0.0,0.0,1.0);
306
XAxis = YAxis.Crossed(gp_Vec(ZAxis));
307
if (XAxis.Magnitude() < Precision::Confusion()){
309
XAxis = (gp_Vec(1,0,0)*ZAxis.Z()).Normalized();
311
ax3 = gp_Ax3(Origin, ZAxis, XAxis);
312
} else if (makeLegacyFlatFaceOrientation) {
316
throw AttachEngineException("AttachEngine::placementFactory: for Legacy mode, placement of the reference must be supplied. Got null instead!");
317
Base::Placement &Place = *placeOfRef;
318
Base::Vector3d dX,dY,dZ;
319
Place.getRotation().multVec(Base::Vector3d(1,0,0),dX);
320
Place.getRotation().multVec(Base::Vector3d(0,1,0),dY);
321
Place.getRotation().multVec(Base::Vector3d(0,0,1),dZ);
322
gp_Dir dirX(dX.x, dX.y, dX.z);
323
gp_Dir dirY(dY.x, dY.y, dY.z);
324
gp_Dir dirZ(dZ.x, dZ.y, dZ.z);
325
double cosNX = ZAxis.Dot(dirX);
326
double cosNY = ZAxis.Dot(dirY);
327
double cosNZ = ZAxis.Dot(dirZ);
328
std::vector<double> cosXYZ;
329
cosXYZ.push_back(fabs(cosNX));
330
cosXYZ.push_back(fabs(cosNY));
331
cosXYZ.push_back(fabs(cosNZ));
333
int pos = std::max_element(cosXYZ.begin(), cosXYZ.end()) - cosXYZ.begin();
338
ax3 = gp_Ax3(Origin, ZAxis, dirY);
340
ax3 = gp_Ax3(Origin, ZAxis, -dirY);
345
ax3 = gp_Ax3(Origin, ZAxis, -dirX);
347
ax3 = gp_Ax3(Origin, ZAxis, dirX);
351
ax3 = gp_Ax3(Origin, ZAxis, dirX);
355
if(this->mapReverse){
362
Trf.SetTransformation(ax3);
364
Trf.SetScaleFactor(Standard_Real(1.0));
367
TopoShape::convertToMatrix(Trf,mtrx);
369
return Base::Placement(mtrx);
373
void AttachEngine::suggestMapModes(SuggestResult &result) const
375
std::vector<eMapMode> &mlist = result.allApplicableModes;
377
mlist.reserve(mmDummy_NumberOfModes);
379
std::set<eRefType> &hints = result.nextRefTypeHint;
382
std::map<eMapMode,refTypeStringList> &mlist_reachable = result.reachableModes;
383
mlist_reachable.clear();
385
result.message = SuggestResult::srLinkBroken;
386
result.bestFitMode = mmDeactivated;
389
std::vector<App::GeoFeature*> parts;
390
std::vector<const TopoDS_Shape*> shapes;
391
std::vector<TopoDS_Shape> shapeStorage;
392
std::vector<eRefType> typeStr;
394
readLinks(getRefObjects(),subnames, parts, shapes, shapeStorage, typeStr);
395
} catch (Base::Exception &err) {
396
result.references_Types = typeStr;
397
result.message = SuggestResult::srLinkBroken;
398
result.error.Exception::operator = (err);
402
result.references_Types = typeStr;
405
int bestMatchScore = -1;
406
result.message = SuggestResult::srNoModesFit;
407
for (std::size_t iMode = 0; iMode < this->modeRefTypes.size(); ++iMode) {
408
if (! this->modeEnabled[iMode])
410
const refTypeStringList &listStrings = modeRefTypes[iMode];
411
for (const auto & str : listStrings) {
413
for (std::size_t iChr = 0; iChr < str.size() && iChr < typeStr.size(); ++iChr) {
414
int match = AttachEngine::isShapeOfType(typeStr[iChr], str[iChr]);
432
if (score > 0 && str.size() > typeStr.size()){
434
hints.insert(str[typeStr.size()]);
437
refTypeString extraRefs;
438
extraRefs.resize(str.size() - typeStr.size());
439
for (std::size_t iChr = typeStr.size(); iChr < str.size(); iChr++) {
440
extraRefs[iChr - typeStr.size()] = str[iChr];
444
auto it_r = mlist_reachable.find(eMapMode(iMode));
445
if (it_r == mlist_reachable.end()){
446
it_r = mlist_reachable.insert(std::pair<eMapMode,refTypeStringList>(eMapMode(iMode),refTypeStringList())).first;
448
refTypeStringList &list = it_r->second;
449
list.push_back(extraRefs);
453
if (str.size() != typeStr.size())
457
if (score > bestMatchScore){
458
bestMatchScore = score;
459
result.bestFitMode = eMapMode(iMode);
460
result.message = score > 0 ? SuggestResult::srOK : SuggestResult::srIncompatibleGeometry;
465
mlist.push_back(eMapMode(iMode));
466
else if (mlist.back() != eMapMode(iMode))
467
mlist.push_back(eMapMode(iMode));
474
void AttachEngine::EnableAllSupportedModes()
476
this->modeEnabled.resize(mmDummy_NumberOfModes,false);
477
assert(modeRefTypes.size() > 0);
478
for (std::size_t i = 0; i < this->modeEnabled.size(); i++) {
479
modeEnabled[i] = !modeRefTypes[i].empty();
483
eRefType AttachEngine::getShapeType(const TopoDS_Shape& sh)
488
switch (sh.ShapeType()){
495
case TopAbs_COMPOUND:{
496
const TopoDS_Compound &cmpd = TopoDS::Compound(sh);
497
TopoDS_Iterator it (cmpd, Standard_False, Standard_False);
500
const TopoDS_Shape &sh1 = it.Value();
507
return getShapeType(sh1);
510
case TopAbs_COMPSOLID:
515
const TopoDS_Face &f = TopoDS::Face(sh);
516
BRepAdaptor_Surface surf(f, Standard_False);
517
switch(surf.GetType()) {
520
case GeomAbs_Cylinder:
521
return rtCylindricalFace;
523
return rtConicalFace;
525
return rtSphericalFace;
527
return rtToroidalFace;
528
case GeomAbs_BezierSurface:
530
case GeomAbs_BSplineSurface:
532
case GeomAbs_SurfaceOfRevolution:
534
case GeomAbs_SurfaceOfExtrusion:
536
case GeomAbs_OffsetSurface:
538
case GeomAbs_OtherSurface:
544
const TopoDS_Edge &e = TopoDS::Edge(sh);
545
BRepAdaptor_Curve crv(e);
546
switch (crv.GetType()){
551
case GeomAbs_Ellipse:
553
case GeomAbs_Hyperbola:
555
case GeomAbs_Parabola:
557
case GeomAbs_BezierCurve:
558
case GeomAbs_BSplineCurve:
559
case GeomAbs_OtherCurve:
560
case GeomAbs_OffsetCurve:
569
throw AttachEngineException("AttachEngine::getShapeType: unexpected TopoDS_Shape::ShapeType");
574
eRefType AttachEngine::getShapeType(const App::DocumentObject *obj, const std::string &subshape)
576
App::PropertyLinkSubList tmpLink;
578
tmpLink.setValue(const_cast<App::DocumentObject*>(obj), subshape.c_str());
580
std::vector<App::GeoFeature*> parts;
581
std::vector<const TopoDS_Shape*> shapes;
582
std::vector<TopoDS_Shape> copiedShapeStorage;
583
std::vector<eRefType> types;
584
readLinks(tmpLink.getValues(),tmpLink.getSubValues(), parts, shapes, copiedShapeStorage, types);
586
assert(types.size() == 1);
590
eRefType AttachEngine::downgradeType(eRefType type)
593
type = eRefType(type & (rtFlagHasPlacement - 1));
614
case rtSphericalFace:
617
case rtCylindricalFace:
627
throw AttachEngineException("AttachEngine::downgradeType: unknown type");
631
int AttachEngine::getTypeRank(eRefType type)
634
type = eRefType(type & (rtFlagHasPlacement - 1));
637
while (type != rtAnything) {
638
type = downgradeType(type);
645
int AttachEngine::isShapeOfType(eRefType shapeType, eRefType requirement)
648
if (requirement & rtFlagHasPlacement) {
649
if(! (shapeType & rtFlagHasPlacement))
654
shapeType = eRefType(shapeType & (rtFlagHasPlacement - 1));
655
requirement = eRefType(requirement & (rtFlagHasPlacement - 1));
657
if (requirement == rtAnything)
660
int reqRank = getTypeRank(requirement);
663
eRefType shDeg = shapeType;
664
while(shDeg != rtAnything){
665
if (shDeg == requirement)
667
shDeg = downgradeType(shDeg);
671
requirement = downgradeType(requirement);
672
if (requirement != rtAnything) {
673
eRefType shDeg = shapeType;
674
while(shDeg != rtAnything){
675
if (shDeg == requirement)
677
shDeg = downgradeType(shDeg);
685
std::string AttachEngine::getModeName(eMapMode mmode)
687
if(mmode < 0 || mmode >= mmDummy_NumberOfModes)
688
throw AttachEngineException("AttachEngine::getModeName: Attachment Mode index is out of range");
689
return {AttachEngine::eMapModeStrings[mmode]};
692
eMapMode AttachEngine::getModeByName(const std::string &modeName)
694
for (int mmode = 0 ; mmode < mmDummy_NumberOfModes ; mmode++){
695
if (strcmp(eMapModeStrings[mmode],modeName.c_str())==0) {
696
return eMapMode(mmode);
699
std::stringstream errMsg;
700
errMsg << "AttachEngine::getModeByName: mode with this name doesn't exist: " << modeName;
701
throw AttachEngineException(errMsg.str());
704
std::string AttachEngine::getRefTypeName(eRefType shapeType)
706
eRefType flagless = eRefType(shapeType & 0xFF);
707
if(flagless < 0 || flagless >= rtDummy_numberOfShapeTypes)
708
throw AttachEngineException("eRefType value is out of range");
709
std::string result = std::string(eRefTypeStrings[flagless]);
710
if (shapeType & rtFlagHasPlacement){
711
result.append("|Placement");
716
eRefType AttachEngine::getRefTypeByName(const std::string& typeName)
718
std::string flagless;
720
size_t seppos = typeName.find('|');
721
flagless = typeName.substr(0, seppos);
722
if(seppos != std::string::npos ){
723
flags = typeName.substr(seppos+1);
725
for(int irt = 0 ; irt < rtDummy_numberOfShapeTypes ; irt++){
726
if(strcmp(flagless.c_str(),eRefTypeStrings[irt]) == 0){
727
if(strcmp("Placement",flags.c_str()) == 0){
728
return eRefType(irt | rtFlagHasPlacement);
729
} else if (flags.length() == 0){
730
return eRefType(irt);
732
std::stringstream errmsg;
733
errmsg << "RefType flag not recognized: " << flags;
734
throw AttachEngineException(errmsg.str());
738
std::stringstream errmsg;
739
errmsg << "RefType not recognized: " << typeName;
740
throw AttachEngineException(errmsg.str());
743
GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector<const TopoDS_Shape*> &shapes)
746
TopTools_HSequenceOfShape totalSeq;
747
for (const TopoDS_Shape* pSh : shapes) {
748
ShapeExtend_Explorer xp;
749
totalSeq.Append( xp.SeqFromCompound(*pSh, true));
751
if (totalSeq.Length() == 0)
752
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: no geometry provided");
753
const TopoDS_Shape &sh0 = totalSeq.Value(1);
754
switch (sh0.ShapeType()){
757
for (int i = 0 ; i < totalSeq.Length() ; i++){
758
const TopoDS_Shape &sh = totalSeq.Value(i+1);
759
if (sh.ShapeType() != TopAbs_VERTEX)
760
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: provided shapes are incompatible (not only vertices)");
761
gpr.AddPoint(BRep_Tool::Pnt(TopoDS::Vertex(sh)));
767
GProp_GProps gpr_acc;
769
for (int i = 0 ; i < totalSeq.Length() ; i++){
770
const TopoDS_Shape &sh = totalSeq.Value(i+1);
771
if (sh.ShapeType() != TopAbs_EDGE && sh.ShapeType() != TopAbs_WIRE)
772
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: provided shapes are incompatible (not only edges/wires)");
774
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: infinite shape provided");
775
BRepGProp::LinearProperties(sh,gpr);
782
GProp_GProps gpr_acc;
784
for (int i = 0 ; i < totalSeq.Length() ; i++){
785
const TopoDS_Shape &sh = totalSeq.Value(i+1);
786
if (sh.ShapeType() != TopAbs_FACE && sh.ShapeType() != TopAbs_SHELL)
787
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: provided shapes are incompatible (not only faces/shells)");
789
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: infinite shape provided");
790
BRepGProp::SurfaceProperties(sh,gpr);
796
case TopAbs_COMPSOLID:{
797
GProp_GProps gpr_acc;
799
for (int i = 0 ; i < totalSeq.Length() ; i++){
800
const TopoDS_Shape &sh = totalSeq.Value(i+1);
801
if (sh.ShapeType() != TopAbs_SOLID && sh.ShapeType() != TopAbs_COMPSOLID)
802
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: provided shapes are incompatible (not only solids/compsolids)");
804
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: infinite shape provided");
805
BRepGProp::VolumeProperties(sh,gpr);
811
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: unexpected shape type");
822
void AttachEngine::readLinks(const std::vector<App::DocumentObject*> &objs,
823
const std::vector<std::string> &sub,
824
std::vector<App::GeoFeature*> &geofs,
825
std::vector<const TopoDS_Shape*> &shapes,
826
std::vector<TopoDS_Shape> &storage,
827
std::vector<eRefType> &types)
829
geofs.resize(objs.size());
830
storage.reserve(objs.size());
831
shapes.resize(objs.size());
832
types.resize(objs.size());
833
for (std::size_t i = 0; i < objs.size(); i++) {
834
if (!objs[i]->getTypeId().isDerivedFrom(App::GeoFeature::getClassTypeId())) {
835
FC_THROWM(AttachEngineException,
836
"AttachEngine3D: attached to a non App::GeoFeature '"
837
<< objs[i]->getNameInDocument() << "'");
839
auto* geof = dynamic_cast<App::GeoFeature*>(objs[i]);
841
Part::TopoShape shape;
842
if (geof->isDerivedFrom(App::Plane::getClassTypeId())) {
845
geof->Placement.getValue().getRotation().multVec(Base::Vector3d(0.0, 0.0, 1.0), norm);
847
geof->Placement.getValue().multVec(Base::Vector3d(), org);
849
gp_Pln plane = gp_Pln(gp_Pnt(org.x, org.y, org.z), gp_Dir(norm.x, norm.y, norm.z));
850
TopoDS_Shape myShape = BRepBuilderAPI_MakeFace(plane).Shape();
851
myShape.Infinite(true);
852
storage.emplace_back(myShape);
853
shapes[i] = &(storage[storage.size() - 1]);
855
else if (geof->isDerivedFrom(App::Line::getClassTypeId())) {
860
geof->Placement.getValue().getRotation().multVec(Base::Vector3d(1.0, 0.0, 0.0), dir);
862
geof->Placement.getValue().multVec(Base::Vector3d(), org);
864
gp_Lin line = gp_Lin(gp_Pnt(org.x, org.y, org.z), gp_Dir(dir.x, dir.y, dir.z));
865
TopoDS_Shape myShape = BRepBuilderAPI_MakeEdge(line).Shape();
866
myShape.Infinite(true);
867
storage.emplace_back(myShape);
868
shapes[i] = &(storage[storage.size() - 1]);
872
shape = Part::Feature::getTopoShape(geof, sub[i].c_str(), true);
874
if (shape.isNull()) {
875
FC_THROWM(AttachEngineException,
876
"AttachEngine3D: subshape not found "
877
<< objs[i]->getNameInDocument() << '.' << sub[i]);
879
if (shape.shapeType() != TopAbs_COMPOUND
880
|| shape.countSubShapes(TopAbs_SHAPE) != 1) {
884
shape = shape.getSubTopoShape(TopAbs_SHAPE, 1);
886
storage.emplace_back(shape.getShape());
888
catch (Standard_Failure& e) {
889
FC_THROWM(AttachEngineException,
890
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
891
<< '.' << sub[i] << std::endl
892
<< e.GetMessageString());
894
catch (Base::CADKernelError& e) {
895
FC_THROWM(AttachEngineException,
896
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
897
<< '.' << sub[i] << std::endl
900
if (storage.back().IsNull()) {
901
FC_THROWM(AttachEngineException,
902
"AttachEngine3D: null subshape " << objs[i]->getNameInDocument() << '.'
905
shapes[i] = &(storage.back());
910
types[i] = getShapeType(*(shapes[i]));
911
if (sub[i].length() == 0) {
912
types[i] = eRefType(types[i] | rtFlagHasPlacement);
918
void AttachEngine::throwWrongMode(eMapMode mmode)
920
std::stringstream errmsg;
921
if (mmode >= 0 && mmode<mmDummy_NumberOfModes) {
922
if (AttachEngine::eMapModeStrings[mmode]) {
923
errmsg << "Attachment mode " << AttachEngine::eMapModeStrings[mmode] << " is not implemented." ;
925
errmsg << "Attachment mode " << int(mmode) << " is undefined." ;
928
errmsg << "Attachment mode index (" << int(mmode) << ") is out of range." ;
930
throw Base::ValueError(errmsg.str().c_str());
933
void AttachEngine::verifyReferencesAreSafe(const App::PropertyLinkSubList &references)
935
const std::vector<App::DocumentObject*> links = references.getValues();
936
const std::vector<App::Document*> docs = App::GetApplication().getDocuments();
937
for(App::DocumentObject* lnk : links){
939
for(App::Document* doc : docs){
945
throw AttachEngineException("AttachEngine: verifyReferencesAreSafe: references point to deleted object.");
950
std::vector<App::DocumentObject*> AttachEngine::getRefObjects() const
952
std::vector<App::DocumentObject*> objs;
953
if (objNames.empty()) {
956
auto doc = App::GetApplication().getDocument(docName.c_str());
958
FC_THROWM(AttachEngineException, "AttachEngine: document '" << docName << "' not found");
960
objs.reserve(objNames.size());
961
for (auto& name : objNames) {
962
objs.push_back(doc->getObject(name.c_str()));
964
FC_THROWM(AttachEngineException,
965
"AttachEngine: object '" << docName << "#" << name << "' not found");
971
Base::Placement AttachEngine::calculateAttachedPlacement(const Base::Placement& origPlacement,
974
std::map<int, std::pair<std::string, std::string>> subChanges;
976
auto objs = getRefObjects();
977
for (auto obj : objs) {
979
auto& sub = subnames[i];
980
auto& shadow = shadowSubs[i];
981
if (shadow.empty() || !Data::hasMissingElement(sub.c_str())) {
984
auto related = Part::Feature::getRelatedElements(obj,
986
Part::HistoryTraceType::followTypeChange,
988
if (!related.empty()) {
989
auto& res = subChanges[i];
990
res.first = Data::ComplexGeoData::elementMapPrefix();
991
related.front().name.appendToBuffer(res.first);
993
related.front().index.appendToStringBuffer(res.second);
996
std::string name = Data::oldElementName(shadow.c_str());
998
auto& res = subChanges[i];
1003
subnames[i] = shadow;
1007
if (!subChanges.empty()) {
1012
auto subs = subnames;
1013
for (auto& change : subChanges) {
1014
auto [subkey, namechange] =change;
1015
auto [_oldname, newname] = namechange;
1016
subs[subkey] = newname;
1018
auto pla = _calculateAttachedPlacement(objs, subs, origPlacement);
1020
if (pla.getPosition().IsEqual(origPlacement.getPosition(), Precision::Confusion())
1021
&& pla.getRotation().isSame(origPlacement.getRotation(), Precision::Angular())) {
1027
subnames = std::move(subs);
1028
for (auto& v : subChanges) {
1029
shadowSubs[v.first] = v.second.first;
1035
return _calculateAttachedPlacement(objs, subnames, origPlacement);
1042
TYPESYSTEM_SOURCE(Attacher::AttachEngine3D, Attacher::AttachEngine)
1044
AttachEngine3D::AttachEngine3D()
1047
modeRefTypes.resize(mmDummy_NumberOfModes);
1049
refTypeStringList ss;
1051
modeRefTypes[mmTranslate].push_back(cat(rtVertex));
1054
ss.push_back(cat(eRefType(rtAnything | rtFlagHasPlacement)));
1055
ss.push_back(cat(rtConic));
1056
modeRefTypes[mmObjectXY] = ss;
1057
modeRefTypes[mmObjectXZ] = ss;
1058
modeRefTypes[mmObjectYZ] = ss;
1060
modeRefTypes[mmParallelPlane].push_back(
1061
cat(eRefType(rtFlatFace | rtFlagHasPlacement), rtVertex));
1062
modeRefTypes[mmParallelPlane].push_back(
1063
cat(eRefType(rtAnything | rtFlagHasPlacement), rtVertex));
1065
modeRefTypes[mmInertialCS].push_back(cat(rtAnything));
1066
modeRefTypes[mmInertialCS].push_back(cat(rtAnything,rtAnything));
1067
modeRefTypes[mmInertialCS].push_back(cat(rtAnything,rtAnything,rtAnything));
1068
modeRefTypes[mmInertialCS].push_back(cat(rtAnything,rtAnything,rtAnything,rtAnything));
1070
modeRefTypes[mmFlatFace].push_back(cat(rtFlatFace));
1072
modeRefTypes[mmTangentPlane].push_back(cat(rtFace, rtVertex));
1073
modeRefTypes[mmTangentPlane].push_back(cat(rtVertex, rtFace));
1078
modeRefTypes[mmNormalToPath].push_back(s);
1081
modeRefTypes[mmFrenetNB].push_back(s);
1082
modeRefTypes[mmFrenetTN].push_back(s);
1083
modeRefTypes[mmFrenetTB].push_back(s);
1084
modeRefTypes[mmRevolutionSection].push_back(s);
1085
modeRefTypes[mmConcentric].push_back(s);
1087
modeRefTypes[mmRevolutionSection].push_back(s);
1088
modeRefTypes[mmConcentric].push_back(s);
1092
s=cat(rtEdge, rtVertex);
1093
modeRefTypes[mmNormalToPath].push_back(s);
1094
s=cat(rtVertex, rtEdge);
1095
modeRefTypes[mmNormalToPath].push_back(s);
1097
s=cat(rtCurve, rtVertex);
1098
modeRefTypes[mmFrenetNB].push_back(s);
1099
modeRefTypes[mmFrenetTN].push_back(s);
1100
modeRefTypes[mmFrenetTB].push_back(s);
1101
modeRefTypes[mmRevolutionSection].push_back(s);
1102
modeRefTypes[mmConcentric].push_back(s);
1103
s = cat(rtCircle, rtVertex);
1104
modeRefTypes[mmRevolutionSection].push_back(s);
1105
modeRefTypes[mmConcentric].push_back(s);
1107
s=cat(rtVertex, rtCurve);
1108
modeRefTypes[mmFrenetNB].push_back(s);
1109
modeRefTypes[mmFrenetTN].push_back(s);
1110
modeRefTypes[mmFrenetTB].push_back(s);
1111
modeRefTypes[mmRevolutionSection].push_back(s);
1112
modeRefTypes[mmConcentric].push_back(s);
1113
s = cat(rtVertex, rtCircle);
1114
modeRefTypes[mmRevolutionSection].push_back(s);
1115
modeRefTypes[mmConcentric].push_back(s);
1119
s = cat(rtVertex, rtVertex, rtVertex);
1120
modeRefTypes[mmThreePointsPlane].push_back(s);
1121
modeRefTypes[mmThreePointsNormal].push_back(s);
1123
s = cat(rtLine, rtVertex);
1124
modeRefTypes[mmThreePointsPlane].push_back(s);
1125
modeRefTypes[mmThreePointsNormal].push_back(s);
1127
s = cat(rtVertex, rtLine);
1128
modeRefTypes[mmThreePointsPlane].push_back(s);
1129
modeRefTypes[mmThreePointsNormal].push_back(s);
1131
s = cat(rtLine, rtLine);
1132
modeRefTypes[mmThreePointsPlane].push_back(s);
1133
modeRefTypes[mmThreePointsNormal].push_back(s);
1136
for (int mmode = mmOZX; mmode <= mmOYX; ++mmode){
1137
modeRefTypes[mmode].push_back(cat(rtVertex, rtVertex, rtVertex));
1138
modeRefTypes[mmode].push_back(cat(rtVertex, rtVertex, rtLine));
1139
modeRefTypes[mmode].push_back(cat(rtVertex, rtLine, rtVertex));
1140
modeRefTypes[mmode].push_back(cat(rtVertex, rtLine, rtLine));
1141
modeRefTypes[mmode].push_back(cat(rtVertex, rtVertex));
1142
modeRefTypes[mmode].push_back(cat(rtVertex, rtLine));
1146
modeRefTypes[mmFolding].push_back(cat(rtLine, rtLine, rtLine, rtLine));
1148
this->EnableAllSupportedModes();
1151
AttachEngine3D* AttachEngine3D::copy() const
1153
AttachEngine3D* p = new AttachEngine3D;
1159
AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObject*>& objs,
1160
const std::vector<std::string>& subs,
1161
const Base::Placement& origPlacement) const
1163
const eMapMode mmode = this->mapMode;
1164
if (mmode == mmDeactivated) {
1165
throw ExceptionCancel();
1168
std::vector<App::GeoFeature*> parts;
1169
std::vector<const TopoDS_Shape*> shapes;
1170
std::vector<TopoDS_Shape> copiedShapeStorage;
1171
std::vector<eRefType> types;
1172
readLinks(objs, subs, parts, shapes, copiedShapeStorage, types);
1174
if (parts.empty()) {
1175
throw ExceptionCancel();
1179
gp_Pnt refOrg(0.0, 0.0, 0.0);
1180
Base::Placement Place = parts[0]->Placement.getValue();
1181
refOrg = gp_Pnt(Place.getPosition().x, Place.getPosition().y, Place.getPosition().z);
1186
gp_Dir SketchNormal;
1188
gp_Pnt SketchBasePoint;
1196
if (shapes.empty()) {
1197
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: no subobjects "
1198
"specified (need one vertex).");
1200
const TopoDS_Shape& sh = *shapes[0];
1202
throw Base::ValueError(
1203
"Null shape in AttachEngine3D::calculateAttachedPlacement()!");
1205
if (sh.ShapeType() != TopAbs_VERTEX) {
1206
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: no subobjects "
1207
"specified (need one vertex).");
1209
gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(sh));
1210
Base::Placement plm = Base::Placement();
1211
plm.setPosition(Base::Vector3d(p.X(), p.Y(), p.Z()));
1212
plm.setPosition(plm.getPosition() + this->attachmentOffset.getPosition());
1213
plm.setRotation(origPlacement.getRotation());
1219
case mmParallelPlane: {
1221
gp_Dir dirX, dirY, dirZ;
1222
if (types[0] & rtFlagHasPlacement) {
1223
Base::Vector3d dX, dY,
1225
Place.getRotation().multVec(Base::Vector3d(1, 0, 0), dX);
1226
Place.getRotation().multVec(Base::Vector3d(0, 1, 0), dY);
1227
Place.getRotation().multVec(Base::Vector3d(0, 0, 1), dZ);
1228
dirX = gp_Dir(dX.x, dX.y, dX.z);
1229
dirY = gp_Dir(dY.x, dY.y, dY.z);
1230
dirZ = gp_Dir(dZ.x, dZ.y, dZ.z);
1232
gp_Pnt(Place.getPosition().x, Place.getPosition().y, Place.getPosition().z);
1234
else if (isShapeOfType(types[0], rtConic) > 0) {
1235
const TopoDS_Edge& e = TopoDS::Edge(*shapes[0]);
1236
BRepAdaptor_Curve adapt(e);
1238
switch (adapt.GetType()) {
1239
case GeomAbs_Ellipse: {
1240
gp_Elips cc = adapt.Ellipse();
1241
pos = gp_Ax3(cc.Position());
1243
case GeomAbs_Hyperbola: {
1244
gp_Hypr cc = adapt.Hyperbola();
1245
pos = gp_Ax3(cc.Position());
1247
case GeomAbs_Parabola: {
1248
gp_Parab cc = adapt.Parabola();
1249
pos = gp_Ax3(cc.Position());
1255
dirX = pos.XDirection();
1256
dirY = pos.YDirection();
1257
dirZ = pos.Axis().Direction();
1258
SketchBasePoint = pos.Location();
1261
throw Base::ValueError(
1262
"AttachEngine3D::calculateAttachedPlacement: need either a conic section edge, "
1263
"or a whole object for ObjectXY-like modes.");
1268
SketchNormal = dirZ;
1269
SketchXAxis = gp_Vec(dirX);
1272
SketchNormal = dirY.Reversed();
1273
SketchXAxis = gp_Vec(dirX);
1276
SketchNormal = dirX;
1277
SketchXAxis = gp_Vec(dirY);
1279
case mmParallelPlane: {
1280
if (shapes.size() < 2) {
1281
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: not "
1282
"enough subshapes (need one plane and one vertex).");
1285
TopoDS_Vertex vertex;
1287
vertex = TopoDS::Vertex(*(shapes[1]));
1291
if (vertex.IsNull()) {
1292
throw Base::ValueError(
1293
"Null vertex in AttachEngine3D::calculateAttachedPlacement()!");
1296
SketchNormal = dirZ;
1297
SketchXAxis = gp_Vec(dirX);
1300
Handle(Geom_Line) hCurve(new Geom_Line(SketchBasePoint, dirZ));
1301
gp_Pnt p = BRep_Tool::Pnt(vertex);
1302
GeomAPI_ProjectPointOnCurve projector(p, hCurve);
1303
SketchBasePoint = projector.NearestPoint();
1310
case mmInertialCS: {
1311
GProp_GProps gpr = AttachEngine::getInertialPropsOfShape(shapes);
1312
GProp_PrincipalProps pr = gpr.PrincipalProperties();
1313
if (pr.HasSymmetryPoint()) {
1314
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement:InertialCS: "
1315
"inertia tensor is trivial, principal axes are undefined.");
1317
if (pr.HasSymmetryAxis()) {
1318
Base::Console().Warning(
1319
"AttachEngine3D::calculateAttachedPlacement:InertialCS: inertia tensor has "
1320
"axis of symmetry. Second and third axes of inertia are undefined.\n");
1326
Standard_Real I1, I2, I3;
1327
pr.Moments(I1, I2, I3);
1328
Standard_Real d12, d23, d31;
1329
d12 = fabs(I1 - I2);
1330
d23 = fabs(I2 - I3);
1331
d31 = fabs(I3 - I1);
1332
if (d12 < d23 && d12 < d31) {
1333
SketchNormal = pr.ThirdAxisOfInertia();
1335
else if (d23 < d31 && d23 < d12) {
1336
SketchNormal = pr.FirstAxisOfInertia();
1339
SketchNormal = pr.SecondAxisOfInertia();
1343
SketchNormal = pr.FirstAxisOfInertia();
1344
SketchXAxis = pr.SecondAxisOfInertia();
1346
SketchBasePoint = gpr.CentreOfMass();
1349
if (shapes.empty()) {
1350
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: no subobjects "
1351
"specified (needed one planar face).");
1356
bool Reverse = false;
1358
face = TopoDS::Face(*(shapes[0]));
1362
if (face.IsNull()) {
1363
if (!TopoShape(*shapes[0]).findPlane(plane)) {
1364
throw Base::ValueError(
1365
"No planar face in AttachEngine3D::calculateAttachedPlacement()!");
1369
BRepAdaptor_Surface adapt(face);
1370
if (adapt.GetType() == GeomAbs_Plane) {
1371
plane = adapt.Plane();
1374
TopLoc_Location loc;
1375
Handle(Geom_Surface) surf = BRep_Tool::Surface(face, loc);
1376
GeomLib_IsPlanarSurface check(surf);
1377
if (check.IsPlanar()) {
1378
plane = check.Plan();
1381
throw Base::ValueError(
1382
"No planar face in AttachEngine3D::calculateAttachedPlacement()!");
1386
if (face.Orientation() == TopAbs_REVERSED) {
1391
Standard_Boolean ok = plane.Direct();
1397
gp_Ax1 Normal = plane.Axis();
1401
SketchNormal = Normal.Direction();
1403
Handle(Geom_Plane) gPlane = new Geom_Plane(plane);
1404
GeomAPI_ProjectPointOnSurf projector(refOrg, gPlane);
1405
SketchBasePoint = projector.NearestPoint();
1408
case mmTangentPlane: {
1409
if (shapes.size() < 2) {
1410
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: not enough "
1411
"subshapes (need one face and one vertex).");
1414
bool bThruVertex = false;
1415
if (shapes[0]->ShapeType() == TopAbs_VERTEX) {
1416
std::swap(shapes[0], shapes[1]);
1422
face = TopoDS::Face(*(shapes[0]));
1426
if (face.IsNull()) {
1427
throw Base::ValueError(
1428
"Null face in AttachEngine3D::calculateAttachedPlacement()!");
1431
TopoDS_Vertex vertex;
1433
vertex = TopoDS::Vertex(*(shapes[1]));
1437
if (vertex.IsNull()) {
1438
throw Base::ValueError(
1439
"Null vertex in AttachEngine3D::calculateAttachedPlacement()!");
1442
Handle(Geom_Surface) hSurf = BRep_Tool::Surface(face);
1443
gp_Pnt p = BRep_Tool::Pnt(vertex);
1445
GeomAPI_ProjectPointOnSurf projector(p, hSurf);
1447
if (projector.NbPoints() == 0) {
1448
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: projecting "
1449
"point onto surface failed.");
1452
projector.LowerDistanceParameters(u, v);
1453
BRepAdaptor_Surface surf(face);
1454
BRepLProp_SLProps prop(surf, u, v, 1, Precision::Confusion());
1456
Standard_Boolean done;
1458
Tools::getNormal(face, u, v, Precision::Confusion(), SketchNormal, done);
1461
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: finding normal "
1462
"to surface at projected point failed.");
1466
if (prop.IsTangentUDefined()) {
1467
prop.TangentU(dirX);
1468
if (face.Orientation() == TopAbs_REVERSED) {
1475
prop.TangentV(dirY);
1476
dirX = dirY.Crossed(SketchNormal);
1479
SketchXAxis = gp_Vec(dirX).Reversed();
1482
SketchBasePoint = p;
1485
SketchBasePoint = projector.NearestPoint();
1488
case mmNormalToPath:
1492
case mmRevolutionSection:
1493
case mmConcentric: {
1494
if (shapes.empty()) {
1495
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: no subshapes "
1496
"specified (need one edge, and an optional vertex).");
1499
bool bThruVertex = false;
1500
if (shapes[0]->ShapeType() == TopAbs_VERTEX && shapes.size() >= 2) {
1501
std::swap(shapes[0], shapes[1]);
1507
path = TopoDS::Edge(*(shapes[0]));
1511
if (path.IsNull()) {
1512
throw Base::ValueError(
1513
"Null path in AttachEngine3D::calculateAttachedPlacement()!");
1516
BRepAdaptor_Curve adapt(path);
1519
double u1 = adapt.FirstParameter();
1520
double u2 = adapt.LastParameter();
1521
if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) {
1531
if (shapes.size() >= 2) {
1532
TopoDS_Vertex vertex;
1534
vertex = TopoDS::Vertex(*(shapes[1]));
1538
if (vertex.IsNull()) {
1539
throw Base::ValueError(
1540
"Null vertex in AttachEngine3D::calculateAttachedPlacement()!");
1542
p_in = BRep_Tool::Pnt(vertex);
1544
Handle(Geom_Curve) hCurve = BRep_Tool::Curve(path, u1, u2);
1546
GeomAPI_ProjectPointOnCurve projector(p_in, hCurve);
1547
u = projector.LowerDistanceParameter();
1550
u = u1 + this->attachParameter * (u2 - u1);
1556
if (d.Magnitude() < Precision::Confusion()) {
1557
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: path curve "
1558
"derivative is below 1e-7, too low, can't align");
1564
SketchBasePoint = p_in;
1567
SketchBasePoint = p;
1570
if (mmode == mmRevolutionSection || mmode == mmConcentric || mmode == mmFrenetNB
1571
|| mmode == mmFrenetTN || mmode == mmFrenetTB) {
1574
adapt.D2(u, p, d, dd);
1576
catch (Standard_Failure& e) {
1578
dd = gp_Vec(0., 0., 0.);
1579
Base::Console().Warning("AttachEngine3D::calculateAttachedPlacement: can't "
1580
"calculate second derivative of curve. OCC error: %s\n",
1581
e.GetMessageString());
1587
T.Multiplied(dd.Dot(T)));
1588
if (N.Magnitude() > Precision::SquareConfusion()) {
1593
Base::Console().Warning(
1594
"AttachEngine3D::calculateAttachedPlacement: path curve second derivative "
1595
"is below 1e-14, can't align x axis.\n");
1596
N = gp_Vec(0., 0., 0.);
1597
B = gp_Vec(0., 0., 0.);
1603
case mmRevolutionSection:
1604
SketchNormal = T.Reversed();
1606
SketchXAxis = N.Reversed();
1610
if (N.Magnitude() == 0.0) {
1611
throw Base::ValueError(
1612
"AttachEngine3D::calculateAttachedPlacement: Frenet-Serret normal "
1613
"is undefined. Can't align to TN plane.");
1619
if (N.Magnitude() == 0.0) {
1620
throw Base::ValueError(
1621
"AttachEngine3D::calculateAttachedPlacement: Frenet-Serret normal "
1622
"is undefined. Can't align to TB plane.");
1624
SketchNormal = N.Reversed();
1631
if (mmode == mmRevolutionSection || mmode == mmConcentric) {
1633
if (N.Magnitude() == 0.0) {
1634
throw Base::ValueError(
1635
"AttachEngine3D::calculateAttachedPlacement: path has infinite radius "
1636
"of curvature at the point. Can't align for revolving.");
1638
double curvature = dd.Dot(N) / pow(d.Magnitude(), 2);
1640
pv.Add(N.Multiplied(
1642
SketchBasePoint = gp_Pnt(pv.XYZ());
1647
else if (mmode == mmNormalToPath) {
1650
gp_Dir(d.Reversed());
1655
case mmThreePointsPlane:
1656
case mmThreePointsNormal: {
1658
std::vector<gp_Pnt> points;
1660
for (const auto & shape : shapes) {
1661
const TopoDS_Shape &sh = *shape;
1663
throw Base::ValueError(
1664
"Null shape in AttachEngine3D::calculateAttachedPlacement()!");
1666
if (sh.ShapeType() == TopAbs_VERTEX) {
1667
const TopoDS_Vertex& v = TopoDS::Vertex(sh);
1668
points.push_back(BRep_Tool::Pnt(v));
1670
else if (sh.ShapeType() == TopAbs_EDGE) {
1671
const TopoDS_Edge& e = TopoDS::Edge(sh);
1672
BRepAdaptor_Curve crv(e);
1673
double u1 = crv.FirstParameter();
1674
double u2 = crv.LastParameter();
1675
if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) {
1679
points.push_back(crv.Value(u1));
1680
points.push_back(crv.Value(u2));
1682
if (points.size() >= 3) {
1687
if (points.size() < 3) {
1688
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: less than 3 "
1689
"points are specified, cannot derive the plane.");
1692
gp_Pnt p0 = points[0];
1693
gp_Pnt p1 = points[1];
1694
gp_Pnt p2 = points[2];
1696
gp_Vec vec01(p0, p1);
1697
gp_Vec vec02(p0, p2);
1698
if (vec01.Magnitude() < Precision::Confusion()
1699
|| vec02.Magnitude() < Precision::Confusion()) {
1700
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: some of 3 "
1701
"points are coincident. Can't make a plane");
1707
if (mmode == mmThreePointsPlane) {
1708
norm = vec01.Crossed(vec02);
1709
if (norm.Magnitude() < Precision::Confusion()) {
1710
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: points are "
1711
"collinear. Can't make a plane");
1714
SketchBasePoint = gp_Pnt(
1715
gp_Vec(p0.XYZ()).Added(p1.XYZ()).Added(p2.XYZ()).Multiplied(1.0 / 3.0).XYZ());
1717
else if (mmode == mmThreePointsNormal) {
1718
norm = vec02.Subtracted(vec01.Multiplied(vec02.Dot(vec01)))
1720
if (norm.Magnitude() < Precision::Confusion()) {
1721
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: points are "
1722
"collinear. Can't make a plane");
1726
Handle(Geom_Plane) gPlane = new Geom_Plane(p0, gp_Dir(norm));
1727
GeomAPI_ProjectPointOnSurf projector(p2, gPlane);
1728
SketchBasePoint = projector.NearestPoint();
1732
SketchNormal = gp_Dir(norm);
1742
if (shapes.size() < 4) {
1743
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: not enough "
1744
"shapes (need 4 lines: edgeA, axisA, axisB, edgeB).");
1748
const TopoDS_Edge* edges[4];
1749
BRepAdaptor_Curve adapts[4];
1751
for (int i = 0; i < 4; i++) {
1753
edges[i] = &TopoDS::Edge(*(shapes[i]));
1757
if (edges[i]->IsNull()) {
1758
throw Base::ValueError(
1759
"Null edge in AttachEngine3D::calculateAttachedPlacement()!");
1762
adapts[i] = BRepAdaptor_Curve(*(edges[i]));
1763
if (adapts[i].GetType() != GeomAbs_Line) {
1764
throw Base::ValueError(
1765
"AttachEngine3D::calculateAttachedPlacement: Folding - non-straight edge.");
1767
lines[i] = adapts[i].Line();
1771
gp_Pnt p, p1, p2, p3, p4;
1772
double signs[4] = {0, 0, 0, 0};
1774
p1 = adapts[0].Value(adapts[0].FirstParameter());
1775
p2 = adapts[0].Value(adapts[0].LastParameter());
1776
p3 = adapts[1].Value(adapts[1].FirstParameter());
1777
p4 = adapts[1].Value(adapts[1].LastParameter());
1779
if (p1.Distance(p3) < Precision::Confusion()) {
1784
else if (p1.Distance(p4) < Precision::Confusion()) {
1789
else if (p2.Distance(p3) < Precision::Confusion()) {
1794
else if (p2.Distance(p4) < Precision::Confusion()) {
1800
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: Folding - "
1801
"edges to not share a vertex.");
1803
for (int i = 2; i < 4; i++) {
1804
p1 = adapts[i].Value(adapts[i].FirstParameter());
1805
p2 = adapts[i].Value(adapts[i].LastParameter());
1806
if (p.Distance(p1) < Precision::Confusion()) {
1809
else if (p.Distance(p2) < Precision::Confusion()) {
1813
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: Folding - "
1814
"edges to not share a vertex.");
1819
for (int i = 0; i < 4; i++) {
1820
assert(fabs(signs[i]) == 1.0);
1821
dirs[i] = gp_Vec(lines[i].Direction()).Multiplied(signs[i]);
1824
double ang = this->calculateFoldAngle(dirs[1], dirs[2], dirs[0], dirs[3]);
1826
gp_Vec norm = dirs[1].Crossed(dirs[2]);
1829
norm.Rotate(gp_Ax1(gp_Pnt(), gp_Dir(dirs[1])), -ang);
1830
SketchNormal = norm.Reversed();
1832
SketchXAxis = dirs[1];
1834
SketchBasePoint = p;
1843
const char orderStrings[6][4] = {
1851
const char* orderString = orderStrings[mmode - mmOZX];
1860
for (int i = 0; i < 3; ++i) {
1861
order[i] = orderString[i] - 'X';
1864
if (shapes.size() < 2) {
1865
THROWM(Base::ValueError,
1866
"AttachEngine3D::calculateAttachedPlacement: not enough shapes linked (at "
1867
"least two are required).");
1873
if (shapes[0]->IsNull()) {
1874
THROWM(Base::TypeError, "AttachEngine3D::calculateAttachedPlacement: null shape!")
1876
if (shapes[0]->ShapeType() != TopAbs_VERTEX) {
1877
THROWM(Base::TypeError,
1878
"AttachEngine3D::calculateAttachedPlacement: first reference must be a "
1881
SketchBasePoint = BRep_Tool::Pnt(TopoDS::Vertex(*(shapes[0])));
1884
for (size_t i = 1; i < 3 && i < shapes.size(); ++i) {
1885
if (shapes[i]->IsNull()) {
1886
THROWM(Base::TypeError,
1887
"AttachEngine3D::calculateAttachedPlacement: null shape!")
1889
if (shapes[i]->ShapeType() == TopAbs_VERTEX) {
1890
gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(*(shapes[i])));
1891
dirs[order[i - 1]] = gp_Vec(SketchBasePoint, p);
1893
else if (shapes[i]->ShapeType() == TopAbs_EDGE) {
1894
const TopoDS_Edge& e = TopoDS::Edge(*(shapes[i]));
1895
BRepAdaptor_Curve crv(e);
1896
double u1 = crv.FirstParameter();
1897
double u2 = crv.LastParameter();
1898
if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) {
1902
gp_Pnt p1 = crv.Value(u1);
1903
gp_Pnt p2 = crv.Value(u2);
1904
dirs[order[i - 1]] = gp_Vec(p1, p2);
1909
Base::Rotation rot = Base::Rotation::makeRotationByAxes(
1910
Base::Vector3d(dirs[0].X(), dirs[0].Y(), dirs[0].Z()),
1911
Base::Vector3d(dirs[1].X(), dirs[1].Y(), dirs[1].Z()),
1912
Base::Vector3d(dirs[2].X(), dirs[2].Y(), dirs[2].Z()),
1914
if (this->mapReverse) {
1915
rot = rot * Base::Rotation(Base::Vector3d(0, 1, 0), D_PI);
1918
Base::Placement plm = Base::Placement(
1919
Base::Vector3d(SketchBasePoint.X(), SketchBasePoint.Y(), SketchBasePoint.Z()),
1921
plm *= this->attachmentOffset;
1925
throwWrongMode(mmode);
1930
Base::Placement plm =
1931
this->placementFactory(SketchNormal,
1938
mmode == mmFlatFace,
1940
plm *= this->attachmentOffset;
1944
double AttachEngine3D::calculateFoldAngle(gp_Vec axA, gp_Vec axB, gp_Vec edA, gp_Vec edB) const
1954
gp_Vec norm = axA.Crossed(axB);
1955
if (norm.Magnitude() < Precision::Confusion())
1956
throw AttachEngineException("calculateFoldAngle: Folding axes are parallel, folding angle cannot be computed.");
1958
double a = edA.Dot(axA);
1959
double ra = edA.Crossed(axA).Magnitude();
1960
if (fabs(ra) < Precision::Confusion())
1961
throw AttachEngineException("calculateFoldAngle: axisA and edgeA are parallel, folding can't be computed.");
1962
double b = edB.Dot(axB);
1963
double costheta = axB.Dot(axA);
1964
double sintheta = axA.Crossed(axB).Dot(norm);
1965
double singama = -costheta;
1966
double cosgama = sintheta;
1967
double k = b*cosgama;
1968
double l = a + b*singama;
1969
double xa = k + l*singama/cosgama;
1970
double cos_unfold = -xa/ra;
1971
if (fabs(cos_unfold)>0.999)
1972
throw AttachEngineException("calculateFoldAngle: cosine of folding angle is too close to or above 1.");
1973
return acos(cos_unfold);
1979
TYPESYSTEM_SOURCE(Attacher::AttachEnginePlane, Attacher::AttachEngine)
1981
AttachEnginePlane::AttachEnginePlane()
1984
AttachEngine3D attacher3D;
1985
this->modeRefTypes = attacher3D.modeRefTypes;
1986
this->EnableAllSupportedModes();
1989
AttachEnginePlane *AttachEnginePlane::copy() const
1991
AttachEnginePlane* p = new AttachEnginePlane;
1996
Base::Placement AttachEnginePlane::_calculateAttachedPlacement(
1997
const std::vector<App::DocumentObject*>&objs,
1998
const std::vector<std::string> &subs,
1999
const Base::Placement &origPlacement) const
2002
Base::Placement plm;
2003
AttachEngine3D attacher3D;
2004
attacher3D.setUp(*this);
2005
plm = attacher3D._calculateAttachedPlacement(objs,subs,origPlacement);
2011
TYPESYSTEM_SOURCE(Attacher::AttachEngineLine, Attacher::AttachEngine)
2013
AttachEngineLine::AttachEngineLine()
2016
modeRefTypes.resize(mmDummy_NumberOfModes);
2020
AttachEngine3D attacher3D;
2021
modeRefTypes[mm1AxisX] = attacher3D.modeRefTypes[mmObjectYZ];
2022
modeRefTypes[mm1AxisY] = attacher3D.modeRefTypes[mmObjectXZ];
2023
modeRefTypes[mm1AxisZ] = attacher3D.modeRefTypes[mmObjectXY];
2024
modeRefTypes[mm1AxisCurv] = attacher3D.modeRefTypes[mmRevolutionSection];
2025
modeRefTypes[mm1Binormal] = attacher3D.modeRefTypes[mmFrenetTN];
2026
modeRefTypes[mm1Normal] = attacher3D.modeRefTypes[mmFrenetTB];
2027
modeRefTypes[mm1Tangent] = attacher3D.modeRefTypes[mmNormalToPath];
2029
modeRefTypes[mm1TwoPoints].push_back(cat(rtVertex,rtVertex));
2030
modeRefTypes[mm1TwoPoints].push_back(cat(rtLine));
2032
modeRefTypes[mm1Asymptote1].push_back(cat(rtHyperbola));
2033
modeRefTypes[mm1Asymptote2].push_back(cat(rtHyperbola));
2035
modeRefTypes[mm1Directrix1].push_back(cat(rtConic));
2037
modeRefTypes[mm1Directrix2].push_back(cat(rtEllipse));
2038
modeRefTypes[mm1Directrix2].push_back(cat(rtHyperbola));
2040
modeRefTypes[mm1Proximity].push_back(cat(rtAnything, rtAnything));
2042
modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything));
2043
modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything,rtAnything));
2044
modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything,rtAnything,rtAnything));
2045
modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything,rtAnything,rtAnything,rtAnything));
2046
modeRefTypes[mm1AxisInertia2] = modeRefTypes[mm1AxisInertia1];
2047
modeRefTypes[mm1AxisInertia3] = modeRefTypes[mm1AxisInertia1];
2049
modeRefTypes[mm1FaceNormal] = attacher3D.modeRefTypes[mmTangentPlane];
2051
modeRefTypes[mm1Intersection].push_back(cat(rtFace,rtFace));
2053
this->EnableAllSupportedModes();
2056
AttachEngineLine *AttachEngineLine::copy() const
2058
AttachEngineLine* p = new AttachEngineLine;
2064
AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObject*>& objs,
2065
const std::vector<std::string>& subs,
2066
const Base::Placement& origPlacement) const
2068
eMapMode mmode = this->mapMode;
2071
bool bReUsed = true;
2072
Base::Placement presuperPlacement;
2075
throw ExceptionCancel();
2087
mmode = mmRevolutionSection;
2089
presuperPlacement.setRotation(
2090
Base::Rotation(Base::Vector3d(0.0, 0.0, 1.0), Base::Vector3d(0.0, 1.0, 0.0)));
2099
mmode = mmNormalToPath;
2102
mmode = mmTangentPlane;
2109
Base::Placement plm;
2111
std::vector<App::GeoFeature*> parts;
2112
std::vector<const TopoDS_Shape*> shapes;
2113
std::vector<TopoDS_Shape> copiedShapeStorage;
2114
std::vector<eRefType> types;
2115
readLinks(objs, subs, parts, shapes, copiedShapeStorage, types);
2117
if (parts.empty()) {
2118
throw ExceptionCancel();
2123
gp_Pnt refOrg(0.0, 0.0, 0.0);
2124
Base::Placement Place = parts[0]->Placement.getValue();
2125
refOrg = gp_Pnt(Place.getPosition().x, Place.getPosition().y, Place.getPosition().z);
2130
gp_Pnt LineBasePoint;
2134
case mm1AxisInertia1:
2135
case mm1AxisInertia2:
2136
case mm1AxisInertia3: {
2137
GProp_GProps gpr = AttachEngine::getInertialPropsOfShape(shapes);
2138
LineBasePoint = gpr.CentreOfMass();
2139
GProp_PrincipalProps pr = gpr.PrincipalProperties();
2140
if (pr.HasSymmetryPoint()) {
2141
throw Base::ValueError(
2142
"AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia "
2143
"tensor is trivial, principal axes are undefined.");
2149
Standard_Real I1, I2, I3;
2150
pr.Moments(I1, I2, I3);
2151
Standard_Real d12, d23, d31;
2152
d12 = fabs(I1 - I2);
2153
d23 = fabs(I2 - I3);
2154
d31 = fabs(I3 - I1);
2156
if (mmode == mm1AxisInertia1) {
2157
LineDir = pr.FirstAxisOfInertia();
2158
if (pr.HasSymmetryAxis() && !(d23 < d31 && d23 < d12)) {
2159
throw Base::ValueError(
2160
"AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia "
2161
"tensor has axis of symmetry; first axis of inertia is undefined.");
2164
else if (mmode == mm1AxisInertia2) {
2165
LineDir = pr.SecondAxisOfInertia();
2166
if (pr.HasSymmetryAxis() && !(d31 < d12 && d31 < d23)) {
2167
throw Base::ValueError(
2168
"AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia "
2169
"tensor has axis of symmetry; second axis of inertia is undefined.");
2172
else if (mmode == mm1AxisInertia3) {
2173
LineDir = pr.ThirdAxisOfInertia();
2174
if (pr.HasSymmetryAxis() && !(d12 < d23 && d12 < d31)) {
2175
throw Base::ValueError(
2176
"AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia "
2177
"tensor has axis of symmetry; third axis of inertia is undefined.");
2181
case mm1TwoPoints: {
2182
std::vector<gp_Pnt> points;
2184
for (const auto & shape : shapes) {
2185
const TopoDS_Shape &sh = *shape;
2187
throw Base::ValueError(
2188
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
2190
if (sh.ShapeType() == TopAbs_VERTEX) {
2191
const TopoDS_Vertex& v = TopoDS::Vertex(sh);
2192
points.push_back(BRep_Tool::Pnt(v));
2194
else if (sh.ShapeType() == TopAbs_EDGE) {
2195
const TopoDS_Edge& e = TopoDS::Edge(sh);
2196
BRepAdaptor_Curve crv(e);
2197
double u1 = crv.FirstParameter();
2198
double u2 = crv.LastParameter();
2199
if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) {
2203
points.push_back(crv.Value(u1));
2204
points.push_back(crv.Value(u2));
2206
if (points.size() >= 2) {
2211
if (points.size() < 2) {
2212
throw Base::ValueError("AttachEngineLine::calculateAttachedPlacement: less "
2213
"than 2 points are specified, cannot derive the line.");
2216
gp_Pnt p0 = points[0];
2217
gp_Pnt p1 = points[1];
2219
LineDir = gp_Dir(gp_Vec(p0, p1));
2224
case mm1Asymptote2: {
2225
if (shapes[0]->IsNull()) {
2226
throw Base::ValueError(
2227
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
2231
e = TopoDS::Edge(*(shapes[0]));
2236
throw Base::ValueError(
2237
"Null edge in AttachEngineLine::calculateAttachedPlacement()!");
2239
BRepAdaptor_Curve adapt(e);
2240
if (adapt.GetType() != GeomAbs_Hyperbola) {
2241
throw Base::ValueError(
2242
"AttachEngineLine::calculateAttachedPlacement: Asymptotes are available "
2243
"only for hyperbola-shaped edges, the one supplied is not.");
2245
gp_Hypr hyp = adapt.Hyperbola();
2246
if (mmode == mm1Asymptote1) {
2247
LineDir = hyp.Asymptote1().Direction();
2250
LineDir = hyp.Asymptote2().Direction();
2252
LineBasePoint = hyp.Location();
2255
case mm1Directrix2: {
2256
if (shapes[0]->IsNull()) {
2257
throw Base::ValueError(
2258
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
2262
e = TopoDS::Edge(*(shapes[0]));
2267
throw Base::ValueError(
2268
"Null edge in AttachEngineLine::calculateAttachedPlacement()!");
2270
BRepAdaptor_Curve adapt(e);
2272
switch (adapt.GetType()) {
2273
case GeomAbs_Ellipse: {
2274
gp_Elips cc = adapt.Ellipse();
2275
dx1 = cc.Directrix1();
2276
dx2 = cc.Directrix2();
2278
case GeomAbs_Hyperbola: {
2279
gp_Hypr cc = adapt.Hyperbola();
2280
dx1 = cc.Directrix1();
2281
dx2 = cc.Directrix2();
2283
case GeomAbs_Parabola: {
2284
gp_Parab cc = adapt.Parabola();
2285
dx1 = cc.Directrix();
2286
if (mmode == mm1Directrix2) {
2287
throw Base::ValueError("AttachEngineLine::calculateAttachedPlacement: "
2288
"Parabola has no second directrix");
2292
throw Base::ValueError(
2293
"AttachEngineLine::calculateAttachedPlacement: referenced edge is not "
2294
"a conic section with a directrix");
2296
if (mmode == mm1Directrix1) {
2297
LineDir = dx1.Direction();
2298
LineBasePoint = dx1.Location();
2301
LineDir = dx2.Direction();
2302
LineBasePoint = dx2.Location();
2305
case mm1Intersection: {
2306
if (shapes.size() < 2) {
2307
throw Base::ValueError(
2308
"AttachEngineLine::calculateAttachedPlacement: Intersection mode requires "
2309
"two shapes; only one is supplied");
2311
if (shapes[0]->IsNull() || shapes[1]->IsNull()) {
2312
throw Base::ValueError(
2313
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
2316
const TopoDS_Face& face1 = TopoDS::Face(*(shapes[0]));
2317
const TopoDS_Face& face2 = TopoDS::Face(*(shapes[1]));
2319
Handle(Geom_Surface) hSurf1 = BRep_Tool::Surface(face1);
2320
Handle(Geom_Surface) hSurf2 = BRep_Tool::Surface(face2);
2321
GeomAPI_IntSS intersector(hSurf1, hSurf2, Precision::Confusion());
2322
if (!intersector.IsDone()) {
2323
throw Base::ValueError(
2324
"AttachEngineLine::calculateAttachedPlacement: Intersection failed");
2327
const Standard_Integer intLines = intersector.NbLines();
2328
if (intLines == 0) {
2329
throw Base::ValueError("AttachEngineLine::calculateAttachedPlacement: The two "
2330
"shapes don't intersect");
2332
if (intLines != 1) {
2333
throw Base::ValueError("AttachEngineLine::calculateAttachedPlacement: "
2334
"Intersection is not a single curve");
2337
GeomAdaptor_Curve adapt(intersector.Line(1));
2338
if (adapt.GetType() != GeomAbs_Line) {
2339
throw Base::ValueError("AttachEngineLine::calculateAttachedPlacement: "
2340
"Intersection is not a straight line");
2343
LineBasePoint = adapt.Line().Location();
2344
LineDir = adapt.Line().Direction();
2346
case mm1Proximity: {
2347
if (shapes.size() < 2) {
2348
throw Base::ValueError(
2349
"AttachEngineLine::calculateAttachedPlacement: Proximity mode requires two "
2350
"shapes; only one is supplied");
2352
if (shapes[0]->IsNull()) {
2353
throw Base::ValueError(
2354
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
2356
if (shapes[1]->IsNull()) {
2357
throw Base::ValueError(
2358
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
2360
BRepExtrema_DistShapeShape distancer(*(shapes[0]), *(shapes[1]));
2361
if (!distancer.IsDone()) {
2362
throw Base::ValueError("AttachEngineLine::calculateAttachedPlacement: "
2363
"proximity calculation failed.");
2365
if (distancer.NbSolution() > 1) {
2366
Base::Console().Warning("AttachEngineLine::calculateAttachedPlacement: "
2367
"proximity calculation gave %i solutions, ambiguous.\n",
2368
int(distancer.NbSolution()));
2370
gp_Pnt p1 = distancer.PointOnShape1(1);
2371
gp_Pnt p2 = distancer.PointOnShape2(1);
2373
gp_Vec dist = gp_Vec(p1, p2);
2374
if (dist.Magnitude() < Precision::Confusion()) {
2375
throw Base::ValueError(
2376
"AttachEngineLine::calculateAttachedPlacement: can't make proximity line, "
2377
"because shapes touch or intersect");
2379
LineDir = gp_Dir(dist);
2382
throwWrongMode(mmode);
2385
plm = this->placementFactory(LineDir,
2392
AttachEngine3D attacher3D;
2393
attacher3D.setUp(*this);
2394
attacher3D.mapMode = mmode;
2395
attacher3D.attachmentOffset =
2398
plm = attacher3D._calculateAttachedPlacement(objs, subs, origPlacement);
2399
plm *= presuperPlacement;
2401
plm *= this->attachmentOffset;
2408
TYPESYSTEM_SOURCE(Attacher::AttachEnginePoint, Attacher::AttachEngine)
2410
AttachEnginePoint::AttachEnginePoint()
2413
modeRefTypes.resize(mmDummy_NumberOfModes);
2417
AttachEngine3D attacher3D;
2418
modeRefTypes[mm0Origin] = attacher3D.modeRefTypes[mmObjectXY];
2419
modeRefTypes[mm0CenterOfCurvature] = attacher3D.modeRefTypes[mmRevolutionSection];
2420
modeRefTypes[mm0OnEdge] = attacher3D.modeRefTypes[mmNormalToPath];
2422
modeRefTypes[mm0Vertex].push_back(cat(rtVertex));
2423
modeRefTypes[mm0Vertex].push_back(cat(rtLine));
2425
modeRefTypes[mm0Focus1].push_back(cat(rtConic));
2427
modeRefTypes[mm0Focus2].push_back(cat(rtEllipse));
2428
modeRefTypes[mm0Focus2].push_back(cat(rtHyperbola));
2430
s = cat(rtAnything, rtAnything);
2431
modeRefTypes[mm0ProximityPoint1].push_back(s);
2432
modeRefTypes[mm0ProximityPoint2].push_back(s);
2434
modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything));
2435
modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything,rtAnything));
2436
modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything,rtAnything,rtAnything));
2437
modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything,rtAnything,rtAnything,rtAnything));
2439
this->EnableAllSupportedModes();
2442
AttachEnginePoint *AttachEnginePoint::copy() const
2444
AttachEnginePoint* p = new AttachEnginePoint;
2450
AttachEnginePoint::_calculateAttachedPlacement(const std::vector<App::DocumentObject*>& objs,
2451
const std::vector<std::string>& subs,
2452
const Base::Placement& origPlacement) const
2454
eMapMode mmode = this->mapMode;
2457
bool bReUsed = true;
2460
throw ExceptionCancel();
2465
case mm0CenterOfCurvature:
2466
mmode = mmRevolutionSection;
2470
mmode = mmNormalToPath;
2476
Base::Placement plm;
2478
std::vector<App::GeoFeature*> parts;
2479
std::vector<const TopoDS_Shape*> shapes;
2480
std::vector<TopoDS_Shape> copiedShapeStorage;
2481
std::vector<eRefType> types;
2482
readLinks(objs, subs, parts, shapes, copiedShapeStorage, types);
2484
if (parts.empty()) {
2485
throw ExceptionCancel();
2496
std::vector<gp_Pnt> points;
2497
assert(!shapes.empty());
2499
const TopoDS_Shape& sh = *shapes[0];
2501
throw Base::ValueError(
2502
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
2504
if (sh.ShapeType() == TopAbs_VERTEX) {
2505
const TopoDS_Vertex& v = TopoDS::Vertex(sh);
2506
BasePoint = BRep_Tool::Pnt(v);
2508
else if (sh.ShapeType() == TopAbs_EDGE) {
2509
const TopoDS_Edge& e = TopoDS::Edge(sh);
2510
BRepAdaptor_Curve crv(e);
2511
double u = crv.FirstParameter();
2512
if (Precision::IsInfinite(u)) {
2513
throw Base::ValueError("Edge is infinite");
2515
BasePoint = crv.Value(u);
2521
if (shapes[0]->IsNull()) {
2522
throw Base::ValueError(
2523
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
2527
e = TopoDS::Edge(*(shapes[0]));
2532
throw Base::ValueError(
2533
"Null edge in AttachEnginePoint::calculateAttachedPlacement()!");
2535
BRepAdaptor_Curve adapt(e);
2537
switch (adapt.GetType()) {
2538
case GeomAbs_Ellipse: {
2539
gp_Elips cc = adapt.Ellipse();
2543
case GeomAbs_Hyperbola: {
2544
gp_Hypr cc = adapt.Hyperbola();
2548
case GeomAbs_Parabola: {
2549
gp_Parab cc = adapt.Parabola();
2551
if (mmode == mm0Focus2) {
2552
throw Base::ValueError("AttachEnginePoint::calculateAttachedPlacement: "
2553
"Parabola has no second focus");
2557
throw Base::ValueError(
2558
"AttachEnginePoint::calculateAttachedPlacement: referenced edge is not "
2559
"a conic section with a directrix");
2561
if (mmode == mm0Focus1) {
2568
case mm0ProximityPoint1:
2569
case mm0ProximityPoint2: {
2570
if (shapes.size() < 2) {
2571
throw Base::ValueError(
2572
"AttachEnginePoint::calculateAttachedPlacement: Proximity mode requires "
2573
"two shapes; only one is supplied");
2575
if (shapes[0]->IsNull()) {
2576
throw Base::ValueError(
2577
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
2579
if (shapes[1]->IsNull()) {
2580
throw Base::ValueError(
2581
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
2584
BasePoint = getProximityPoint(mmode, *(shapes[0]), *(shapes[1]));
2586
case mm0CenterOfMass: {
2587
GProp_GProps gpr = AttachEngine::getInertialPropsOfShape(shapes);
2588
BasePoint = gpr.CentreOfMass();
2591
throwWrongMode(mmode);
2594
plm = this->placementFactory(gp_Vec(0.0, 0.0, 1.0),
2595
gp_Vec(1.0, 0.0, 0.0),
2600
AttachEngine3D attacher3D;
2601
attacher3D.setUp(*this);
2602
attacher3D.mapMode = mmode;
2603
attacher3D.attachmentOffset =
2606
plm = attacher3D._calculateAttachedPlacement(objs, subs, origPlacement);
2608
plm *= this->attachmentOffset;
2612
gp_Pnt AttachEnginePoint::getProximityPoint(eMapMode mmode, const TopoDS_Shape& s1, const TopoDS_Shape& s2) const
2621
TopoDS_Shape face, edge;
2622
if (s1.ShapeType() == TopAbs_FACE &&
2623
s2.ShapeType() == TopAbs_EDGE) {
2627
else if (s1.ShapeType() == TopAbs_EDGE &&
2628
s2.ShapeType() == TopAbs_FACE) {
2634
if (!edge.IsNull() && !face.IsNull()) {
2636
BRepAdaptor_Curve crv(TopoDS::Edge(edge));
2638
GeomAdaptor_Curve typedcrv;
2647
typedcrv.Load(GeomAdaptor::MakeCurve(crv));
2649
catch (const Standard_DomainError&) {
2650
Handle(Geom_Curve) curve = crv.Curve().Curve();
2651
if (curve.IsNull()) {
2653
typedcrv = crv.Curve();
2656
curve = Handle(Geom_Curve)::DownCast(curve->Copy());
2657
curve->Transform(crv.Trsf());
2658
typedcrv.Load(curve);
2662
BRepIntCurveSurface_Inter intCS;
2663
intCS.Init(face, typedcrv, Precision::Confusion());
2664
std::vector<gp_Pnt> points;
2665
for (; intCS.More(); intCS.Next()) {
2666
gp_Pnt pnt = intCS.Pnt();
2667
points.push_back(pnt);
2670
if (points.size() > 1)
2671
Base::Console().Warning("AttachEnginePoint::calculateAttachedPlacement: proximity calculation gave %d solutions, ambiguous.\n", int(points.size()));
2675
if (!points.empty())
2676
return points.front();
2679
catch (const Standard_Failure&) {
2683
BRepExtrema_DistShapeShape distancer (s1, s2);
2684
if (!distancer.IsDone())
2685
throw Base::ValueError("AttachEnginePoint::calculateAttachedPlacement: proximity calculation failed.");
2686
if (distancer.NbSolution() > 1)
2687
Base::Console().Warning("AttachEnginePoint::calculateAttachedPlacement: proximity calculation gave %i solutions, ambiguous.\n",int(distancer.NbSolution()));
2689
gp_Pnt p1 = distancer.PointOnShape1(1);
2690
gp_Pnt p2 = distancer.PointOnShape2(1);
2691
if (mmode == mm0ProximityPoint1)