Ejemplo n.º 1
0
void NudgeSelection (ENudgeDirection direction, float fAmount, EViewType viewtype)
{
	AxisBase axes(AxisBase_forViewType(viewtype));
	Vector3 view_direction(-axes.z);
	Vector3 nudge(AxisBase_axisForDirection(axes, direction) * fAmount);
	GlobalSelectionSystem().NudgeManipulator(nudge, view_direction);
}
Ejemplo n.º 2
0
void cSpace::movePointOutsideCSpace(btVector3& pt)
{
	float angle=0;
	float zHeight = pt.z();
	pt.setZ(0);
	btVector3 nudge(0.01,0,0);
	btVector3 npt = pt;
	
	while(isPointInsideCSpace(npt))							// check if the point is inside of the object
	{
		npt = pt + nudge.rotate(btVector3(0,0,1),angle);	// calculate a new point a radius of vector nudge away at angle
		angle -= 0.2;										// in radians, CCW search direction
		
		if(angle < -PI) {									// if the search has gone a full rotation
			nudge.setX(nudge.x() + 0.01);					// add another centemeter to the search vector radius
			if(nudge.length() > 1) {
				qDebug("Nudge length is greater than 1");
				break;
			}
			angle = 0;
		}
	}
	
	pt = npt;
	pt.setZ(zHeight);
}
Ejemplo n.º 3
0
	/// move toward a given world-coordinate point 
	void nudgeToward(const Vec3d& p, double amt=1.) {
		Vec3d rotEuler;
		Vec3d target(p - pos());
		target.normalize();	// unit vector of direction to move (in world frame)
		// rotate target into local frame:
		target = quat().rotate(target);
		// push ourselves in that particular direction:
		nudge(target * amt);
	}
