Tetrahedron Surface Area

16

The challenge

This challenge is very straightforward. Given four 3-dimensional points, calculate the surface area of the tetrahedron that they form. This is , so shortest code wins. Standard loopholes apply, with the added stipulation that any built-in function to do this task given four points is prohibited.

You can assume all four points will be distinct, and will be given via STDIN, 1 point per line. Each point will consist of three 16-bit unsigned integers. The exact format of each point can be modified if it makes things easier, such as three space separated integers. Having each point on a separate line is mandatory however. Output should be through STDOUT, to at least 2 decimal places.

For those of you who do not know, a tetrahedron is a 3-d solid, formed by 4 triangular faces.

Example

# input (format is up to you, see clarification above)
[23822, 47484, 57901]
[3305, 23847, 42159]
[19804, 11366, 14013]
[52278, 28626, 52757]

# output
2932496435.95

Please leave a note if you notice my math is wrong.

stokastic

Posted 2014-10-03T17:21:43.887

Reputation: 981

@BetaDecay No, the idea is that they will be input via STDIN on four separate lines. I will edit the question to clarify this. – stokastic – 2014-10-03T18:18:01.487

Can the input be a [[list],[of],[lists]]? – phosgene – 2014-10-03T18:31:06.333

@phosgene I like to think reading the input is part of the challenge, so I'm going to say no. I will try to be more lenient with input specifications in future challenges. – stokastic – 2014-10-03T18:36:36.513

Is this a regular or irregular tetrahedron? – James Williams – 2014-10-03T19:24:18.243

@JamesWilliams the example posted is irregular. Your program should handle any input though, including regular tetrahedrons. – stokastic – 2014-10-03T19:25:56.963

Answers

5

Python, 198 178 161 chars

V=eval('input(),'*4)
A=0
for i in range(4):F=V[:i]+V[i+1:];a,b,c=map(lambda e:sum((a-b)**2for a,b in zip(*e)),zip(F,F[1:]+F));A+=(4*a*b-(a+b-c)**2)**.5
print A/4

The input format is as given in the question.

It calculates the length of the edges adjacent to each of the faces and then uses Heron's formula.

Keith Randall

Posted 2014-10-03T17:21:43.887

Reputation: 19 865

4

Matlab/Octave 103

I assume the values to be stored in the variable c. This uses the fact that the area of a triangle is the half length of the cross product of two of its side vectors.

%input
[23822, 47484, 57901;
3305, 23847, 42159;
19804, 11366, 14013;
52278, 28626, 52757]



%actual code
c=input('');
a=0;
for i=1:4;
    d=c;d(i,:)=[];
    d=d(1:2,:)-[1 1]'*d(3,:);
    a=a+norm(cross(d(1,:),d(2,:)))/2;
end
a

flawr

Posted 2014-10-03T17:21:43.887

Reputation: 40 560

Each point must be entered on a separate line as standard input. – DavidC – 2014-10-04T01:30:07.527

I first thought there is no such thing as standard input in Matlab, but I discovered a function that can be used to simulate this via the command window, so now you can pass the input as you could in other languages. – flawr – 2014-10-04T09:18:19.383

Interesting. That's the same command that Mathematica uses, Input[] – DavidC – 2014-10-04T11:59:26.233

Why do you think that this is interesting? 'input' seems to me like a pretty generic name for a function that does this. – flawr – 2014-10-04T12:12:09.370

Until yesterday, I didn't really know what "standard input" meant, and I thought that Mathematica did not have "standard" input, even though I had regularly used Input[], InputString[], Import[], and ImportString[]. – DavidC – 2014-10-04T12:31:24.427

Ah, honestly I have never used Mathematica but it seems like a powerful program, do you use it professionally? – flawr – 2014-10-04T13:06:14.110

I use Mathematica in university courses we offer for in-service middle school teachers. For example, our teachers recently interviewed their students using a Mathematica app about multiplication as dilations on the line and in the plane. I find it powerful and elegant. Teachers who want to design their own apps will generally find GeoGebra more appropriate and approachable. – DavidC – 2014-10-04T14:17:38.553

