Volumes of ASCII boxes Introduction

In this challenge, you are given as input the ASCII representation of the net (unfolded surface) of a rectangular cuboid (3D box).
The format is this:

....+--+.......
....|##|.......
....|##|.......
....|##|.......
+---+--+---+--+
|###|##|###|##|
+---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......


Each face of the cuboid is a rectangle of #s surrounded by +-|-characters.
The outside of the net is filled with .s.
The net will always have the same orientation: there's a middle face surrounded by its four neighboring faces, and the counterpart of the middle face is at the right border of the input.
The input is padded with .s to a rectangular shape and will not contain extra rows or columns of .s.

The task

Your task is to take as input a diagram as above, and compute the volume of the cuboid that it represents, which is just the product of its height, width and depth.
You can take the input as a newline-delimited string or an array of strings.

The length of each edge is the distance between the +-characters at its two ends.
For example, the horizontal edge +--+ has length 3, and the vertical edge

+
|
|
|
+


has length 4.
The minimum length of an edge is 1.
The example cuboid above has volume 2*3*4 = 24.

Rules and scoring

You can write a full program or a function, and the lowest byte count wins.

Test cases

.++..
+++++
+++++
.++..
1

...++....
...||....
...||....
+--++--++
+--++--++
...||....
...||....
...++....
3

..+-+....
..|#|....
+-+-+-+-+
|#|#|#|#|
|#|#|#|#|
+-+-+-+-+
..|#|....
..+-+....
12

.+---+.....
++---++---+
||###||###|
||###||###|
||###||###|
++---++---+
.+---+.....
16

....++.....
....||.....
....||.....
....||.....
+---++---++
|###||###||
|###||###||
|###||###||
+---++---++
....||.....
....||.....
....||.....
....++.....
16

...+--+......
...|##|......
...|##|......
+--+--+--+--+
|##|##|##|##|
+--+--+--+--+
...|##|......
...|##|......
...+--+......
18

....+--+.......
....|##|.......
....|##|.......
....|##|.......
+---+--+---+--+
|###|##|###|##|
+---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......
24

....+-----+..........
....|#####|..........
....|#####|..........
....|#####|..........
+---+-----+---+-----+
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
+---+-----+---+-----+
....|#####|..........
....|#####|..........
....|#####|..........
....+-----+..........
120
Retina, 29 28 bytes

T`.p`xy`\G\..+¶
xy

¶\|
$`
y


Try it online!

There's a lot of ways to approach this in Retina, depending on which area you want to multiply with which side, so I'm not sure how optimal this is, but it's actually already a lot shorter than I thought it would be.

I've currently got two other solutions at the same byte count which seem a bit more golfable than the above approach:

\G\..+¶

¶\|
$'¶
G`\.
T`.|+



¶\||\+¶\.\D+
$'¶
G`\.
T`.|+



Although in these I could save a byte each if I assume that the input ends with a trailing linefeed, but I'd rather not have to rely on that.

And another one, still at 28 bytes (this one actually multiplies three sides instead of multiplying one area by a side):

\G\.
x
-(?&lt;=^.+)
$`
¶\|
$`
x


Explanation

The main idea is to multiply the area of the face on top by the length of the vertical side that touches the length border of the input.

I'll use the following input as an example (it has side lengths 2, 3 and 4, so an area of 24):

...+---+.......
...|###|.......
...|###|.......
+--+---+--+---+
|##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......


Stage 1: Transliterate

T`.p`xy`\G\..+¶


The regex \G\..+¶ matches a line which starts with . and is immediately adjacent to the previous line. So this matches all the lines that contain the top face. The stage itself turns . into x and all other characters (any of |+-#) into y. This gives us the following result:

xxxyyyyyxxxxxxx
xxxyyyyyxxxxxxx
xxxyyyyyxxxxxxx
+--+---+--+---+
|##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......


This has one more column of y than we need to represent the area of the top face. We fix this with the next stage.

Stage 2: Replace

xy



So we match a y that is preceded by an x (which is exactly one of them per line) and remove them both from the string. We get this:

xxyyyyxxxxxxx
xxyyyyxxxxxxx
xxyyyyxxxxxxx
+--+---+--+---+
|##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......


So now we've got the area of the top face represented by the number of ys.

Stage 3: Replace

¶\|
$`


Our goal here is to multiply this area A by the missing side length, which is the number of | at the beginning of a line plus 1. However, it's actually easier to multiply by a number n+1 because we've already got one copy of A in the string. If we replace n things with A, we end up with n+1 copies of A. This makes things a lot easier for us.

So we simply replace any | immediately after a linefeed with everything in front of the match. This mangles the string quite a lot and makes it a fair bit larger than we need, but the number of ys ends up being the result we're looking for:

xxyyyyxxxxxxx
xxyyyyxxxxxxx
xxyyyyxxxxxxx
+--+---+--+---+xxyyyyxxxxxxx
xxyyyyxxxxxxx
xxyyyyxxxxxxx
+--+---+--+---+##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......


Stage 4: Match

y


All that's left is to count the number of ys, which is printed as a decimal number at the end.