예제 #1
0
// Note: with no antialiasing, the coordinates in QPointF are rounded to the nearest integer.
void
TransitionWidget::paintEvent(QPaintEvent*)
{
	if (pointList_ == nullptr) {
		return;
	}

	QPainter painter(this);
	painter.setFont(QFont("monospace"));

	if (dataUpdated_) {
		QFontMetrics fm = painter.fontMetrics();
		textYOffset_ = 0.5 * fm.ascent();
		leftMargin_ = MARGIN + TEXT_MARGIN + fm.width(transitionYLabels[0]);
		updateScales();

		dataUpdated_ = false;
	}

	if (special_) {
		// Gray area.
		painter.fillRect(QRectF(QPointF(leftMargin_, MARGIN + 7.0 * yStep_), QPointF(leftMargin_ + graphWidth_, MARGIN + 14.0 * yStep_)), Qt::gray);

		// Y labels.
		for (unsigned int i = 0; i < specialTransitionYLabels.size(); ++i) {
			double y = MARGIN + i * yStep_ + textYOffset_;
			painter.drawText(QPointF(MARGIN, y), specialTransitionYLabels[i]);
			painter.drawText(QPointF(leftMargin_ + graphWidth_ + TEXT_MARGIN, y), specialTransitionYLabels[i]);
		}
	} else {
		// Gray areas.
		painter.fillRect(QRectF(QPointF(leftMargin_, MARGIN), QPointF(leftMargin_ + graphWidth_, MARGIN + 2.0 * yStep_)), Qt::gray);
		painter.fillRect(QRectF(QPointF(leftMargin_, MARGIN + 12.0 * yStep_), QPointF(leftMargin_ + graphWidth_, MARGIN + 14.0 * yStep_)), Qt::gray);

		// Y labels.
		for (unsigned int i = 0; i < transitionYLabels.size(); ++i) {
			double y = MARGIN + i * yStep_ + textYOffset_;
			painter.drawText(QPointF(MARGIN, y), transitionYLabels[i]);
			painter.drawText(QPointF(leftMargin_ + graphWidth_ + TEXT_MARGIN, y), transitionYLabels[i]);
		}
	}
	// Horizontal lines.
	for (int i = 0; i < 15; ++i) {
		double y = MARGIN + i * yStep_;
		painter.drawLine(QPointF(leftMargin_, y), QPointF(leftMargin_ + graphWidth_, y));
	}

	QPen pen;
	QPen pen2;
	pen2.setWidth(2);

	painter.setRenderHint(QPainter::Antialiasing);

	// Lines.
	if (!pointList_->empty()) {
		painter.setPen(pen2);

		QPointF prevP(0.5 + timeToX(0.0), 0.5 + valueToY(0.0));

		for (unsigned int i = 0, size = pointList_->size(); i < size; ++i) {
			const auto& point = (*pointList_)[i];
			QPointF p(0.5 + timeToX(point.time), 0.5 + valueToY(point.value));
			painter.drawLine(prevP, p);

			prevP = p;
			if (i != size - 1) {
				if (point.type != (*pointList_)[i + 1].type) {
					prevP.setY(0.5 + valueToY(0.0));
				}
			}
		}

		QPointF p(0.5 + timeToX(ruleDuration_), 0.5 + valueToY(special_ ? 0.0 : 100.0));
		painter.drawLine(prevP, p);

		painter.setPen(pen);
	}

	painter.setBrush(QBrush(Qt::black));

	// Points.
	if (!pointList_->empty()) {
		for (auto& point : *pointList_) {
			double x = 0.5 + timeToX(point.time);
			double y = 0.5 + valueToY(point.value);
			switch (point.type) {
			case TRMControlModel::Transition::Point::TYPE_DIPHONE:
				drawDiPoint(painter, x, y);
				break;
			case TRMControlModel::Transition::Point::TYPE_TRIPHONE:
				drawTriPoint(painter, x, y);
				break;
			case TRMControlModel::Transition::Point::TYPE_TETRAPHONE:
				drawTetraPoint(painter, x, y);
				break;
			default:
				break;
			}
		}
	}

	// Posture markers.
	double yMarker = 0.5 + 0.5 * yStep_ + textYOffset_;
	switch (transitionType_) {
	case TRMControlModel::Transition::TYPE_DIPHONE:
		drawDiPoint(painter, 0.5 + timeToX(ruleDuration_), yMarker);
		break;
	case TRMControlModel::Transition::TYPE_TRIPHONE:
		drawDiPoint( painter, 0.5 + timeToX(mark1_)       , yMarker);
		drawTriPoint(painter, 0.5 + timeToX(ruleDuration_), yMarker);
		break;
	case TRMControlModel::Transition::TYPE_TETRAPHONE:
		drawDiPoint(   painter, 0.5 + timeToX(mark1_)       , yMarker);
		drawTriPoint(  painter, 0.5 + timeToX(mark2_)       , yMarker);
		drawTetraPoint(painter, 0.5 + timeToX(ruleDuration_), yMarker);
		break;
	default:
		break;
	}

	painter.setBrush(QBrush());
	painter.setRenderHint(QPainter::Antialiasing, false);

	// Posture vertical lines.
	double yPosture1 = special_ ? valueToY(-140.0) : valueToY(-20.0);
	double yPosture2 = special_ ? valueToY( 140.0) : valueToY(120.0);

	double x = timeToX(0.0);
	painter.drawLine(QPointF(x, yPosture1), QPointF(x, yPosture2));

	switch (transitionType_) {
	case TRMControlModel::Transition::TYPE_DIPHONE:
		x = timeToX(ruleDuration_);
		painter.drawLine(QPointF(x, yPosture1), QPointF(x, yPosture2));
		break;
	case TRMControlModel::Transition::TYPE_TRIPHONE:
		x = timeToX(mark1_);
		painter.drawLine(QPointF(x, yPosture1), QPointF(x, yPosture2));
		x = timeToX(ruleDuration_);
		painter.drawLine(QPointF(x, yPosture1), QPointF(x, yPosture2));
		break;
	case TRMControlModel::Transition::TYPE_TETRAPHONE:
		x = timeToX(mark1_);
		painter.drawLine(QPointF(x, yPosture1), QPointF(x, yPosture2));
		x = timeToX(mark2_);
		painter.drawLine(QPointF(x, yPosture1), QPointF(x, yPosture2));
		x = timeToX(ruleDuration_);
		painter.drawLine(QPointF(x, yPosture1), QPointF(x, yPosture2));
		break;
	default:
		break;
	}

	if (!pointList_->empty()) {
		if (!special_) {
			// Slopes.
			double y1 = MARGIN + 15.0 * yStep_;
			double y2 = y1 + yStep_;
			double yText = y2 - 0.5 * yStep_ + textYOffset_;
			for (unsigned int i = 0, end = pointList_->size() - 1; i < end; ++i) {
				const auto& point1 = (*pointList_)[i];
				if (point1.hasSlope) {
					const auto& point2 = (*pointList_)[i + 1];
					painter.setPen(Qt::gray);
					painter.drawRect(QRectF(QPointF(timeToX(point1.time), y1), QPointF(timeToX(point2.time), y2)));
					painter.setPen(Qt::black);

					painter.drawText(
						QPointF(timeToX(point1.time) + SLOPE_TEXT_MARGIN, yText),
						QString("%1").arg(point1.slope, 0, 'f', 1));
				}
			}
		}

		// Selected point.
		if (selectedPointIndex_ >= 0 && static_cast<std::size_t>(selectedPointIndex_) < pointList_->size()) {
			const auto& point = (*pointList_)[selectedPointIndex_];
			double x = timeToX(point.time);
			double y = valueToY(point.value);
			painter.drawRect(QRectF(
				 QPointF(x - SELECTION_SIZE, y - SELECTION_SIZE),
				 QPointF(x + SELECTION_SIZE, y + SELECTION_SIZE)));
		}
	}
}
예제 #2
0
// fit a polyline to a bezier patch, return true is treshhold not exceeded (ie: you can continue)
// version that uses tables from the previous iteration, to minimize amount of work done
bool Path::AttemptSimplify (fitting_tables &data,double treshhold, PathDescrCubicTo & res,int &worstP)
{
    Geom::Point start,end;
    // pour une coordonnee
    Geom::Point cp1, cp2;
  
    worstP = 1;
    if (pts.size() == 2) {
        return true;
    }
  
    start[0] = data.Xk[0];
    start[1] = data.Yk[0];
    cp1[0] = data.Xk[1];
    cp1[1] = data.Yk[1];
    end[0] = data.Xk[data.nbPt - 1];
    end[1] = data.Yk[data.nbPt - 1];
    cp2 = cp1;
  
    if (pts.size()  == 3) {
        // start -> cp1 -> end
        res.start = cp1 - start;
        res.end = end - cp1;
        worstP = 1;
        return true;
    }
  
    if ( FitCubic(start, res, data.Xk, data.Yk, data.Qk, data.tk, data.nbPt) ) {
        cp1 = start + res.start / 3;
        cp2 = end - res.end / 3;
    } else {
        // aie, non-inversible
        double worstD = 0;
        worstP = -1;
        for (int i = 1; i < data.nbPt; i++) {
            Geom::Point nPt;
            nPt[Geom::X] = data.Xk[i];
            nPt[Geom::Y] = data.Yk[i];
            double nle = DistanceToCubic(start, res, nPt);
            if ( data.fk[i] ) {
                // forced points are favored for splitting the recursion; we do this by increasing their distance
                if ( worstP < 0 || 2 * nle > worstD ) {
                    worstP = i;
                    worstD = 2 * nle;
                }
            } else {
                if ( worstP < 0 || nle > worstD ) {
                    worstP = i;
                    worstD = nle;
                }
            }
        }
        return false;
    }
   
    // calcul du delta= pondere par les longueurs des segments
    double delta = 0;
    {
        double worstD = 0;
        worstP = -1;
        Geom::Point prevAppP;
        Geom::Point prevP;
        double prevDist;
        prevP[Geom::X] = data.Xk[0];
        prevP[Geom::Y] = data.Yk[0];
        prevAppP = prevP; // le premier seulement
        prevDist = 0;
#ifdef with_splotch_killer
        if ( data.nbPt <= 20 ) {
            for (int i = 1; i < data.nbPt - 1; i++) {
                Geom::Point curAppP;
                Geom::Point curP;
                double curDist;
                Geom::Point midAppP;
                Geom::Point midP;
                double midDist;
                
                curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] +
                    N23(data.tk[i]) * cp2[Geom::X] +
                    N03(data.tk[i]) * data.Xk[0] +
                    N33(data.tk[i]) * data.Xk[data.nbPt - 1];
                
                curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] +
                    N23(data.tk[i]) * cp2[Geom::Y] +
                    N03(data.tk[i]) * data.Yk[0] +
                    N33(data.tk[i]) * data.Yk[data.nbPt - 1];
                
                curP[Geom::X] = data.Xk[i];
                curP[Geom::Y] = data.Yk[i];
                double mtk = 0.5 * (data.tk[i] + data.tk[i - 1]);
                
                midAppP[Geom::X] = N13(mtk) * cp1[Geom::X] +
                    N23(mtk) * cp2[Geom::X] +
                    N03(mtk) * data.Xk[0] +
                    N33(mtk) * data.Xk[data.nbPt - 1];
                
                midAppP[Geom::Y] = N13(mtk) * cp1[Geom::Y] +
                    N23(mtk) * cp2[Geom::Y] +
                    N03(mtk) * data.Yk[0] +
                    N33(mtk) * data.Yk[data.nbPt - 1];
                
                midP = 0.5 * (curP + prevP);
        
                Geom::Point diff = curAppP - curP;
                curDist = dot(diff, diff);
                diff = midAppP - midP;
                midDist = dot(diff, diff);
        
                delta += 0.3333 * (curDist + prevDist + midDist) * data.lk[i];
                if ( curDist > worstD ) {
                    worstD = curDist;
                    worstP = i;
                } else if ( data.fk[i] && 2 * curDist > worstD ) {
                    worstD = 2*curDist;
                    worstP = i;
                }
                prevP = curP;
                prevAppP = curAppP;
                prevDist = curDist;
            }
            delta /= data.totLen;
            
        } else {
#endif
            for (int i = 1; i < data.nbPt - 1; i++) {
                Geom::Point curAppP;
                Geom::Point curP;
                double    curDist;
        
                curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] +
                    N23(data.tk[i]) * cp2[Geom::X] +
                    N03(data.tk[i]) * data.Xk[0] +
                    N33(data.tk[i]) * data.Xk[data.nbPt - 1];
                
                curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] +
                    N23(data.tk[i]) * cp2[Geom::Y] +
                    N03(data.tk[i]) * data.Yk[0] +
                    N33(data.tk[i]) * data.Yk[data.nbPt - 1];
                
                curP[Geom::X] = data.Xk[i];
                curP[Geom::Y] = data.Yk[i];
      
                Geom::Point diff = curAppP-curP;
                curDist = dot(diff, diff);
                delta += curDist;
        
                if ( curDist > worstD ) {
                    worstD = curDist;
                    worstP = i;
                } else if ( data.fk[i] && 2 * curDist > worstD ) {
                    worstD = 2*curDist;
                    worstP = i;
                }
                prevP = curP;
                prevAppP = curAppP;
                prevDist = curDist;
            }
