Mathematica, 193 183 177 173 169 166 bytes
Yay, matemáticas! Estoy trazando la región que satisface un cierto conjunto (bastante complicado) de desigualdades:
e=RegionPlot[(1<Abs@y<3||c)&&{x,y+12}.(d=2{-5Sin@40°-6,m=5Cos@40°})*{x+15,y+1-2Sign@y}.d<0||c&&x<2m/.c->100<x^2+y^2<144,{x,-15,9},{y,-12,12},Frame->0>1,ImageSize->#]&
El uso es e[height]
, por ejemplo e[100]
:
O e[200]
:
Puede notar que los bordes más afilados están ligeramente redondeados. Esto se debe a que la región solo se puede trazar muestreando los puntos en el espacio, y Mathematica no muestrea cada píxel de forma predeterminada. La resolución de muestreo se puede aumentar agregando otra opción PlotPoints->#
(que usa una muestra por píxel), que agrega 14 caracteres . No recomiendo ejecutarlo con esa opción, ya que aumenta significativamente el tiempo de ejecución y apenas aumenta el atractivo visual más allá #/4
. Por lo tanto, (después de la aprobación del OP) no se incluye en el puntaje.
Aquí hay una versión ungolfed:
e[height_] := (
angle = 40°;
d = {-5 Sin[angle] - 6, 5 Cos[angle]};
RegionPlot[
(Abs[y] > .5 && Abs[y] < 1.5
||
r > 25 && r < 36)
&&
{x, y + 6}.d > 0
&&
{x + 7.5, y + .5 - Sign[y]}.d < 0
||
r > 25 && r < 36 && x < 5 Cos[angle]
/. r -> x^2 + y^2
,
{x, -7.5, 4.5},
{y, -6, 6},
Frame -> False,
ImageSize -> height
]
);
Tenga en cuenta que en la versión de golf, he escalado el sistema de coordenadas en un factor de 2 para evitar la .5
s, pero resulta que el recuento de caracteres es realmente idéntico.
Aquí hay una explicación de cómo calculé la fórmula. Dividí la forma en dos regiones. Uno contiene el anillo y las rayas y se corta a la derecha con la BCDE
pendiente y a la izquierda con las pendientes IJ
y GH
(más sobre eso más adelante). El otro contiene el mismo anillo, pero simplemente está cortado en la coordenada x del punto D
. Las condiciones para las dos regiones se combinan con ||
, lo que actúa como una unión establecida aquí.
El anillo se define simplemente como 5 < r < 6
, donde r
está la distancia desde el origen. r²
Sin embargo x²+y²
, es más fácil de resolver ( ), así que estoy usando 25 < x² + y² < 36
para obtener todos los puntos en el ring.
Las rayas están entre ±.5
y ±1.5
. Podemos manejar ambas franjas al mismo tiempo, tomando el módulo de y , por lo que las franjas (de longitud infinita) simplemente se cumplen .5 < |y| < 1.5
. Nuevamente, para tomar la unión de las rayas y el anillo, solo estoy usando ||
.
Sin embargo, lo interesante es probablemente cómo obtener las "máscaras". El punto D
tiene una coordenada x de 5 cos 40°
, por lo que la máscara que cuida el borde inferior (combinada solo con el anillo) es justa x < 5 cos 40°
. Esto se puede aplicar a través de la intersección establecida que se traduce &&
en lógica.
Las otras máscaras son la parte realmente complicada. Primero, obtengamos la pendiente de BCDE
. Podemos construir fácilmente puntos C
y D
, como (0, -6)
y 5 (cos 40°, sin 40°)
, respectivamente. El vector que apunta a lo largo de la línea es justo D - C = (5 cos 40°, 5 sin 40° + 6)
. Para aplicar la máscara a la derecha, solo necesito averiguar si un punto se encuentra a la izquierda o a la derecha de esa línea (llamemos al vector de línea p
). Puedo resolver esto tomando el vector desde C
mi punto de interés y proyectándolo en un vector perpendicular a p
. El signo de la proyección me dirá de qué lado está el punto. Obtener el vector perpendicular es bastante simple en 2D: voltea las coordenadas e invierte el signo de una de ellas. Esa es la variable d
en mi código:(-5 sin 40° - 6, 5 cos 40°)
. El vector desde C
un punto de interés q = (x, y)
es q - C = (x, y + 6)
. La proyección es solo el producto escalar (o producto de puntos) entre q
y d
. La forma en que lo elegí d
apunta a la izquierda, así que quiero d.(q-C) > 0
. Esta condición aplica la máscara de la mano derecha.
Para la máscara de la izquierda puedo usar básicamente la misma idea. La pendiente es la misma y, por lo tanto, también lo es d
. Solo necesito compensar mi punto desde las esquinas inferiores a la izquierda de las rayas en lugar de desde C
. Esos tienen coordenadas (-7.5, 0.5)
(franja superior) y (-7.5, -1.5)
(franja inferior). Entonces eso requeriría dos reglas independientes para las dos franjas. Sin embargo, tenga en cuenta que todos los puntos afectados por la máscara inferior están en la franja inferior y, por lo tanto, tienen una y negativa . Y todos los puntos afectados por la máscara superior tienen y positivo . Entonces, simplemente puedo cambiar mi desplazamiento usando Sign[y]
cuál es 1
para positivo y -1
para negativo y
. Entonces mi punto de compensación se convierte en(-7.5, -0.5 + Sign[y])
. De lo contrario, la máscara funciona igual que la máscara de la derecha. Por supuesto, esta vez la proyección debe ser negativa. Entonces, ingenuamente sería algo así RH-projection > 0 && LH-projection < 0
(que también es lo que originalmente tenía en el código). Pero podemos acortar esto, porque multiplicar un número positivo y uno negativo tiene que dar un número negativo, por lo que es justo RH * LH < 0
(dónde RH
y LH
son las proyecciones respectivas).
Eso es. Poner todo junto lleva a la siguiente estructura lógica:
(
(is_in_circle || is_in_stripe)
&&
is_between_left_and_right_mask
)
||
(
is_in_circle && left_of_edge
)
Para ser claros, las coordenadas en mi explicación se refieren al diagrama de construcción dado en el desafío. Como se mencionó anteriormente, mi código en realidad los multiplica a todos por 2
: lo cambié para guardar bytes, pero el recuento de bytes es idéntico y no me molesté en revertir el cambio nuevamente. También los enteros se ven mejor.