//this routine is the big time consumer. gets called many times (and is slow?)) //note param gets modified here bool DrawProjectSplit::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds) { bool result = false; bool outOfBox = false; param = -2; //eliminate obvious cases Bnd_Box sBox; BRepBndLib::Add(e, sBox); sBox.SetGap(0.1); if (sBox.IsVoid()) { Base::Console().Message("DPS::isOnEdge - Bnd_Box is void\n"); } else { gp_Pnt pt = BRep_Tool::Pnt(v); if (sBox.IsOut(pt)) { outOfBox = true; } } if (!outOfBox) { double dist = DrawUtil::simpleMinDist(v,e); if (dist < 0.0) { Base::Console().Error("DPS::isOnEdge - simpleMinDist failed: %.3f\n",dist); result = false; } else if (dist < Precision::Confusion()) { const gp_Pnt pt = BRep_Tool::Pnt(v); //have to duplicate method 3 to get param BRepAdaptor_Curve adapt(e); const Handle_Geom_Curve c = adapt.Curve().Curve(); double maxDist = 0.000001; //magic number. less than this gives false positives. //bool found = (void) GeomLib_Tool::Parameter(c,pt,maxDist,param); //already know point it on curve result = true; } if (result) { TopoDS_Vertex v1 = TopExp::FirstVertex(e); TopoDS_Vertex v2 = TopExp::LastVertex(e); if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) { if (!allowEnds) { result = false; } } } } //!outofbox return result; }
//! get the projected edges with all their new intersections. std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDrawGeometry::GeometryObject* geometryObject) { const std::vector<TechDrawGeometry::BaseGeom*>& goEdges = geometryObject->getVisibleFaceEdges(true,true); std::vector<TechDrawGeometry::BaseGeom*>::const_iterator itEdge = goEdges.begin(); std::vector<TopoDS_Edge> origEdges; for (;itEdge != goEdges.end(); itEdge++) { origEdges.push_back((*itEdge)->occEdge); } std::vector<TopoDS_Edge> faceEdges; std::vector<TopoDS_Edge> nonZero; for (auto& e:origEdges) { //drop any zero edges (shouldn't be any by now!!!) if (!DrawUtil::isZeroEdge(e)) { nonZero.push_back(e); } else { Base::Console().Message("INFO - DPS::getEdges found ZeroEdge!\n"); } } faceEdges = nonZero; origEdges = nonZero; //HLR algo does not provide all edge intersections for edge endpoints. //need to split long edges touched by Vertex of another edge std::vector<splitPoint> splits; std::vector<TopoDS_Edge>::iterator itOuter = origEdges.begin(); int iOuter = 0; for (; itOuter != origEdges.end(); ++itOuter, iOuter++) { TopoDS_Vertex v1 = TopExp::FirstVertex((*itOuter)); TopoDS_Vertex v2 = TopExp::LastVertex((*itOuter)); Bnd_Box sOuter; BRepBndLib::Add(*itOuter, sOuter); sOuter.SetGap(0.1); if (sOuter.IsVoid()) { Base::Console().Message("DPS::Extract Faces - outer Bnd_Box is void\n"); continue; } if (DrawUtil::isZeroEdge(*itOuter)) { Base::Console().Message("DPS::extractFaces - outerEdge: %d is ZeroEdge\n",iOuter); //this is not finding ZeroEdges continue; //skip zero length edges. shouldn't happen ;) } int iInner = 0; std::vector<TopoDS_Edge>::iterator itInner = faceEdges.begin(); for (; itInner != faceEdges.end(); ++itInner,iInner++) { if (iInner == iOuter) { continue; } if (DrawUtil::isZeroEdge((*itInner))) { continue; //skip zero length edges. shouldn't happen ;) } Bnd_Box sInner; BRepBndLib::Add(*itInner, sInner); sInner.SetGap(0.1); if (sInner.IsVoid()) { Base::Console().Log("INFO - DPS::Extract Faces - inner Bnd_Box is void\n"); continue; } if (sOuter.IsOut(sInner)) { //bboxes of edges don't intersect, don't bother continue; } double param = -1; if (isOnEdge((*itInner),v1,param,false)) { gp_Pnt pnt1 = BRep_Tool::Pnt(v1); splitPoint s1; s1.i = iInner; s1.v = Base::Vector3d(pnt1.X(),pnt1.Y(),pnt1.Z()); s1.param = param; splits.push_back(s1); } if (isOnEdge((*itInner),v2,param,false)) { gp_Pnt pnt2 = BRep_Tool::Pnt(v2); splitPoint s2; s2.i = iInner; s2.v = Base::Vector3d(pnt2.X(),pnt2.Y(),pnt2.Z()); s2.param = param; splits.push_back(s2); } } //inner loop } //outer loop std::vector<splitPoint> sorted = sortSplits(splits,true); auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual); //duplicates to back sorted.erase(last, sorted.end()); //remove dupls std::vector<TopoDS_Edge> newEdges = splitEdges(faceEdges,sorted); if (newEdges.empty()) { Base::Console().Log("LOG - DPS::extractFaces - no newEdges\n"); } newEdges = removeDuplicateEdges(newEdges); return newEdges; }
//this routine is the big time consumer. gets called many times (and is slow?)) //note param gets modified here bool DrawViewPart::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds) { bool result = false; bool outOfBox = false; param = -2; //eliminate obvious cases Bnd_Box sBox; BRepBndLib::Add(e, sBox); sBox.SetGap(0.1); if (sBox.IsVoid()) { Base::Console().Message("DVP::isOnEdge - Bnd_Box is void for %s\n",getNameInDocument()); } else { gp_Pnt pt = BRep_Tool::Pnt(v); if (sBox.IsOut(pt)) { outOfBox = true; } } if (!outOfBox) { if (m_interAlgo == 1) { //1) using projPointOnCurve. roughly similar to dist to shape w/ bndbox. hangs(?) w/o bndbox try { gp_Pnt pt = BRep_Tool::Pnt(v); BRepAdaptor_Curve adapt(e); Handle_Geom_Curve c = adapt.Curve().Curve(); GeomAPI_ProjectPointOnCurve proj(pt,c); int n = proj.NbPoints(); if (n > 0) { if (proj.LowerDistance() < Precision::Confusion()) { param = proj.LowerDistanceParameter(); result = true; } if (result) { TopoDS_Vertex v1 = TopExp::FirstVertex(e); TopoDS_Vertex v2 = TopExp::LastVertex(e); if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) { if (!allowEnds) { result = false; } } } } } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); //no perp projection } } else if (m_interAlgo == 2) { //can't provide param as is double dist = simpleMinDist(v,e); if (dist < 0.0) { Base::Console().Error("DVP::isOnEdge - simpleMinDist failed: %.3f\n",dist); result = false; } else if (dist < Precision::Confusion()) { const gp_Pnt pt = BRep_Tool::Pnt(v); //have to duplicate method 3 to get param BRepAdaptor_Curve adapt(e); const Handle_Geom_Curve c = adapt.Curve().Curve(); double maxDist = 0.000001; //magic number. less than this gives false positives. //bool found = (void) GeomLib_Tool::Parameter(c,pt,maxDist,param); //already know point it on curve result = true; } if (result) { TopoDS_Vertex v1 = TopExp::FirstVertex(e); TopoDS_Vertex v2 = TopExp::LastVertex(e); if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) { if (!allowEnds) { result = false; } } } } else if (m_interAlgo == 3) { const gp_Pnt pt = BRep_Tool::Pnt(v); BRepAdaptor_Curve adapt(e); const Handle_Geom_Curve c = adapt.Curve().Curve(); double par = -1; double maxDist = 0.000001; //magic number. less than this gives false positives. bool found = GeomLib_Tool::Parameter(c,pt,maxDist,par); if (found) { result = true; param = par; TopoDS_Vertex v1 = TopExp::FirstVertex(e); TopoDS_Vertex v2 = TopExp::LastVertex(e); if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) { if (!allowEnds) { result = false; } } } } } //!outofbox return result; }
//! make faces from the existing edge geometry void DrawViewPart::extractFaces() { geometryObject->clearFaceGeom(); const std::vector<TechDrawGeometry::BaseGeom*>& goEdges = geometryObject->getVisibleFaceEdges(SmoothVisible.getValue(),SeamVisible.getValue()); std::vector<TechDrawGeometry::BaseGeom*>::const_iterator itEdge = goEdges.begin(); std::vector<TopoDS_Edge> origEdges; for (;itEdge != goEdges.end(); itEdge++) { origEdges.push_back((*itEdge)->occEdge); } std::vector<TopoDS_Edge> faceEdges; std::vector<TopoDS_Edge> nonZero; for (auto& e:origEdges) { //drop any zero edges (shouldn't be any by now!!!) if (!DrawUtil::isZeroEdge(e)) { nonZero.push_back(e); } else { Base::Console().Message("INFO - DVP::extractFaces for %s found ZeroEdge!\n",getNameInDocument()); } } faceEdges = nonZero; origEdges = nonZero; //HLR algo does not provide all edge intersections for edge endpoints. //need to split long edges touched by Vertex of another edge std::vector<splitPoint> splits; std::vector<TopoDS_Edge>::iterator itOuter = origEdges.begin(); int iOuter = 0; for (; itOuter != origEdges.end(); ++itOuter, iOuter++) { TopoDS_Vertex v1 = TopExp::FirstVertex((*itOuter)); TopoDS_Vertex v2 = TopExp::LastVertex((*itOuter)); Bnd_Box sOuter; BRepBndLib::Add(*itOuter, sOuter); sOuter.SetGap(0.1); if (sOuter.IsVoid()) { Base::Console().Message("DVP::Extract Faces - outer Bnd_Box is void for %s\n",getNameInDocument()); continue; } if (DrawUtil::isZeroEdge(*itOuter)) { Base::Console().Message("DVP::extractFaces - outerEdge: %d is ZeroEdge\n",iOuter); //this is not finding ZeroEdges continue; //skip zero length edges. shouldn't happen ;) } int iInner = 0; std::vector<TopoDS_Edge>::iterator itInner = faceEdges.begin(); for (; itInner != faceEdges.end(); ++itInner,iInner++) { if (iInner == iOuter) { continue; } if (DrawUtil::isZeroEdge((*itInner))) { continue; //skip zero length edges. shouldn't happen ;) } Bnd_Box sInner; BRepBndLib::Add(*itInner, sInner); sInner.SetGap(0.1); if (sInner.IsVoid()) { Base::Console().Log("INFO - DVP::Extract Faces - inner Bnd_Box is void for %s\n",getNameInDocument()); continue; } if (sOuter.IsOut(sInner)) { //bboxes of edges don't intersect, don't bother continue; } double param = -1; if (DrawProjectSplit::isOnEdge((*itInner),v1,param,false)) { gp_Pnt pnt1 = BRep_Tool::Pnt(v1); splitPoint s1; s1.i = iInner; s1.v = Base::Vector3d(pnt1.X(),pnt1.Y(),pnt1.Z()); s1.param = param; splits.push_back(s1); } if (DrawProjectSplit::isOnEdge((*itInner),v2,param,false)) { gp_Pnt pnt2 = BRep_Tool::Pnt(v2); splitPoint s2; s2.i = iInner; s2.v = Base::Vector3d(pnt2.X(),pnt2.Y(),pnt2.Z()); s2.param = param; splits.push_back(s2); } } //inner loop } //outer loop std::vector<splitPoint> sorted = DrawProjectSplit::sortSplits(splits,true); auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual); //duplicates to back sorted.erase(last, sorted.end()); //remove dupl splits std::vector<TopoDS_Edge> newEdges = DrawProjectSplit::splitEdges(faceEdges,sorted); if (newEdges.empty()) { Base::Console().Log("LOG - DVP::extractFaces - no newEdges\n"); return; } newEdges = DrawProjectSplit::removeDuplicateEdges(newEdges); //find all the wires in the pile of faceEdges EdgeWalker ew; ew.loadEdges(newEdges); bool success = ew.perform(); if (!success) { Base::Console().Warning("DVP::extractFaces - input is not planar graph. No face detection\n"); return; } std::vector<TopoDS_Wire> fw = ew.getResultNoDups(); std::vector<TopoDS_Wire> sortedWires = ew.sortStrip(fw,true); std::vector<TopoDS_Wire>::iterator itWire = sortedWires.begin(); for (; itWire != sortedWires.end(); itWire++) { //version 1: 1 wire/face - no voids in face TechDrawGeometry::Face* f = new TechDrawGeometry::Face(); const TopoDS_Wire& wire = (*itWire); TechDrawGeometry::Wire* w = new TechDrawGeometry::Wire(wire); f->wires.push_back(w); geometryObject->addFaceGeom(f); } }
bool RoomLayoutPillarController::PreRender3D() { auto& imp_ = *ImpUPtr_; plane3df plan(0,0,0,0,1,0); auto line = GetRenderContextSPtr()->Smgr_->getSceneCollisionManager()->getRayFromScreenCoordinates(imp_.CursorIPos_); plan.getIntersectionWithLine(line.start, line.getVector(), imp_.CurrentPos_); imp_.CurrentPos_.Y = 0; gp_Pnt cursorPnt(imp_.CurrentPos_.X, imp_.CurrentPos_.Y, imp_.CurrentPos_.Z); switch (imp_.State_) { case EPilarState::EPS_SWEEPING: { if ( GetPickingODL().expired() ) { break; } auto activePilar = std::static_pointer_cast<PillarODL>(GetPickingODL().lock()); activePilar->SetSweeping(true); if ( imp_.CtrllHolding_ ) { imp_.State_ = EPilarState::EPS_MODIFY_INIT; break; } if ( imp_.LMousePressDown_ ) { auto box = activePilar->GetBaseBndBox(); auto pos = activePilar->GetTranslation(); Standard_Real xMin,xMax,yMin,yMax,zMin,zMax; box.Get(xMin, yMin, zMin, xMax, yMax, zMax); imp_.EventInfo_ = SEventPillarInfo(); imp_.EventInfo_->XLength_ = static_cast<float>(xMax-xMin); imp_.EventInfo_->YLength_ = static_cast<float>(yMax-yMin); imp_.EventInfo_->ZLength_ = static_cast<float>(zMax-zMin); imp_.EventInfo_->OffsetHeight_ = activePilar->GetOffsetHeight(); imp_.SavePos_ = imp_.CurrentPos_; imp_.State_ = EPilarState::EPS_MOUSEHOLDING; } } break; case EPilarState::EPS_MODIFY_INIT: { auto activePilar = std::static_pointer_cast<PillarODL>(GetPickingODL().lock()); activePilar->SetSweeping(true); if ( !imp_.CtrllHolding_ ) { GetRenderContextSPtr()->CursorControl_->setActiveIcon(gui::ECI_NORMAL); imp_.State_ = EPilarState::EPS_SWEEPING; imp_.CtrllHolding_ = false; break; } auto box = activePilar->GetBaseBndBox(); Standard_Real xMin,xMax,yMin,yMax,zMin,zMax; box.Get(xMin, yMin, zMin, xMax, yMax, zMax); auto modifyAlign = 100; Bnd_Box smallBox,bigBox; smallBox.Update(xMin+modifyAlign < 0 ? xMin+modifyAlign : 0, yMin+modifyAlign < 0 ? yMin+modifyAlign : 0, zMin+modifyAlign < 0 ? zMin+modifyAlign : 0, xMax-modifyAlign > 0 ? xMax-modifyAlign : 0, yMax-modifyAlign > 0 ? yMax-modifyAlign : 0, zMax-modifyAlign > 0 ? zMax-modifyAlign : 0); bigBox.Update(xMin-modifyAlign, yMin-modifyAlign, zMin-modifyAlign, xMax+modifyAlign, yMax+modifyAlign, zMax+modifyAlign); auto relationCursorPnt = cursorPnt.Transformed(activePilar->GetAbsoluteTransform().Inverted()); relationCursorPnt.SetY(0); if ( Standard_True == bigBox.IsOut(relationCursorPnt) ) { GetRenderContextSPtr()->CursorControl_->setActiveIcon(gui::ECI_NORMAL); imp_.State_ = EPilarState::EPS_SWEEPING; imp_.CtrllHolding_ = false; break; } if ( Standard_False == smallBox.IsOut(relationCursorPnt) ) { GetRenderContextSPtr()->CursorControl_->setActiveIcon(gui::ECI_NORMAL); break; } gp_Dir cursorDir = gp_Vec(gp::Origin(), relationCursorPnt); { auto rad = gp::DX().AngleWithRef(cursorDir, gp::DY()); rad = rad < 0 ? M_PI * 2 + rad : rad; auto mod = std::fmod(rad, M_PI_2); if ( mod < M_PI_4 ) { rad -= mod; } else { rad = rad - mod + M_PI_2; } cursorDir = gp::DX().Rotated(gp::OY(), rad); mod = std::fmod(rad, M_PI); if ( mod < Precision::Angular() ) { GetRenderContextSPtr()->CursorControl_->setActiveIcon(gui::ECI_SIZEWE); } else { GetRenderContextSPtr()->CursorControl_->setActiveIcon(gui::ECI_SIZENS); } } if ( imp_.LMousePressDown_ ) { auto edge = BRepBuilderAPI_MakeEdge(gp_Lin(gp::Origin().Transformed(activePilar->GetAbsoluteTransform()), cursorDir.Transformed(activePilar->GetAbsoluteTransform()))).Edge(); BRepAdaptor_Curve moveBC(edge); GeomAPI_ProjectPointOnCurve ppc(relationCursorPnt.Transformed(activePilar->GetAbsoluteTransform()), moveBC.Curve().Curve()); imp_.ModifyEdge_ = moveBC; imp_.ModifyPar_ = ppc.LowerDistanceParameter(); imp_.State_ = EPilarState::EPS_MODIFY; break; } } break; case EPilarState::EPS_MODIFY: { auto activePilar = std::static_pointer_cast<PillarODL>(GetPickingODL().lock()); activePilar->SetPicking(true); if ( imp_.LMouseLeftUp_ ) { activePilar->UpdateMesh(); imp_.State_ = EPilarState::EPS_SWEEPING; break; } GeomAPI_ProjectPointOnCurve ppcCur(cursorPnt, imp_.ModifyEdge_.Curve().Curve()); auto curPar = ppcCur.LowerDistanceParameter(); if ( std::abs(curPar - imp_.ModifyPar_) < Precision::Confusion() ) { break; } //偏移的起始点、终点(绝对) gp_Pnt fromPnt,toPnt; imp_.ModifyEdge_.D0(imp_.ModifyPar_, fromPnt); imp_.ModifyEdge_.D0(curPar, toPnt); gp_Vec moveOffset(fromPnt, toPnt); auto relationMoveOffset = moveOffset.Transformed(activePilar->GetAbsoluteTransform().Inverted()); auto modifyDir = imp_.ModifyEdge_.Line().Direction().Transformed(activePilar->GetAbsoluteTransform().Inverted()); auto modifyOffset = relationMoveOffset; { modifyOffset.SetX(modifyOffset.X() * modifyDir.X()); modifyOffset.SetY(modifyOffset.Y() * modifyDir.Y()); modifyOffset.SetZ(modifyOffset.Z() * modifyDir.Z()); } auto curPillarSize = activePilar->GetSize(); if ( Standard_False == imp_.ModifyEdge_.Line().Direction().IsEqual(gp_Dir(moveOffset), Precision::Angular()) ) {//防止大小缩成0 auto testSize = curPillarSize + modifyOffset.XYZ(); auto minSize = 100; auto alignSize = testSize - gp_XYZ(minSize,minSize,minSize); if ( alignSize.X() < Precision::Confusion() || alignSize.Y() < Precision::Confusion() || alignSize.Z() < Precision::Confusion() ) { break; } } Bnd_Box pillarBox; auto pillarBoxSize = curPillarSize + modifyOffset.XYZ(); gp_Trsf pillarTranslation,pillarRotation,pillarTransformation; { pillarBox.Update(-pillarBoxSize.X()/2, -pillarBoxSize.Y()/2, -pillarBoxSize.Z()/2, pillarBoxSize.X()/2, pillarBoxSize.Y()/2, pillarBoxSize.Z()/2); auto translation = activePilar->GetTranslation() + relationMoveOffset.XYZ()/2; pillarTranslation.SetTranslationPart(translation); pillarRotation.SetRotation(activePilar->GetRotation()); } pillarTransformation = pillarTranslation * pillarRotation; auto offsetHeight = activePilar->GetOffsetHeight(); //新的位置 gp_Pnt newPnt = gp::Origin().Transformed(pillarTransformation); //吸附距离 static auto alignDis = 200.0; //当前的吸附物体 auto alignODLs = activePilar->GetAlignList(); alignODLs.erase(std::remove_if(alignODLs.begin(), alignODLs.end(), [&pillarBox,&pillarTransformation](const BaseODLSPtr& alignODL) { if ( !alignODL ) { return true; } return alignODL->GetBaseBndBox().Distance(pillarBox.Transformed(alignODL->GetAbsoluteTransform().Inverted() * pillarTransformation)) > alignDis; }), alignODLs.end()); activePilar->SetAlignList(BaseODLList()); std::multimap<double,BaseODLSPtr> disMap; for ( auto& curODL : RootODL_.lock()->GetChildrenList() ) { if ( EODLT_PILLAR != curODL->GetType() && EODLT_WALL != curODL->GetType() ) { continue; } if ( std::find(alignODLs.begin(), alignODLs.end(), curODL) != alignODLs.end() ) { continue; } if ( EODLT_PILLAR == curODL->GetType() && curODL == activePilar ) { continue; } auto dis = curODL->GetBaseBndBox().Distance(pillarBox.Transformed(curODL->GetAbsoluteTransform().Inverted() * pillarTransformation)); if ( dis > alignDis ) { continue; } disMap.emplace(dis, curODL); } for ( auto& curODL : disMap ) { alignODLs.push_back(curODL.second); } for ( auto& curODL : alignODLs ) { auto alignTransformation = curODL->GetAbsoluteTransform(); //调整柱box的旋转 auto activeRotationPillarBox = pillarBox; { gp_Trsf tfsODL; tfsODL.SetRotation(alignTransformation.GetRotation()); activeRotationPillarBox = activeRotationPillarBox.Transformed(tfsODL.Inverted() * pillarRotation); } Bnd_Box movingBox,alignODLBox; { auto curBox = curODL->GetBaseBndBox(); Standard_Real xAlignMin,yAlignMin,zAlignMin,xAlignMax,yAlignMax,zAlignMax; curBox.Get(xAlignMin, yAlignMin, zAlignMin, xAlignMax, yAlignMax, zAlignMax); Standard_Real xPillarMin,yPillarMin,zPillarMin,xPillarMax,yPillarMax,zPillarMax; activeRotationPillarBox.Get(xPillarMin, yPillarMin, zPillarMin, xPillarMax, yPillarMax, zPillarMax); movingBox.Update(xAlignMin+xPillarMin, yAlignMin+yPillarMin, zAlignMin+zPillarMin, xAlignMax+xPillarMax, yAlignMax+yPillarMax, zAlignMax+zPillarMax); alignODLBox.Update(xAlignMin+xPillarMin-alignDis, yAlignMin+yPillarMin-alignDis, zAlignMin+zPillarMin-alignDis, xAlignMax+xPillarMax+alignDis, yAlignMax+yPillarMax+alignDis, zAlignMax+zPillarMax+alignDis); } auto inODLPnt = newPnt.Transformed(curODL->GetAbsoluteTransform().Inverted()); if ( Standard_True == alignODLBox.IsOut(inODLPnt) ) { continue; } //当前被停靠物体的box shape Standard_Real xMin,yMin,zMin,xMax,yMax,zMax; movingBox.Get(xMin, yMin, zMin, xMax, yMax, zMax); auto alignBoxShape = BRepPrimAPI_MakeBox(gp_Pnt(xMin, yMin, zMin), gp_Pnt(xMax, yMax, zMax)).Shape(); TopExp_Explorer exp(alignBoxShape, TopAbs_SHELL); BRepExtrema_DistShapeShape dss(imp_.ModifyEdge_.Edge().Moved(curODL->GetAbsoluteTransform().Inverted()), exp.Current()); auto needContinue = false; std::map<double, gp_Pnt> tmp; for ( auto index=1; index<=dss.NbSolution(); ++index ) { if ( dss.SupportTypeShape2(index) == BRepExtrema_IsOnEdge ) { activePilar->AddAlign(curODL); needContinue = true; break; } auto pntOnEdge = dss.PointOnShape1(index); auto pntOnBox = dss.PointOnShape2(index); if ( pntOnEdge.Distance(pntOnBox) > Precision::Confusion() ) { continue; } tmp.emplace(pntOnEdge.Distance(inODLPnt), pntOnEdge); } if ( needContinue ) { continue; } auto foundPnt = tmp.begin()->second.Transformed(curODL->GetAbsoluteTransform()); if ( foundPnt.Distance(newPnt) < 1) { activePilar->AddAlign(curODL); continue; } else { newPnt = foundPnt; break; } } auto finalOffset = gp_Vec(pillarTranslation.TranslationPart(), newPnt); auto finalRelationOffset = finalOffset.Transformed(pillarTransformation.Inverted()); auto finalModifyOffset = finalRelationOffset; { finalModifyOffset.SetX(finalModifyOffset.X()*modifyDir.X()); finalModifyOffset.SetY(finalModifyOffset.Y()*modifyDir.Y()); finalModifyOffset.SetZ(finalModifyOffset.Z()*modifyDir.Z()); } auto finalSize = pillarBoxSize + finalModifyOffset.XYZ(); auto finalTranslation = pillarTranslation.TranslationPart() + finalRelationOffset.XYZ()/2; activePilar->SetSize(finalSize); activePilar->SetTranslation(finalTranslation); { vector3df newPos(static_cast<float>(finalTranslation.X()), static_cast<float>(finalTranslation.Y()), static_cast<float>(finalTranslation.Z())); activePilar->GetDataSceneNode()->setPosition(newPos); } activePilar->Update2DMesh(); imp_.ModifyPar_ = curPar; } break; case EPilarState::EPS_MOUSEHOLDING: { auto activePillar = std::static_pointer_cast<PillarODL>(GetPickingODL().lock()); activePillar->SetPicking(true); if ( imp_.SavePos_.getDistanceFromSQ(imp_.CurrentPos_) > 100 * 100 ) { imp_.State_ = EPilarState::EPS_MOVING; imp_.Valid_ = true; } else if ( imp_.LMouseLeftUp_ ) { imp_.PropertyCallBack_ = boost::none; imp_.State_ = EPilarState::EPS_PROPERTY; auto pointer = reinterpret_cast<int>(static_cast<void*>(&(*imp_.EventInfo_))); ::PostMessage((HWND)GetRenderContextSPtr()->GetHandle(), WM_IRR_DLG_MSG, WM_USER_ROOMLAYOUT_PILLAR_PROPERTY, pointer); } } break; case EPilarState::EPS_PROPERTY: { if ( !imp_.PropertyCallBack_ ) { break; } auto activePillar = std::static_pointer_cast<PillarODL>(GetPickingODL().lock()); switch (*(imp_.PropertyCallBack_)) { case EUT_ROOMLAYOUT_PILLAR_NONE: { imp_.State_ = EPilarState::EPS_SWEEPING; } break; case EUT_ROOMLAYOUT_PILLAR_UPDATE: { activePillar->SetSize(imp_.EventInfo_->XLength_, imp_.EventInfo_->YLength_, imp_.EventInfo_->ZLength_); activePillar->SetOffsetHeight(imp_.EventInfo_->OffsetHeight_); { auto curTrans = activePillar->GetTranslation(); curTrans.SetY(imp_.EventInfo_->YLength_/2 + imp_.EventInfo_->OffsetHeight_); activePillar->SetTranslation(curTrans); auto curPos = activePillar->GetDataSceneNode()->getPosition(); curPos.Y = static_cast<float>(imp_.EventInfo_->YLength_/2 + imp_.EventInfo_->OffsetHeight_); activePillar->GetDataSceneNode()->setPosition(curPos); } activePillar->UpdateMesh(); imp_.State_ = EPilarState::EPS_SWEEPING; } break; case EUT_ROOMLAYOUT_PILLAR_MOVE: { imp_.State_ = EPilarState::EPS_MOVING; } break; case EUT_ROOMLAYOUT_PILLAR_DELETE: { activePillar->RemoveFromParent(); imp_.State_ = EPilarState::EPS_SWEEPING; } break; default: assert(0); break; } } break; case EPilarState::EPS_CREATING_INIT: { assert(imp_.EventInfo_); auto newPilar = PillarODL::Create<PillarODL>(GetRenderContextSPtr()); newPilar->SetSize(imp_.EventInfo_->XLength_, imp_.EventInfo_->YLength_, imp_.EventInfo_->ZLength_); newPilar->SetOffsetHeight(imp_.EventInfo_->OffsetHeight_); newPilar->UpdateMesh(); RootODL_.lock()->AddChild(newPilar); auto newPos = imp_.CurrentPos_; newPos.Y = imp_.EventInfo_->YLength_/2; newPilar->SetTranslation(gp_XYZ(newPos.X, newPos.Y, newPos.Z)); newPilar->GetDataSceneNode()->setPosition(newPos); SetPickingODL(newPilar); imp_.State_ = EPilarState::EPS_MOVING; } break; case EPilarState::EPS_MOVING: { auto activePilar = std::static_pointer_cast<PillarODL>(GetPickingODL().lock()); activePilar->SetPicking(true); activePilar->SetVaildPosition(imp_.Valid_); if ( imp_.LMouseLeftUp_ ) { if ( imp_.Valid_ ) { ImpUPtr_->Valid_ = false; ImpUPtr_->EventInfo_ = boost::none; imp_.State_ = EPilarState::EPS_SWEEPING; break; } } if ( imp_.EscapePressDown_ ) { activePilar->RemoveFromParent(); imp_.State_ = EPilarState::EPS_SWEEPING; break; } //当前柱的Box auto activeTransitionBox = activePilar->GetBaseBndBox(); { gp_Trsf tfs; tfs.SetTranslationPart(activePilar->GetTranslation()); activeTransitionBox = activeTransitionBox.Transformed(tfs); } activePilar->SetRotation(gp_Quaternion(gp::DZ(), gp::DZ())); activePilar->GetDataSceneNode()->setRotation(vector3df(0)); auto size = activePilar->GetSize(); auto offset = activePilar->GetOffsetHeight(); //新的位置 auto newPos = imp_.CurrentPos_; newPos.Y = static_cast<float>(size.Y()/2) + offset; gp_Pnt newPnt(newPos.X, newPos.Y, newPos.Z); //吸附距离 static auto alignDis = 200.0; //当前的吸附物体 auto alignODLs = activePilar->GetAlignList(); alignODLs.erase(std::remove_if(alignODLs.begin(), alignODLs.end(), [&activePilar, &activeTransitionBox](const BaseODLSPtr& alignODL) { if ( !alignODL ) { return true; } return alignODL->GetBaseBndBox().Distance(activeTransitionBox.Transformed(alignODL->GetAbsoluteTransform().Inverted())) > alignDis; }), alignODLs.end()); activePilar->SetAlignList(BaseODLList()); std::multimap<double,BaseODLSPtr> disMap; for ( auto& curODL : RootODL_.lock()->GetChildrenList() ) { if ( EODLT_PILLAR != curODL->GetType() && EODLT_WALL != curODL->GetType() ) { continue; } if ( std::find(alignODLs.begin(), alignODLs.end(), curODL) != alignODLs.end() ) { continue; } if ( EODLT_PILLAR == curODL->GetType() && curODL == activePilar ) { continue; } auto dis = curODL->GetBaseBndBox().Distance(activeTransitionBox.Transformed(curODL->GetAbsoluteTransform().Inverted())); if ( dis > alignDis ) { continue; } disMap.emplace(dis, curODL); } for ( auto& curODL : disMap ) { alignODLs.push_back(curODL.second); } //锁定旋转 auto lockRotation = false; //锁定位置 auto lockPosition = false; //移动方向 TopoDS_Edge movingEdge; for ( auto& curODL : alignODLs ) { auto alignTransformation = curODL->GetAbsoluteTransform(); //如果锁定了旋转,则调整柱的box auto activeRotationPillarBox = activePilar->GetBaseBndBox(); if ( lockRotation ) { gp_Trsf tfsODL, tfsPillar; tfsODL.SetRotation(alignTransformation.GetRotation()); tfsPillar.SetRotation(activePilar->GetRotation()); activeRotationPillarBox = activeRotationPillarBox.Transformed(tfsODL.Inverted() * tfsPillar); } Bnd_Box movingBox; { auto curBox = curODL->GetBaseBndBox(); Standard_Real xAlignMin,yAlignMin,zAlignMin,xAlignMax,yAlignMax,zAlignMax; curBox.Get(xAlignMin, yAlignMin, zAlignMin, xAlignMax, yAlignMax, zAlignMax); Standard_Real xPillarMin,yPillarMin,zPillarMin,xPillarMax,yPillarMax,zPillarMax; activeRotationPillarBox.Get(xPillarMin, yPillarMin, zPillarMin, xPillarMax, yPillarMax, zPillarMax); movingBox.Update(xAlignMin+xPillarMin, yAlignMin+yPillarMin, zAlignMin+zPillarMin, xAlignMax+xPillarMax, yAlignMax+yPillarMax, zAlignMax+zPillarMax); } auto inODLPnt = newPnt.Transformed(curODL->GetAbsoluteTransform().Inverted()); //当位置锁定了以后,只需要判断是不是相交 if ( lockPosition ) { if ( Standard_True == movingBox.IsOut(inODLPnt) ) { continue; } Bnd_Box pntBox; pntBox.Add(inODLPnt); if ( pntBox.Distance(movingBox) < Precision::Confusion() ) { continue; } imp_.Valid_ = false; break; } Bnd_Box alignODLBox; { auto curBox = curODL->GetBaseBndBox(); Standard_Real xAlignMin,yAlignMin,zAlignMin,xAlignMax,yAlignMax,zAlignMax; curBox.Get(xAlignMin, yAlignMin, zAlignMin, xAlignMax, yAlignMax, zAlignMax); Standard_Real xPillarMin,yPillarMin,zPillarMin,xPillarMax,yPillarMax,zPillarMax; activeRotationPillarBox.Get(xPillarMin, yPillarMin, zPillarMin, xPillarMax, yPillarMax, zPillarMax); alignODLBox.Update(xAlignMin+xPillarMin-alignDis, yAlignMin+yPillarMin-alignDis, zAlignMin+zPillarMin-alignDis, xAlignMax+xPillarMax+alignDis, yAlignMax+yPillarMax+alignDis, zAlignMax+zPillarMax+alignDis); } if ( Standard_True == alignODLBox.IsOut(inODLPnt) ) { continue; } //当前被停靠物体的box shape Standard_Real xMin,yMin,zMin,xMax,yMax,zMax; movingBox.Get(xMin, yMin, zMin, xMax, yMax, zMax); auto alignBoxShape = BRepPrimAPI_MakeBox(gp_Pnt(xMin, yMin, zMin), gp_Pnt(xMax, yMax, zMax)).Shape(); TopExp_Explorer exp(alignBoxShape, TopAbs_SHELL); if ( !lockRotation ) {//找到第一个被停靠物体 BRepExtrema_DistShapeShape dss(BRepBuilderAPI_MakeVertex(inODLPnt).Shape(), exp.Current()); assert(0 != dss.NbSolution()); inODLPnt = dss.PointOnShape2(1); newPnt = inODLPnt.Transformed(curODL->GetAbsoluteTransform()).XYZ(); auto rot = curODL->GetAbsoluteTransform().GetRotation(); Standard_Real rX,rY,rZ; rot.GetEulerAngles(gp_Extrinsic_XYZ, rX, rY, rZ); vector3df rotation(static_cast<float>(irr::core::radToDeg(rX)), static_cast<float>(irr::core::radToDeg(rY)), static_cast<float>(irr::core::radToDeg(rZ))); activePilar->GetDataSceneNode()->setRotation(rotation); activePilar->SetRotation(rot); gp_Dir movingDir; if ( std::abs(std::abs(inODLPnt.X()) - xMax) < Precision::Confusion() ) { movingDir = gp::DZ(); } else { movingDir = gp::DX(); } auto curMovingEdge = BRepBuilderAPI_MakeEdge(gp_Lin(inODLPnt, movingDir)).Edge(); movingEdge = TopoDS::Edge(curMovingEdge.Moved(curODL->GetAbsoluteTransform())); activePilar->AddAlign(curODL); imp_.Valid_ = true; lockRotation = true; } else {//第二个被停靠物体 BRepExtrema_DistShapeShape dss(movingEdge.Moved(curODL->GetAbsoluteTransform().Inverted()), exp.Current()); auto foundSecond = false; std::map<double, gp_Pnt> tmp; for ( auto index=1; index<=dss.NbSolution(); ++index ) { auto pntOnEdge = dss.PointOnShape1(index); auto pntOnBox = dss.PointOnShape2(index); if ( pntOnEdge.Distance(pntOnBox) > Precision::Confusion() ) { continue; } tmp.emplace(pntOnEdge.Distance(inODLPnt), pntOnEdge); foundSecond = true; } if ( !foundSecond ) { imp_.Valid_ = false; break; } newPnt = tmp.begin()->second.Transformed(curODL->GetAbsoluteTransform()); activePilar->AddAlign(curODL); lockPosition = true; } } if ( activePilar->GetAlignList().empty() ) { imp_.Valid_ = true; } newPos.X = static_cast<float>(newPnt.X()); newPos.Y = static_cast<float>(newPnt.Y()); newPos.Z = static_cast<float>(newPnt.Z()); activePilar->GetDataSceneNode()->setPosition(newPos); activePilar->SetTranslation(newPnt.XYZ()); for ( auto& curAlign : activePilar->GetAlignList() ) { curAlign->SetSweeping(true); } } break; default: break; } imp_.LMousePressDown_ = false; imp_.LMouseLeftUp_ = false; imp_.EscapePressDown_ = false; return false; }