0votos

calculo de la altura que alcanza un liquido en un recipiente,python en Haskell

por josejuan hace 4 años

Se calcula de forma abstracta para cualquier tipo de geometría (y en particular cualquier número de dimensiones) y cualquier tipo de representación de sólidos (poliedros, CSG, etc...).

Altura que alcanza el agua en una vasija al 80% de volumen con distintas formas(esferica,piramidal,etc) en estado de reposo, en python o sage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
{-# LANGUAGE MultiParamTypeClasses, BangPatterns #-} 
import Data.List 
{- 
 
    Una forma muy sencilla (y elegante creo yo) de calcular la integral de un 
    volumen arbitrario es calcular un recubrimiento topológico del sólido. 
    Para ello, es suficiente con disponer de la función 
 
        IntersectionType SolidCoverIntersection( solid, cover ) 
 
            IntersectionType := Inside | Outside | Intersect 
 
    Donde `solid` es el sólido del que se quiere calcular el volumen y `cover` 
    es un recubrimiento en la topología. 
 
    No es necesario ningún otro conocimiento sobre la geometría del sólido a 
    integrar ni del propio sólido, por lo que es independiente de la geometría 
    y de la representación del sólido. 
 
    En particular, dicho procedimiento servirá para cualquier tipo de volumen 
    (ej. poligonal estilo Autodesk Maya o CSG estilo POV-Ray) y para cualquier 
    número de dimensiones. 
 
    En cuanto al problema concreto de obtener la altura, es trivial una vez se 
    tiene el recubrimiento, porque se puede calcular, también de forma abstracta 
    (sin conocer la geometría de base) con una simple búsqueda dicotómica. 
 
    Por simplicidad el cálculo del error cometido se hará considerando el tamaño 
    mínimo del recubrimiento (así, si el sólido tiene mayor superfície, el error 
    será mayor que si tiene menor superfície); es decir, no obtenemos una acotación 
    directa del error cometido. 
 
-} 
 
-- Cubiertas topológicas (pero orientadas a geometrías analíticas) 
class Cover a where 
    subdivide :: a -> [a] 
    volume    :: a -> Float 
    split     :: Float -> a -> (a, a) -- no es muy general, divide el espacio en dos sobre algún eje, es para búsqueda dicotómica 
 
data IntersectionType = Inside | Outside | Intersect deriving Show 
 
-- Podremos analizar cualquier cosa que intersecte con las anteriores cubiertas topológicas 
class Cover a => Intersectable a b where 
    intersection :: a -> b -> IntersectionType 
 
-- El algoritmo para calcular el recubrimiento topológico de un sólido sería 
cover :: (Cover a, Intersectable a b) => Float -> b -> [a] -> [a] 
cover e s = foldr check [] 
    where check c rs = if volume c <= e 
                         then rs 
                         else case intersection c s of 
                              Outside   -> rs 
                              Inside    -> c : rs 
                              Intersect -> foldr check [] (subdivide c) ++ rs 
 
-- Y ya está el cálculo de cubiertas (volúmenes). 
 
 
 
 
 
 
solidVolume :: (Cover a, Intersectable a b) => Float -> b -> [a] -> Float 
solidVolume e s = sum . map volume . cover e s 
 
-- Búsqueda de la altura tal que el volumen del sólido es X% del total (devuelve el % de altura) 
level :: (Cover a, Intersectable a b) => Float -> Float -> b -> a -> Float 
level x e s c = let v h = solidVolume e s [snd $ split h c] 
                    vt = v 1                    -- volumen total 
                    vx = x * vt                 -- volumen objetivo 
                    search a b va vb = 
                        let c = (a + b) / 2 
                            vc = v c 
                        in  if vc < vx - e / 2 then search c b vc vb 
                                               else if vx + e / 2 < vc then search a c va vc 
                                                                       else c 
                in  search 0 1 0 vt 
 
-- Y ya está solucionado el problema planteado para cualquier tipo de geometría (nº de dimensiones, etc...). 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-- Por ejemplo, supongamos las cajas como abiertos del espacio euclídeo 
type P2 = (Float, Float) 
data Box = Box !P2 !P2 deriving Show 
instance Cover Box where 
    subdivide (Box (a, b) (c, d)) = let ac = (a + c) / 2 
                                        bd = (b + d) / 2 
                                    in  [ Box (a, b ) (ac, bd), Box (ac,  b) (c, bd) 
                                        , Box (a, bd) (ac,  d), Box (ac, bd) (c,  d) ] 
    volume (Box (a, b) (c, d)) = (c - a) * (b - d) 
    split h (Box (a, b) (c, d)) = let bd = d + (b - d) * h 
                                  in  (Box (a, b) (c, bd), Box (a, bd) (c, d)) 
 
-- Y como sólido los discos cerrados centrados en el orígen con radio R 
data Disk = Disk Float 
instance Intersectable Box Disk where 
    intersection (Box (a, b) (c, d)) (Disk r) = 
        let inout = nub $ sort $ map (\(x, y) -> sqrt (x * x + y * y) >= r) [(a, b), (c, b), (a, d), (c, d)] 
        in  case inout of 
            [False] -> Inside 
            [True]  -> if (a < 0 && 0 < c && (d < r && b > -r)) || (d < 0 && 0 < b && (a < r && c > -r)) 
                            then Intersect 
                            else Outside 
            _       -> Intersect 
 
-- Por ejemplo, calcular el volumen del disco de radio unidad es 
aproximatePi = sum $ map volume $ cover 1e-8 (Disk 1) [Box (-1, 1) (1, -1)] 
 
-- Que lógicamente da un valor cercano a Pi de 3.1400304 
 
-- Si ahora queremos saber a que altura tenemos la cuarta parte de su volumen, es 
halfDisk = level 0.25 1e-8 (Disk 1) (Box (-1, 1) (1, -1)) 
 
-- Que nos da un valor aproximado de 0.2979973% es decir, una altura de 0.5959946 desde la base del disco. 
-- El ángulo del casquete es 2 * acos (1 - 0.5959946) = 2.31 y su volumen por tanto (2.31-sin 2.31)/2 = 0.7855 
-- que es precisamente la cuarta parte del volumen del disco unidad (Pi). 

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.