Ejemplo n.º 4
0
// Specialised overload, called by the general nudgeSelected() routine
void nudgeSelected(ENudgeDirection direction, float amount, EViewType viewtype)
{
	AxisBase axes(AxisBase_forViewType(viewtype));

	Vector3 view_direction(-axes.z);
	Vector3 nudge(AxisBase_axisForDirection(axes, direction) * amount);

	if (GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eTranslate ||
        GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eDrag ||
        GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip)
    {
        GlobalSelectionSystem().translateSelected(nudge);

        // In clip mode, update the clipping plane
        if (GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip)
        {
            GlobalClipper().update();
        }
    }
}
Ejemplo n.º 5
0
// UpDownWndProc:
//
LRESULT CALLBACK UpDownWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    RECT rc;
    int i;
    PUDSTATE np = (PUDSTATE)GetWindowInt(hwnd, 0);

    if (np) {
        if ((uMsg >= WM_MOUSEFIRST) && (uMsg <= WM_MOUSELAST) &&
            (np->ci.style & UDS_HOTTRACK) && !np->fTrackSet) {

            TRACKMOUSEEVENT tme;

            np->fTrackSet = TRUE;

            tme.cbSize = sizeof(tme);
            tme.hwndTrack = np->ci.hwnd;
            tme.dwFlags = TME_LEAVE;

            TrackMouseEvent(&tme);
        }
    }

    switch (uMsg)
    {

    case WM_MOUSEMOVE:
        UD_OnMouseMove(np, lParam);
        break;

    case WM_MOUSELEAVE:
        np->fTrackSet = FALSE;
        UD_Invalidate(np, np->uHot, FALSE);
        np->uHot = UD_HITNOWHERE;
        break;

    case WM_LBUTTONDOWN:
    {
        // Don't set a timer if on the middle border
        BOOL bTimeIt = TRUE;

        if (np->hwndBuddy && !IsWindowEnabled(np->hwndBuddy))
            break;

        SetCapture(hwnd);
        getint(np);

        switch (np->uClass)
        {
        case CLASS_EDIT:
        case CLASS_LISTBOX:
            SetFocus(np->hwndBuddy);
            break;
        }

        switch(UD_HitTest(np, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) {
        case UD_HITDOWN:
            np->bDown = TRUE;
            squish(np, FALSE, TRUE);
            break;

        case UD_HITUP:
            np->bDown = FALSE;
            squish(np, TRUE, FALSE);
            break;

        case UD_HITNOWHERE:
            bTimeIt = FALSE;
            break;
        }

        if (bTimeIt)
        {
            SetTimer(hwnd, 1, GetProfileInt(TEXT("windows"), TEXT("CursorBlinkRate"), 530), NULL);
            bump(np);
        }
        break;
    }

    case WM_TIMER:
    {
        POINT pt;

        if (GetCapture() != hwnd)
        {
            goto EndScroll;
        }

        SetTimer(hwnd, 1, 100, NULL);

        GetWindowRect(hwnd, &rc);
        if (np->ci.style & UDS_HORZ) {
            i = (rc.left + rc.right) / 2;
            if (np->bDown)
            {
                rc.right = i;
            }
            else
            {
                rc.left = i;
            }
        } else {
            i = (rc.top + rc.bottom) / 2;
            if (np->bDown)
            {
                rc.top = i;
            }
            else
            {
                rc.bottom = i;
            }
        }
        InflateRect(&rc, (g_cxFrame+1)/2, (g_cyFrame+1)/2);
        GetCursorPos(&pt);
        if (PtInRect(&rc, pt))
        {
            squish(np, !np->bDown, np->bDown);
            bump(np);
        }
        else
        {
            squish(np, FALSE, FALSE);
        }
        break;
    }

    case WM_LBUTTONUP:
        if (np->hwndBuddy && !IsWindowEnabled(np->hwndBuddy))
            break;

        if (GetCapture() == hwnd)
        {
EndScroll:
            squish(np, FALSE, FALSE);
            ReleaseCapture();
            KillTimer(hwnd, 1);

            if (np->uClass == CLASS_EDIT)
                Edit_SetSel(np->hwndBuddy, 0, -1);

                        if (np->ci.style & UDS_HORZ)
                            FORWARD_WM_HSCROLL(np->ci.hwndParent, np->ci.hwnd,
                                      SB_ENDSCROLL, np->nPos, SendMessage);
                        else
                            FORWARD_WM_VSCROLL(np->ci.hwndParent, np->ci.hwnd,
                                      SB_ENDSCROLL, np->nPos, SendMessage);
        }
        break;

    case WM_ENABLE:
        InvalidateRect(hwnd, NULL, TRUE);
        break;

    case WM_WININICHANGE:
        if (np && (!wParam ||
            (wParam == SPI_SETNONCLIENTMETRICS) ||
            (wParam == SPI_SETICONTITLELOGFONT))) {
            InitGlobalMetrics(wParam);
            unachor(np);
            anchor(np);
        }
        break;

    case WM_PRINTCLIENT:
    case WM_PAINT:
        PaintUpDownControl(np, (HDC)wParam);
        break;

    case UDM_SETRANGE:
        np->nUpper = GET_X_LPARAM(lParam);
        np->nLower = GET_Y_LPARAM(lParam);
        nudge(np);
        break;

    case UDM_GETRANGE:
        return MAKELONG(np->nUpper, np->nLower);

    case UDM_SETBASE:
        // wParam: new base
        // lParam: not used
        // return: 0 if invalid base is specified,
        //         previous base otherwise
        return (LRESULT)setbase(np, (UINT)wParam);

    case UDM_GETBASE:
        return np->nBase;

    case UDM_SETPOS:
    {
        int iNewPos = GET_X_LPARAM(lParam);
        if (compare(np, np->nLower, np->nUpper, DONTCARE) < 0) {

            if (compare(np, iNewPos, np->nUpper, DONTCARE) > 0) {
                iNewPos = np->nUpper;
            }

            if (compare(np, iNewPos, np->nLower, DONTCARE) < 0) {
                iNewPos = np->nLower;
            }
        } else {
            if (compare(np, iNewPos, np->nUpper, DONTCARE) < 0) {
                iNewPos = np->nUpper;
            }

            if (compare(np, iNewPos, np->nLower, DONTCARE) > 0) {
                iNewPos = np->nLower;
            }
        }

        i = np->nPos;
        np->nPos = iNewPos;
        setint(np);
#ifdef ACTIVE_ACCESSIBILITY
        MyNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, np->ci.hwnd, OBJID_CLIENT, 0);
#endif
        return (LRESULT)i;
    }

    case UDM_GETPOS:
        return getint(np);

    case UDM_SETBUDDY:
        return setbuddy(np, (HWND)wParam);

    case UDM_GETBUDDY:
        return (LRESULT)(int)np->hwndBuddy;

    case UDM_SETACCEL:
            if (wParam == 0)
                return(FALSE);
            if (wParam >= NUM_UDACCELS)
            {
                HANDLE npPrev = (HANDLE)np;
                np = (PUDSTATE)LocalReAlloc((HLOCAL)np, sizeof(UDSTATE)+(wParam-NUM_UDACCELS)*sizeof(UDACCEL),
                    LMEM_MOVEABLE);
                if (!np)
                {
                    return(FALSE);
                }
                else
                {
                    SetWindowInt(hwnd, 0, (int)np);

                    if ((np->ci.style & UDS_ARROWKEYS) && np->hwndBuddy)
                    {
                        SetWindowSubclass(np->hwndBuddy, ArrowKeyProc, 0,
                            (DWORD)np);
                    }
                }
            }

            np->nAccel = wParam;
        for (i=0; i<(int)wParam; ++i)
        {
                np->udAccel[i] = ((LPUDACCEL)lParam)[i];
        }
        return(TRUE);

    case UDM_GETACCEL:
        if (wParam > np->nAccel)
        {
            wParam = np->nAccel;
        }
        for (i=0; i<(int)wParam; ++i)
        {
            ((LPUDACCEL)lParam)[i] = np->udAccel[i];
        }
        return(np->nAccel);

    case WM_NOTIFYFORMAT:
        return CIHandleNotifyFormat(&np->ci, lParam);

    case WM_CREATE:
        // Allocate the instance data space.
        np = (PUDSTATE)LocalAlloc(LPTR, sizeof(UDSTATE));
        if (!np)
            return -1;

        SetWindowInt(hwnd, 0, (int)np);

            #define lpCreate ((CREATESTRUCT FAR *)lParam)

        CIInitialize(&np->ci, hwnd, lpCreate);

        // np->fUp =
        // np->fDown =
            // np->fUnsigned =
            // np->fSharedBorder =
            // np->fSunkenBorder =
        //  FALSE;

        if (lpCreate->dwExStyle & WS_EX_CLIENTEDGE)
            np->fSunkenBorder = TRUE;

        np->nBase = BASE_DECIMAL;
        np->nUpper = 0;
        np->nLower = 100;
        np->nPos = 0;
        np->hwndBuddy = NULL;
        np->uClass = CLASS_UNKNOWN;

            np->nAccel = NUM_UDACCELS;
            np->udAccel[0].nSec = 0;
            np->udAccel[0].nInc = 1;
        np->udAccel[1].nSec = 2;
            np->udAccel[1].nInc = 5;
            np->udAccel[2].nSec = 5;
            np->udAccel[2].nInc = 20;

        /* This does the pickbuddy and anchor
         */
        setbuddy(np, NULL);
        setint(np);
        break;

    case WM_DESTROY:
        if (np) {
            if (np->hwndBuddy)
            {
                // Make sure that our buddy is unsubclassed.
                DebugMsg(DM_ERROR, TEXT("UpDown Destroyed while buddy subclassed"));
                np->fUpDownDestroyed = TRUE;
            }
            else
                LocalFree((HLOCAL)np);
            SetWindowInt(hwnd, 0, 0);
        }
        break;

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    return 0L;
}
Ejemplo n.º 6
0
// Use this to click the pos up or down by one.
//
void NEAR PASCAL bump(PUDSTATE np)
{
    BOOL bChanged = FALSE;
    UINT uElapsed, increment;
    int direction, i;

    /* So I'm not really getting seconds here; it's close enough, and
     * dividing by 1024 keeps __aFuldiv from being needed.
     */
    uElapsed = (UINT)((GetTickCount() - np->dwStart) / 1024);

    increment = np->udAccel[0].nInc;
    for (i=np->nAccel-1; i>=0; --i)
    {
        if (np->udAccel[i].nSec <= uElapsed)
        {
            increment = np->udAccel[i].nInc;
            break;
        }
    }

    if (increment == 0)
    {
        DebugMsg(DM_ERROR, TEXT("bad accelerator value"));
        return;
    }

    direction = compare(np,np->nUpper,np->nLower, DONTCARE) < 0 ? -1 : 1;
    if (np->fUp)
    {
        bChanged = TRUE;
    }
    if (np->fDown)
    {
        direction = -direction;
        bChanged = TRUE;
    }

    if (bChanged)
    {
        /* Make sure we have a multiple of the increment
         * Note that we should loop only when the increment changes
         */
        NM_UPDOWN nm;

        nm.iPos = np->nPos;
        nm.iDelta = increment*direction;
        if (SendNotifyEx(np->ci.hwndParent, np->ci.hwnd, UDN_DELTAPOS, &nm.hdr, FALSE))
            return;

        np->nPos += nm.iDelta;
        for ( ; ; )
        {
            if (!((int)np->nPos % (int)increment))
            {
                break;
            }
            np->nPos += direction;
        }

        nudge(np);
        setint(np);
        if (np->ci.style & UDS_HORZ)
            FORWARD_WM_HSCROLL(np->ci.hwndParent, np->ci.hwnd, SB_THUMBPOSITION, np->nPos, SendMessage);
        else
            FORWARD_WM_VSCROLL(np->ci.hwndParent, np->ci.hwnd, SB_THUMBPOSITION, np->nPos, SendMessage);

#ifdef ACTIVE_ACCESSIBILITY
        MyNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, np->ci.hwnd, OBJID_CLIENT, 0);
#endif

    }
}
Ejemplo n.º 7
0
// Gets the caption of the buddy
//
LRESULT NEAR PASCAL getint(PUDSTATE np)
{
    TCHAR szInt[MAX_INTLENGTH]; // big enough for all intl stuff, too
    TCHAR szThousand[2];
    TCHAR cTemp;
    int nPos;
    int sign = 1;
    LPTSTR p = szInt;
    BOOL bInValid = TRUE;

    isgoodbuddy(np);
    if (np->hwndBuddy && np->ci.style & UDS_SETBUDDYINT)
    {
        if (np->uClass == CLASS_LISTBOX)
        {
            np->nPos = (int)SendMessage(np->hwndBuddy, LB_GETCURSEL, 0, 0L);
            bInValid = nudge(np);
        }
        else
        {
            GetWindowText(np->hwndBuddy, szInt, ARRAYSIZE(szInt));

            switch (np->nBase)
            {
                case BASE_HEX:
                    if ((*p == TEXT('x')) || (*p == TEXT('X')))
                        // ignore first character
                        p++;
                    else if ((*p == TEXT('0')) && ((*(p + 1) == TEXT('x')) || (*(p + 1) == TEXT('X'))))
                        // ignore first two characters (TEXT("0x") or "0X")
                        p += 2;

                    for (nPos = 0; *p; p++)
                    {
                        if ((*p >= TEXT('A')) && (*p <= TEXT('F')))
                            cTemp = (TCHAR)(*p - TEXT('A') + 10);
                        else if ((*p >= TEXT('a')) && (*p <= TEXT('f')))
                            cTemp = (TCHAR)(*p - TEXT('a') + 10);
                        else if ((*p >= TEXT('0')) && (*p <= TEXT('9')))
                            cTemp = (TCHAR)(*p - TEXT('0'));
                        else
                            goto BadValue;

                        nPos = (nPos * 16) + cTemp;
                    }
                    np->nPos = nPos;
                    break;

                case BASE_DECIMAL:
        default:
                    getthousands(szThousand);
                    if (*p == TEXT('-'))
                    {
                        sign = -1;
                        ++p;
                    }

                    for (nPos=0; *p; p++)
                    {
                        cTemp = *p;

                        // If there is a thousand separator, make sure it is in the
                        // right place
                        if (cTemp == szThousand[0] && lstrlen(p)==4)
                        {
                            continue;
                        }

                        cTemp -= TEXT('0');
                        if ((UINT)cTemp > 9)
                        {
                            goto BadValue;
                        }
                        nPos = (nPos*10) + cTemp;
                    }

                    np->nPos = nPos*sign;
                    break;
            }
            bInValid = nudge(np);
        }
    }

BadValue:
    return(MAKELRESULT(np->nPos, bInValid));
}
Ejemplo n.º 8
0
bool AttentionPlugin::incomingStanza(int account, const QDomElement& stanza) {
    if (enabled) {
        if(stanza.tagName() == "message"
           && stanza.attribute("type") == "headline"
           && !stanza.firstChildElement("attention").isNull()) {

            if(disableDnd && accInfoHost->getStatus(account) == "dnd")
                return false;

            QString from = stanza.attribute("from");

            int i = blockedJids_.size();
            if(findAcc(account, from, i)) {
                Blocked &B = blockedJids_[i];
                if(QDateTime::currentDateTime().secsTo(B.LastMes) > -timeout_) {
                    return false;
                } else {
                    B.LastMes = QDateTime::currentDateTime();
                }
            } else {
                Blocked B = { account, from, QDateTime::currentDateTime() };
                blockedJids_ << B;
            }

            const QString optAway = "options.ui.notifications.passive-popups.suppress-while-away";
            QVariant suppressAway = psiOptions->getGlobalOption(optAway);
            const QString optDnd = "options.ui.notifications.passive-popups.suppress-while-dnd";
            QVariant suppressDnd = psiOptions->getGlobalOption(optDnd);
            int interval = popup->popupDuration(POPUP_OPTION);
            if(infPopup && (accInfoHost->getStatus(account) == "away" || accInfoHost->getStatus(account) == "xa")) {
                psiOptions->setGlobalOption(optAway, false);
                popup->setPopupDuration(POPUP_OPTION, -1);
            }
            psiOptions->setGlobalOption(optDnd, disableDnd);

            showPopup(account, from.split("/").first(), from + tr(" sends Attention message to you!"));
            psiOptions->setGlobalOption(optAway, suppressAway);
            psiOptions->setGlobalOption(optDnd, suppressDnd);
            popup->setPopupDuration(POPUP_OPTION, interval);

            if(psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool())
                playSound(soundFile);

            /*QTextEdit *te = activeTab->getEditBox();
              if(te)
              nudgeWindow_ = te->window();

              else
              nudgeWindow_ = qApp->activeWindow();*/



            if(nudgeWindow_ && nudgeWindow_->isVisible())
                nudge();
        }

        else if(stanza.tagName() == "iq" && stanza.attribute("type") == "get")
        {
            QDomElement query = stanza.firstChildElement("query");
            if(!query.isNull() && query.attribute("xmlns") == "http://jabber.org/protocol/disco#info")
            {
                if(query.attribute("node") == "http://psi-dev.googlecode.com/caps#at-pl") {
                    QString reply = QString("<iq type=\"result\" to=\"%1\" id=\"%2\">"
                                            "<query xmlns=\"http://jabber.org/protocol/disco#info\" node=\"http://psi-dev.googlecode.com/caps#at-pl\">"
                                            "<feature var=\"urn:xmpp:attention:0\"/></query></iq>")
                                            .arg(stanzaSender->escape(stanza.attribute("from")), stanzaSender->escape(stanza.attribute("id")));
                    stanzaSender->sendStanza(account, reply);
                    return true;
                }
            }
        }
    }
    return false;
}
/**
 * Core function for computing the ROM waveform.
 * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi).
 * Construct 1D splines for amplitude and phase.
 * Compute strain waveform from amplitude and phase.
*/
static int SEOBNRv1ROMEffectiveSpinCore(
  COMPLEX16FrequencySeries **hptilde,
  COMPLEX16FrequencySeries **hctilde,
  double phiRef,
  double fRef,
  double distance,
  double inclination,
  double Mtot_sec,
  double q,
  double chi,
  const REAL8Sequence *freqs_in, /* Frequency points at which to evaluate the waveform (Hz) */
  double deltaF
  /* If deltaF > 0, the frequency points given in freqs are uniformly spaced with
   * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
   * Then we will use deltaF = 0 to create the frequency series we return. */
  )
{
  /* Check output arrays */
  if(!hptilde || !hctilde)
    XLAL_ERROR(XLAL_EFAULT);
  SEOBNRROMdata *romdata=&__lalsim_SEOBNRv1ROMSS_data;
  if(*hptilde || *hctilde) {
    XLALPrintError("(*hptilde) and (*hctilde) are supposed to be NULL, but got %p and %p",(*hptilde),(*hctilde));
    XLAL_ERROR(XLAL_EFAULT);
  }
  int retcode=0;

  // 'Nudge' parameter values to allowed boundary values if close by
  if (q < 1.0)    nudge(&q, 1.0, 1e-6);
  if (q > 100.0)  nudge(&q, 100.0, 1e-6);
  if (chi < -1.0) nudge(&chi, -1.0, 1e-6);
  if (chi > 0.6)  nudge(&chi, 0.6, 1e-6);

  /* If either spin > 0.6, model not available, exit */
  if ( chi < -1.0 || chi > 0.6 ) {
    XLALPrintError( "XLAL Error - %s: chi smaller than -1 or larger than 0.6!\nSEOBNRv1ROMEffectiveSpin is only available for spins in the range -1 <= a/M <= 0.6.\n", __func__);
    XLAL_ERROR( XLAL_EDOM );
  }

  if (q > 100) {
    XLALPrintError( "XLAL Error - %s: q=%lf larger than 100!\nSEOBNRv1ROMEffectiveSpin is only available for q in the range 1 <= q <= 100.\n", __func__,q);
    XLAL_ERROR( XLAL_EDOM );
  }

  if (q >= 20 && q <= 40 && chi < -0.75 && chi > -0.9) {
    XLALPrintWarning( "XLAL Warning - %s: q in [20,40] and chi in [-0.8]. The SEOBNRv1 model is not trustworthy in this region!\nSee Fig 15 in CQG 31 195010, 2014 for details.", __func__);
    XLAL_ERROR( XLAL_EDOM );
  }

  /* Find frequency bounds */
  if (!freqs_in) XLAL_ERROR(XLAL_EFAULT);
  double fLow  = freqs_in->data[0];
  double fHigh = freqs_in->data[freqs_in->length - 1];

  if(fRef==0.0)
    fRef=fLow;

  /* Convert to geometric units for frequency */
  double Mf_ROM_min = fmax(gA[0], gPhi[0]);               // lowest allowed geometric frequency for ROM
  double Mf_ROM_max = fmin(gA[nk_amp-1], gPhi[nk_phi-1]); // highest allowed geometric frequency for ROM
  double fLow_geom = fLow * Mtot_sec;
  double fHigh_geom = fHigh * Mtot_sec;
  double fRef_geom = fRef * Mtot_sec;
  double deltaF_geom = deltaF * Mtot_sec;

  // Enforce allowed geometric frequency range
  if (fLow_geom < Mf_ROM_min)
    XLAL_ERROR(XLAL_EDOM, "Starting frequency Mflow=%g is smaller than lowest frequency in ROM Mf=%g. Starting at lowest frequency in ROM.\n", fLow_geom, Mf_ROM_min);
  if (fHigh_geom == 0)
    fHigh_geom = Mf_ROM_max;
  else if (fHigh_geom > Mf_ROM_max) {
	  XLALPrintWarning("Maximal frequency Mf_high=%g is greater than highest ROM frequency Mf_ROM_Max=%g. Using Mf_high=Mf_ROM_Max.", fHigh_geom, Mf_ROM_max);
	  fHigh_geom = Mf_ROM_max;
  }
  else if (fHigh_geom < Mf_ROM_min)
    XLAL_ERROR(XLAL_EDOM, "End frequency %g is smaller than starting frequency %g!\n", fHigh_geom, fLow_geom);
  if (fRef_geom > Mf_ROM_max) {
	  XLALPrintWarning("Reference frequency Mf_ref=%g is greater than maximal frequency in ROM Mf=%g. Starting at maximal frequency in ROM.\n", fRef_geom, Mf_ROM_max);
    fRef_geom = Mf_ROM_max; // If fref > fhigh we reset fref to default value of cutoff frequency.
  }
  if (fRef_geom < Mf_ROM_min) {
    XLALPrintWarning("Reference frequency Mf_ref=%g is smaller than lowest frequency in ROM Mf=%g. Starting at lowest frequency in ROM.\n", fLow_geom, Mf_ROM_min);
    fRef_geom = Mf_ROM_min;
  }

  /* Internal storage for w.f. coefficiencts */
  SEOBNRROMdata_coeff *romdata_coeff=NULL;
  SEOBNRROMdata_coeff_Init(&romdata_coeff);
  REAL8 amp_pre;

  /* Interpolate projection coefficients and evaluate them at (q,chi) */
  retcode=TP_Spline_interpolation_2d(
    q,                         // Input: q-value for which projection coefficients should be evaluated
    chi,                       // Input: chi-value for which projection coefficients should be evaluated
    romdata->cvec_amp,         // Input: data for spline coefficients for amplitude
    romdata->cvec_phi,         // Input: data for spline coefficients for phase
    romdata->cvec_amp_pre,     // Input: data for spline coefficients for amplitude prefactor
    romdata_coeff->c_amp,      // Output: interpolated projection coefficients for amplitude
    romdata_coeff->c_phi,      // Output: interpolated projection coefficients for phase
    &amp_pre                   // Output: interpolated amplitude prefactor
  );

  if(retcode!=0) {
    SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
    XLAL_ERROR(retcode, "Parameter-space interpolation failed.");
  }

  // Compute function values of amplitude an phase on sparse frequency points by evaluating matrix vector products
  // amp_pts = B_A^T . c_A
  // phi_pts = B_phi^T . c_phi
  gsl_vector* amp_f = gsl_vector_alloc(nk_amp);
  gsl_vector* phi_f = gsl_vector_alloc(nk_phi);
  gsl_blas_dgemv(CblasTrans, 1.0, romdata->Bamp, romdata_coeff->c_amp, 0.0, amp_f);
  gsl_blas_dgemv(CblasTrans, 1.0, romdata->Bphi, romdata_coeff->c_phi, 0.0, phi_f);

  // Setup 1d splines in frequency
  gsl_interp_accel *acc_amp = gsl_interp_accel_alloc();
  gsl_spline *spline_amp = gsl_spline_alloc(gsl_interp_cspline, nk_amp);
  gsl_spline_init(spline_amp, gA, gsl_vector_const_ptr(amp_f,0), nk_amp);

  gsl_interp_accel *acc_phi = gsl_interp_accel_alloc();
  gsl_spline *spline_phi = gsl_spline_alloc(gsl_interp_cspline, nk_phi);
  gsl_spline_init(spline_phi, gPhi, gsl_vector_const_ptr(phi_f,0), nk_phi);


  size_t npts = 0;
  LIGOTimeGPS tC = {0, 0};
  UINT4 offset = 0; // Index shift between freqs and the frequency series
  REAL8Sequence *freqs = NULL;
  if (deltaF > 0)  { // freqs contains uniform frequency grid with spacing deltaF; we start at frequency 0
    /* Set up output array with size closest power of 2 */
    npts = NextPow2(fHigh_geom / deltaF_geom) + 1;
    if (fHigh_geom < fHigh * Mtot_sec) /* Resize waveform if user wants f_max larger than cutoff frequency */
      npts = NextPow2(fHigh * Mtot_sec / deltaF_geom) + 1;

    XLALGPSAdd(&tC, -1. / deltaF);  /* coalesce at t=0 */
    *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
    *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);

    // Recreate freqs using only the lower and upper bounds
    UINT4 iStart = (UINT4) ceil(fLow_geom / deltaF_geom);
    UINT4 iStop = (UINT4) ceil(fHigh_geom / deltaF_geom);
    freqs = XLALCreateREAL8Sequence(iStop - iStart);
    if (!freqs) {
      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
    }
    for (UINT4 i=iStart; i<iStop; i++)
      freqs->data[i-iStart] = i*deltaF_geom;

    offset = iStart;
  } else { // freqs contains frequencies with non-uniform spacing; we start at lowest given frequency
    npts = freqs_in->length;
    *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
    *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
    offset = 0;

    freqs = XLALCreateREAL8Sequence(freqs_in->length);
    if (!freqs) {
      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
    }
    for (UINT4 i=0; i<freqs_in->length; i++)
      freqs->data[i] = freqs_in->data[i] * Mtot_sec;
  }


  if (!(*hptilde) || !(*hctilde))
  {
      XLALDestroyREAL8Sequence(freqs);
      gsl_spline_free(spline_amp);
      gsl_spline_free(spline_phi);
      gsl_interp_accel_free(acc_amp);
      gsl_interp_accel_free(acc_phi);
      gsl_vector_free(amp_f);
      gsl_vector_free(phi_f);
      SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
      XLAL_ERROR(XLAL_EFUNC, "Waveform allocation failed.");
  }
  memset((*hptilde)->data->data, 0, npts * sizeof(COMPLEX16));
  memset((*hctilde)->data->data, 0, npts * sizeof(COMPLEX16));

  XLALUnitMultiply(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
  XLALUnitMultiply(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);

  COMPLEX16 *pdata=(*hptilde)->data->data;
  COMPLEX16 *cdata=(*hctilde)->data->data;

  REAL8 cosi = cos(inclination);
  REAL8 pcoef = 0.5*(1.0 + cosi*cosi);
  REAL8 ccoef = cosi;

  REAL8 s = 1.0/sqrt(2.0); // Scale polarization amplitude so that strain agrees with FFT of SEOBNRv1
  double Mtot = Mtot_sec / LAL_MTSUN_SI;
  double amp0 = Mtot * amp_pre * Mtot_sec * LAL_MRSUN_SI / (distance); // Correct overall amplitude to undo mass-dependent scaling used in single-spin ROM

  // Evaluate reference phase for setting phiRef correctly
  double phase_change = gsl_spline_eval(spline_phi, fRef_geom, acc_phi) - 2*phiRef;

  // Assemble waveform from aplitude and phase
  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
    double f = freqs->data[i];
    if (f > Mf_ROM_max) continue; // We're beyond the highest allowed frequency; since freqs may not be ordered, we'll just skip the current frequency and leave zero in the buffer
    int j = i + offset; // shift index for frequency series if needed
    double A = gsl_spline_eval(spline_amp, f, acc_amp);
    double phase = gsl_spline_eval(spline_phi, f, acc_phi) - phase_change;
    COMPLEX16 htilde = s*amp0*A * cexp(I*phase);
    pdata[j] =      pcoef * htilde;
    cdata[j] = -I * ccoef * htilde;
  }

  /* Correct phasing so we coalesce at t=0 (with the definition of the epoch=-1/deltaF above) */

  // Get SEOBNRv1 ringdown frequency for 22 mode
  double Mf_final = SEOBNRROM_Ringdown_Mf_From_Mtot_q(Mtot_sec, q, chi, chi, SEOBNRv1);

  UINT4 L = freqs->length;
  // prevent gsl interpolation errors
  if (Mf_final > freqs->data[L-1])
    Mf_final = freqs->data[L-1];
  if (Mf_final < freqs->data[0])
  {
      XLALDestroyREAL8Sequence(freqs);
      gsl_spline_free(spline_amp);
      gsl_spline_free(spline_phi);
      gsl_interp_accel_free(acc_amp);
      gsl_interp_accel_free(acc_phi);
      gsl_vector_free(amp_f);
      gsl_vector_free(phi_f);
      SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
      XLAL_ERROR(XLAL_EDOM, "f_ringdown < f_min");
  }

  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
  // We compute the dimensionless time correction t/M since we use geometric units.
  REAL8 t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI);

  // Now correct phase
  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
    double f = freqs->data[i] - fRef_geom;
    int j = i + offset; // shift index for frequency series if needed
    pdata[j] *= cexp(-2*LAL_PI * I * f * t_corr);
    cdata[j] *= cexp(-2*LAL_PI * I * f * t_corr);
  }

  XLALDestroyREAL8Sequence(freqs);

  gsl_spline_free(spline_amp);
  gsl_spline_free(spline_phi);
  gsl_interp_accel_free(acc_amp);
  gsl_interp_accel_free(acc_phi);
  gsl_vector_free(amp_f);
  gsl_vector_free(phi_f);
  SEOBNRROMdata_coeff_Cleanup(romdata_coeff);

  return(XLAL_SUCCESS);
}
/**
 *	This function builds up a matrix describing the movement of the
 *	camera over dTime seconds.
 */
