Implementing piecewise linear functions
A similar question has been asked before, that may answer your question, here. Quoting the answer:

This is basically an instance of the line segment intersection problem.  One standard approach is to use a sweep line algorithm.  For instance, the Bentley-Ottman algorithm would be a reasonable choice, and is not too difficult to implement.
At each iteration of the algorithm, we have some value of $x$, and we calculate what is the next largest value of $x$ where something interesting happens.  Here, &quot;something interesting&quot; is either (1) two pieces intersect each other at a point, or (2) we reach the end of one of the current pieces.  Then we advance $x$ to this next value.
At each iteration, we keep track of which pieces are currently active (i.e., $x$ is within the domain of that piece) and the order of the pieces, ordered by their $y$-value for that particular value of $x$.  Store them in sorted order, sorted by $y$-value.

So, in some sense it is a matter of proper abstraction: you need to implement a function
 something_interesting_happens(real x, function f1, function f2)

the function should return, given an x-value x, the next x-value where either an intersection occurs or the start or end of a line segment occurs. With this functionality out of the way, to return your maximum function, you just iterate over all the interesting x-values, starting from 0 and repeatedly using something_interesting_happens to get the next interesting x-value. It is a bit simpler for you as you are looking to only maximize two functions, and in the above quote they consider maximizing $n$ functions.
The final issue is that you need to settle on a representation for your piecewise linear functions. As plop points out in the comments, your current representation has an issue: it can't represent discontinuous functions.
Here's one possibility, for simplicity:

Define a piece to be either an open line segment, represented by a pair of points $(x_1, y_1), (x_2, y_2)$, or a single point, represented by $(x_1, y_1)$. This gives you sufficient expressiveness to have both closed and open line segments, without worrying about representing open and closed line segments separately. In particular, a closed line segment will be an open line segment, plus points at both of the endpoints.

It will be probably useful to have some functions on pieces, such as:
intersect(piece p1, piece p2)

to indicate if two pieces intersect in the $x$-values they consider, and
less-than(piece p1, piece p2)

which means that p1 and p2 don't intersect, and p1 is before p2.

Represent a piecewise linear function by a (possibly empty) sequence of pieces. The pieces should be sorted, so that less-than(p1, p2) holds for all pieces in the list p1 and p2 where p1 occurs before than p1.