다각형의 중심을 구합니다


16

에서 위키 백과 :

n 개의 꼭짓점 ( x 0 , y 0 ), ( x 1 , y 1 ), ..., ( x n − 1 , y n-1 )에 의해 정의 된 자체 교차하지 않는 닫힌 다각형의 중심 포인트 ( C x , C y ), 여기서

중심에 대한 공식

여기서 A 는 다각형의 부호있는 영역입니다.

다각형 면적 공식

이 공식에서 정점은 다각형의 둘레를 따라 나타나는 순서대로 번호가 매겨져 있다고 가정합니다. 또한 정점 ( x n , y n )은 ( x 0 , y 0 ) 과 같다고 가정합니다. , 마지막 경우 i + 1i = 0으로 반복되어야합니다 . 포인트가 시계 방향으로 번호가 매겨지면 위와 같이 계산 된 영역 A 는 음의 부호를 갖습니다. 그러나이 경우에도 중심 좌표가 정확합니다.


  • 시계 방향 또는 시계 반대 방향으로 정점 목록이 주어지면 정점으로 표시되는 자체 교차하지 않는 닫힌 다각형의 중심을 찾으십시오.
    • 도움이되는 경우 입력을 CW 또는 CCW로만 가정 할 수 있습니다. 필요한 경우 답을 말씀하십시오.
  • 좌표는 정수일 필요는 없으며 음수를 포함 할 수 있습니다.
  • 입력은 항상 유효하며 3 개 이상의 꼭짓점을 포함합니다.
  • 언어의 기본 부동 소수점 데이터 유형에 맞는 입력 만 처리하면됩니다.
  • 입력 숫자는 항상 소수점을 포함한다고 가정 할 수 있습니다.
  • 입력 정수가 .또는로 끝나는 것으로 가정 할 수 있습니다 .0.
  • 입력에 복소수를 사용할 수 있습니다.
  • 출력은 가장 가까운 천분의 일까지 정확해야합니다.

[(0.,0.), (1.,0.), (1.,1.), (0.,1.)]        -> (0.5, 0.5)
[(-15.21,0.8), (10.1,-0.3), (-0.07,23.55)]  -> -1.727 8.017
[(-39.00,-55.94), (-56.08,-4.73), (-72.64,12.12), (-31.04,53.58), (-30.36,28.29), (17.96,59.17), (0.00,0.00), (10.00,0.00), (20.00,0.00), (148.63,114.32), (8.06,-41.04), (-41.25,34.43)]   -> 5.80104769975, 15.0673812762

좌표 평면에 각 다각형이 너무 많으면 이 페이지 의 "편집"메뉴에서 대괄호없이 좌표를 붙여 넣으십시오 .

Polygon Centroid Point Calculator를 사용하여 결과를 확인했습니다 . 한 번에 모든 정점을 입력 할 수 있거나 -처음 입력 할 때 부호 를 지우려고하지 않은 것을 찾을 수 없습니다 . 사람들이 대답 할 기회를 얻은 후에 사용할 수 있도록 Python 솔루션을 게시하겠습니다.


모든 x와 y의 평균을 구하는 훨씬 간단한 기술은 처음 두 세트에 적용되지만 세 번째 세트에는 적용되지 않습니다. 차이점이 무엇인지 궁금합니다.
ETHproductions

1
@ETHproductions 세 번째 다각형은 볼록하지 않습니다.
JungHwan Min 2018

1
@ETHproductions 다각형을 사용하여 원을 근사화하는 경우 중심점에 거의 영향을 미치지 않고 다각형 볼록한 상태를 유지하면서 해당 점에 가까운 점을 더 사용하여 임의의 평균 점을 원의 점에 가깝게 이동할 수 있습니다.
Christian Sievers

2
@ETHproductions 실제로 볼록성이 이유 가 아닙니다 . 모든 xs 및 ys를 평균 하면 몸 전체에 분산되는 대신 정점에 모든 가중치가 적용됩니다. 첫 번째는 규칙적이기 때문에 작동하기 때문에 두 방법 모두 대칭 중심에 있습니다. 두 번째 방법은 삼각형의 경우 두 방법이 모두 같은 점으로 이어지기 때문에 작동합니다.
Ton Hospel