Matrix& CameraControl::calculateDeltaMatrix( float dTime )
{
    BW_GUARD;
    Matrix	m;

    deltaMatrix_.setIdentity();

    strafeRate_ += strafeRateVel_;

    strafeRate_ = strafeRate_ > 0.0f ? strafeRate_ : 0.0f;

    if (0)	// turning left
    {
        m.setRotateY( DEG_TO_RAD(60.f*dTime));
        deltaMatrix_.postMultiply(m);
    }

    if (0)	// turning right
    {
        m.setRotateY( -DEG_TO_RAD(60.f*dTime));
        deltaMatrix_.postMultiply(m);
    }

    if (0)	// rolling left
    {
        m.setRotateZ( -DEG_TO_RAD(60.f*dTime));
        deltaMatrix_.postMultiply(m);
    }

    if (0)	// rolling right
    {
        m.setRotateZ( DEG_TO_RAD(60.f*dTime));
        deltaMatrix_.postMultiply(m);
    }

    Vector3 newNudge( xNudge_ + xVel_, yNudge_ + yVel_, zNudge_ + zVel_ );
    newNudge *= strafeRate_;
    CameraControl::nudge( newNudge );


    // Update nudge and velocity.

    float halfLife = cameraMass() * 0.1f;
    if ( halfLife > 0.0 )
    {
        float x = nudge().x == 0.0f ?
                  Math::decay( velocity().x, nudge().x, halfLife * 0.3f, dTime ) :
                  Math::decay( velocity().x, nudge().x, halfLife, dTime );
        float y = nudge().y == 0.0f ?
                  Math::decay( velocity().y, nudge().y, halfLife * 0.3f, dTime ) :
                  Math::decay( velocity().y, nudge().y, halfLife, dTime );
        float z = nudge().z == 0.0f ?
                  Math::decay( velocity().z, nudge().z, halfLife * 0.3f, dTime ) :
                  Math::decay( velocity().z, nudge().z, halfLife, dTime );
        Vector3 newVelocity( x, y, z );
        CameraControl::velocity( newVelocity );
    }
    else
    {
        CameraControl::velocity( nudge() );
    }


    // CameraControl::velocity( nudge() );

    // Update position.
    m.setTranslate( velocity() * dTime );
    deltaMatrix_.postMultiply( m );

    return deltaMatrix_;
}