#ifdef with_splotch_killer
        }
#endif
    }
  
    if (delta < treshhold * treshhold) {
        // premier jet
    
        // Refine a little.
        for (int i = 1; i < data.nbPt - 1; i++) {
            Geom::Point pt(data.Xk[i], data.Yk[i]);
            data.tk[i] = RaffineTk(pt, start, cp1, cp2, end, data.tk[i]);
            if (data.tk[i] < data.tk[i - 1]) {
                // Force tk to be monotonic non-decreasing.
                data.tk[i] = data.tk[i - 1];
	    }
        }
    
        if ( FitCubic(start, res, data.Xk, data.Yk, data.Qk, data.tk, data.nbPt) == false) {
            // ca devrait jamais arriver, mais bon
            res.start = 3.0 * (cp1 - start);
            res.end = 3.0 * (end - cp2 );
            return true;
        }
        
        double ndelta = 0;
        {
            double worstD = 0;
            worstP = -1;
            Geom::Point prevAppP;
            Geom::Point prevP(data.Xk[0], data.Yk[0]);
            double prevDist = 0;
            prevAppP = prevP; // le premier seulement
#ifdef with_splotch_killer
            if ( data.nbPt <= 20 ) {
                for (int i = 1; i < data.nbPt - 1; i++) {
                    Geom::Point curAppP;
                    Geom::Point curP;
                    double  curDist;
                    Geom::Point midAppP;
                    Geom::Point midP;
                    double  midDist;
          
                    curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] +
                        N23(data.tk[i]) * cp2[Geom::X] +
                        N03(data.tk[i]) * data.Xk[0] +
                        N33(data.tk[i]) * data.Xk[data.nbPt - 1];
                    
                    curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] +
                        N23(data.tk[i]) * cp2[Geom::Y] +
                        N03(data.tk[i]) * data.Yk[0] +
                        N33(data.tk[i]) * data.Yk[data.nbPt - 1];
                    
                    curP[Geom::X] = data.Xk[i];
                    curP[Geom::Y] = data.Yk[i];
                    double mtk = 0.5 * (data.tk[i] + data.tk[i - 1]);
                    
                    midAppP[Geom::X] = N13(mtk) * cp1[Geom::X] +
                        N23(mtk) * cp2[Geom::X] +
                        N03(mtk) * data.Xk[0] +
                        N33(mtk) * data.Xk[data.nbPt - 1];
                    
                    midAppP[Geom::Y] = N13(mtk) * cp1[Geom::Y] +
                        N23(mtk) * cp2[Geom::Y] +
                        N03(mtk) * data.Yk[0] +
                        N33(mtk) * data.Yk[data.nbPt - 1];
                    
                    midP = 0.5 * (curP + prevP);
          
                    Geom::Point diff = curAppP - curP;
                    curDist = dot(diff, diff);
          
                    diff = midAppP - midP;
                    midDist = dot(diff, diff);
          
                    ndelta += 0.3333 * (curDist + prevDist + midDist) * data.lk[i];
          
                    if ( curDist > worstD ) {
                        worstD = curDist;
                        worstP = i;
                    } else if ( data.fk[i] && 2 * curDist > worstD ) {
                        worstD = 2*curDist;
                        worstP = i;
                    }
                    
                    prevP = curP;
                    prevAppP = curAppP;
                    prevDist = curDist;
                }
                ndelta /= data.totLen;
            } else {
#endif
                for (int i = 1; i < data.nbPt - 1; i++) {
                    Geom::Point curAppP;
                    Geom::Point curP;
                    double    curDist;
                    
                    curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] +
                        N23(data.tk[i]) * cp2[Geom::X] +
                        N03(data.tk[i]) * data.Xk[0] +
                        N33(data.tk[i]) * data.Xk[data.nbPt - 1];
                    
                    curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] +
                        N23(data.tk[i]) * cp2[1] +
                        N03(data.tk[i]) * data.Yk[0] +
                        N33(data.tk[i]) * data.Yk[data.nbPt - 1];
                    
                    curP[Geom::X] = data.Xk[i];
                    curP[Geom::Y] = data.Yk[i];
        
                    Geom::Point diff = curAppP - curP;
                    curDist = dot(diff, diff);

                    ndelta += curDist;

                    if ( curDist > worstD ) {
                        worstD = curDist;
                        worstP = i;
                    } else if ( data.fk[i] && 2 * curDist > worstD ) {
                        worstD = 2 * curDist;
                        worstP = i;
                    }
                    prevP = curP;
                    prevAppP = curAppP;
                    prevDist = curDist;
                }
#ifdef with_splotch_killer
            }
#endif
        }
    
        if (ndelta < delta + 0.00001) {
            return true;
        } else {
            // nothing better to do
            res.start = 3.0 * (cp1 - start);
            res.end = 3.0 * (end - cp2 );
        }
        
        return true;
    }
  
  return false;
}