Merge pull request #269 from FlyingGaz/issue268

Support XY-scaling on linear_extrude (resolves #268)
This commit is contained in:
Julia Longtin 2020-06-12 19:45:41 +01:00 committed by GitHub
commit 9ac59e955e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 64 additions and 36 deletions

View File

@ -33,7 +33,7 @@ import Graphics.Implicit.Primitives as P (translate, scale, complement, union, i
import Graphics.Implicit.ExtOpenScad as E (runOpenscad)
-- typesclasses and types defining the world, or part of the world.
import Graphics.Implicit.Definitions as W (, SymbolicObj2, SymbolicObj3)
import Graphics.Implicit.Definitions as W (, SymbolicObj2, SymbolicObj3, ExtrudeRMScale(C1, C2, Fn))
-- Functions for writing files based on the result of operations on primitives.
import qualified Graphics.Implicit.Export as Export (writeSVG, writeDXF2, writeSTL, writeBinSTL, writeOBJ, writeSCAD2, writeSCAD3, writeTHREEJS, writeGCodeHacklabLaser, writePNG)

View File

@ -70,13 +70,16 @@ module Graphics.Implicit.Definitions (
ExtrudeRM,
ExtrudeOnEdgeOf,
RotateExtrude),
ExtrudeRMScale(C1, C2, Fn),
fromto,
fromFastto,
fromtoFloat
fromtoFloat,
toScaleFn,
isScaleID,
)
where
import Prelude (Show, Double, Either, show, (*), (/), fromIntegral, Float, realToFrac)
import Prelude (Show, Double, Either(Left, Right), Bool(True, False), show, (*), (/), fromIntegral, Float, realToFrac)
import Data.Maybe (Maybe)
@ -142,6 +145,9 @@ instance Show ( -> ) where
instance Show ( -> 2) where
show _ = "<expand -> 2>"
instance Show ( -> Either 2) where
show _ = "<function -> Either 2>"
instance Show (2 -> ) where
show _ = "<collapse 2 -> >"
@ -276,7 +282,7 @@ data SymbolicObj3 =
| ExtrudeRM
-- rounding radius
(Either ( -> )) -- twist
(Either ( -> )) -- scale
ExtrudeRMScale -- scale
(Either 2 ( -> 2)) -- translate
SymbolicObj2 -- object to extrude
(Either (2 -> )) -- height to extrude to
@ -289,3 +295,20 @@ data SymbolicObj3 =
| ExtrudeOnEdgeOf SymbolicObj2 SymbolicObj2
deriving Show
data ExtrudeRMScale =
C1 -- constant
| C2 2 -- constant 2
| Fn ( -> Either 2) -- function mapping height to either or 2
deriving Show
toScaleFn :: ExtrudeRMScale -> -> 2
toScaleFn (C1 s) _ = (s, s)
toScaleFn (C2 s) _ = s
toScaleFn (Fn f) z = case f z of
Left s -> (s, s)
Right s -> s
isScaleID :: ExtrudeRMScale -> Bool
isScaleID (C1 1) = True
isScaleID (C2 (1, 1)) = True
isScaleID _ = False

View File

@ -10,7 +10,7 @@ module Graphics.Implicit.Export.SymbolicFormats (scad2, scad3) where
import Prelude(Either(Left, Right), ($), (*), ($!), (-), (/), pi, error, (+), (==), take, floor, (&&), const, pure, (<>), sequenceA, (<$>))
import Graphics.Implicit.Definitions(, SymbolicObj2(RectR, Circle, PolygonR, Complement2, UnionR2, DifferenceR2, IntersectR2, Translate2, Scale2, Rotate2, Outset2, Shell2, EmbedBoxedObj2), SymbolicObj3(Rect3R, Sphere, Cylinder, Complement3, UnionR3, IntersectR3, DifferenceR3, Translate3, Scale3, Rotate3, Rotate3V, Outset3, Shell3, ExtrudeR, ExtrudeRotateR, ExtrudeRM, EmbedBoxedObj3, RotateExtrude, ExtrudeOnEdgeOf))
import Graphics.Implicit.Definitions(, SymbolicObj2(RectR, Circle, PolygonR, Complement2, UnionR2, DifferenceR2, IntersectR2, Translate2, Scale2, Rotate2, Outset2, Shell2, EmbedBoxedObj2), SymbolicObj3(Rect3R, Sphere, Cylinder, Complement3, UnionR3, IntersectR3, DifferenceR3, Translate3, Scale3, Rotate3, Rotate3V, Outset3, Shell3, ExtrudeR, ExtrudeRotateR, ExtrudeRM, EmbedBoxedObj3, RotateExtrude, ExtrudeOnEdgeOf), isScaleID)
import Graphics.Implicit.Export.TextBuilderUtils(Text, Builder, toLazyText, fromLazyText, bf)
import Control.Monad.Reader (Reader, runReader, ask)
@ -91,7 +91,7 @@ buildS3 (ExtrudeR r obj h) | r == 0 = callNaked "linear_extrude" ["height = " <>
buildS3 (ExtrudeRotateR r twist obj h) | r == 0 = callNaked "linear_extrude" ["height = " <> bf h, "twist = " <> bf twist] [buildS2 obj]
-- FIXME: handle scale, center.
buildS3 (ExtrudeRM r twist (Left scale) (Left translate) obj (Left height)) | r == 0 && scale == 1 && translate == (0,0) = do
buildS3 (ExtrudeRM r twist scale (Left translate) obj (Left height)) | r == 0 && isScaleID scale && translate == (0,0) = do
res <- ask
let
twist' = case twist of

View File

@ -17,7 +17,7 @@ module Graphics.Implicit.ExtOpenScad.Primitives (primitiveModules) where
import Prelude(Either(Left, Right), Bool(True, False), Maybe(Just, Nothing), ($), pure, either, id, (-), (==), (&&), (<), (*), cos, sin, pi, (/), (>), const, uncurry, fromInteger, round, (/=), (||), not, null, fmap, (<>), otherwise)
import Graphics.Implicit.Definitions (, 2, 3, , SymbolicObj2, SymbolicObj3, fromto)
import Graphics.Implicit.Definitions (, 2, 3, , SymbolicObj2, SymbolicObj3, ExtrudeRMScale(C1), fromto, isScaleID)
import Graphics.Implicit.ExtOpenScad.Definitions (OVal (OObj2, OObj3, ONModule), ArgParser, Symbol(Symbol), StateC, SourcePosition)
@ -428,7 +428,7 @@ extrude = moduleWithSuite "linear_extrude" $ \_ children -> do
`doc` "center? (the z component)"
twistArg :: Either ( -> ) <- argument "twist" `defaultTo` Left 0
`doc` "twist as we extrude, either a total amount to twist or a function..."
scaleArg :: Either ( -> ) <- argument "scale" `defaultTo` Left 1
scaleArg :: ExtrudeRMScale <- argument "scale" `defaultTo` C1 1
`doc` "scale according to this funciton as we extrude..."
translateArg :: Either 2 ( -> 2) <- argument "translate" `defaultTo` Left (0,0)
`doc` "translate according to this funciton as we extrude..."
@ -450,15 +450,12 @@ extrude = moduleWithSuite "linear_extrude" $ \_ children -> do
isTwistID = case twistArg of
Left constant -> constant == 0
Right _ -> False
isScaleID = case scaleArg of
Left constant -> constant == 1
Right _ -> False
isTransID = case translateArg of
Left constant -> constant == (0,0)
Right _ -> False
pure $ pure $ obj2UpMap (
\obj -> case height of
Left constHeight | isTwistID && isScaleID && isTransID ->
Left constHeight | isTwistID && isScaleID scaleArg && isTransID ->
shiftAsNeeded $ Prim.extrudeR r obj constHeight
_ ->
shiftAsNeeded $ Prim.extrudeRM r twistArg scaleArg translateArg obj height'

View File

@ -16,7 +16,7 @@ module Graphics.Implicit.ExtOpenScad.Util.OVal(OTypeMirror, (<||>), fromOObj, to
import Prelude(Maybe(Just, Nothing), Bool(True, False), Either(Left,Right), (==), fromInteger, floor, ($), (.), fmap, error, (<>), show, flip, filter, not, return)
import Graphics.Implicit.Definitions(, , SymbolicObj2, SymbolicObj3, fromto)
import Graphics.Implicit.Definitions(, 2, , SymbolicObj2, SymbolicObj3, ExtrudeRMScale(C1, C2, Fn), fromto)
import Graphics.Implicit.ExtOpenScad.Definitions (OVal(ONum, OBool, OString, OList, OFunc, OUndefined, OUModule, ONModule, OVargsModule, OError, OObj2, OObj3))
@ -118,6 +118,16 @@ instance (OTypeMirror a, OTypeMirror b) => OTypeMirror (Either a b) where
toOObj (Right x) = toOObj x
toOObj (Left x) = toOObj x
instance OTypeMirror ExtrudeRMScale where
fromOObj (fromOObj -> Just (x :: )) = Just $ C1 x
fromOObj (fromOObj -> Just (x :: 2)) = Just $ C2 x
fromOObj (fromOObj -> Just (x :: ( -> Either 2))) = Just $ Fn x
fromOObj _ = Nothing
toOObj (C1 x) = toOObj x
toOObj (C2 x) = toOObj x
toOObj (Fn x) = toOObj x
-- A string representing each type.
oTypeStr :: OVal -> Text
oTypeStr OUndefined = "Undefined"

View File

@ -5,9 +5,9 @@
module Graphics.Implicit.ObjectUtil.GetBox3 (getBox3) where
import Prelude(Eq, Bool(False), Fractional, Either (Left, Right), (==), (||), max, (/), (-), (+), fmap, unzip, ($), filter, not, (.), unzip3, minimum, maximum, min, (>), (&&), head, (*), (<), abs, either, error, const, otherwise, take, fst, snd)
import Prelude(Eq, Bool(False), Fractional, Either (Left, Right), (==), (||), max, (/), (-), (+), fmap, unzip, ($), (<$>), filter, not, (.), unzip3, minimum, maximum, min, (>), (&&), head, (*), (<), abs, either, error, const, otherwise, take, fst, snd)
import Graphics.Implicit.Definitions (, Fast, Box3, SymbolicObj3 (Rect3R, Sphere, Cylinder, Complement3, UnionR3, IntersectR3, DifferenceR3, Translate3, Scale3, Rotate3, Rotate3V, Shell3, Outset3, EmbedBoxedObj3, ExtrudeR, ExtrudeOnEdgeOf, ExtrudeRM, RotateExtrude, ExtrudeRotateR), SymbolicObj2 (Rotate2, RectR), (*), fromFastto, fromFast)
import Graphics.Implicit.Definitions (, Fast, Box3, SymbolicObj3 (Rect3R, Sphere, Cylinder, Complement3, UnionR3, IntersectR3, DifferenceR3, Translate3, Scale3, Rotate3, Rotate3V, Shell3, Outset3, EmbedBoxedObj3, ExtrudeR, ExtrudeOnEdgeOf, ExtrudeRM, RotateExtrude, ExtrudeRotateR), SymbolicObj2 (Rotate2, RectR), ExtrudeRMScale(C1, C2), (*), fromFastto, fromFast, toScaleFn)
import Graphics.Implicit.ObjectUtil.GetBox2 (getBox2, getBox2R)
@ -141,17 +141,18 @@ getBox3 (ExtrudeRM _ twist scale translate symbObj height) =
(twistXmin, twistYmin, twistXmax, twistYmax) =
let
scale' = case scale of
Left sval -> sval
Right sfun -> maximum $ fmap (abs . sfun) hrange
smin v = min v (scale' * v)
smax v = max v (scale' * v)
both f (a, b) = (f a, f b)
(scalex', scaley') = case scale of
C1 s -> (s, s)
C2 s -> s
s -> both maximum . unzip $ both abs . toScaleFn s <$> hrange
smin s v = min v (s * v)
smax s v = max v (s * v)
-- FIXME: assumes minimums are negative, and maximums are positive.
scaleVal d = scale' * d
scaleEach ((d1, d2),(d3, d4)) = (scaleVal d1, scaleVal d2, scaleVal d3, scaleVal d4)
scaleEach ((d1, d2),(d3, d4)) = (scalex' * d1, scaley' * d2, scalex' * d3, scaley' * d4)
in case twist of
Left twval -> if twval == 0
then (smin x1, smin y1, smax x2, smax y2)
then (smin scalex' x1, smin scaley' y1, smax scalex' x2, smax scaley' y2)
else scaleEach $ getBox2R symbObj twval
Right _ -> scaleEach $ getBox2R symbObj 360 -- we can't range functions yet, so assume a full circle.

View File

@ -10,7 +10,7 @@ import Prelude (Either(Left, Right), abs, (-), (/), (*), sqrt, (+), atan2, max,
import Graphics.Implicit.Definitions (, , 2, 3, (/), Obj3,
SymbolicObj3(Shell3, UnionR3, IntersectR3, DifferenceR3, Translate3, Scale3, Rotate3,
Outset3, Rect3R, Sphere, Cylinder, Complement3, EmbedBoxedObj3, Rotate3V,
ExtrudeR, ExtrudeRM, ExtrudeOnEdgeOf, RotateExtrude, ExtrudeRotateR), fromto, (), min)
ExtrudeR, ExtrudeRM, ExtrudeOnEdgeOf, RotateExtrude, ExtrudeRotateR), fromto, toScaleFn, (), min)
import Graphics.Implicit.MathUtil (rmaximum, rminimum, rmax)
@ -139,13 +139,9 @@ getImplicit3 (ExtrudeRM r twist scale translate symbObj height) =
(xTrans, yTrans) = case trans of
Left tval -> tval
Right tfun -> tfun z
scaleVec :: Either ( -> ) -> -> 2 -> 2
scaleVec scale' s (x,y) =
case scale' of
Left sval -> if sval == 1
then (x,y)
else (x/sval , y/sval)
Right sfun -> (x/sfun s, y/sfun s)
scaleVec :: -> 2 -> 2
scaleVec z (x, y) = let (sx, sy) = toScaleFn scale z
in (x / sx, y / sy)
rotateVec :: -> 2 -> 2
rotateVec θ (x,y)
| θ == 0 = (x,y)
@ -159,7 +155,7 @@ getImplicit3 (ExtrudeRM r twist scale translate symbObj height) =
res = rmax r
(obj
. rotateVec (-k*twistVal twist z h)
. scaleVec scale z
. scaleVec z
. translatePos translate z
$ (x,y))
(abs (z - h/2) - h/2)

View File

@ -74,7 +74,8 @@ import Graphics.Implicit.Definitions (, 2, 3, Box2,
ExtrudeRM,
RotateExtrude,
ExtrudeOnEdgeOf
)
),
ExtrudeRMScale
)
import Graphics.Implicit.MathUtil (pack)
import Graphics.Implicit.ObjectUtil (getBox2, getBox3, getImplicit2, getImplicit3)
@ -245,7 +246,7 @@ extrudeRotateR = ExtrudeRotateR
extrudeRM ::
-> Either ( -> )
-> Either ( -> )
-> ExtrudeRMScale
-> Either 2 ( -> 2)
-> SymbolicObj2
-> Either (2 -> )

View File

@ -12,7 +12,7 @@ import Prelude (($), (*), (/), String, IO, cos, pi, fmap, zip3, Either(Left, Rig
import Criterion.Main (Benchmark, bgroup, bench, nf, nfAppIO, defaultMain)
-- The parts of ImplicitCAD we know how to benchmark.
import Graphics.Implicit (union, circle, sphere, SymbolicObj2, SymbolicObj3, writeDXF2, writeSVG, writePNG2, writeSTL, writeBinSTL, unionR, translate, difference, extrudeRM, rect3R)
import Graphics.Implicit (union, circle, sphere, SymbolicObj2, SymbolicObj3, ExtrudeRMScale(C1), writeDXF2, writeSVG, writePNG2, writeSTL, writeBinSTL, unionR, translate, difference, extrudeRM, rect3R)
import Graphics.Implicit.Export.SymbolicObj2 (symbolicGetContour)
import Graphics.Implicit.Export.SymbolicObj3 (symbolicGetMesh)
@ -36,7 +36,7 @@ obj2d_1 =
-- | An extruded version of obj2d_1, should be identical to the website's example, and example5.escad.
object1 :: SymbolicObj3
object1 = extrudeRM 0 (Right twist) (Left 1) (Left (0,0)) obj2d_1 (Left 40)
object1 = extrudeRM 0 (Right twist) (C1 1) (Left (0,0)) obj2d_1 (Left 40)
where
twist :: ->
twist h = 35*cos(h*2*pi/60)