{-# Language
TypeFamilies
#-}moduleData.Geometry.LinewhereimportPreludehiding(length)importData.Geometry.PointimportData.Geometry.GeometryimportqualifiedData.ListasL----------------------------------------------------------------------- | A simple line segment in 2D consisint of a start and an end-pointdataLineSegment2'a=LineSegment2{startPoint::Point2'a,endPoint::Point2'a}deriving(Eq,Ord,Show,Read)instanceFunctorLineSegment2'wherefmapf(LineSegment2pq)=LineSegment2(fmapfp)(fmapfq)instanceIsPoint2FunctorLineSegment2'wherep2fmapf(LineSegment2pq)=LineSegment2(fp)(fq)instanceHasPointsLineSegment2'wherepoints(LineSegment2pq)=[p,q]----------------------------------------------------------------------- | An infinite linenewtypeLine2'a=Line2(LineSegment2'a)deriving(Eq,Ord,Show,Read)instanceFunctorLine2'wherefmapf(Line2l)=Line2$fmapflinstanceIsPoint2FunctorLine2'wherep2fmapf(Line2l)=Line2$p2fmapflinstanceHasPointsLine2'wherepoints(Line2l)=pointsl----------------------------------------------------------------------- | PolylinesnewtypePolyline2'a=Polyline2[LineSegment2'a]deriving(Eq,Show,Read)instanceIsPoint2FunctorPolyline2'wherep2fmapf(Polyline2ls)=Polyline2(map(p2fmapf)ls)instanceHasPointsPolyline2'wherepoints(Polyline2ls)=caselsof[]->[](l:ls')->pointsl++mapendPointls'----------------------------------------------------------------------- | Constructing polylinespolyLine::[Point2'a]->Polyline2'apolyLine=Polyline2.makeLineswheremakeLines::[Point2'a]->[LineSegment2'a]makeLines[]=error"Polyline consists of at least two points. No points given."makeLines[_]=error"Polyline consists of at least two points. Only one point given."makeLinespts=zipWithLineSegment2pts(tailpts)----------------------------------------------------------------------- | functions on Linesegments and PolylinesisSimpleLine::Polyline2'a->BoolisSimpleLine(Polyline2[])=error"polyline without line segments"isSimpleLine(Polyline2[_])=TrueisSimpleLine_=FalsetoSimpleLine::Polyline2'a->LineSegment2'atoSimpleLine(Polyline2ls)=headlstoSimpleLineOption::Polyline2'a->Maybe(LineSegment2'a)toSimpleLineOptionp=ifisSimpleLinepthenJust(toSimpleLinep)elseNothing----------------------------------------------------------------------- | Linear interpolation / points on line segments etc.-- | simple linear interpolation, assuming t in [0,1]linear::Numa=>a->a->a->alineartxy=(1-t)*x+t*yinRange::Orda=>a->(a,a)->Boolx`inRange`(a,b)=a<=x&&x<=bonLineSegment::(Orda,Fractionala)=>Point2'a->LineSegment2'a->Boolp`onLineSegment`l@(LineSegment2st)=ift==sthenp==selse(lambda`inRange`(0,1)&&p==pointAtlambdal)wherea=p|-|s-- the vector from s to pb=t|-|s-- the vector from s to tlambda=(a|@|b)/(lenb)-- we translate such that s corresponds with the origin. In this coord system-- b represents the input line segment.-- We orthoganally project a onto b. Let c be this point (on the vector b)-- then : d = a |@| b / length b denotes the distance between (0,0) and c-- We can now get the lambda such that : c = linear (0,0) b by dividing-- d / length b. Hence in total we divide through (length b)^2. This means-- we can avoid computing the square root.len(Point2(x,y))=x^2+y^2classHasLengthcwheretypePMc-- the precision model-- | The length of the line-like segmentlength::c->PMcinstanceFloatinga=>HasLength(LineSegment2'a)wheretypePM(LineSegment2'a)=alength(LineSegment2st)=diststinstanceFloatinga=>HasLength(Polyline2'a)wheretypePM(Polyline2'a)=alength(Polyline2ls)=sum.maplength$lsclassLineLikecwhere-- | get the point at `time' t (t in [0,1])pointAt::Numa=>a->ca->Point2'ainstanceLineLikeLineSegment2'wherepointAtt(LineSegment2(Point2(px,py))(Point2(qx,qy)))=Point2(lineartpxqx,lineartpyqy)