1
I / O에 복소수를 사용할 수 있습니까?
xnor

답변:


16

젤리 , 25 24 22 21 18 바이트

S×3÷@×"
ṙ-żµÆḊçS€S

문제에 표시된 공식을 적용합니다.

@ Jonathan Allan의 도움으로 3 바이트를 절약했습니다 .

온라인으로 사용해보십시오! 또는 모든 테스트 사례를 확인하십시오.

설명

S×3÷@×"  Helper link. Input: determinants on LHS, sum of pairs on RHS
S        Sum the determinants
 ×3      Multiply by 3
     ×"  Vectorized multiply between determinants and sums
   ÷@    Divide that by the determinant sum multipled by 3 and return

ṙ-żµÆḊçS€S  Main link. Input: 2d list of points
ṙ-          Rotate the list of points by 1 to the right
  ż         Interleave those with the original points
            This creates all overlapping slices of length 2
   µ        Start new monadic chain
    ÆḊ      Get the determinant of each slice
       S€   Get the sum of each slice (sum of pairs of points)
      ç     Call the helper link
         S  Sum and return

당신은 대체 할 수 ṁL‘$ṡ2ṙ1ż@żṙ1$
조나단 앨런에게

@JonathanAllan 덕분에, 또한 나는에 의해 회전 할 수 ṙ-ż스왑을 피하기 위해 다른 바이트 저장
마일

아 그래!
Jonathan Allan

17

매스 매 티카, 23 바이트

RegionCentroid@*Polygon

가지고 , 젤리!

편집 : 하나는 단순히 젤리를 이길 수 없습니다 ...

설명

Polygon

지정된 점에 정점이있는 다각형을 생성합니다.

RegionCentroid

다각형의 중심을 찾으십시오.


2
글쎄, 당신은 나를 이겼지 만 아마 내가 가진 것보다 짧은 방법이있을 것입니다, 나는 아직 젤리에 대한 완전한 이해가 없습니다
miles

