Q:

Fill time series per origin-destination pair in Postgresql with cross join

SQLfiddle : http://sqlfiddle.com/#!17/0ba48b
Let's say I have a table like this 
CREATE TABLE trips (origin int, destination int, t TIMESTAMP);

INSERT INTO trips VALUES
    (1, 1, '2016-06-22 08:02:00'),
    (1, 3, '2016-06-22 08:10:00'),
    (1, 3, '2016-06-22 08:12:00'),
    (2, 1, '2016-06-22 08:49:00');

The set of origin/destinations is {1,2,3}. I want to generate a table like this:
origin | destination |      t       |count 
--------------------------------------------
      1 |          1 |     08:00:00 | 1
      1 |          1 |     08:15:00 | 0
      1 |          1 |     08:30:00 | 0
      1 |          1 |     08:45:00 | 0
      1 |          2 |     08:00:00 | 0
     ...|            |              |
      1 |          3 |     08:00:00 | 2
      1 |          3 |     08:15:00 | 0

Basically, for each origin-destination pair, I want to generate the whole timeseries (with 15 minute intervals), aggregating the trips and inserting 0/null when needed. 
My attempt so far: 
with 

    -- generate bins
    bins as (
    select bin
        from 
        (select generate_series(
      date_trunc('hour', 
          (SELECT min(t) 
      FROM trips 
      LIMIT 1)) , -- start at one day ago, rounded to the hour
      date_trunc('hour', (SELECT max(t) 
      FROM trips 
      LIMIT 1))+ '1 day'::interval,  -- stop at now, rounded to the hour
      '15 minutes'::interval -- one hour intervals
        ) as bin ) intervals
      where extract('ISODOW' FROM bin) < 6  -- exclude weekends
    ),
    -- bin the od table https://gis.stackexchange.com/a/127874/13965
    od as (
    SELECT COUNT(*) cnt, origin, destination,
    to_timestamp(floor((extract('epoch' from t) / 900 )) * 900)  -- this bins it to 15 minutes, but has many missing values 
    AT TIME ZONE 'UTC' as interval_alias_exit
    FROM 
    trips
    GROUP BY interval_alias_exit, origin, destination
    )
    -- merge the two
    select 
    * from 
    bins 
    left join od
    on bins.bin = od.interval_alias_exit
    where origin = '1'

But this does not create a time series per OD pair. For example, it will only return two rows for when origin is 1. Please look at the fiddle for an example. 

A:

You need to cross join all points with all points to get all origin destination pairs and then cross join that with time series. You can then left join the trips on equal origin and destination and the timestamp being larger or equal to the timestamp of the series but less than that timestamp of the series plus 15 minutes. Then aggregate by origin, destination and the timestamp of the series and take the count of the trip's timestamp.
SELECT o.origin,
       d.destination,
       gs.t,
       count(t.t) count
       FROM (SELECT origin
                    FROM trips
             UNION
             SELECT destination
                    FROM trips) o
            CROSS JOIN (SELECT destination
                               FROM trips
                        UNION
                        SELECT origin
                               FROM trips) d
            CROSS JOIN generate_series((SELECT date_trunc('hour', min(t))
                                               + concat(floor(extract('minutes' FROM min(t)) / 15) * 15,
                                                        ' minutes')::interval
                                               FROM trips),
                                       (SELECT date_trunc('hour', max(t))
                                               + concat(floor(extract('minutes' FROM max(t)) / 15) * 15,
                                                        ' minutes')::interval
                                               FROM trips),
                                       '15 minutes'::interval) gs (t)
            LEFT JOIN trips t
                      ON t.origin = o.origin
                         AND t.destination = d.destination
                         AND t.t >= gs.t
                         AND t.t < gs.t + '15 minutes'::interval
       GROUP BY o.origin,
                d.destination,
                gs.t
       ORDER BY o.origin,
                d.destination,
                gs.t;

(You seem to have another logic for the boundaries of the time series in your example's desired result than in the query you posted. I tried to match the former. But I guess you'll figure out how to change it to fit your actual needs.)
SQL Fiddle