Well the thing is also that GeoGebebra is available for free while Mathematica can - depending on what organization - still be expensive. – flawr – 2014-10-05T16:16:21.087

4

APL, 59

f←{+.×⍨⊃1 2-.⌽(⊂⍵)×1 2⌽¨⊂⍺}
.5×.5+.*⍨(f/2-/x),2f/4⍴x←⎕⎕⎕-⊂⎕

Works by calculating cross products

Explanation
The first line defines a function that takes two arguments (implicity named and ), implicitly expects them to be numerical arrays of length 3, treat them as 3d vectors, and calculates the squared magnitude of their cross product.

                        ⊂⍺   # Wrap the argument in a scalar
                   1 2⌽¨     # Create an array of 2 arrays, by rotating `⊂⍺` by 1 and 2 places
             (⊂⍵)×           # Coordinate-wise multiply each of them with the other argument
        1 2-.⌽               # This is a shorthand for:
        1 2  ⌽               #   Rotate the first array item by 1 and the second by 2
           -.                #   Then subtract the second from the first, coordinate-wise
       ⊃                     # Unwrap the resulting scalar to get the (sorta) cross product
   +.×                       # Calculate the dot product of that...
      ⍨                      # ...with itself
f←{+.×⍨⊃1 2-.⌽(⊂⍵)×1 2⌽¨⊂⍺} # Assign function to `f`

The second line does the rest.

                         ⎕⎕⎕-⊂⎕ # Take 4 array inputs, create an array of arrays by subtracting one of them from the other 3
                       x←        # Assign that to x
                     4⍴          # Duplicate the first item and append to the end
                  2f/            # Apply f to each consecutive pair
            2-/x                 # Apply subtraction to consecutive pairs in x
          f/                     # Apply f to the 2 resulting arrays
         (f/2-/x),2f/4⍴x←⎕⎕⎕-⊂⎕ # Concatenate to an array of 4 squared cross products
   .5+.*⍨                        # Again a shorthand for:
   .5  *⍨                        #   Take square root of each element (by raising to 0.5)
     +.                          #   And sum the results
.5×                              # Finally, divide by 2 to get the answer

TwiNight

Posted 2014-10-03T17:21:43.887

Reputation: 4 187

If you are not sure whether it is hieroglyphs or a corrupted dll file it is probably gonna be APL. Could you perhaps explain somewhat more what some of those symbols do? It's not that I want to learn it but I am still rather intrigued by how you can program with those seemingly obscure symbols=P – flawr – 2014-10-06T16:55:53.193

@flawr I usually does that because golfing in APL mostly comes down to algorithm design and would most likely result in an uncommon approach to the problem. But I felt like "calculating cross product" conveys enough about the algorithm here. If you want a full-on explanation I will do it later today. – TwiNight – 2014-10-07T12:05:34.927

The idea of calculating the cross product was clear, but the code itself leaves me without any clue, so I just thought some few words about what parts of the code do what would be great, but of course I do not want to urge you to write a detailed explaination! – flawr – 2014-10-07T12:33:10.203

3

Python 3, 308 298 292 279 258 254

from itertools import*
def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**.5
z,x,c,v,b,n=((lambda i,j:(sum((i[x]-j[x])**2for x in[0,1,2]))**.5)(x[0],x[1])for*x,in combinations([eval(input())for i in">"*4],2))
print(a(z,x,v)+a(z,c,b)+a(b,v,n)+a(x,c,n))

This uses:

  • The Pythagorean Theorem (in 3D) to work out the length of each line
  • Heron's Formula to work out the area of each triangle

monopole

Posted 2014-10-03T17:21:43.887

Reputation: 1 559

1I used the same method for testing my solution. I'll have to try golfing mine and post it later. – stokastic – 2014-10-03T19:54:50.463