3
@miles aw ... :(
JungHwan Min

4

J, 29 바이트

2+/@(+/\(*%3*1#.])-/ .*\)],{.

문제에 표시된 공식을 적용합니다.

용법

   f =: 2+/@(+/\(*%3*1#.])-/ .*\)],{.
   f 0 0 , 1 0 , 1 1 ,: 0 1
0.5 0.5
   f _15.21 0.8 , 10.1 _0.3 ,: _0.07 23.55
_1.72667 8.01667
   f _39 _55.94 , _56.08 _4.73 , _72.64 12.12 , _31.04 53.58 , _30.36 28.29 , 17.96 59.17 , 0 0 , 10 0 , 20 0 , 148.63 114.32 , 8.06 _41.04 ,: _41.25 34.43
5.80105 15.0674

설명

2+/@(+/\(*%3*1#.])-/ .*\)],{.  Input: 2d array of points P [[x1 y1] [x2 y2] ...]
                           {.  Head of P
                         ]     Get P
                          ,    Join, makes the end cycle back to the front
2                              The constant 2
2                      \       For each pair of points
                  -/ .*        Take the determinant
2    +/\                       Sum each pair of points
         *                     Multiply the sum of each pair by its determinant
          %                    Divide each by
             1#.]              The sum of the determinants
           3*                  Multiplied by 3
 +/@                           Sum and return

4

맥시 124 118 116 112 106 바이트

f(l):=(l:endcons(l[1],l),l:sum([3,l[i-1]+l[i]]*determinant(matrix(l[i-1],l[i])),i,2,length(l)),l[2]/l[1]);

나는 Maxima에 경험이 없으므로 힌트를 환영합니다.

용법:

(%i6) f([[-15.21,0.8], [10.1,-0.3], [-0.07,23.55]]);
(%o6)              [- 1.726666666666668, 8.016666666666668]

3

라켓 420 바이트

(let*((lr list-ref)(getx(lambda(i)(lr(lr l i)0)))(gety(lambda(i)(lr(lr l i)1)))(n(length l))(j(λ(i)(if(= i(sub1 n))0(add1 i))))
(A(/(for/sum((i n))(-(*(getx i)(gety(j i)))(*(getx(j i))(gety i))))2))
(cx(/(for/sum((i n))(*(+(getx i)(getx(j i)))(-(*(getx i)(gety(j i)))(*(getx(j i))(gety i)))))(* 6 A)))
(cy(/(for/sum((i n))(*(+(gety i)(gety(j i)))(-(*(getx i)(gety(j i)))(*(getx(j i))(gety i)))))(* 6 A))))
(list cx cy))

언 골프 드 :

(define(f l)
  (let* ((lr list-ref)
         (getx (lambda(i)(lr (lr l i)0)))
         (gety (lambda(i)(lr (lr l i)1)))
         (n (length l))
         (j (lambda(i) (if (= i (sub1 n)) 0 (add1 i))))
         (A (/(for/sum ((i n))
                (-(* (getx i) (gety (j i)))
                  (* (getx (j i)) (gety i))))
              2))
         (cx (/(for/sum ((i n))
                 (*(+(getx i)(getx (j i)))
                   (-(*(getx i)(gety (j i)))
                     (*(getx (j i))(gety i)))))
               (* 6 A)))
         (cy (/(for/sum ((i n))
                 (*(+(gety i)(gety (j i)))
                   (-(*(getx i)(gety (j i)))
                     (*(getx (j i))(gety i)))))
               (* 6 A))))
    (list cx cy)))

테스트 :

(f '[(-15.21 0.8)  (10.1 -0.3)  (-0.07 23.55)] ) 
(f '[(-39.00 -55.94)  (-56.08 -4.73)  (-72.64 12.12)  (-31.04 53.58) 
     (-30.36 28.29)  (17.96 59.17)  (0.00 0.00)  (10.00 0.00)  
     (20.00 0.00) (148.63 114.32)  (8.06 -41.04)  (-41.25 34.43)])

산출:

'(-1.7266666666666677 8.01666666666667)
'(5.8010476997538465 15.067381276150996)

3

R, 129127 바이트

function(l){s=sapply;x=s(l,`[`,1);y=s(l,`[`,2);X=c(x[-1],x[1]);Y=c(y[-1],y[1]);p=x*Y-X*y;c(sum((x+X)*p),sum((y+Y)*p))/sum(p)/3}

튜플의 R- 목록을 입력으로 사용하는 이름이없는 함수입니다. 명명 된 동등 물은 다음을 사용하여 호출 할 수 있습니다.

f(list(c(-15.21,0.8),c(10.1,-0.3),c(-0.07,23.55)))

언 골프 및 설명

f=function(l){s=sapply;                           # Alias for sapply
              x=s(l,`[`,1);                       # Split list of tuples into vector of first elements
              y=s(l,`[`,2);                       # =||= but for second element 
              X=c(x[-1],x[1]);                    # Generate a vector for x(i+1)
              Y=c(y[-1],y[1]);                    # Generate a vector for y(i+1)
              p=x*Y-X*y;                          # Calculate the outer product used in both A, Cx and Cy
              c(sum((x+X)*p),sum((y+Y)*p))/sum(p)/3    # See post for explanation
}

마지막 단계 (c(sum((x+X)*p),sum((y+Y)*p))/sum(p)*2/6 )을 모두 산출하는 벡터화 방법 CxCy. 대한 수식의 합 CxCy벡터 저장 결과적 "의 합으로 나누어진다 A" *2/6. 예 :

(SUMinCx, SUMinCy) / SUMinA / 3

그런 다음 암시 적으로 인쇄됩니다.

R 바이올린에서 사용해보십시오


*2/6아마도 /3?
mbomb007

@ mbomb007 너무나 당연한 일이지만, 다른 부분을 골라내는 일에 푹 빠져 버린 것 같습니다. /
shrug

우아한, 나는 당신 sapply이 그 목록을 다루는 사용을 좋아합니다 ! 여기 골프에 대한 범위가있을 수 있습니다. 허용 가능한 입력이 얼마나 유연한 지 잘 모르겠습니다. 과 같은 일련의 좌표 만 입력 c(-15.21,0.8,10.1,-0.3,-0.07,23.55)할 수 있으면 함수의 첫 번째 줄을로 바꾸어 17 바이트를 절약 할 수 있습니다 y=l[s<-seq(2,sum(1|l),2)];x=l[-s];. 즉 설정된다 y모든 짝수 요소로 l, 그리고 x모든 홀수 인덱스 요소한다.
rturnbull

그러나 더 좋은 matrix(c(-15.21,0.8,10.1,-0.3,-0.07,23.55),2)방법은 함수의 시작 부분이 될 수있는 것처럼 행렬 (또는 배열)을 입력 할 수 있다면 x=l[1,];y=l[2,];35 바이트를 절약하는 것입니다. (이 경우 입력 행렬을 전치 할 수 있습니다 x=l[,1];y=l[,2];.) 물론 가장 쉬운 방법은 xy점이 별도의 벡터로 입력 된 function(x,y)것이지만 허용되지는 않습니다 ...
rturnbull

@rturnbull 나는 의견에 OP를 물었고 그는 특히 튜플 목록 (R에서 매우 불편 함)을 원했기 때문에 매트릭스 접근법이 허용되지 않는다고 생각합니다. 그리고 그것이 입력 되더라도 입력은 벡터 부분이어야하고 (즉 c(...)) 함수 내에서 행렬 변환이 수행되어야합니다.
Billywob

2

파이썬, 156127 바이트

def f(p):n=len(p);p=p+p[:1];i=s=0;exec'd=(p[i].conjugate()*p[i+1]).imag;s+=d;p[i]=(p[i]+p[i+1])*d;i+=1;'*n;print sum(p[:n])/s/3

언 골프 드 :

def f(points):
  n = len(points)
  points = points + [points[0]]
  determinantSum = 0
  for i in range(n):
    determinant = (points[i].conjugate() * points[i+1]).imag
    determinantSum += determinant
    points[i] = (points[i] + points[i+1]) * determinant
  print sum(points[:n]) / determinantSum / 3

무시 했어

각 점 쌍을 [x, y]복소수로 취하고 x + y*j결과 중심을 동일한 형식의 복소수로 출력합니다.

포인트 쌍 [a, b]과에 대해 [c, d], a*d - b*c각 포인트 쌍에 필요한 값 은 행렬의 결정 요인으로부터 계산 될 수 있습니다.

| a b |
| c d |

복소 값 복잡한 산술 사용 a + b*jc + d*j같이 사용될 수있다

conjugate(a + b*j) * (c + d*j)
(a - b*j) * (c + d*j)
(a*c + b*d) + (a*d - b*c)*j

허수 부는 결정자와 같습니다. 또한 복잡한 값을 사용하면 다른 작업에서 포인트를 구성 요소별로 쉽게 합칠 수 있습니다.


2

R + sp (46 바이트)

sp패키지가 설치 되었다고 가정 합니다 ( https://cran.r-project.org/web/packages/sp/ )

(예를 들어, 정점의 목록을 소요 list(c(0.,0.), c(1.,0.), c(1.,1.), c(0.,1.)))

다각형의 "중간"이 중심이라는 사실을 이용합니다.

function(l)sp::Polygon(do.call(rbind,l))@labpt

2

자바 스크립트 (ES6), 102

공식의 직접적인 구현

l=>[...l,l[0]].map(([x,y],i)=>(i?(a+=w=t*y-x*u,X+=(t+x)*w,Y+=(u+y)*w):X=Y=a=0,t=x,u=y))&&[X/3/a,Y/3/a]

테스트

f=
l=>[...l,l[0]].map(([x,y],i)=>(i?(a+=w=t*y-x*u,X+=(t+x)*w,Y+=(u+y)*w):X=Y=a=0,t=x,u=y))&&[X/3/a,Y/3/a]

function go()
{
  var c=[],cx,cy;
  // build coordinates array
  I.value.match(/-?[\d.]+/g).map((v,i)=>i&1?t[1]=+v:c.push(t=[+v]));
  console.log(c+''),
  [cx,cy]=f(c);
  O.textContent='CX:'+cx+' CY:'+cy;
  // try to display the polygon
  var mx=Math.max(...c.map(v=>v[0])),
    nx=Math.min(...c.map(v=>v[0])),
    my=Math.max(...c.map(v=>v[1])),
    ny=Math.min(...c.map(v=>v[1])),  
    dx=mx-nx, dy=my-ny,
    ctx=C.getContext("2d"),
    cw=C.width, ch=C.height,
    fx=(mx-nx)/cw, fy=(my-ny)/ch, fs=Math.max(fx,fy)
  C.width=cw
  ctx.setTransform(1,0,0,1,0,0);
  ctx.beginPath();
  c.forEach(([x,y],i)=>ctx.lineTo((x-nx)/fs,(y-ny)/fs));
  ctx.closePath();
  ctx.stroke();
  ctx.fillStyle='#ff0000';
  ctx.fillRect((cx-nx)/fs-2,(cy-ny)/fs-2,5,5);
}
go()
#I { width:90% }
#C { width:90%; height:200px;}
<input id=I value='[[-15.21,0.8], [10.1,-0.3], [-0.07,23.55]]'>
<button onclick='go()'>GO</button>
<pre id=O></pre>
<canvas id=C></canvas>


1

파이썬 2, 153 바이트

복소수를 사용하지 않습니다.

P=input()
A=x=y=0;n=len(P)
for i in range(n):m=-~i%n;a=P[i][0];b=P[i][1];c=P[m][0];d=P[m][1];t=a*d-b*c;A+=t;x+=t*(a+c);y+=t*(b+d)
k=1/(3*A);print x*k,y*k

온라인으로 사용해보십시오

언 골프 드 :

def centroid(P):
    A=x=y=0
    n=len(P)
    for i in range(n):
        m=-~i%n
        x0=P[i][0];y0=P[i][1]
        x1=P[m][0];y1=P[m][1]
        t = x0*y1 - y0*x1
        A += t/2.
        x += t * (x0 + x1)
        y += t * (y0 + y1)
    k = 1/(6*A)
    x *= k
    y *= k
    return x,y

1

실제로 45 40 39 바이트

마일의 젤리 답변 과 유사한 알고리즘을 사용합니다 . 내적을 사용하여 결정자를 계산하는 더 짧은 방법이 있지만 현재 플로트 목록과 함께 작동하지 않는 Actuals의 내적 제품에 버그가 있습니다. 골프 제안을 환영합니다. 온라인으로 사용해보십시오!

;\Z♂#;`i¥`M@`i│N@F*)F@N*-`M;Σ3*)♀*┬♂Σ♀/

언 골핑

         Implicit input pts.
;\       Duplicate pts, rotate right.
Z        Zip rot_pts and pts together.
♂#       Convert the iterables inside the zip to lists
         (currently necessary due to a bug with duplicate)
;        Duplicate the zip.
`...`M   Get the sum each pair of points in the zip.
  i        Flatten the pair to the stack.
  ¥        Pairwise add the two coordinate vectors.
@        Swap with the other zip.
`...`M   Get the determinants of the zip.
  i│       Flatten to stack and duplicate entire stack.
           Stack: [a,b], [c,d], [a,b], [c,d]
  N@F*)    Push b*c and move it to BOS.
  F@N*     Push a*d.
  -        Get a*d-b*c.
;Σ3*)    Push 3 * sum(determinants) and move it to BOS.
♀*       Vector multiply the determinants and the sums.
┬        Transpose the coordinate pairs in the vector.
♂Σ       Sum the x's, then the y's.
♀/       Divide the x and y of this last coordinate pair by 3*sum(determinants).
         Implicit return.

짧고 비경쟁적인 버전

이것은 복소수를 사용하는 또 다른 24 바이트 버전입니다. 이 문제를 해결 한 버그 수정에 의존하기 때문에 비 경쟁적입니다. 온라인으로 사용해보십시오!

;\│¥)Z`iá*╫@X`M;Σ3*)♀*Σ/

언 골핑

         Implicit input a list of complex numbers, pts.
;\       Duplicate pts, rotate right.
│        Duplicate stack. Stack: rot_pts, pts, rot_pts, pts.
¥)       Pairwise sum the two lists of points together and rotate to BOS.
Z        Zip rot_pts and pts together.
`...`M   Map the following function over the zipped points to get our determinants.
  i        Flatten the list of [a+b*i, c+d*i].
  á        Push the complex conjugate of a+bi, i.e. a-b*i.
  *        Multiply a-b*i by c+d*i, getting (a*c+b*d)+(a*d-b*c)*i.
           Our determinant is the imaginary part of this result.
  ╫@X      Push Re(z), Im(z) to the stack, and immediately discard Re(z).
           This map returns a list of these determinants.
;        Duplicate list_determinants.
Σ3*)     Push 3 * sum(list_determinants) and rotate that to BOS.
♀*Σ      Pairwise multiply the sums of pairs of points and the determinants and sum.
/        Divide that sum by 3*sum(list_determinants).
         Implicit return.

1

C ++ 14, 241 바이트

struct P{float x;float y;};
#define S(N,T)auto N(P){return 0;}auto N(P a,P b,auto...V){return(T)*(a.x*b.y-b.x*a.y)+N(b,V...);}
S(A,1)S(X,a.x+b.x)S(Y,a.y+b.y)auto f(auto q,auto...p){auto a=A(q,p...,q)*3;return P{X(q,p...,q)/a,Y(q,p...,q)/a};}

출력은 도우미 구조체입니다 P.

언 골프 드 :

 //helper struct
struct P{float x;float y;};

//Area, Cx and Cy are quite similar
#define S(N,T)\  //N is the function name, T is the term in the sum
auto N(P){return 0;} \   //end of recursion for only 1 element
auto N(P a,P b,auto...V){ \ //extract the first two elements
  return (T)*(a.x*b.y-b.x*a.y) //compute with a and b
         + N(b,V...); \        //recursion without first element
}

//instantiate the 3 formulas
S(A,1)
S(X,a.x+b.x)
S(Y,a.y+b.y)


auto f(auto q,auto...p){
  auto a=A(q,p...,q)*3; //q,p...,q appends the first element to the end
  return P{X(q,p...,q)/a,Y(q,p...,q)/a};
}

용법:

f(P{0.,0.}, P{1.,0.}, P{1.,1.}, P{0.,1.})
f(P{-15.21,0.8}, P{10.1,-0.3}, P{-0.07,23.55})

1

Clojure에서, 177 156 143 바이트

업데이트 : 콜백 대신 [a b c d 1]함수로 사용 하고 인수는이 벡터에 대한 인덱스 목록입니다. 1계산할 때 센티넬 값으로 사용A .

업데이트 2 : 입력 벡터를 1 씩 오프셋하는 데 사용하여 A에서 사전 계산하지 않습니다 .let(rest(cycle %))

#(let[F(fn[I](apply +(map(fn[[a b][c d]](*(apply +(map[a b c d 1]I))(-(* a d)(* c b))))%(rest(cycle %)))))](for[i[[0 2][1 3]]](/(F i)(F[4])3)))

원본 버전 :

#(let[F(fn[L](apply +(map(fn[[a b][c d]](*(L[a b c d])(-(* a d)(* c b))))%(conj(subvec % 1)(% 0)))))A(*(F(fn[& l]1))3)](map F[(fn[v](/(+(v 0)(v 2))A))(fn[v](/(+(v 1)(v 3))A))]))

덜 골프 단계에서 :

(def f (fn[v](let[F (fn[l](apply +(map
                                    (fn[[a b][c d]](*(l a b c d)(-(* a d)(* c b))))
                                    v
                                    (conj(subvec v 1)(v 0)))))
                  A (* (F(fn[& l] 1)) 3)]
                [(F (fn[a b c d](/(+ a c)A)))
                 (F (fn[a b c d](/(+ b d)A)))])))

F모든 콜백으로 합계를 구현 하는 도우미 함수 를 만듭니다 l. 위해 A지속적으로 콜백 반환 1X 및 Y 좌표 반면 자신의 기능을 가지고 있습니다. (conj(subvec v 1)(v 0))첫 번째 요소를 삭제하고 끝에 추가합니다. 이렇게하면 쉽게 추적 x_i하고x_(i+1) . 어쩌면 특히 마지막에 제거해야 할 반복이있을 수 있습니다 (map F[....

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.