Beispiel #1
0
void RS_Grid::createIsometricGrid(LC_Rect const& rect, RS_Vector const& gridWidth)
{
	double const left=rect.minP().x;
	double const right=rect.maxP().x;
	//top/bottom reversed
	double const top=rect.maxP().y;
	double const bottom=rect.minP().y;
	int numberY = (RS_Math::round((top-bottom) / gridWidth.y) + 1);
	double dx=sqrt(3.)*gridWidth.y;
	cellV.set(fabs(dx),fabs(gridWidth.y));
	double hdx=0.5*dx;
	double hdy=0.5*gridWidth.y;
	int numberX = (RS_Math::round((right-left) / dx) + 1);
	int number = 2*numberX*numberY;
	baseGrid.set(left+remainder(-left,dx),bottom+remainder(-bottom,fabs(gridWidth.y)));

	if (number<=0 || number>maxGridPoints) return;

	pt.resize(number);

	int i=0;
	RS_Vector bp0(baseGrid),dbp1(hdx,hdy);
	for (int y=0; y<numberY; ++y) {
		RS_Vector bp1(bp0);
		for (int x=0; x<numberX; ++x) {
			pt[i++] = bp1;
			pt[i++] = bp1+dbp1;
			bp1.x += dx;
		}
		bp0.y += gridWidth.y;
	}
	//find metaGrid
	if (metaGridWidth.y>minimumGridWidth &&
			graphicView->toGuiDY(metaGridWidth.y)>2) {

		metaGridWidth.x=(metaGridWidth.x<0.)?-sqrt(3.)*fabs(metaGridWidth.y):sqrt(3.)*fabs(metaGridWidth.y);
		RS_Vector baseMetaGrid(left+remainder(-left,metaGridWidth.x)-fabs(metaGridWidth.x),bottom+remainder(-bottom,metaGridWidth.y)-fabs(metaGridWidth.y));

		// calculate number of visible meta grid lines:
		int numMetaX = (RS_Math::round((right-left) / metaGridWidth.x) + 1);
		int numMetaY = (RS_Math::round((top-bottom) / metaGridWidth.y) + 1);

		if (numMetaX<=0 || numMetaY<=0) return;
		// create meta grid arrays:
		metaX.resize(numMetaX);
		metaY.resize(numMetaY);

		double x0(baseMetaGrid.x);
		for (int i=0; i<numMetaX; x0 += metaGridWidth.x) {
			metaX[i++] = x0;
		}
		x0=baseMetaGrid.y;
		for (int i=0; i<numMetaY; x0 += metaGridWidth.y) {
			metaY[i++] = x0;
		}
	}
}
Beispiel #2
0
/**
 * Calculates the intersection point(s) between two entities.
 *
 * @param onEntities true: only return intersection points which are
 *                   on both entities.
 *                   false: return all intersection points.
 *
 * @todo support more entities
 *
 * @return All intersections of the two entities. The tangent flag in
 * RS_VectorSolutions is set if one intersection is a tangent point.
 */
