You can find the intersection points of two Bezier curves fully analytically using a technique called implicitization. It's nearly fully analytical, as you have to find the roots of a 9th-degree polynomial, but let's not be picky. The best resource I found on this subject are the Computer Aided Geometric Design notes by Thomas W. Sederberg.
I implemented this technique. I found out that it works really well (also performance-wise) in most cases, including cases one might call tough (e.g., nine points of intersection). The following screenshots come from the custom GUI helper tool using that implementation.
Interestingly, some cases appear extremely simple, yet pose a great challenge to the implicitization-based intersection finding algorithm. These two curves have a single prominent intersection:
The simple approximation intersection finding algorithms, like subdivision-based intersection finding, don't have any issues with this case (it isn't even challenging in any way to them). For implicitization, though, this is kryptonite.
If we minimally adjust a single control point, the implicitization-based algorithm magically starts finding the solution:
I picked an example that's not trying to hide the underlying problem. These are two simple Bezier curves that were "extracted" from a single self-intersecting curve.
Another example of such "problematic" curves, this time using screenshots from a vector computer graphics application:
Now, highlighting their underlying curve:
Their intersection polynomial is a constant 0 polynomial. It has infinitely many solutions, as the implicitization-based approach can't help but analyze the curves in their whole t-value domain (not just in the primary 0..1 range).
One might argue that this is actually a correct answer (as both curves actually overlap in a certain sense), but it's not. The curves we started with are defined in the 0..1 range, and it's a mathematical nuance how they "behave" outside of that range. In fact, this is a fundamental weakness of the implicitization-based intersection finding algorithm when applied to the standard Bezier curves defined in the 0..1 range.
How to analytically find the intersection of two cubic Bezier curves (restricted to the 0..1 range) in general? By saying "in general", I mean that the method should work in all cases that appear trivial at first glance, including the corner case I mentioned. If that helps, it might not work well (or at all) in obviously degenerate cases, like Bezier curves degenerating to a line or a point.
While a fully or mostly analytical solution is preferred (as I've come this far sticking to as analytical methods as possible), some ideas for approximated solutions described from a mathematical perspective are also welcome. For example, one of my ideas is to detect that the two curves overlap outside of their 0..1 range and then just... "shake" them a bit (pseudo-randomly move their control points by an epsilon in any direction). This should give a nearly perfect solution by "tricking" the intersection polynomial to become non-zero. Sounds silly, but might work.
Ideally, the solution wouldn't add computational overhead in the general case (99.999999.. % of cases) to handle the pathological cases. One of my ideas is to pick any point on the first curve and then pass it to the second curve's inverse polynomial to find the second curve's t-value. From that t-value, we can easily get the corresponding point by evaluating its basis function. If that's not the same point that we started with (the one from the first curve), then we know that this is not the pathological case and both curves are truly different (and it's safe to solve the intersection polynomial). Otherwise, we can proceed to some more sophisticated checks, as we already know that this either is a pathological case (and it's fine that it requires more computations) or we're just very unlucky (and it's also fine to add more computations in rare unlucky cases).