void RS_Line::draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) { if (painter==NULL || view==NULL) { return; } //only draw the visible portion of line QVector<RS_Vector> endPoints(0); RS_Vector vpMin(view->toGraph(0,view->getHeight())); RS_Vector vpMax(view->toGraph(view->getWidth(),0)); QPolygonF visualBox(QRectF(vpMin.x,vpMin.y,vpMax.x-vpMin.x, vpMax.y-vpMin.y)); if( getStartpoint().isInWindowOrdered(vpMin, vpMax) ) endPoints<<getStartpoint(); if( getEndpoint().isInWindowOrdered(vpMin, vpMax) ) endPoints<<getEndpoint(); if(endPoints.size()<2){ QVector<RS_Vector> vertex; for(unsigned short i=0;i<4;i++){ const QPointF& vp(visualBox.at(i)); vertex<<RS_Vector(vp.x(),vp.y()); } for(unsigned short i=0;i<4;i++){ RS_Line line(NULL,RS_LineData(vertex.at(i),vertex.at((i+1)%4))); auto&& vpIts=RS_Information::getIntersection(static_cast<RS_Entity*>(this), &line, true); if( vpIts.size()==0) continue; endPoints<<vpIts.get(0); } } if(endPoints.size()<2) return; if( (endPoints[0] - getStartpoint()).squared() > (endPoints[1] - getStartpoint()).squared() ) std::swap(endPoints[0],endPoints[1]); RS_Vector pStart(view->toGui(endPoints.at(0))); RS_Vector pEnd(view->toGui(endPoints.at(1))); // std::cout<<"draw line: "<<pStart<<" to "<<pEnd<<std::endl; RS_Vector direction=pEnd-pStart; if(isHelpLayer(true) && direction.squared() > RS_TOLERANCE){ //extend line on a help layer to fill the whole view RS_Vector lb(0,0); RS_Vector rt(view->getWidth(),view->getHeight()); QList<RS_Vector> rect; rect<<lb<<RS_Vector(rt.x,lb.y); rect<<rt<<RS_Vector(lb.x,rt.y); rect<<lb; RS_VectorSolutions sol; RS_Line dLine(pStart,pEnd); for(int i=0;i<4;i++){ RS_Line bLine(rect.at(i),rect.at(i+1)); RS_VectorSolutions sol2=RS_Information::getIntersection(&bLine, &dLine); if( sol2.getNumber()>0 && bLine.isPointOnEntity(sol2.get(0),RS_TOLERANCE)) { sol.push_back(sol2.get(0)); } } switch(sol.getNumber()){ case 2: pStart=sol.get(0); pEnd=sol.get(1); break; case 3: case 4: pStart=sol.get(0); pEnd=sol.get(2); break; default: return; } direction=pEnd-pStart; } double length=direction.magnitude(); patternOffset -= length; if (( !isSelected() && ( getPen().getLineType()==RS2::SolidLine || view->getDrawingMode()==RS2::ModePreview)) ) { //if length is too small, attempt to draw the line, could be a potential bug painter->drawLine(pStart,pEnd); return; } // double styleFactor = getStyleFactor(view); // Pattern: RS_LineTypePattern* pat; if (isSelected()) { // styleFactor=1.; pat = &patternSelected; } else { pat = view->getPattern(getPen().getLineType()); } if (pat==NULL) { // patternOffset -= length; RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Line::draw: Invalid line pattern"); painter->drawLine(pStart,pEnd); return; } // patternOffset = remainder(patternOffset - length-0.5*pat->totalLength,pat->totalLength)+0.5*pat->totalLength; if(length<=RS_TOLERANCE){ painter->drawLine(pStart,pEnd); return; //avoid division by zero } direction/=length; //cos(angle), sin(angle) // Pen to draw pattern is always solid: RS_Pen pen = painter->getPen(); pen.setLineType(RS2::SolidLine); painter->setPen(pen); // index counter int i; // pattern segment length: double patternSegmentLength = pat->totalLength; double styleFactor = view->getStyleFactor(); /* ++++++++++++++++ new added, in SETTINGS adapt. */ // create pattern: RS_Vector* dp=new RS_Vector[pat->num > 0?pat->num:0]; double* ds=new double[pat->num > 0?pat->num:0]; if (pat->num >0 ){ double dpmm=static_cast<RS_PainterQt*>(painter)->getDpmm(); for (i=0; i<pat->num; ++i) { // ds[j]=pat->pattern[i] * styleFactor; //fixme, styleFactor support needed ds[i]=dpmm * styleFactor * pat->pattern[i]; if( fabs(ds[i]) < 1. ) ds[i] = (ds[i]>=0.)?1.:-1.; dp[i] = direction * fabs(ds[i]); } }else { delete[] dp; delete[] ds; RS_DEBUG->print(RS_Debug::D_WARNING,"invalid line pattern for line, draw solid line instread"); painter->drawLine(view->toGui(getStartpoint()), view->toGui(getEndpoint())); return; } double total= remainder(patternOffset-0.5*patternSegmentLength,patternSegmentLength) -0.5*patternSegmentLength; // double total= patternOffset-patternSegmentLength; RS_Vector p1,p2,p3; RS_Vector curP(pStart+direction*total); double t2; for(int j=0;total<length;j=(j+1)%i) { // line segment (otherwise space segment) t2=total+fabs(ds[j]); p3=curP+dp[j]; if (ds[j]>0.0 && t2 > 0.0) { // drop the whole pattern segment line, for ds[i]<0: // trim end points of pattern segment line to line p1 =(total > -0.5)? curP:pStart; p2 =(t2<length+0.5)?p3:pEnd; painter->drawLine(p1,p2); } total=t2; curP=p3; } delete[] dp; delete[] ds; }
void RS_ActionDrawEllipseAxis::mouseMoveEvent(QMouseEvent* e) { RS_DEBUG->print("RS_ActionDrawEllipseAxis::mouseMoveEvent begin"); RS_Vector mouse = snapPoint(e); switch (getStatus()) { // case SetCenter: // break; case SetMajor: if (center.valid) { deletePreview(); RS_EllipseData ed(center, mouse-center, 0.5, 0.0, isArc?2.*M_PI:0.0, false); preview->addEntity(new RS_Ellipse(preview.get(), ed)); drawPreview(); } break; case SetMinor: if (center.valid && major.valid) { deletePreview(); RS_Line line(NULL, RS_LineData(center-major, center+major)); double d = line.getDistanceToPoint(mouse); ratio = d/(line.getLength()/2); RS_EllipseData ed(center, major, ratio, 0.0, isArc?2.*M_PI:0.0, false); preview->addEntity(new RS_Ellipse(preview.get(), ed)); drawPreview(); } break; case SetAngle1: if (center.valid && major.valid) { deletePreview(); //angle1 = center.angleTo(mouse); RS_Vector m = mouse; m.rotate(center, -major.angle()); RS_Vector v = m-center; v.scale(RS_Vector(1.0, 1.0/ratio)); angle1 = v.angle(); // + major.angle(); preview->addEntity(new RS_Line(preview.get(), RS_LineData(center, mouse))); RS_EllipseData ed(center, major, ratio, angle1, angle1+1.0, false); preview->addEntity(new RS_Ellipse(preview.get(), ed)); drawPreview(); } break; case SetAngle2: if (center.valid && major.valid) { deletePreview(); //angle2 = center.angleTo(mouse); RS_Vector m = mouse; m.rotate(center, -major.angle()); RS_Vector v = m-center; v.scale(RS_Vector(1.0, 1.0/ratio)); angle2 = v.angle(); // + major.angle(); preview->addEntity(new RS_Line(preview.get(), RS_LineData(center, mouse))); RS_EllipseData ed( center, major, ratio, angle1, angle2, false); preview->addEntity(new RS_Ellipse(preview.get(), ed)); drawPreview(); } default: break; } RS_DEBUG->print("RS_ActionDrawEllipseAxis::mouseMoveEvent end"); }
void RS_ActionModifyStretch::mouseMoveEvent(QMouseEvent* e) { RS_DEBUG->print("RS_ActionModifyStretch::mouseMoveEvent begin"); RS_Vector mouse = snapPoint(e); switch (getStatus()) { case SetFirstCorner: break; case SetSecondCorner: if (firstCorner.valid) { secondCorner = snapPoint(e); deletePreview(); preview->addEntity( new RS_Line(preview, RS_LineData(RS_Vector(firstCorner.x, firstCorner.y), RS_Vector(secondCorner.x, firstCorner.y)))); preview->addEntity( new RS_Line(preview, RS_LineData(RS_Vector(secondCorner.x, firstCorner.y), RS_Vector(secondCorner.x, secondCorner.y)))); preview->addEntity( new RS_Line(preview, RS_LineData(RS_Vector(secondCorner.x, secondCorner.y), RS_Vector(firstCorner.x, secondCorner.y)))); preview->addEntity( new RS_Line(preview, RS_LineData(RS_Vector(firstCorner.x, secondCorner.y), RS_Vector(firstCorner.x, firstCorner.y)))); drawPreview(); } break; case SetReferencePoint: break; case SetTargetPoint: if (referencePoint.valid) { targetPoint = mouse; deletePreview(); preview->addStretchablesFrom(*container, firstCorner, secondCorner); //preview->move(targetPoint-referencePoint); preview->stretch(firstCorner, secondCorner, targetPoint-referencePoint); drawPreview(); } break; default: break; } RS_DEBUG->print("RS_ActionModifyStretch::mouseMoveEvent end"); }
/** * Updates the sub entities of this dimension. Called when the * dimension or the position, alignment, .. changes. * * @param autoText Automatically reposition the text label */ void RS_DimRadial::updateDim(bool autoText) { RS_DEBUG->print("RS_DimRadial::update"); clear(); if (isUndone()) { return; } // dimension line: //updateCreateDimensionLine(data.definitionPoint, edata.definitionPoint, //false, true); // general scale (DIMSCALE) double dimscale = getGeneralScale(); RS_Vector p1 = data.definitionPoint; RS_Vector p2 = edata.definitionPoint; double angle = p1.angleTo(p2); // text height (DIMTXT) double dimtxt = getTextHeight()*dimscale; // text distance to line (DIMGAP) double dimgap = getDimensionLineGap()*dimscale; // arrow size: double arrowSize = getArrowSize()*dimscale; // length of dimension line: double length = p1.distanceTo(p2); RS_MTextData textData; textData = RS_MTextData(RS_Vector(0.0,0.0), dimtxt, 30.0, RS_MTextData::VAMiddle, RS_MTextData::HACenter, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, getLabel(), "standard", 0.0); RS_MText* text = new RS_MText(this, textData); double textWidth = text->getSize().x; // do we have to put the arrow / text outside of the arc? bool outsideArrow = (length<arrowSize*2+textWidth); double arrowAngle; if (outsideArrow) { length += arrowSize*2 + textWidth; arrowAngle = angle+M_PI; } else { arrowAngle = angle; } // create arrow: RS_SolidData sd; RS_Solid* arrow; arrow = new RS_Solid(this, sd); arrow->shapeArrow(p2, arrowAngle, arrowSize); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); RS_Vector p3; p3.setPolar(length, angle); p3 += p1; // Create dimension line: RS_Line* dimensionLine = new RS_Line(this, RS_LineData(p1, p3)); dimensionLine->setPen(RS_Pen(RS2::FlagInvalid)); dimensionLine->setLayer(NULL); addEntity(dimensionLine); RS_Vector distV; double textAngle; // rotate text so it's readable from the bottom or right (ISO) // quadrant 1 & 4 if (angle>M_PI_2*3.0+0.001 || angle<M_PI_2+0.001) { distV.setPolar(dimgap + dimtxt/2.0, angle+M_PI_2); textAngle = angle; } // quadrant 2 & 3 else { distV.setPolar(dimgap + dimtxt/2.0, angle-M_PI_2); textAngle = angle+M_PI; } // move text label: RS_Vector textPos; if (data.middleOfText.valid && !autoText) { textPos = data.middleOfText; } else { if (outsideArrow) { textPos.setPolar(length-textWidth/2.0-arrowSize, angle); } else { textPos.setPolar(length/2.0, angle); } textPos+=p1; // move text away from dimension line: textPos += distV; data.middleOfText = textPos; } text->rotate(RS_Vector(0.0,0.0), textAngle); text->move(textPos); text->setPen(RS_Pen(RS2::FlagInvalid)); text->setLayer(NULL); addEntity(text); calculateBorders(); }
/** * Creates a vertex from the endpoint of the last element or * sets the startpoint to the point 'v'. * * The very first vertex added is the starting point. * * @param v vertex coordinate * @param bulge The bulge of the arc (see DXF documentation) * @param prepend true: Prepend instead of append at end * * @return Pointer to the entity that was created or NULL if this * was the first vertex added. */ RS_Entity* RS_Polyline::createVertex(const RS_Vector& v, double bulge, bool prepend) { RS_Entity* entity=NULL; RS_DEBUG->print("RS_Polyline::createVertex: %f/%f to %f/%f bulge: %f", data.endpoint.x, data.endpoint.y, v.x, v.y, bulge); // create line for the polyline: if (fabs(bulge)<RS_TOLERANCE) { if (prepend==false) { entity = new RS_Line(this, RS_LineData(data.endpoint, v)); } else { entity = new RS_Line(this, RS_LineData(v, data.startpoint)); } entity->setSelected(isSelected()); entity->setPen(RS_Pen(RS2::FlagInvalid)); entity->setLayer(NULL); //RS_EntityContainer::addEntity(entity); //data.endpoint = v; } // create arc for the polyline: else { bool reversed = (bulge<0.0); double alpha = atan(bulge)*4.0; double radius; RS_Vector center; RS_Vector middle; double dist; double angle; if (prepend==false) { middle = (data.endpoint+v)/2.0; dist = data.endpoint.distanceTo(v)/2.0; angle = data.endpoint.angleTo(v); } else { middle = (data.startpoint+v)/2.0; dist = data.startpoint.distanceTo(v)/2.0; angle = v.angleTo(data.startpoint); } // alpha can't be 0.0 at this point radius = fabs(dist / sin(alpha/2.0)); double wu = fabs(RS_Math::pow(radius, 2.0) - RS_Math::pow(dist, 2.0)); double h = sqrt(wu); if (bulge>0.0) { angle+=M_PI/2.0; } else { angle-=M_PI/2.0; } if (fabs(alpha)>M_PI) { h*=-1.0; } center.setPolar(h, angle); center+=middle; double a1; double a2; if (prepend==false) { a1 = center.angleTo(data.endpoint); a2 = center.angleTo(v); } else { a1 = center.angleTo(v); a2 = center.angleTo(data.startpoint); } RS_ArcData d(center, radius, a1, a2, reversed); entity = new RS_Arc(this, d); entity->setSelected(isSelected()); entity->setPen(RS_Pen(RS2::FlagInvalid)); entity->setLayer(NULL); } return entity; }
/** * Creates a bisecting line of the angle between the entities * e1 and e2. Out of the 4 possible bisectors, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which bisector we want (typically a * mouse coordinate). * @param length Length of the bisecting line. * @param num Number of bisectors * @param l1 First line. * @param l2 Second line. * * @return Pointer to the first bisector created or NULL if no bisectors * were created. */ RS_Line* RS_Creation::createBisector(const RS_Vector& coord1, const RS_Vector& coord2, double length, int num, RS_Line* l1, RS_Line* l2) { RS_VectorSolutions sol; // check given entities: if (l1==NULL || l2==NULL || l1->rtti()!=RS2::EntityLine || l2->rtti()!=RS2::EntityLine) { return NULL; } // intersection between entities: sol = RS_Information::getIntersection(l1, l2, false); RS_Vector inters = sol.get(0); if (inters.valid==false) { return NULL; } double angle1 = inters.angleTo(l1->getNearestPointOnEntity(coord1)); double angle2 = inters.angleTo(l2->getNearestPointOnEntity(coord2)); double angleDiff = RS_Math::getAngleDifference(angle1, angle2); if (angleDiff>M_PI) { angleDiff = angleDiff - 2*M_PI; } RS_Line* ret = NULL; if (document!=NULL && handleUndo) { document->startUndoCycle(); } for (int n=1; n<=num; ++n) { double angle = angle1 + (angleDiff / (num+1) * n); RS_LineData d; RS_Vector v; RS_Vector c; v.setPolar(length, angle); d = RS_LineData(inters, inters + v); RS_Line* newLine = new RS_Line(container, d); if (container!=NULL) { newLine->setLayerToActive(); newLine->setPenToActive(); container->addEntity(newLine); } if (document!=NULL && handleUndo) { document->addUndoable(newLine); } if (graphicView!=NULL) { graphicView->drawEntity(newLine); } if (ret==NULL) { ret = newLine; } } if (document!=NULL && handleUndo) { document->endUndoCycle(); } return ret; }
/** * Creates a tangent between two circles or arcs. * Out of the 4 possible tangents, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which tangent we want (typically a * mouse coordinate). * @param circle1 1st circle or arc entity. * @param circle2 2nd circle or arc entity. */ RS_Line* RS_Creation::createTangent2(const RS_Vector& coord, RS_Entity* circle1, RS_Entity* circle2) { RS_Line* ret = NULL; RS_Vector circleCenter1; RS_Vector circleCenter2; double circleRadius1 = 0.0; double circleRadius2 = 0.0; // check given entities: if (circle1==NULL || circle2==NULL || (circle1->rtti()!=RS2::EntityArc && circle1->rtti()!=RS2::EntityCircle) || (circle2->rtti()!=RS2::EntityArc && circle2->rtti()!=RS2::EntityCircle) ) { return NULL; } if (circle1->rtti()==RS2::EntityCircle) { circleCenter1 = ((RS_Circle*)circle1)->getCenter(); circleRadius1 = ((RS_Circle*)circle1)->getRadius(); } else if (circle1->rtti()==RS2::EntityArc) { circleCenter1 = ((RS_Arc*)circle1)->getCenter(); circleRadius1 = ((RS_Arc*)circle1)->getRadius(); } if (circle2->rtti()==RS2::EntityCircle) { circleCenter2 = ((RS_Circle*)circle2)->getCenter(); circleRadius2 = ((RS_Circle*)circle2)->getRadius(); } else if (circle2->rtti()==RS2::EntityArc) { circleCenter2 = ((RS_Arc*)circle2)->getCenter(); circleRadius2 = ((RS_Arc*)circle2)->getRadius(); } // create all possible tangents: RS_Line* poss[4]; for (int i=0; i<4; ++i) { poss[i] = NULL; } RS_LineData d; double angle1 = circleCenter1.angleTo(circleCenter2); double dist1 = circleCenter1.distanceTo(circleCenter2); if (dist1>1.0e-6) { // outer tangents: double dist2 = circleRadius2 - circleRadius1; if (dist1>dist2) { double angle2 = asin(dist2/dist1); double angt1 = angle1 + angle2 + M_PI/2.0; double angt2 = angle1 - angle2 - M_PI/2.0; RS_Vector offs1; RS_Vector offs2; offs1.setPolar(circleRadius1, angt1); offs2.setPolar(circleRadius2, angt1); d = RS_LineData(circleCenter1 + offs1, circleCenter2 + offs2); poss[0] = new RS_Line(NULL, d); offs1.setPolar(circleRadius1, angt2); offs2.setPolar(circleRadius2, angt2); d = RS_LineData(circleCenter1 + offs1, circleCenter2 + offs2); poss[1] = new RS_Line(NULL, d); } // inner tangents: double dist3 = circleRadius2 + circleRadius1; if (dist1>dist3) { double angle3 = asin(dist3/dist1); double angt3 = angle1 + angle3 + M_PI/2.0; double angt4 = angle1 - angle3 - M_PI/2.0; RS_Vector offs1; RS_Vector offs2; offs1.setPolar(circleRadius1, angt3); offs2.setPolar(circleRadius2, angt3); d = RS_LineData(circleCenter1 - offs1, circleCenter2 + offs2); poss[2] = new RS_Line(NULL, d); offs1.setPolar(circleRadius1, angt4); offs2.setPolar(circleRadius2, angt4); d = RS_LineData(circleCenter1 - offs1, circleCenter2 + offs2); poss[3] = new RS_Line(NULL, d); } } // find closest tangent: double minDist = RS_MAXDOUBLE; double dist; int idx = -1; for (int i=0; i<4; ++i) { if (poss[i]!=NULL) { dist = poss[i]->getDistanceToPoint(coord); if (dist<minDist) { minDist = dist; idx = i; } } } if (idx!=-1) { RS_LineData d = poss[idx]->getData(); for (int i=0; i<4; ++i) { if (poss[i]!=NULL) { delete poss[i]; } } if (document!=NULL && handleUndo) { document->startUndoCycle(); } ret = new RS_Line(container, d); ret->setLayerToActive(); ret->setPenToActive(); if (container!=NULL) { container->addEntity(ret); } if (document!=NULL && handleUndo) { document->addUndoable(ret); document->endUndoCycle(); } if (graphicView!=NULL) { graphicView->drawEntity(ret); } } else { ret = NULL; } return ret; }
void RS_ActionDrawLineRectangle::reset() { for (int i=0; i<4; ++i) { data[i] = RS_LineData(RS_Vector(false), RS_Vector(false)); } }
double RS_ActionDrawPolyline::solveBulge(RS_Vector mouse) { double b(0.); bool suc; RS_Arc arc(NULL, RS_ArcData()); RS_Line line(NULL,RS_LineData()); double direction,direction2,delta; RS_AtomicEntity* lastentity; calculatedSegment=false; switch (Mode) { // case Line: // b=0.0; // break; case Tangential: if (polyline!=NULL) { lastentity = (RS_AtomicEntity*)polyline->lastEntity(); direction = RS_Math::correctAngle( lastentity->getDirection2()+M_PI); line.setStartpoint(point); line.setEndpoint(mouse); direction2=RS_Math::correctAngle(line.getDirection2()+M_PI); delta=direction2-direction; if( fabs(remainder(delta,M_PI))>RS_TOLERANCE_ANGLE ) { b=tan(delta/2); suc = arc.createFrom2PBulge(point,mouse,b); if (suc) arc_data = arc.getData(); else b=0; } break; // if(delta<RS_TOLERANCE_ANGLE || // (delta<M_PI+RS_TOLERANCE_ANGLE && // delta>M_PI-RS_TOLERANCE_ANGLE)) // b=0; // else{ // b=tan((direction2-direction)/2); // suc = arc.createFrom2PBulge(point,mouse,b); // if (suc) // arc_data = arc.getData(); // else // b=0; // } } // else // b=0; // break; case TanRad: if (polyline!=NULL) { lastentity = (RS_AtomicEntity*)polyline->lastEntity(); direction = RS_Math::correctAngle( lastentity->getDirection2()+M_PI); suc = arc.createFrom2PDirectionRadius(point, mouse, direction,Radius); if (suc) { arc_data = arc.getData(); b=arc.getBulge(); calculatedEndpoint = arc.getEndpoint(); calculatedSegment=true; } // else // b=0; } // else // b=0; break; /* case TanAng: b=tan(Reversed*Angle*M_PI/720.0); break; case TanRadAng: b=tan(Reversed*Angle*M_PI/720.0); break;*/ case Ang: b=tan(Reversed*Angle*M_PI/720.0); suc = arc.createFrom2PBulge(point,mouse,b); if (suc) arc_data = arc.getData(); else b=0; break; default: break; /* case RadAngEndp: b=tan(Reversed*Angle*M_PI/720.0); break; case RadAngCenp: b=tan(Reversed*Angle*M_PI/720.0);*/ } return b; }
/** * Creates a dimensioning line (line with one, two or no arrows and a text). * * @param forceAutoText Automatically reposition the text label. */ void RS_Dimension::updateCreateDimensionLine(const RS_Vector& p1, const RS_Vector& p2, bool arrow1, bool arrow2, bool forceAutoText) { // text height (DIMTXT) double dimtxt = getTextHeight(); // text distance to line (DIMGAP) double dimgap = getDimensionLineGap(); // length of dimension line: double distance = p1.distanceTo(p2); // do we have to put the arrows outside of the line? bool outsideArrows = (distance<getArrowSize()*2.5); // arrow angles: double arrowAngle1, arrowAngle2; // Create dimension line: RS_Line* dimensionLine = new RS_Line(this, RS_LineData(p1, p2)); dimensionLine->setPen(RS_Pen(RS2::FlagInvalid)); dimensionLine->setLayer(NULL); addEntity(dimensionLine); if (outsideArrows==false) { arrowAngle1 = dimensionLine->getAngle2(); arrowAngle2 = dimensionLine->getAngle1(); } else { arrowAngle1 = dimensionLine->getAngle1(); arrowAngle2 = dimensionLine->getAngle2(); // extend dimension line outside arrows RS_Vector dir; dir.setPolar(getArrowSize()*2, arrowAngle2); dimensionLine->setStartpoint(p1 + dir); dimensionLine->setEndpoint(p2 - dir); } double dimtsz=getTickSize(); if(dimtsz < 0.01) { //display arrow // Arrows: RS_SolidData sd; RS_Solid* arrow; if (arrow1) { // arrow 1 arrow = new RS_Solid(this, sd); arrow->shapeArrow(p1, arrowAngle1, getArrowSize()); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); } if (arrow2) { // arrow 2: arrow = new RS_Solid(this, sd); arrow->shapeArrow(p2, arrowAngle2, getArrowSize()); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); } }else{ //display ticks // Arrows: RS_Line* tick; RS_Vector tickVector; tickVector.setPolar(dimtsz,arrowAngle1 + M_PI*0.25); //tick is 45 degree away if (arrow1) { // tick 1 tick = new RS_Line(this, p1-tickVector, p1+tickVector); tick->setPen(RS_Pen(RS2::FlagInvalid)); tick->setLayer(NULL); addEntity(tick); } if (arrow2) { // tick 2: tick = new RS_Line(this, p2-tickVector, p2+tickVector); tick->setPen(RS_Pen(RS2::FlagInvalid)); tick->setLayer(NULL); addEntity(tick); } } // Text label: RS_MTextData textData; RS_Vector textPos; double dimAngle1 = dimensionLine->getAngle1(); double textAngle; bool corrected=false; if (getAlignText()) textAngle =0.0; else textAngle = RS_Math::makeAngleReadable(dimAngle1, true, &corrected); if (data.middleOfText.valid && !forceAutoText) { textPos = data.middleOfText; } else { textPos = dimensionLine->getMiddlePoint(); if (!getAlignText()) { RS_Vector distV; // rotate text so it's readable from the bottom or right (ISO) // quadrant 1 & 4 if (corrected) { distV.setPolar(dimgap + dimtxt/2.0, dimAngle1-M_PI/2.0); } else { distV.setPolar(dimgap + dimtxt/2.0, dimAngle1+M_PI/2.0); } // move text away from dimension line: textPos+=distV; } //// the next update should still be able to adjust this //// auto text position. leave it invalid data.middleOfText = textPos; } textData = RS_MTextData(textPos, dimtxt, 30.0, RS_MTextData::VAMiddle, RS_MTextData::HACenter, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, getLabel(), "standard", textAngle); RS_MText* text = new RS_MText(this, textData); // move text to the side: RS_Vector distH; if (text->getUsedTextWidth()>distance) { distH.setPolar(text->getUsedTextWidth()/2.0 +distance/2.0+dimgap, textAngle); text->move(distH); } text->setPen(RS_Pen(RS2::FlagInvalid)); text->setLayer(NULL); //horizontal text, split dimensionLine if (getAlignText()) { double w =text->getUsedTextWidth()/2+dimgap; double h = text->getUsedTextHeight()/2+dimgap; RS_Vector v1 = textPos - RS_Vector(w, h); RS_Vector v2 = textPos + RS_Vector(w, h); RS_Line l[] = { RS_Line(NULL, RS_LineData(v1, RS_Vector(v2.x, v1.y))), RS_Line(NULL, RS_LineData(RS_Vector(v2.x, v1.y), v2)), RS_Line(NULL, RS_LineData(v2, RS_Vector(v1.x, v2.y))), RS_Line(NULL, RS_LineData(RS_Vector(v1.x, v2.y), v1)) }; RS_VectorSolutions sol1, sol2; int inters= 0; do { sol1 = RS_Information::getIntersection(dimensionLine, &(l[inters++]), true); } while (!sol1.hasValid() && inters < 4); do { sol2 = RS_Information::getIntersection(dimensionLine, &(l[inters++]), true); } while (!sol2.hasValid() && inters < 4); //are text intersecting dimensionLine? if (sol1.hasValid() && sol2.hasValid()) { //yes, split dimension line RS_Line* dimensionLine2 = (RS_Line*)dimensionLine->clone(); v1 = sol1.get(0); v2 = sol2.get(0); if (p1.distanceTo(v1) < p1.distanceTo(v2)) { dimensionLine->setEndpoint(v1); dimensionLine2->setStartpoint(v2); } else { dimensionLine->setEndpoint(v2); dimensionLine2->setStartpoint(v1); } addEntity(dimensionLine2); } } addEntity(text); }
void RS_ActionDrawLineRectangle::preparePreview() { data[0] = RS_LineData(corner1, RS_Vector(corner2.x, corner1.y)); data[1] = RS_LineData(RS_Vector(corner2.x, corner1.y), corner2); data[2] = RS_LineData(corner2, RS_Vector(corner1.x, corner2.y)); data[3] = RS_LineData(RS_Vector(corner1.x, corner2.y), corner1); }
/** * Checks if the given coordinate is inside the given contour. * * @param point Coordinate to check. * @param contour One or more entities which shape a contour. * If the given contour is not closed, the result is undefined. * The entities don't need to be in a specific order. * @param onContour Will be set to true if the given point it exactly * on the contour. */ bool RS_Information::isPointInsideContour(const RS_Vector& point, RS_EntityContainer* contour, bool* onContour) { if (contour==NULL) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Information::isPointInsideContour: contour is NULL"); return false; } if (point.x < contour->getMin().x || point.x > contour->getMax().x || point.y < contour->getMin().y || point.y > contour->getMax().y) { return false; } double width = contour->getSize().x+1.0; bool sure; int counter; int tries = 0; double rayAngle = 0.0; do { sure = true; // create ray: RS_Vector v; v.setPolar(width*10.0, rayAngle); RS_Line ray(NULL, RS_LineData(point, point+v)); counter = 0; RS_VectorSolutions sol; if (onContour!=NULL) { *onContour = false; } for (RS_Entity* e = contour->firstEntity(RS2::ResolveAll); e!=NULL; e = contour->nextEntity(RS2::ResolveAll)) { // intersection(s) from ray with contour entity: sol = RS_Information::getIntersection(&ray, e, true); for (int i=0; i<=1; ++i) { RS_Vector p = sol.get(i); if (p.valid) { // point is on the contour itself if (p.distanceTo(point)<1.0e-5) { if (onContour!=NULL) { *onContour = true; } } else { if (e->rtti()==RS2::EntityLine) { RS_Line* line = (RS_Line*)e; // ray goes through startpoint of line: if (p.distanceTo(line->getStartpoint())<1.0e-4) { if (RS_Math::correctAngle(line->getAngle1())<M_PI) { sure = false; } } // ray goes through endpoint of line: else if (p.distanceTo(line->getEndpoint())<1.0e-4) { if (RS_Math::correctAngle(line->getAngle2())<M_PI) { sure = false; } } // else: ray goes through the line counter++; } else if (e->rtti()==RS2::EntityArc) { RS_Arc* arc = (RS_Arc*)e; if (p.distanceTo(arc->getStartpoint())<1.0e-4) { double dir = arc->getDirection1(); if ((dir<M_PI && dir>=1.0e-5) || ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) && arc->getCenter().y>p.y)) { counter++; sure = false; } } else if (p.distanceTo(arc->getEndpoint())<1.0e-4) { double dir = arc->getDirection2(); if ((dir<M_PI && dir>=1.0e-5) || ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) && arc->getCenter().y>p.y)) { counter++; sure = false; } } else { counter++; } } else if (e->rtti()==RS2::EntityCircle) { // tangent: if (i==0 && sol.get(1).valid==false) { if (!sol.isTangent()) { counter++; } else { sure = false; } } else if (i==1 || sol.get(1).valid==true) { counter++; } } else if (e->rtti()==RS2::EntityEllipse) { RS_Ellipse* ellipse=static_cast<RS_Ellipse*>(e); if(ellipse->isArc()){ if (p.distanceTo(ellipse->getStartpoint())<1.0e-4) { double dir = ellipse->getDirection1(); if ((dir<M_PI && dir>=1.0e-5) || ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) && ellipse->getCenter().y>p.y)) { counter++; sure = false; } } else if (p.distanceTo(ellipse->getEndpoint())<1.0e-4) { double dir = ellipse->getDirection2(); if ((dir<M_PI && dir>=1.0e-5) || ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) && ellipse->getCenter().y>p.y)) { counter++; sure = false; } } else { counter++; } }else{ // tangent: if (i==0 && sol.get(1).valid==false) { if (!sol.isTangent()) { counter++; } else { sure = false; } } else if (i==1 || sol.get(1).valid==true) { counter++; } } } } } } } rayAngle+=0.02; tries++; } while (!sure && rayAngle<2*M_PI && tries<6); // remove double intersections: /* QList<RS_Vector> is2; bool done; RS_Vector* av; do { done = true; double minDist = RS_MAXDOUBLE; double dist; av = NULL; for (RS_Vector* v = is.first(); v!=NULL; v = is.next()) { dist = point.distanceTo(*v); if (dist<minDist) { minDist = dist; done = false; av = v; } } if (!done && av!=NULL) { is2.append(*av); } } while (!done); */ return ((counter%2)==1); }
/** * Updates the sub entities of this dimension. Called when the * text or the position, alignment, .. changes. * * @param autoText Automatically reposition the text label */ void RS_DimAligned::update(bool autoText) { RS_DEBUG->print("RS_DimAligned::update"); clear(); if (isUndone()) { return; } // general scale (DIMSCALE) double dimscale = getGeneralScale(); // distance from entities (DIMEXO) double dimexo = getExtensionLineOffset()*dimscale; // definition line definition (DIMEXE) double dimexe = getExtensionLineExtension()*dimscale; // text height (DIMTXT) //double dimtxt = getTextHeight(); // text distance to line (DIMGAP) //double dimgap = getDimensionLineGap(); // Angle from extension endpoints towards dimension line double extAngle = edata.extensionPoint2.angleTo(data.definitionPoint); // extension lines length double extLength = edata.extensionPoint2.distanceTo(data.definitionPoint); RS_Vector v1, v2, e1; RS_LineData ld; RS_Line* line; v1.setPolar(dimexo, extAngle); v2.setPolar(dimexe, extAngle); e1.setPolar(1.0, extAngle); // Extension line 1: ld = RS_LineData(edata.extensionPoint1 + v1, edata.extensionPoint1 + e1*extLength + v2); line = new RS_Line(this, ld); //line->setLayerToActive(); //line->setPenToActive(); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // Extension line 2: ld = RS_LineData(edata.extensionPoint2 + v1, edata.extensionPoint2 + e1*extLength + v2); line = new RS_Line(this, ld); //line->setLayerToActive(); //line->setPenToActive(); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // Dimension line: updateCreateDimensionLine(edata.extensionPoint1 + e1*extLength, edata.extensionPoint2 + e1*extLength, true, true, autoText); calculateBorders(); }
/** * Creates a tangent between two circles or arcs. * Out of the 4 possible tangents, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which tangent we want (typically a * mouse coordinate). * @param circle1 1st circle or arc entity. * @param circle2 2nd circle or arc entity. */ RS_Line* RS_Creation::createTangent2(const RS_Vector& coord, RS_Entity* circle1, RS_Entity* circle2) { RS_Line* ret = NULL; RS_Vector circleCenter1; RS_Vector circleCenter2; double circleRadius1 = 0.0; double circleRadius2 = 0.0; // check given entities: if (circle1==NULL || circle2==NULL || ((circle1->rtti()!=RS2::EntityArc && circle1->rtti()!=RS2::EntityEllipse && circle1->rtti()!=RS2::EntityCircle) || (circle2->rtti()!=RS2::EntityArc && circle2->rtti()!=RS2::EntityEllipse && circle2->rtti()!=RS2::EntityCircle) )) { return NULL; } QVector<RS_Line*> poss; // for (int i=0; i<4; ++i) { // poss[i] = NULL; // } RS_LineData d; if( circle1->rtti() == RS2::EntityEllipse) { std::swap(circle1,circle2);//move Ellipse to the second place } circleCenter1=circle1->getCenter(); circleRadius1=circle1->getRadius(); circleCenter2=circle2->getCenter(); circleRadius2=circle2->getRadius(); if(circle2->rtti() != RS2::EntityEllipse) { //no ellipse // create all possible tangents: double angle1 = circleCenter1.angleTo(circleCenter2); double dist1 = circleCenter1.distanceTo(circleCenter2); if (dist1>1.0e-6) { // outer tangents: double dist2 = circleRadius2 - circleRadius1; if (dist1>dist2) { double angle2 = asin(dist2/dist1); double angt1 = angle1 + angle2 + M_PI/2.0; double angt2 = angle1 - angle2 - M_PI/2.0; RS_Vector offs1; RS_Vector offs2; offs1.setPolar(circleRadius1, angt1); offs2.setPolar(circleRadius2, angt1); d = RS_LineData(circleCenter1 + offs1, circleCenter2 + offs2); poss.push_back( new RS_Line(NULL, d)); offs1.setPolar(circleRadius1, angt2); offs2.setPolar(circleRadius2, angt2); d = RS_LineData(circleCenter1 + offs1, circleCenter2 + offs2); poss.push_back( new RS_Line(NULL, d)); } // inner tangents: double dist3 = circleRadius2 + circleRadius1; if (dist1>dist3) { double angle3 = asin(dist3/dist1); double angt3 = angle1 + angle3 + M_PI/2.0; double angt4 = angle1 - angle3 - M_PI/2.0; RS_Vector offs1; RS_Vector offs2; offs1.setPolar(circleRadius1, angt3); offs2.setPolar(circleRadius2, angt3); d = RS_LineData(circleCenter1 - offs1, circleCenter2 + offs2); poss.push_back( new RS_Line(NULL, d)); offs1.setPolar(circleRadius1, angt4); offs2.setPolar(circleRadius2, angt4); d = RS_LineData(circleCenter1 - offs1, circleCenter2 + offs2); poss.push_back( new RS_Line(NULL, d)); } } } else { //circle2 is Ellipse RS_Ellipse* e2=(RS_Ellipse*)circle2->clone(); // RS_Ellipse* e2=new RS_Ellipse(NULL,RS_EllipseData(RS_Vector(4.,1.),RS_Vector(2.,0.),0.5,0.,0.,false)); // RS_Ellipse e3(NULL,RS_EllipseData(RS_Vector(4.,1.),RS_Vector(2.,0.),0.5,0.,0.,false)); // RS_Ellipse* circle1=new RS_Ellipse(NULL,RS_EllipseData(RS_Vector(0.,0.),RS_Vector(1.,0.),1.,0.,0.,false)); RS_Vector m0(circle1->getCenter()); // std::cout<<"translation: "<<-m0<<std::endl; e2->move(-m0); //circle1 centered at origin double a,b; double a0(0.); if(circle1->rtti() != RS2::EntityEllipse) { //circle1 is either arc or circle a=fabs(circle1->getRadius()); b=a; if(fabs(a)<RS_TOLERANCE) return NULL; } else { //circle1 is ellipse RS_Ellipse* e1=static_cast<RS_Ellipse*>(circle1); a0=e1->getAngle(); // std::cout<<"rotation: "<<-a0<<std::endl; e2->rotate(-a0);//e1 major axis along x-axis a=e1->getMajorRadius(); b=e1->getRatio()*a; if(fabs(a)<RS_TOLERANCE || fabs(b)<RS_TOLERANCE) return NULL; } RS_Vector factor1(1./a,1./b); // std::cout<<"scaling: factor1="<<factor1<<std::endl; e2->scale(RS_Vector(0.,0.),factor1);//circle1 is a unit circle factor1.set(a,b); double a2(e2->getAngle()); // std::cout<<"rotation: a2="<<-a2<<std::endl; e2->rotate(-a2); //ellipse2 with major axis in x-axis direction a=e2->getMajorP().x; b=a*e2->getRatio(); RS_Vector v(e2->getCenter()); // std::cout<<"Center: (x,y)="<<v<<std::endl; std::vector<double> m(0,0.); m.push_back(1./(a*a)); //ma000 m.push_back(1./(b*b)); //ma000 m.push_back(v.y*v.y-1.); //ma100 m.push_back(v.x*v.y); //ma101 m.push_back(v.x*v.x-1.); //ma111 m.push_back(2.*a*b*v.y); //mb10 m.push_back(2.*a*b*v.x); //mb11 m.push_back(a*a*b*b); //mc1 auto&& vs0=RS_Math::simultaneousQuadraticSolver(m); //to hold solutions if (vs0.getNumber()<1) return NULL; for(int i=0; i<vs0.getNumber(); i++) { // std::cout<<"i="<<i<<"\n"; RS_Vector vpec=vs0.get(i); //this holds ( a*sin(t), b*cos(t)) // std::cout<<"solution "<<i<<" ="<<vpec<<std::endl; RS_Vector vpe2(e2->getCenter()+ RS_Vector(vpec.y/e2->getRatio(),vpec.x*e2->getRatio())); vpec.x *= -1.;//direction vector of tangent RS_Vector vpe1(vpe2 - vpec*(RS_Vector::dotP(vpec,vpe2)/vpec.squared())); // std::cout<<"vpe1.squared()="<<vpe1.squared()<<std::endl; RS_Line *l=new RS_Line(NULL,RS_LineData(vpe1,vpe2)); l->rotate(a2); l->scale(factor1); l->rotate(a0); l->move(m0); poss.push_back(l); } delete e2; //debugging } // find closest tangent: if(poss.size()<1) return NULL; double minDist = RS_MAXDOUBLE; double dist; int idx = -1; for (int i=0; i<poss.size(); ++i) { if (poss[i]!=NULL) { poss[i]->getNearestPointOnEntity(coord,false,&dist); // std::cout<<poss.size()<<": i="<<i<<" dist="<<dist<<"\n"; if (dist<minDist) { minDist = dist; idx = i; } } } //idx=static_cast<int>(poss.size()*(random()/(double(1.0)+RAND_MAX))); if (idx!=-1) { RS_LineData d = poss[idx]->getData(); for (int i=0; i<poss.size(); ++i) { if (poss[i]!=NULL) { delete poss[i]; } } if (document!=NULL && handleUndo) { document->startUndoCycle(); } ret = new RS_Line(container, d); ret->setLayerToActive(); ret->setPenToActive(); if (container!=NULL) { container->addEntity(ret); } if (document!=NULL && handleUndo) { document->addUndoable(ret); document->endUndoCycle(); } if (graphicView!=NULL) { graphicView->drawEntity(ret); } } else { ret = NULL; } return ret; }
/** * Updates the sub entities of this dimension. Called when the * dimension or the position, alignment, .. changes. * * @param autoText Automatically reposition the text label */ void RS_DimAngular::update(bool /*autoText*/) { RS_DEBUG->print("RS_DimAngular::update"); clear(); if (isUndone()) { return; } // distance from entities (DIMEXO) double dimexo = getExtensionLineOffset(); // extension line extension (DIMEXE) double dimexe = getExtensionLineExtension(); // text height (DIMTXT) double dimtxt = getTextHeight(); // text distance to line (DIMGAP) double dimgap = getDimensionLineGap(); // find out center: RS_Vector center = getCenter(); if (!center.valid) { return; } double ang1 = 0.0; double ang2 = 0.0; bool reversed = false; RS_Vector p1; RS_Vector p2; getAngles(ang1, ang2, reversed, p1, p2); double rad = edata.definitionPoint4.distanceTo(center); RS_Line* line; RS_Vector dir; double len; double dist; // 1st extension line: dist = center.distanceTo(p1); len = rad - dist + dimexe; dir.setPolar(1.0, ang1); line = new RS_Line(this, RS_LineData(center + dir*dist + dir*dimexo, center + dir*dist + dir*len)); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // 2nd extension line: dist = center.distanceTo(p2); len = rad - dist + dimexe; dir.setPolar(1.0, ang2); line = new RS_Line(this, RS_LineData(center + dir*dist + dir*dimexo, center + dir*dist + dir*len)); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // Create dimension line (arc): RS_Arc* arc = new RS_Arc(this, RS_ArcData(center, rad, ang1, ang2, reversed)); arc->setPen(RS_Pen(RS2::FlagInvalid)); arc->setLayer(NULL); addEntity(arc); // length of dimension arc: double distance = arc->getLength(); // do we have to put the arrows outside of the arc? bool outsideArrows = (distance<getArrowSize()*2); // arrow angles: double arrowAngle1, arrowAngle2; double arrowAng; if (rad>1.0e-6) { arrowAng = getArrowSize() / rad; } else { arrowAng = 0.0; } RS_Vector v1, v2; if (!arc->isReversed()) { v1.setPolar(rad, arc->getAngle1()+arrowAng); } else { v1.setPolar(rad, arc->getAngle1()-arrowAng); } v1+=arc->getCenter(); arrowAngle1 = arc->getStartpoint().angleTo(v1); if (!arc->isReversed()) { v2.setPolar(rad, arc->getAngle2()-arrowAng); } else { v2.setPolar(rad, arc->getAngle2()+arrowAng); } v2+=arc->getCenter(); arrowAngle2 = arc->getEndpoint().angleTo(v2); if (!outsideArrows) { arrowAngle1 = arrowAngle1+M_PI; arrowAngle2 = arrowAngle2+M_PI; } // Arrows: RS_SolidData sd; RS_Solid* arrow; // arrow 1 arrow = new RS_Solid(this, sd); arrow->shapeArrow(arc->getStartpoint(), arrowAngle1, getArrowSize()); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); // arrow 2: arrow = new RS_Solid(this, sd); arrow->shapeArrow(arc->getEndpoint(), arrowAngle2, getArrowSize()); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); // text label: RS_TextData textData; RS_Vector textPos = arc->getMiddlepoint(); RS_Vector distV; double textAngle; double dimAngle1 = textPos.angleTo(arc->getCenter())-M_PI/2.0; // rotate text so it's readable from the bottom or right (ISO) // quadrant 1 & 4 if (dimAngle1>M_PI/2.0*3.0+0.001 || dimAngle1<M_PI/2.0+0.001) { distV.setPolar(dimgap, dimAngle1+M_PI/2.0); textAngle = dimAngle1; } // quadrant 2 & 3 else { distV.setPolar(dimgap, dimAngle1-M_PI/2.0); textAngle = dimAngle1+M_PI; } // move text away from dimension line: textPos+=distV; textData = RS_TextData(textPos, dimtxt, 30.0, RS2::VAlignBottom, RS2::HAlignCenter, RS2::LeftToRight, RS2::Exact, 1.0, getLabel(), "standard", textAngle); RS_Text* text = new RS_Text(this, textData); // move text to the side: text->setPen(RS_Pen(RS2::FlagInvalid)); text->setLayer(NULL); addEntity(text); calculateBorders(); }
/** * Selects all circles (and arcs min. 3/4 circle) with same diameter and same layer, * in a window (v1, v2) * mosty used with CAM bores * * @param e Must be an circle or arc (min. 3/4 circle) */ void RS_Selection::selectCircles(RS_Entity* e, RS_Vector v1, RS_Vector v2 /*, bool inside=true */ ) { if (e==NULL) return; if (!e->isAtomic()) return; e->toggleSelected(); // bool cross = v2.y > v1.y; bool cross = v1.x > v2.x; bool select = !e->isSelected(); RS_AtomicEntity* ae = (RS_AtomicEntity*)e; double r_clicked = 0; RS_Layer* layer_clicked = 0; if (graphicView!=NULL) graphicView->drawEntity(e); if (ae->rtti()==RS2::EntityArc || ae->rtti()==RS2::EntityCircle) { r_clicked = ae->getRadius(); if (ae->rtti()==RS2::EntityArc) if(ae->getAngleLength() < 4.66) /* ca. 267 grad (knapp 3/4 kreis) */ { r_clicked = 0; RS_DIALOGFACTORY->commandMessage("selected arc has AngleLength < 4.66"); } layer_clicked = ae->getLayer(); } for (RS_Entity* en=container->firstEntity(); en!=NULL; en=container->nextEntity()) { int included = 0; if (en!=NULL && en->isVisible() && en->isAtomic() && en->isSelected()!=select && (en->rtti()==RS2::EntityArc || en->rtti()==RS2::EntityCircle) && (en->getLayer()==NULL || en->getLayer()->isLocked()==false)) { ae = (RS_AtomicEntity*)en; if(en->isInWindow(v1, v2)) included++; if (cross == true) { RS_Line l[] = { RS_Line(NULL, RS_LineData(v1, RS_Vector(v2.x, v1.y))), RS_Line(NULL, RS_LineData(RS_Vector(v2.x, v1.y), v2)), RS_Line(NULL, RS_LineData(v2, RS_Vector(v1.x, v2.y))), RS_Line(NULL, RS_LineData(RS_Vector(v1.x, v2.y), v1)) }; RS_VectorSolutions sol; if (ae->isContainer()) continue; else { for (int i=0; i<4; ++i) { sol = RS_Information::getIntersection(ae, &l[i], true); if (sol.hasValid()) { included++; break; } } } } // ----------------------- if(included) { double rc = ae->getRadius(); double rdiff = fabs (rc - r_clicked); if ((r_clicked > 0.000003) && (0.000003 > rdiff) && (ae->getLayer() == layer_clicked)) { if (graphicView!=NULL) { graphicView->deleteEntity(ae); } ae->setSelected(select); if (graphicView!=NULL) { graphicView->drawEntity(ae); } } } } } //std::cerr << "ende in rs_selection.cpp \n"; }
/** * Creates a line parallel to the given line e. * Out of the 2 possible parallels, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which parallel we want (typically a * mouse coordinate). * @param distance Distance of the parallel. * @param number Number of parallels. * @param e Original entity. * * @return Pointer to the first created parallel or NULL if no * parallel has been created. */ RS_Line* RS_Creation::createParallelLine(const RS_Vector& coord, double distance, int number, RS_Line* e) { if (e==NULL) { return NULL; } double ang = e->getAngle1() + M_PI/2.0; RS_Vector p1, p2; RS_LineData parallelData; RS_Line* ret = NULL; if (document!=NULL && handleUndo) { document->startUndoCycle(); } for (int num=1; num<=number; ++num) { // calculate 1st parallel: p1.setPolar(distance*num, ang); p1 += e->getStartpoint(); p2.setPolar(distance*num, ang); p2 += e->getEndpoint(); RS_Line parallel1(NULL, RS_LineData(p1, p2)); // calculate 2nd parallel: p1.setPolar(distance*num, ang+M_PI); p1 += e->getStartpoint(); p2.setPolar(distance*num, ang+M_PI); p2 += e->getEndpoint(); RS_Line parallel2(NULL, RS_LineData(p1, p2)); double dist1 = parallel1.getDistanceToPoint(coord); double dist2 = parallel2.getDistanceToPoint(coord); double minDist = std::min(dist1, dist2); if (minDist<RS_MAXDOUBLE) { if (dist1<dist2) { parallelData = parallel1.getData(); } else { parallelData = parallel2.getData(); } RS_Line* newLine = new RS_Line(container, parallelData); newLine->setLayerToActive(); newLine->setPenToActive(); if (ret==NULL) { ret = newLine; } if (container!=NULL) { container->addEntity(newLine); } if (document!=NULL && handleUndo) { document->addUndoable(newLine); //document->endUndoCycle(); } if (graphicView!=NULL) { graphicView->drawEntity(newLine); } } } if (document!=NULL && handleUndo) { document->endUndoCycle(); } return ret; }
/*RS_EntityContainer* parent, const RS_LineData& d*/ Plugin_Entity::Plugin_Entity(RS_EntityContainer* parent, enum DPI::ETYPE type){ hasContainer = false; entity = NULL; switch (type) { case DPI::POINT: entity = new RS_Point(parent, RS_PointData(RS_Vector(0,0))); break; case DPI::LINE: entity = new RS_Line(parent, RS_LineData()); break; /* case DPI::CONSTRUCTIONLINE: entity = new RS_ConstructionLine(); break;*/ case DPI::CIRCLE: entity = new RS_Circle(parent, RS_CircleData()); break; case DPI::ARC: entity = new RS_Arc(parent, RS_ArcData()); break; case DPI::ELLIPSE: entity = new RS_Ellipse(parent, RS_EllipseData(RS_Vector(0,0), RS_Vector(0,0),0.0,0.0,0.0,false)); break; case DPI::IMAGE: entity = new RS_Image(parent, RS_ImageData()); break; /* case DPI::OVERLAYBOX: entity = new RS_OverlayBox(); break; case DPI::SOLID: entity = new RS_Solid(); break;*/ case DPI::TEXT: entity = new RS_Text(parent, RS_TextData()); break; /* case DPI::INSERT: entity = new RS_Insert(); break;*/ case DPI::POLYLINE: entity = new RS_Polyline(parent, RS_PolylineData()); break; /* case DPI::SPLINE: entity = new RS_Spline(); break; case DPI::HATCH: entity = new RS_Hatch(); break; case DPI::DIMLEADER: entity = new RS_Leader(); break; case DPI::DIMALIGNED: entity = new RS_DimAligned(); break; case DPI::DIMLINEAR: entity = new RS_DimLinear(); break; case DPI::DIMRADIAL: entity = new RS_DimRadial(); break; case DPI::DIMDIAMETRIC: entity = new RS_DimDiametric(); break; case DPI::DIMANGULAR: entity = new RS_DimAngular(); break;*/ default: break; } }
/** * Creates a tangent between a given point and a circle or arc. * Out of the 2 possible tangents, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which tangent we want (typically a * mouse coordinate). * @param point Point. * @param circle Circle, arc or ellipse entity. */ RS_Line* RS_Creation::createTangent1(const RS_Vector& coord, const RS_Vector& point, RS_Entity* circle) { RS_Line* ret = NULL; RS_Vector circleCenter; // check given entities: if (circle==NULL || !point.valid || (circle->rtti()!=RS2::EntityArc && circle->rtti()!=RS2::EntityCircle && circle->rtti()!=RS2::EntityEllipse)) { return NULL; } if (circle->rtti()==RS2::EntityCircle) { circleCenter = ((RS_Circle*)circle)->getCenter(); } else if (circle->rtti()==RS2::EntityArc) { circleCenter = ((RS_Arc*)circle)->getCenter(); } else if (circle->rtti()==RS2::EntityEllipse) { circleCenter = ((RS_Ellipse*)circle)->getCenter(); } // the two tangent points: RS_VectorSolutions sol; // calculate tangent points for arcs / circles: if (circle->rtti()!=RS2::EntityEllipse) { // create temp. thales circle: RS_Vector tCenter = (point + circleCenter)/2.0; double tRadius = point.distanceTo(tCenter); RS_Circle tmp(NULL, RS_CircleData(tCenter, tRadius)); // get the two intersection points which are the tangent points: sol = RS_Information::getIntersection(&tmp, circle, false); } // calculate tangent points for ellipses: else { RS_Ellipse* el = (RS_Ellipse*)circle; //sol.alloc(2); //sol.set(0, circleCenter); //sol.set(1, circleCenter); double a = el->getMajorRadius(); // the length of the major axis / 2 double b = el->getMinorRadius(); // the length of the minor axis / 2 // rotate and move point: RS_Vector point2 = point; point2.move(-el->getCenter()); point2.rotate(-el->getAngle()); double xp = point2.x; // coordinates of the given point double yp = point2.y; double xt1; // Tangent point 1 double yt1; double xt2; // Tangent point 2 double yt2; double a2 = a * a; double b2 = b * b; double d = a2 / b2 * yp / xp; double e = a2 / xp; double af = b2 * d * d + a2; double bf = -b2 * d * e * 2.0; double cf = b2 * e * e - a2 * b2; double t = sqrt(bf * bf - af * cf * 4.0); yt1 = (t - bf) / (af * 2.0); xt1 = e - d * yt1; yt2 = (-t - bf) / (af * 2.0); xt2 = e - d * yt2; RS_Vector s1 = RS_Vector(xt1, yt1); RS_Vector s2 = RS_Vector(xt2, yt2); s1.rotate(el->getAngle()); s1.move(el->getCenter()); s2.rotate(el->getAngle()); s2.move(el->getCenter()); sol.push_back(s1); sol.push_back(s2); } if (sol.getNumber() < 2 ) { return NULL; } if (!sol.get(0).valid || !sol.get(1).valid) { return NULL; } // create all possible tangents: RS_Line* poss[2]; RS_LineData d; d = RS_LineData(sol.get(0), point); poss[0] = new RS_Line(NULL, d); d = RS_LineData(sol.get(1), point); poss[1] = new RS_Line(NULL, d); // find closest tangent: double minDist = RS_MAXDOUBLE; double dist; int idx = -1; for (int i=0; i<2; ++i) { dist = poss[i]->getDistanceToPoint(coord); if (dist<minDist) { minDist = dist; idx = i; } } // create the closest tangent: if (idx!=-1) { RS_LineData d = poss[idx]->getData(); for (int i=0; i<2; ++i) { delete poss[i]; } if (document!=NULL && handleUndo) { document->startUndoCycle(); } ret = new RS_Line(container, d); ret->setLayerToActive(); ret->setPenToActive(); if (container!=NULL) { container->addEntity(ret); } if (document!=NULL && handleUndo) { document->addUndoable(ret); document->endUndoCycle(); } if (graphicView!=NULL) { graphicView->drawEntity(ret); } } else { ret = NULL; } return ret; }
bool RS_Solid::isInCrossWindow(const RS_Vector& v1,const RS_Vector& v2)const { // bool sol = false; RS_Vector vBL, vTR; RS_VectorSolutions sol; //sort imput vectors to BottomLeft & TopRight if (v1.x<v2.x) { vBL.x = v1.x; vTR.x = v2.x; } else { vBL.x = v2.x; vTR.x = v1.x; } if (v1.y<v2.y) { vBL.y = v1.y; vTR.y = v2.y; } else { vBL.y = v2.y; vTR.y = v1.y; } //Check if is out of window if ( getMin().x > vTR.x || getMax().x < vBL.x || getMin().y > vTR.y || getMax().y < vBL.y) { return false; } std::vector<RS_Line> l; l.push_back(RS_Line(nullptr, RS_LineData(data.corner[0], data.corner[1]))); l.push_back(RS_Line(nullptr, RS_LineData(data.corner[1], data.corner[2]))); if (data.corner[3].valid) { l.push_back(RS_Line(nullptr, RS_LineData(data.corner[2], data.corner[3]))); l.push_back(RS_Line(nullptr, RS_LineData(data.corner[3], data.corner[0]))); } else { l.push_back(RS_Line(nullptr, RS_LineData(data.corner[2], data.corner[0]))); } //Find crossing edge if (getMax().x > vBL.x && getMin().x < vBL.x) {//left RS_Line edge = RS_Line(nullptr, RS_LineData(vBL, RS_Vector(vBL.x, vTR.y))); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } if (getMax().x > vTR.x && getMin().x < vTR.x) {//right RS_Line edge = RS_Line(nullptr, RS_LineData(RS_Vector(vTR.x, vBL.y), vTR)); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } if (getMax().y > vBL.y && getMin().y < vBL.y) {//bottom RS_Line edge = RS_Line(nullptr, RS_LineData(vBL, RS_Vector(vTR.x, vBL.y))); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } if(getMax().y > vTR.y && getMin().y < vTR.y) {//top RS_Line edge = RS_Line(nullptr, RS_LineData(RS_Vector(vBL.x, vTR.y), vTR)); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } return false; }
/** * Updates the Hatch. Called when the * hatch or it's data, position, alignment, .. changes. */ void RS_Hatch::update() { RS_DEBUG->print("RS_Hatch::update"); RS_DEBUG->print("RS_Hatch::update: contour has %d loops", count()); if (updateRunning) { return; } if (updateEnabled==false) { return; } if (data.solid==true) { calculateBorders(); return; } RS_DEBUG->print("RS_Hatch::update"); updateRunning = true; // delete old hatch: if (hatch!=NULL) { removeEntity(hatch); hatch = NULL; } if (isUndone()) { updateRunning = false; return; } if (!validate()) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Hatch::update: invalid contour in hatch found"); updateRunning = false; return; } // search pattern: RS_DEBUG->print("RS_Hatch::update: requesting pattern"); RS_Pattern* pat = RS_PATTERNLIST->requestPattern(data.pattern); if (pat==NULL) { updateRunning = false; RS_DEBUG->print("RS_Hatch::update: requesting pattern: not found"); return; } RS_DEBUG->print("RS_Hatch::update: requesting pattern: OK"); RS_DEBUG->print("RS_Hatch::update: cloning pattern"); pat = (RS_Pattern*)pat->clone(); RS_DEBUG->print("RS_Hatch::update: cloning pattern: OK"); // scale pattern RS_DEBUG->print("RS_Hatch::update: scaling pattern"); pat->scale(RS_Vector(0.0,0.0), RS_Vector(data.scale, data.scale)); pat->calculateBorders(); forcedCalculateBorders(); RS_DEBUG->print("RS_Hatch::update: scaling pattern: OK"); // find out how many pattern-instances we need in x/y: int px1, py1, px2, py2; double f; RS_Hatch* copy = (RS_Hatch*)this->clone(); copy->rotate(RS_Vector(0.0,0.0), -data.angle); copy->forcedCalculateBorders(); // create a pattern over the whole contour. RS_Vector pSize = pat->getSize(); // RS_Vector cPos = getMin(); RS_Vector cSize = getSize(); RS_DEBUG->print("RS_Hatch::update: pattern size: %f/%f", pSize.x, pSize.y); RS_DEBUG->print("RS_Hatch::update: contour size: %f/%f", cSize.x, cSize.y); if (cSize.x<1.0e-6 || cSize.y<1.0e-6 || pSize.x<1.0e-6 || pSize.y<1.0e-6 || cSize.x>RS_MAXDOUBLE-1 || cSize.y>RS_MAXDOUBLE-1 || pSize.x>RS_MAXDOUBLE-1 || pSize.y>RS_MAXDOUBLE-1) { delete pat; delete copy; updateRunning = false; RS_DEBUG->print("RS_Hatch::update: contour size or pattern size too small"); return; } // avoid huge memory consumption: else if (cSize.x/pSize.x>100 || cSize.y/pSize.y>100) { RS_DEBUG->print("RS_Hatch::update: contour size too large or pattern size too small"); return; } f = copy->getMin().x/pat->getSize().x; px1 = (int)floor(f); f = copy->getMin().y/pat->getSize().y; py1 = (int)floor(f); f = copy->getMax().x/pat->getSize().x; px2 = (int)ceil(f) - 1; f = copy->getMax().y/pat->getSize().y; py2 = (int)ceil(f) - 1; RS_EntityContainer tmp; // container for untrimmed lines // adding array of patterns to tmp: RS_DEBUG->print("RS_Hatch::update: creating pattern carpet"); for (int px=px1; px<=px2; px++) { for (int py=py1; py<=py2; py++) { for (RS_Entity* e=pat->firstEntity(); e!=NULL; e=pat->nextEntity()) { RS_Entity* te = e->clone(); te->rotate(RS_Vector(0.0,0.0), data.angle); RS_Vector v1, v2; v1.setPolar(px*pSize.x, data.angle); v2.setPolar(py*pSize.y, data.angle+M_PI/2.0); te->move(v1+v2); tmp.addEntity(te); } } } delete pat; pat = NULL; RS_DEBUG->print("RS_Hatch::update: creating pattern carpet: OK"); RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet"); // cut pattern to contour shape: RS_EntityContainer tmp2; // container for small cut lines RS_Line* line = NULL; RS_Arc* arc = NULL; RS_Circle* circle = NULL; RS_Ellipse* ellipse = NULL; for (RS_Entity* e=tmp.firstEntity(); e!=NULL; e=tmp.nextEntity()) { RS_Vector startPoint; RS_Vector endPoint; RS_Vector center = RS_Vector(false); bool reversed; switch(e->rtti()){ case RS2::EntityLine: line=static_cast<RS_Line*>(e); startPoint = line->getStartpoint(); endPoint = line->getEndpoint(); break; case RS2::EntityArc: arc=static_cast<RS_Arc*>(e); startPoint = arc->getStartpoint(); endPoint = arc->getEndpoint(); center = arc->getCenter(); reversed = arc->isReversed(); break; case RS2::EntityCircle: circle=static_cast<RS_Circle*>(e); startPoint = circle->getCenter() + RS_Vector(circle->getRadius(), 0.0); endPoint = startPoint; center = circle->getCenter(); break; case RS2::EntityEllipse: ellipse = static_cast<RS_Ellipse*>(e); startPoint = ellipse->getStartpoint(); endPoint = ellipse->getEndpoint(); center = ellipse->getCenter(); reversed = ellipse->isReversed(); break; default: continue; } // getting all intersections of this pattern line with the contour: QList<std::shared_ptr<RS_Vector> > is; is.append(std::shared_ptr<RS_Vector>(new RS_Vector(startPoint))); for (RS_Entity* loop=firstEntity(); loop!=NULL; loop=nextEntity()) { if (loop->isContainer()) { for (RS_Entity* p=((RS_EntityContainer*)loop)->firstEntity(); p!=NULL; p=((RS_EntityContainer*)loop)->nextEntity()) { RS_VectorSolutions sol = RS_Information::getIntersection(e, p, true); for (int i=0; i<=1; ++i) { if (sol.get(i).valid) { is.append(std::shared_ptr<RS_Vector>( new RS_Vector(sol.get(i)) )); RS_DEBUG->print(" pattern line intersection: %f/%f", sol.get(i).x, sol.get(i).y); } } } } } is.append(std::shared_ptr<RS_Vector>(new RS_Vector(endPoint))); // sort the intersection points into is2: RS_Vector sp = startPoint; double sa = center.angleTo(sp); if(ellipse != NULL) sa=ellipse->getEllipseAngle(sp); QList<std::shared_ptr<RS_Vector> > is2; bool done; double minDist; double dist = 0.0; std::shared_ptr<RS_Vector> av; std::shared_ptr<RS_Vector> v; RS_Vector last = RS_Vector(false); do { done = true; minDist = RS_MAXDOUBLE; av.reset(); for (int i = 0; i < is.size(); ++i) { v = is.at(i); double a; switch(e->rtti()){ case RS2::EntityLine: dist = sp.distanceTo(*v); break; case RS2::EntityArc: case RS2::EntityCircle: a = center.angleTo(*v); dist = reversed? fmod(sa - a + 2.*M_PI,2.*M_PI): fmod(a - sa + 2.*M_PI,2.*M_PI); break; case RS2::EntityEllipse: a = ellipse->getEllipseAngle(*v); dist = reversed? fmod(sa - a + 2.*M_PI,2.*M_PI): fmod(a - sa + 2.*M_PI,2.*M_PI); break; default: break; } if (dist<minDist) { minDist = dist; done = false; av = v; } } // copy to sorted list, removing double points if (!done && av.get()!=NULL) { if (last.valid==false || last.distanceTo(*av)>RS_TOLERANCE) { is2.append(std::shared_ptr<RS_Vector>(new RS_Vector(*av))); last = *av; } #if QT_VERSION < 0x040400 emu_qt44_removeOne(is, av); #else is.removeOne(av); #endif av.reset(); } } while(!done); // add small cut lines / arcs to tmp2: for (int i = 1; i < is2.size(); ++i) { auto v1 = is2.at(i-1); auto v2 = is2.at(i); if (line!=NULL) { tmp2.addEntity(new RS_Line(&tmp2, RS_LineData(*v1, *v2))); } else if (arc!=NULL || circle!=NULL) { tmp2.addEntity(new RS_Arc(&tmp2, RS_ArcData(center, center.distanceTo(*v1), center.angleTo(*v1), center.angleTo(*v2), reversed))); } } } // updating hatch / adding entities that are inside RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet: OK"); //RS_EntityContainer* rubbish = new RS_EntityContainer(getGraphic()); // the hatch pattern entities: hatch = new RS_EntityContainer(this); hatch->setPen(RS_Pen(RS2::FlagInvalid)); hatch->setLayer(NULL); hatch->setFlag(RS2::FlagTemp); //calculateBorders(); for (RS_Entity* e=tmp2.firstEntity(); e!=NULL; e=tmp2.nextEntity()) { RS_Vector middlePoint; RS_Vector middlePoint2; if (e->rtti()==RS2::EntityLine) { RS_Line* line = (RS_Line*)e; middlePoint = line->getMiddlePoint(); middlePoint2 = line->getNearestDist(line->getLength()/2.1, line->getStartpoint()); } else if (e->rtti()==RS2::EntityArc) { RS_Arc* arc = (RS_Arc*)e; middlePoint = arc->getMiddlePoint(); middlePoint2 = arc->getNearestDist(arc->getLength()/2.1, arc->getStartpoint()); } else { middlePoint = RS_Vector(false); middlePoint2 = RS_Vector(false); } if (middlePoint.valid) { bool onContour=false; if (RS_Information::isPointInsideContour( middlePoint, this, &onContour) || RS_Information::isPointInsideContour(middlePoint2, this)) { RS_Entity* te = e->clone(); te->setPen(RS_Pen(RS2::FlagInvalid)); te->setLayer(NULL); te->reparent(hatch); hatch->addEntity(te); } } } addEntity(hatch); //getGraphic()->addEntity(rubbish); forcedCalculateBorders(); // deactivate contour: activateContour(false); updateRunning = false; RS_DEBUG->print("RS_Hatch::update: OK"); }
bool RS_ActionDrawCircleTan3::getData(){ if(getStatus() != SetCircle3) return false; //find the nearest circle size_t i=0; size_t const countLines=std::count_if(circles.begin(), circles.end(), [](RS_AtomicEntity* e)->bool { return e->rtti()==RS2::EntityLine; }); for(;i<circles.size();++i) if(circles[i]->rtti() == RS2::EntityLine) break; candidates.clear(); size_t i1=(i+1)%3; size_t i2=(i+2)%3; if(i<circles.size() && circles[i]->rtti() == RS2::EntityLine){ //one or more lines LC_Quadratic lc0(circles[i],circles[i1],false); LC_Quadratic lc1; RS_VectorSolutions sol; //detect degenerate case two circles with the same radius switch(countLines){ default: case 0: //this should not happen assert(false); case 1: //1 line, two circles { for(unsigned k=0; k<4; ++k){ //loop through all mirroring cases lc1=LC_Quadratic(circles[i],circles[i1], k & 1u); LC_Quadratic lc2=LC_Quadratic(circles[i],circles[i2], k & 2u); sol.appendTo(LC_Quadratic::getIntersection(lc1,lc2)); } } break; case 2: //2 lines, one circle { if(circles[i2]->rtti()==RS2::EntityLine){ std::swap(i1, i2); } //i2 is circle for(unsigned k=0; k<4; ++k){ //loop through all mirroring cases lc1=LC_Quadratic(circles[i2],circles[i], k & 1u); LC_Quadratic lc2=LC_Quadratic(circles[i2],circles[i1], k & 2u); sol.appendTo(LC_Quadratic::getIntersection(lc1,lc2)); } } break; case 3: //3 lines { lc0=circles[i]->getQuadratic(); lc1=circles[i1]->getQuadratic(); auto lc2=circles[i2]->getQuadratic(); //attempt to have intersections (lc0, lc1), (lc0, lc2) auto sol1=LC_Quadratic::getIntersection(lc0,lc1); if(sol1.size()<1) { std::swap(lc0, lc2); std::swap(i, i2); } sol1=LC_Quadratic::getIntersection(lc0,lc2); if(sol1.size()<1) { std::swap(lc0, lc1); std::swap(i, i1); } RS_Line* line0=static_cast<RS_Line*>(circles[i]); RS_Line* line1=static_cast<RS_Line*>(circles[i1]); RS_Line* line2=static_cast<RS_Line*>(circles[i2]); lc0=line0->getQuadratic(); lc1=line1->getQuadratic(); lc2=line2->getQuadratic(); //intersection 0, 1 sol1=LC_Quadratic::getIntersection(lc0,lc1); if(!sol1.size()) { return false; } RS_Vector const v1=sol1.at(0); double angle1=0.5*(line0->getAngle1()+line1->getAngle1()); //intersection 0, 2 sol1=LC_Quadratic::getIntersection(lc0,lc2); double angle2; if(sol1.size()<1) { return false; } angle2=0.5*(line0->getAngle1()+line2->getAngle1()); RS_Vector const& v2=sol1.at(0); //two bisector lines per intersection for(unsigned j=0; j<2; ++j){ RS_Line l1(nullptr, RS_LineData(v1, v1+RS_Vector(angle1))); for(unsigned j1=0; j1<2; ++j1){ RS_Line l2(nullptr, RS_LineData(v2, v2+RS_Vector(angle2))); sol.appendTo(RS_Information::getIntersectionLineLine(&l1, &l2)); angle2 += M_PI_2; } angle1 += M_PI_2; } } } double d; //line passes circle center, need a second parabola as the image of the line for(int j=1;j<=2;j++){ if(circles[(i+j)%3]->rtti() == RS2::EntityCircle){ circles[i]->getNearestPointOnEntity(circles[(i+j)%3]->getCenter(), false,&d); if(d<RS_TOLERANCE) { LC_Quadratic lc2(circles[i],circles[(i+j)%3], true); sol.appendTo(LC_Quadratic::getIntersection(lc2,lc1)); } } } //clean up duplicate and invalid RS_VectorSolutions sol1; for(const RS_Vector& vp: sol){ if(vp.magnitude()>RS_MAXDOUBLE) continue; if(sol1.size() && sol1.getClosestDistance(vp)<RS_TOLERANCE) continue; sol1.push_back(vp); } for(auto const& v: sol1){ circles[i]->getNearestPointOnEntity(v,false,&d); std::shared_ptr<RS_CircleData> data(new RS_CircleData(v,d)); if(circles[(i+1)%3]->isTangent(*data)==false) continue; if(circles[(i+2)%3]->isTangent(*data)==false) continue; candidates.push_back(data); } }else{ RS_Circle c(nullptr,*cData); auto solutions=c.createTan3(circles); candidates.clear(); for(const RS_Circle& s: solutions){ candidates.push_back(std::make_shared<RS_CircleData>(s.getData())); } } valid = ( candidates.size() >0); return valid; }