1Your for i in">"*4 is clever – stokastic – 2014-10-03T19:58:11.983

You can hard code a length of 3, instead of using len(i) in your range function. – stokastic – 2014-10-03T20:28:51.650

1You could save a few more characters doing the square root as x**0.5, instead of math.sqrt(x). – Snorfalorpagus – 2014-10-03T22:46:13.487

1You can save two bytes by putting def a(t,u,v) on one line like so: def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**0.5. – Beta Decay – 2014-10-04T08:50:16.013

2

Mathematica 168 154

This finds the lengths of the edges of the tetrahedron and uses Heron's formula to determine the areas of the faces.

t = Subsets; p = Table[Input[], {4}];
f@{a_, b_, c_} := Module[{s = (a + b + c)/2}, N[Sqrt[s (s - #) (s - #2) (s -#3)] &[a, b, c], 25]]
  Tr[f /@ (EuclideanDistance @@@ t[#, {2}] & /@ t[p, {3}])]

There is a more direct route that requires only 60 chars, but it violates the rules insofar as it computes the area of each face with a built-in function, Area:

p = Table[Input[], {4}];
N[Tr[Area /@ Polygon /@ Subsets[p, {3}]], 25]

DavidC

Posted 2014-10-03T17:21:43.887

Reputation: 24 524

1

Sage – 103

print sum((x*x*y*y-x*y*x*y)^.5for x,y in map(differences,Combinations(eval('vector(input()),'*4),3)))/2

The input-reading part is adapted from Keith Randall’s answer.

Wrzlprmft

Posted 2014-10-03T17:21:43.887

Reputation: 2 772

0

Python - 260

I'm not sure what the etiquette on posting answers to your own questions is, but her is my solution, which I used to verify my example, golfed:

import copy,math
P=[input()for i in"1234"]
def e(a, b):return math.sqrt(sum([(b[i]-a[i])**2 for i in range(3)]))
o=0
for j in range(4):p=copy.copy(P);p.pop(j);a,b,c=[e(p[i],p[(i+1)%3])for i in range(3)];s=(a+b+c)/2;A=math.sqrt(s*(s-a)*(s-b)*(s-c));o+=A
print o

It uses the same procedure as laurencevs.

stokastic

Posted 2014-10-03T17:21:43.887

Reputation: 981

4As a rule of thumb, it's a best idea to wait a few days before answering your own question, especially if your score is low, in order to not cool down the motivation of the viewers. – Blackhole – 2014-10-03T21:09:13.863

A few tips: You can save some characters by r=range. lambda is shorter than def. math.sqrt can be replaced by (…)**.5. p=copy.copy(P);p.pop(j); can be shortened to p=P[:j-1]+P[j:]. A is only used once. – Wrzlprmft – 2014-10-08T15:34:35.990

0

C, 303

Excluding unnecessary whitespace. However, there's still a lot of golfing to be done here (I will try to come back and do it later.) It's the first time I've declared a for loop in a #define. I've always found ways to minmalise the number of loops before.

I had to change from float to double to get the same answer as the OP for the test case. Before that, it was a round 300.

scanf works the same whether you separate your input with spaces or newlines, so you can format it into as many or as few lines as you like.

#define F ;for(i=0;i<12;i++)
#define D(k) (q[i]-q[(i+k)%12])
double q[12],r[12],s[4],p,n;

main(i){
  F scanf("%lf",&q[i])
  F r[i/3*3]+=D(3)*D(3),r[i/3*3+1]+=D(6)*D(6)
  F r[i]=sqrt(r[i])
  F i%3||(s[i/3]=r[(i+3)%12]/2),s[i/3]+=r[i]/2
  F i%3||(p=s[i/3]-r[(i+3)%12]),p*=s[i/3]-r[i],n+=(i%3>1)*sqrt(p)   
  ;printf("%lf",n);       
}

Level River St

Posted 2014-10-03T17:21:43.887

Reputation: 22 049