RS_VectorSolutions RS_Information::getIntersection(RS_Entity const* e1,
		RS_Entity const* e2, bool onEntities) {

    RS_VectorSolutions ret;
    const double tol = 1.0e-4;

	if (!(e1 && e2) ) {
		RS_DEBUG->print("RS_Information::getIntersection() for nullptr entities");
        return ret;
    }
    if (e1->getId() == e2->getId()) {
        RS_DEBUG->print("RS_Information::getIntersection() of the same entity");
        return ret;
    }

    // unsupported entities / entity combinations:
    if (
        e1->rtti()==RS2::EntityMText || e2->rtti()==RS2::EntityMText ||
        e1->rtti()==RS2::EntityText || e2->rtti()==RS2::EntityText ||
        isDimension(e1->rtti()) || isDimension(e2->rtti())) {
        return ret;
    }

	if (onEntities && !(e1->isConstruction() || e2->isConstruction())) {
	// a little check to avoid doing unneeded intersections, an attempt to avoid O(N^2) increasing of checking two-entity information
		LC_Rect const rect1{e1->getMin(), e1->getMax()};
		LC_Rect const rect2{e2->getMin(), e2->getMax()};

		if (onEntities && !rect1.intersects(rect2, RS_TOLERANCE)) {
			return ret;
		}
	}

    //avoid intersections between line segments the same spline
    /* ToDo: 24 Aug 2011, Dongxu Li, if rtti() is not defined for the parent, the following check for splines may still cause segfault */
	if ( e1->getParent() && e1->getParent() == e2->getParent()) {
        if ( e1->getParent()->rtti()==RS2::EntitySpline ) {
            //do not calculate intersections from neighboring lines of a spline
            if ( abs(e1->getParent()->findEntity(e1) - e1->getParent()->findEntity(e2)) <= 1 ) {
                return ret;
            }
        }
    }

	if(e1->rtti() == RS2::EntitySplinePoints || e2->rtti() == RS2::EntitySplinePoints)
	{
		ret = LC_SplinePoints::getIntersection(e1, e2);
	}
	else
	{
		// issue #484 , quadratic intersection solver is not robust enough for quadratic-quadratic
		// TODO, implement a robust algorithm for quadratic based solvers, and detecting entity type
		// circles/arcs can be removed

		if(e1->rtti()==RS2::EntityCircle && e2->rtti()==RS2::EntityCircle){
			//use specialized arc-arc intersection solver
			ret=getIntersectionArcArc(e1, e2);
		}else{
			const auto qf1=e1->getQuadratic();
			const auto qf2=e2->getQuadratic();
			ret=LC_Quadratic::getIntersection(qf1,qf2);
		}
	}
    RS_VectorSolutions ret2;
	for(const RS_Vector& vp: ret){
		if (!vp.valid) continue;
		if (onEntities) {
            //ignore intersections not on entity
            if (!(
                        (e1->isConstruction(true) || e1->isPointOnEntity(vp, tol)) &&
                        (e2->isConstruction(true) || e2->isPointOnEntity(vp, tol))
                        )
                    ) {
//				std::cout<<"Ignored intersection "<<vp<<std::endl;
//				std::cout<<"because: e1->isPointOnEntity(ret.get(i), tol)="<<e1->isPointOnEntity(vp, tol)
//					<<"\t(e2->isPointOnEntity(ret.get(i), tol)="<<e2->isPointOnEntity(vp, tol)<<std::endl;
                continue;
            }
        }
        // need to test whether the intersection is tangential
		RS_Vector direction1=e1->getTangentDirection(vp);
		RS_Vector direction2=e2->getTangentDirection(vp);
        if( direction1.valid && direction2.valid && fabs(fabs(direction1.dotP(direction2)) - sqrt(direction1.squared()*direction2.squared())) < sqrt(tol)*tol )
            ret2.setTangent(true);
        //TODO, make the following tangential test, nearest test work for all entity types

//        RS_Entity   *lpLine = nullptr,
//                    *lpCircle = nullptr;
//        if( RS2::EntityLine == e1->rtti() && RS2::EntityCircle == e2->rtti()) {
//            lpLine = e1;
//            lpCircle = e2;
//        }
//        else if( RS2::EntityCircle == e1->rtti() && RS2::EntityLine == e2->rtti()) {
//            lpLine = e2;
//            lpCircle = e1;
//        }
//        if( nullptr != lpLine && nullptr != lpCircle) {
//            double dist = 0.0;
//            RS_Vector nearest = lpLine->getNearestPointOnEntity( lpCircle->getCenter(), false, &dist);

//            // special case: line touches circle tangent
//            if( nearest.valid && fabs( dist - lpCircle->getRadius()) < tol) {
//                ret.set(i,nearest);
//                ret2.setTangent(true);
//            }
//        }
        ret2.push_back(vp);
    }

    return ret2;
}
Beispiel #3
0
void RS_Grid::createOrthogonalGrid(LC_Rect const& rect, RS_Vector const& gridWidth)
{
	double const left=rect.minP().x;
	double const right=rect.maxP().x;
	//top/bottom reversed
	double const top=rect.maxP().y;
	double const bottom=rect.minP().y;

	cellV.set(fabs(gridWidth.x),fabs(gridWidth.y));
	int numberX = (RS_Math::round((right-left) / gridWidth.x) + 1);
	int numberY = (RS_Math::round((top-bottom) / gridWidth.y) + 1);
	int number = numberX*numberY;
	//todo, fix baseGrid for orthogonal grid
	baseGrid.set(left,bottom);

	// create grid array:

	if (number<=0 || number>maxGridPoints) return;

	pt.resize(number);

	int i=0;
	RS_Vector bp0(baseGrid);
	for (int y=0; y<numberY; ++y) {
		RS_Vector bp1(bp0);
		for (int x=0; x<numberX; ++x) {
			pt[i++] = bp1;
			bp1.x += gridWidth.x;
		}
		bp0.y += gridWidth.y;
	}
	// find meta grid boundaries
	if (metaGridWidth.x>minimumGridWidth && metaGridWidth.y>minimumGridWidth &&
			graphicView->toGuiDX(metaGridWidth.x)>2 &&
			graphicView->toGuiDY(metaGridWidth.y)>2) {

		double mleft = (int)(graphicView->toGraphX(0) /
							 metaGridWidth.x) * metaGridWidth.x;
		double mright = (int)(graphicView->toGraphX(graphicView->getWidth()) /
							 metaGridWidth.x) * metaGridWidth.x;
		double mtop = (int)(graphicView->toGraphY(0) /
							metaGridWidth.y) * metaGridWidth.y;
		double mbottom = (int)(graphicView->toGraphY(graphicView->getHeight()) /
							 metaGridWidth.y) * metaGridWidth.y;

		mleft -= metaGridWidth.x;
		mright += metaGridWidth.x;
		mtop += metaGridWidth.y;
		mbottom -= metaGridWidth.y;

		// calculate number of visible meta grid lines:
		int numMetaX = (RS_Math::round((mright-mleft) / metaGridWidth.x) + 1);
		int numMetaY = (RS_Math::round((mtop-mbottom) / metaGridWidth.y) + 1);

		if (numMetaX<=0 || numMetaY<=0) return;
		// create meta grid arrays:
		metaX.resize(numMetaX);
		metaY.resize(numMetaY);

		int i=0;
		for (int x=0; x<numMetaX; ++x) {
			metaX[i++] = mleft+x*metaGridWidth.x;
		}
		i=0;
		for (int y=0; y<numMetaY; ++y) {
			metaY[i++] = mbottom+y*metaGridWidth.y;
		}
	}
}
void RS_Line::draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) {
	if (! (painter && view)) {
        return;
    }

    //only draw the visible portion of line
	LC_Rect const viewportRect{view->toGraph(0, 0),
				view->toGraph(view->getWidth(), view->getHeight())};
	RS_VectorSolutions endPoints(0);
	if (viewportRect.inArea(getStartpoint(), RS_TOLERANCE))
		 endPoints.push_back(getStartpoint());
	if (viewportRect.inArea(getEndpoint(), RS_TOLERANCE))
		 endPoints.push_back(getEndpoint());

	RS_EntityContainer ec(nullptr);
	ec.addRectangle(viewportRect.minP(), viewportRect.maxP());

	if (endPoints.size()<2){
		RS_VectorSolutions vpIts;
		for(auto p: ec) {
			auto const sol=RS_Information::getIntersection(this, p, true);
			for (auto const& vp: sol) {
				if (vpIts.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
					continue;
				vpIts.push_back(vp);
			}
		}
		for (auto const& vp: vpIts) {
			if (endPoints.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
				continue;
			endPoints.push_back(vp);
		}
	}

	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 (isConstruction(true) && direction.squared() > RS_TOLERANCE){
        //extend line on a construction layer to fill the whole view
		RS_VectorSolutions vpIts;
		for(auto p: ec) {
			auto const sol=RS_Information::getIntersection(this, p, false);
			for (auto const& vp: sol) {
				if (vpIts.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
					continue;
				vpIts.push_back(vp);
			}
		}

		//draw construction lines up to viewport border
		switch (vpIts.size()) {
		case 2:
			// no need to sort intersections
			break;
		case 3:
		case 4: {
			// will use the inner two points
			size_t i{0};
			for (size_t j = 2; j < vpIts.size(); ++j) {
				if (viewportRect.inArea(vpIts.at(j), RS_TOLERANCE * 10.))
					std::swap(vpIts[j], vpIts[i++]);
			}
		}
			break;
		default:
			//should not happen
			return;
		}
		pStart=view->toGui(vpIts.get(0));
		pEnd=view->toGui(vpIts.get(1));
		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:
    const RS_LineTypePattern* pat;
    if (isSelected()) {
//        styleFactor=1.;
        pat = &RS_LineTypePattern::patternSelected;
    } else {
        pat = view->getPattern(getPen().getLineType());
    }
	if (!pat) {
//        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
	size_t i;

    // pattern segment length:
    double patternSegmentLength = pat->totalLength;

    // create pattern:
	size_t const patnum=pat->num > 0?pat->num:0;
	std::vector<RS_Vector> dp(patnum);
	std::vector<double> ds(patnum, 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*pat->pattern[i];
			if (fabs(ds[i]) < 1. ) ds[i] = (ds[i]>=0.)?1.:-1.;
            dp[i] = direction*fabs(ds[i]);
        }
	} else {
        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 curP{pStart+direction*total};
	for (int j=0; total<length; j=(j+1)%i) {

        // line segment (otherwise space segment)
		double const t2=total+fabs(ds[j]);
		RS_Vector const& 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
			RS_Vector const& p1 =(total > -0.5)?curP:pStart;
			RS_Vector const& p2 =(t2<length+0.5)?p3:pEnd;
            painter->drawLine(p1,p2);
        }
        total=t2;
        curP=p3;
	}

}