diff --git a/project/build.properties b/project/build.properties
index 10fd9ee..22af262 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=1.5.5
+sbt.version=1.7.1
diff --git a/src/main/scala/com/phasmidsoftware/kmldoc/KML.scala b/src/main/scala/com/phasmidsoftware/kmldoc/KML.scala
index bea0b34..5464fb3 100644
--- a/src/main/scala/com/phasmidsoftware/kmldoc/KML.scala
+++ b/src/main/scala/com/phasmidsoftware/kmldoc/KML.scala
@@ -34,7 +34,7 @@ case class KML_Binding(kml: KML, binding: NamespaceBinding)
* @param StyleMaps a sequence of StyleMap elements.
* @param Folders a sequence of Folder elements.
*/
-case class Document(name: Text, description: Text, Styles: Seq[Style], StyleMaps: Seq[StyleMap], Folders: Seq[Folder])
+case class Document(name: Text, maybeOpen: Option[Int], description: Text, Styles: Seq[Style], StyleMaps: Seq[StyleMap], Folders: Seq[Folder])
/**
* Case class to represent a Scale which is represented in XML as, for example: 1.1
@@ -48,6 +48,7 @@ case class Icon(href: Text)
case class HotSpot(_x: Int, _xunits: String, _y: Int, _yunits: String)
case class IconStyle(scale: Scale, Icon: Icon, hotSpot: HotSpot)
+//case class IconStyle(maybeScale: Option[Scale], Icon: Icon, hotSpot: HotSpot)
case class LabelStyle(scale: Scale)
@@ -117,6 +118,7 @@ object KmlExtractors extends Extractors {
implicit val extractorCoordinates: Extractor[Coordinates] = (node: Node) => Success(Coordinates.parse(node.text))
implicit val extractorScale: Extractor[Scale] = extractor10(Scale)
+ // implicit val extractMaybeScale: Extractor[Option[Scale]] = extractorOption
implicit val extractorIcon: Extractor[Icon] = extractor10(Icon)
implicit val extractorColor: Extractor[Color] = extractor10(Color)
implicit val extractorWidth: Extractor[Width] = extractor10(Width)
@@ -145,7 +147,8 @@ object KmlExtractors extends Extractors {
implicit val extractorMultiStyleMap: MultiExtractor[Seq[StyleMap]] = multiExtractor[StyleMap]
implicit val extractorMultiStyle: MultiExtractor[Seq[Style]] = multiExtractor[Style]
implicit val extractorMultiFolder: MultiExtractor[Seq[Folder]] = multiExtractor[Folder]
- implicit val extractorDocument: Extractor[Document] = extractor23(Document)
+ implicit val extractMaybeOpen: Extractor[Option[Int]] = extractorOption
+ implicit val extractorDocument: Extractor[Document] = extractor33(Document)
implicit val extractorMultiDocument: MultiExtractor[Seq[Document]] = multiExtractor[Document]
implicit val extractorKml: Extractor[KML] = extractor01(KML)
implicit val extractorMultiKml: MultiExtractor[Seq[KML]] = multiExtractor[KML]
@@ -172,6 +175,7 @@ trait KmlRenderers extends Renderers {
import Renderers._
implicit val rendererScale: Renderable[Scale] = renderer1(Scale)
+ // implicit val rendererOptionScale: Renderable[Option[Scale]] = optionRenderer
implicit val rendererIcon: Renderable[Icon] = renderer1(Icon)
implicit val rendererColor: Renderable[Color] = renderer1(Color)
implicit val rendererWidth: Renderable[Width] = renderer1(Width)
@@ -204,7 +208,8 @@ trait KmlRenderers extends Renderers {
implicit val rendererFolders: Renderable[Seq[Folder]] = sequenceRenderer[Folder]
implicit val rendererStyles: Renderable[Seq[Style]] = sequenceRenderer[Style]
implicit val rendererStyleMaps: Renderable[Seq[StyleMap]] = sequenceRenderer[StyleMap]
- implicit val rendererDocument: Renderable[Document] = renderer5(Document)
+ implicit val renderOptionOpen: Renderable[Option[Int]] = optionRenderer
+ implicit val rendererDocument: Renderable[Document] = renderer6(Document)
implicit val rendererDocuments: Renderable[Seq[Document]] = sequenceRenderer[Document]
implicit val rendererKml: Renderable[KML] = renderer1(KML)
implicit val rendererKml_Binding: Renderable[KML_Binding] = (t: KML_Binding, format: Format, stateR: StateR) =>
diff --git a/src/main/scala/com/phasmidsoftware/render/Renderers.scala b/src/main/scala/com/phasmidsoftware/render/Renderers.scala
index 5377cb3..04ef15a 100644
--- a/src/main/scala/com/phasmidsoftware/render/Renderers.scala
+++ b/src/main/scala/com/phasmidsoftware/render/Renderers.scala
@@ -115,6 +115,27 @@ trait Renderers {
doNestedRender(format, stateR, wInner, wOuter, r.productElementName(4))
}
+ /**
+ * Method to create a renderer fpr a Product (e.g., case class) with five members.
+ *
+ * @param construct a function which takes a P0, P1, P2, P3, P4 and yields an R (this is usually the apply method of a case class).
+ * @tparam P0 the (Renderable) type of the first member of Product type R.
+ * @tparam P1 the (Renderable) type of the second member of Product type R.
+ * @tparam P2 the (Renderable) type of the third member of Product type R.
+ * @tparam P3 the (Renderable) type of the fourth member of Product type R.
+ * @tparam P4 the (Renderable) type of the fifth member of Product type R.
+ * @tparam R the (Renderable) type of Renderable to be returned (must be a Product).
+ * @return a function which takes an R, a Format, and a StateR as parameters and yields a Renderable[R].
+ */
+ def renderer6[P0: Renderable, P1: Renderable, P2: Renderable, P3: Renderable, P4: Renderable, P5: Renderable, R <: Product : ClassTag](construct: (P0, P1, P2, P3, P4, P5) => R): Renderable[R] = (r: R, format: Format, stateR: StateR) => {
+ val objectOuter = r.productElement(5).asInstanceOf[P5]
+ val constructorInner: (P0, P1, P2, P3, P4) => R = construct(_, _, _, _, _, objectOuter)
+ val objectInner = constructorInner(r.productElement(0).asInstanceOf[P0], r.productElement(1).asInstanceOf[P1], r.productElement(2).asInstanceOf[P2], r.productElement(3).asInstanceOf[P3], r.productElement(4).asInstanceOf[P4])
+ val wInner = renderer5(constructorInner).render(objectInner, format.indent, stateR.recurse)
+ val wOuter = renderOuter(r, objectOuter, 4, format)
+ doNestedRender(format, stateR, wInner, wOuter, r.productElementName(4))
+ }
+
/**
* Method to yield a renderer of Option[R].
*
diff --git a/src/main/scala/com/phasmidsoftware/xml/Extractors.scala b/src/main/scala/com/phasmidsoftware/xml/Extractors.scala
index d4a8840..4a7c5f8 100644
--- a/src/main/scala/com/phasmidsoftware/xml/Extractors.scala
+++ b/src/main/scala/com/phasmidsoftware/xml/Extractors.scala
@@ -28,6 +28,19 @@ trait Extractors {
case Failure(x) => Failure(x) // TESTME
}
+ /**
+ * Method to yield an Extractor which can choose from alternate extractors.
+ *
+ * TESTME
+ *
+ * @tparam R result type.
+ * @tparam P0 first extractor type.
+ * @tparam P1 second extractor type.
+ * @return an Extractor[R].
+ */
+ def extractorAlt[R, P0 <: R : Extractor, P1 <: R : Extractor]: Extractor[R] =
+ (node: Node) => implicitly[Extractor[P0]].extract(node) orElse implicitly[Extractor[P1]].extract(node)
+
/**
* Extractor which will convert an Xml Node into a sequence of P objects where there is evidence of Extractor[P].
*
@@ -476,6 +489,130 @@ trait Extractors {
} yield t
case fs => Failure(XmlException(s"extractor5: insufficient field names: $fs"))
}
+
+ /**
+ * Extractor which will convert an Xml Node into an instance of a case class with six members.
+ *
+ * @param construct a function (P0,P1,P2,P3,P4,P5) => T, usually the apply method of a case class.
+ * @tparam P0 the (Extractor) type of the first member of the Product type T.
+ * @tparam P1 the (Extractor) type of the second member of the Product type T.
+ * @tparam P2 the (Extractor) type of the third member of the Product type T.
+ * @tparam P3 the (Extractor) type of the fourth member of the Product type T.
+ * @tparam P4 the (Extractor) type of the fifth member of the Product type T.
+ * @tparam P5 the (Extractor) type of the sixth member of the Product type T.
+ * @tparam T the underlying type of the result, a Product with five members.
+ * @return an Extractor[T] whose method extract will convert a Node into a T.
+ */
+ def extractor60[P0: Extractor, P1: Extractor, P2: Extractor, P3: Extractor, P4: Extractor, P5: Extractor, T <: Product : ClassTag](construct: (P0, P1, P2, P3, P4, P5) => T, fields: Seq[String] = Nil): Extractor[T] =
+ (node: Node) =>
+ fieldNames(fields) match {
+ case member0 :: fs =>
+ for {
+ p0 <- extractField[P0](member0)(node)
+ t <- extractor50[P1, P2, P3, P4, P5, T](construct(p0, _, _, _, _, _), fs).extract(node)
+ } yield t
+ case fs => Failure(XmlException(s"extractor5: insufficient field names: $fs")) // TESTME
+ }
+
+ /**
+ * Extractor which will convert an Xml Node into an instance of a case class with five members.
+ *
+ * TESTME
+ *
+ * @param construct a function (P0,P1,P2,P3,P4) => T, usually the apply method of a case class.
+ * @tparam PE0 the (Extractor) type of the first member of the Product type T.
+ * @tparam PE1 the (Extractor) type of the second member of the Product type T.
+ * @tparam PE2 the (Extractor) type of the third member of the Product type T.
+ * @tparam PE3 the (Extractor) type of the fourth member of the Product type T.
+ * @tparam PM0 the (MultiExtractor) type of the fourth member of the Product type T.
+ * @tparam PM1 the (MultiExtractor) type of the fifth member of the Product type T.
+ * @tparam T the underlying type of the result, a Product with five members.
+ * @return an Extractor[T] whose method extract will convert a Node into a T.
+ */
+ def extractor42[PE0: Extractor, PE1: Extractor, PE2: Extractor, PE3: Extractor, PM0: MultiExtractor, PM1: MultiExtractor, T <: Product : ClassTag](construct: (PE0, PE1, PE2, PE3, PM0, PM1) => T, fields: Seq[String] = Nil): Extractor[T] =
+ (node: Node) =>
+ fieldNames(fields) match {
+ case member0 :: fs =>
+ for {
+ p0 <- extractField[PE0](member0)(node)
+ t <- extractor32[PE1, PE2, PE3, PM0, PM1, T](construct(p0, _, _, _, _, _), fs).extract(node)
+ } yield t
+ case fs => Failure(XmlException(s"extractor5: insufficient field names: $fs"))
+ }
+
+ /**
+ * Extractor which will convert an Xml Node into an instance of a case class with five members.
+ *
+ * @param construct a function (P0,P1,P2,P3,P4) => T, usually the apply method of a case class.
+ * @tparam PE0 the (Extractor) type of the first member of the Product type T.
+ * @tparam PE1 the (Extractor) type of the second member of the Product type T.
+ * @tparam PE2 the (MultiExtractor) type of the third member of the Product type T.
+ * @tparam PM0 the (MultiExtractor) type of the fourth member of the Product type T.
+ * @tparam PM1 the (MultiExtractor) type of the fifth member of the Product type T.
+ * @tparam T the underlying type of the result, a Product with five members.
+ * @return an Extractor[T] whose method extract will convert a Node into a T.
+ */
+ def extractor33[PE0: Extractor, PE1: Extractor, PE2: Extractor, PM0: MultiExtractor, PM1: MultiExtractor, PM2: MultiExtractor, T <: Product : ClassTag](construct: (PE0, PE1, PE2, PM0, PM1, PM2) => T, fields: Seq[String] = Nil): Extractor[T] =
+ (node: Node) =>
+ fieldNames(fields) match {
+ case member0 :: fs =>
+ for {
+ p0 <- extractField[PE0](member0)(node)
+ t <- extractor23[PE1, PE2, PM0, PM1, PM2, T](construct(p0, _, _, _, _, _), fs).extract(node)
+ } yield t
+ case fs => Failure(XmlException(s"extractor5: insufficient field names: $fs")) // TESTME
+ }
+
+ /**
+ * Extractor which will convert an Xml Node into an instance of a case class with five members.
+ *
+ * TESTME
+ *
+ * @param construct a function (P0,P1,P2,P3,P4) => T, usually the apply method of a case class.
+ * @tparam PE0 the (Extractor) type of the first member of the Product type T.
+ * @tparam P1 the (MultiExtractor) type of the second member of the Product type T.
+ * @tparam P2 the (MultiExtractor) type of the third member of the Product type T.
+ * @tparam P3 the (MultiExtractor) type of the fourth member of the Product type T.
+ * @tparam P4 the (MultiExtractor) type of the fifth member of the Product type T.
+ * @tparam T the underlying type of the result, a Product with five members.
+ * @return an Extractor[T] whose method extract will convert a Node into a T.
+ */
+ def extractor24[PE0: Extractor, PE1: Extractor, P1: MultiExtractor, P2: MultiExtractor, P3: MultiExtractor, P4: MultiExtractor, T <: Product : ClassTag](construct: (PE0, PE1, P1, P2, P3, P4) => T, fields: Seq[String] = Nil): Extractor[T] =
+ (node: Node) =>
+ fieldNames(fields) match {
+ case member0 :: fs =>
+ for {
+ p0 <- extractField[PE0](member0)(node)
+ t <- extractor14[PE1, P1, P2, P3, P4, T](construct(p0, _, _, _, _, _), fs).extract(node)
+ } yield t
+ case fs => Failure(XmlException(s"extractor5: insufficient field names: $fs"))
+ }
+
+ /**
+ * Extractor which will convert an Xml Node into an instance of a case class with five members.
+ *
+ * TESTME
+ *
+ * @param construct a function (P0,P1,P2,P3,P4) => T, usually the apply method of a case class.
+ * @tparam P0 the (MultiExtractor) type of the first member of the Product type T.
+ * @tparam P1 the (MultiExtractor) type of the second member of the Product type T.
+ * @tparam P2 the (MultiExtractor) type of the third member of the Product type T.
+ * @tparam P3 the (MultiExtractor) type of the fourth member of the Product type T.
+ * @tparam P4 the (MultiExtractor) type of the fifth member of the Product type T.
+ * @tparam T the underlying type of the result, a Product with five members.
+ * @return an Extractor[T] whose method extract will convert a Node into a T.
+ */
+ def extractor06[P0: MultiExtractor, P1: MultiExtractor, P2: MultiExtractor, P3: MultiExtractor, P4: MultiExtractor, P5: MultiExtractor, T <: Product : ClassTag](construct: (P0, P1, P2, P3, P4, P5) => T, fields: Seq[String] = Nil): Extractor[T] =
+ (node: Node) =>
+ fieldNames(fields) match {
+ case member0 :: fs =>
+ for {
+ p0 <- extractChildren[P0](node, member0)
+ t <- extractor05[P1, P2, P3, P4, P5, T](construct(p0, _, _, _, _, _), fs).extract(node)
+ } yield t
+ case fs => Failure(XmlException(s"extractor5: insufficient field names: $fs"))
+ }
+
}
/**
@@ -683,6 +820,8 @@ object Extractors {
* @tparam T the type to be constructed.
*/
trait Extractor[T] {
+ self =>
+
/**
* Method to convert a Node into a Try[T].
*
@@ -690,6 +829,16 @@ trait Extractor[T] {
* @return a Try[T].
*/
def extract(node: Node): Try[T]
+
+ /**
+ * Method to combine this Extractor[T] with alt as a disjunctive expression.
+ *
+ * TESTME
+ *
+ * @param alt an alternative Extractor which will be invoked if this Extractor fails.
+ * @return an Extractor based on this and alt.
+ */
+ def |(alt: Extractor[T]): Extractor[T] = (node: Node) => self.extract(node) orElse alt.extract(node)
}
/**
diff --git a/src/test/resources/KML_Samples.kml b/src/test/resources/KML_Samples.kml
new file mode 100644
index 0000000..47ae59a
--- /dev/null
+++ b/src/test/resources/KML_Samples.kml
@@ -0,0 +1,915 @@
+
+
+
+ KML Samples
+ 1
+ Unleash your creativity with the help of these examples!
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Placemarks
+ These are just some of the different kinds of placemarks with
+ which you can mark your favorite places
+
+ -122.0839597145766
+ 37.42222904525232
+ 0
+ -148.4122922628044
+ 40.5575073395506
+ 500.6566641072245
+
+
+ Simple placemark
+ Attached to the ground. Intelligently places itself at the
+ height of the underlying terrain.
+
+ -122.0822035425683,37.42228990140251,0
+
+
+
+ Floating placemark
+ 0
+ Floats a defined distance above the ground.
+
+ -122.0839597145766
+ 37.42222904525232
+ 0
+ -148.4122922628044
+ 40.5575073395506
+ 500.6566641072245
+
+ #downArrowIcon
+
+ relativeToGround
+ -122.084075,37.4220033612141,50
+
+
+
+ Extruded placemark
+ 0
+ Tethered to the ground by a customizable
+ "tail"
+
+ -122.0845787421525
+ 37.42215078737763
+ 0
+ -148.4126684946234
+ 40.55750733918048
+ 365.2646606980322
+
+ #globeIcon
+
+ 1
+ relativeToGround
+ -122.0857667006183,37.42156927867553,50
+
+
+
+
+ Styles and Markup
+ 0
+ With KML it is easy to create rich, descriptive markup to
+ annotate and enrich your placemarks
+
+ -122.0845787422371
+ 37.42215078726837
+ 0
+ -148.4126777488172
+ 40.55750733930874
+ 365.2646826292919
+
+ #noDrivingDirections
+
+ Highlighted Icon
+ 0
+ Place your mouse over the icon to see it display the new
+ icon
+
+ -122.0856552124024
+ 37.4224281311035
+ 0
+ 0
+ 0
+ 265.8520424250024
+
+
+
+
+
+ normal
+ #normalPlacemark
+
+
+ highlight
+ #highlightPlacemark
+
+
+
+ Roll over this icon
+ 0
+ #exampleStyleMap
+
+ -122.0856545755255,37.42243077405461,0
+
+
+
+
+ Descriptive HTML
+ 0
+
+Placemark descriptions can be enriched by using many standard HTML tags.
+For example:
+
+Styles:
+Italics,
+Bold,
+Underlined,
+Strike Out,
+subscriptsubscript,
+superscriptsuperscript,
+Big,
+Small,
+Typewriter,
+Emphasized,
+Strong,
+Code
+
+Fonts:
+red by name,
+leaf green by hexadecimal RGB
+
+size 1,
+size 2,
+size 3,
+size 4,
+size 5,
+size 6,
+size 7
+
+Times,
+Verdana,
+Arial
+
+Links:
+
+Google Earth!
+
+ or: Check out our website at www.google.com
+
+Alignment:
+left
+center
+right
+
+Ordered Lists:
+- First
- Second
- Third
+- First
- Second
- Third
+- First
- Second
- Third
+
+Unordered Lists:
+
+
+
+
+Definitions:
+
+- Google:
- The best thing since sliced bread
+
+
+Centered:
+Time present and time past
+Are both perhaps present in time future,
+And time future contained in time past.
+If all time is eternally present
+All time is unredeemable.
+
+
+Block Quote:
+
+
+We shall not cease from exploration
+And the end of all our exploring
+Will be to arrive where we started
+And know the place for the first time.
+-- T.S. Eliot
+
+
+
+Headings:
+Header 1
+Header 2
+Header 3
+Header 4
+Header 5
+
+Images:
+Remote image
+
+Scaled image
+
+
+Simple Tables:
+
+
+[Did you notice that double-clicking on the placemark doesn't cause the viewer to take you anywhere? This is because it is possible to directly author a "placeless placemark". If you look at the code for this example, you will see that it has neither a point coordinate nor a LookAt element.]]]>
+
+
+
+ Ground Overlays
+ 0
+ Examples of ground overlays
+
+ Large-scale overlay on terrain
+ 0
+ Overlay shows Mount Etna erupting on July 13th, 2001.
+
+ 15.02468937557116
+ 37.67395167941667
+ 0
+ -16.5581842842829
+ 58.31228652890705
+ 30350.36838438907
+
+
+ http://developers.google.com/kml/documentation/images/etna.jpg
+
+
+ 37.91904192681665
+ 37.46543388598137
+ 15.35832653742206
+ 14.60128369746704
+ -0.1556640799496235
+
+
+
+
+ Screen Overlays
+ 0
+ Screen overlays have to be authored directly in KML. These
+ examples illustrate absolute and dynamic positioning in screen space.
+
+ Simple crosshairs
+ 0
+ This screen overlay uses fractional positioning to put the
+ image in the exact center of the screen
+
+ http://developers.google.com/kml/documentation/images/crosshairs.png
+
+
+
+
+
+
+
+ Absolute Positioning: Top left
+ 0
+
+ http://developers.google.com/kml/documentation/images/top_left.jpg
+
+
+
+
+
+
+
+ Absolute Positioning: Top right
+ 0
+
+ http://developers.google.com/kml/documentation/images/top_right.jpg
+
+
+
+
+
+
+
+ Absolute Positioning: Bottom left
+ 0
+
+ http://developers.google.com/kml/documentation/images/bottom_left.jpg
+
+
+
+
+
+
+
+ Absolute Positioning: Bottom right
+ 0
+
+ http://developers.google.com/kml/documentation/images/bottom_right.jpg
+
+
+
+
+
+
+
+ Dynamic Positioning: Top of screen
+ 0
+
+ http://developers.google.com/kml/documentation/images/dynamic_screenoverlay.jpg
+
+
+
+
+
+
+
+ Dynamic Positioning: Right of screen
+ 0
+
+ http://developers.google.com/kml/documentation/images/dynamic_right.jpg
+
+
+
+
+
+
+
+
+ Paths
+ 0
+ Examples of paths. Note that the tessellate tag is by default
+ set to 0. If you want to create tessellated lines, they must be authored
+ (or edited) directly in KML.
+
+ Tessellated
+ 0
+ tag has a value of 1, the line will contour to the underlying terrain]]>
+
+ -112.0822680013139
+ 36.09825589333556
+ 0
+ 103.8120432044965
+ 62.04855796276328
+ 2889.145007690472
+
+
+ 1
+ -112.0814237830345,36.10677870477137,0
+ -112.0870267752693,36.0905099328766,0
+
+
+
+ Untessellated
+ 0
+ tag has a value of 0, the line follow a simple straight-line path from point to point]]>
+
+ -112.0822680013139
+ 36.09825589333556
+ 0
+ 103.8120432044965
+ 62.04855796276328
+ 2889.145007690472
+
+
+ 0
+ -112.080622229595,36.10673460007995,0
+ -112.085242575315,36.09049598612422,0
+
+
+
+ Absolute
+ 0
+ Transparent purple line
+
+ -112.2719329043177
+ 36.08890633450894
+ 0
+ -106.8161545998597
+ 44.60763714063257
+ 2569.386744398339
+
+ #transPurpleLineGreenPoly
+
+ 1
+ absolute
+ -112.265654928602,36.09447672602546,2357
+ -112.2660384528238,36.09342608838671,2357
+ -112.2668139013453,36.09251058776881,2357
+ -112.2677826834445,36.09189827357996,2357
+ -112.2688557510952,36.0913137941187,2357
+ -112.2694810717219,36.0903677207521,2357
+ -112.2695268555611,36.08932171487285,2357
+ -112.2690144567276,36.08850916060472,2357
+ -112.2681528815339,36.08753813597956,2357
+ -112.2670588176031,36.08682685262568,2357
+ -112.2657374587321,36.08646312301303,2357
+
+
+
+ Absolute Extruded
+ 0
+ Transparent green wall with yellow outlines
+
+ -112.2643334742529
+ 36.08563154742419
+ 0
+ -125.7518698668815
+ 44.61038665812578
+ 4451.842204068102
+
+ #yellowLineGreenPoly
+
+ 1
+ 1
+ absolute
+ -112.2550785337791,36.07954952145647,2357
+ -112.2549277039738,36.08117083492122,2357
+ -112.2552505069063,36.08260761307279,2357
+ -112.2564540158376,36.08395660588506,2357
+ -112.2580238976449,36.08511401044813,2357
+ -112.2595218489022,36.08584355239394,2357
+ -112.2608216347552,36.08612634548589,2357
+ -112.262073428656,36.08626019085147,2357
+ -112.2633204928495,36.08621519860091,2357
+ -112.2644963846444,36.08627897945274,2357
+ -112.2656969554589,36.08649599090644,2357
+
+
+
+ Relative
+ 0
+ Black line (10 pixels wide), height tracks terrain
+
+ -112.2580438551384
+ 36.1072674824385
+ 0
+ 4.947421249553717
+ 44.61324882043339
+ 2927.61105910266
+
+ #thickBlackLine
+
+ 1
+ relativeToGround
+ -112.2532845153347,36.09886943729116,645
+ -112.2540466121145,36.09919570465255,645
+ -112.254734666947,36.09984998366178,645
+ -112.255493345654,36.10051310621746,645
+ -112.2563157098468,36.10108441943419,645
+ -112.2568033076439,36.10159722088088,645
+ -112.257494011321,36.10204323542867,645
+ -112.2584106072308,36.10229131995655,645
+ -112.2596588987972,36.10240001286358,645
+ -112.2610581199487,36.10213176873407,645
+ -112.2626285262793,36.10157011437219,645
+
+
+
+ Relative Extruded
+ 0
+ Opaque blue walls with red outline, height tracks terrain
+
+ -112.2683594333433
+ 36.09884362144909
+ 0
+ -72.24271551768405
+ 44.60855445139561
+ 2184.193522571467
+
+ #redLineBluePoly
+
+ 1
+ 1
+ relativeToGround
+ -112.2656634181359,36.09445214722695,630
+ -112.2652238941097,36.09520916122063,630
+ -112.2645079986395,36.09580763864907,630
+ -112.2638827428817,36.09628572284063,630
+ -112.2635746835406,36.09679275951239,630
+ -112.2635711822407,36.09740038871899,630
+ -112.2640296531825,36.09804913435539,630
+ -112.264327720538,36.09880337400301,630
+ -112.2642436562271,36.09963644790288,630
+ -112.2639148687042,36.10055381117246,630
+ -112.2626894973474,36.10149062823369,630
+
+
+
+
+ Polygons
+ 0
+ Examples of polygon shapes
+
+ Google Campus
+ 0
+ A collection showing how easy it is to create 3-dimensional
+ buildings
+
+ -122.084120030116
+ 37.42174011925477
+ 0
+ -34.82469740081282
+ 53.454348562403
+ 276.7870053764046
+
+
+ Building 40
+ 0
+ #transRedPoly
+
+ 1
+ relativeToGround
+
+
+ -122.0848938459612,37.42257124044786,17
+ -122.0849580979198,37.42211922626856,17
+ -122.0847469573047,37.42207183952619,17
+ -122.0845725380962,37.42209006729676,17
+ -122.0845954886723,37.42215932700895,17
+ -122.0838521118269,37.42227278564371,17
+ -122.083792243335,37.42203539112084,17
+ -122.0835076656616,37.42209006957106,17
+ -122.0834709464152,37.42200987395161,17
+ -122.0831221085748,37.4221046494946,17
+ -122.0829247374572,37.42226503990386,17
+ -122.0829339169385,37.42231242843094,17
+ -122.0833837359737,37.42225046087618,17
+ -122.0833607854248,37.42234159228745,17
+ -122.0834204551642,37.42237075460644,17
+ -122.083659133885,37.42251292011001,17
+ -122.0839758438952,37.42265873093781,17
+ -122.0842374743331,37.42265143972521,17
+ -122.0845036949503,37.4226514386435,17
+ -122.0848020460801,37.42261133916315,17
+ -122.0847882750515,37.42256395055121,17
+ -122.0848938459612,37.42257124044786,17
+
+
+
+
+
+ Building 41
+ 0
+ #transBluePoly
+
+ 1
+ relativeToGround
+
+
+ -122.0857412771483,37.42227033155257,17
+ -122.0858169768481,37.42231408832346,17
+ -122.085852582875,37.42230337469744,17
+ -122.0858799945639,37.42225686138789,17
+ -122.0858860101409,37.4222311076138,17
+ -122.0858069157288,37.42220250173855,17
+ -122.0858379542653,37.42214027058678,17
+ -122.0856732640519,37.42208690214408,17
+ -122.0856022926407,37.42214885429042,17
+ -122.0855902778436,37.422128290487,17
+ -122.0855841672237,37.42208171967246,17
+ -122.0854852065741,37.42210455874995,17
+ -122.0855067264352,37.42214267949824,17
+ -122.0854430712915,37.42212783846172,17
+ -122.0850990714904,37.42251282407603,17
+ -122.0856769818632,37.42281815323651,17
+ -122.0860162273783,37.42244918858722,17
+ -122.0857260327004,37.42229239604253,17
+ -122.0857412771483,37.42227033155257,17
+
+
+
+
+
+ Building 42
+ 0
+ #transGreenPoly
+
+ 1
+ relativeToGround
+
+
+ -122.0857862287242,37.42136208886969,25
+ -122.0857312990603,37.42136935989481,25
+ -122.0857312992918,37.42140934910903,25
+ -122.0856077073679,37.42138390166565,25
+ -122.0855802426516,37.42137299550869,25
+ -122.0852186221971,37.42137299504316,25
+ -122.0852277765639,37.42161656508265,25
+ -122.0852598189347,37.42160565894403,25
+ -122.0852598185499,37.42168200156,25
+ -122.0852369311478,37.42170017860346,25
+ -122.0852643957828,37.42176197982575,25
+ -122.0853239032746,37.42176198013907,25
+ -122.0853559454324,37.421852864452,25
+ -122.0854108752463,37.42188921823734,25
+ -122.0854795379357,37.42189285337048,25
+ -122.0855436229819,37.42188921797546,25
+ -122.0856260178042,37.42186013499926,25
+ -122.085937287963,37.42186013453605,25
+ -122.0859428718666,37.42160898590042,25
+ -122.0859655469861,37.42157992759144,25
+ -122.0858640462341,37.42147115002957,25
+ -122.0858548911215,37.42140571326184,25
+ -122.0858091162768,37.4214057134039,25
+ -122.0857862287242,37.42136208886969,25
+
+
+
+
+
+ Building 43
+ 0
+ #transYellowPoly
+
+ 1
+ relativeToGround
+
+
+ -122.0844371128284,37.42177253003091,19
+ -122.0845118855746,37.42191111542896,19
+ -122.0850470999805,37.42178755121535,19
+ -122.0850719913391,37.42143663023161,19
+ -122.084916406232,37.42137237822116,19
+ -122.0842193868167,37.42137237801626,19
+ -122.08421938659,37.42147617161496,19
+ -122.0838086419991,37.4214613409357,19
+ -122.0837899728564,37.42131306410796,19
+ -122.0832796534698,37.42129328840593,19
+ -122.0832609819207,37.42139213944298,19
+ -122.0829373621737,37.42137236399876,19
+ -122.0829062425667,37.42151569778871,19
+ -122.0828502269665,37.42176282576465,19
+ -122.0829435788635,37.42176776969635,19
+ -122.083217411188,37.42179248552686,19
+ -122.0835970430103,37.4217480074456,19
+ -122.0839455556771,37.42169364237603,19
+ -122.0840077894637,37.42176283815853,19
+ -122.084113587521,37.42174801104392,19
+ -122.0840762473784,37.42171341292375,19
+ -122.0841447047739,37.42167881534569,19
+ -122.084144704223,37.42181720660197,19
+ -122.0842503333074,37.4218170700446,19
+ -122.0844371128284,37.42177253003091,19
+
+
+
+
+
+
+ Extruded Polygon
+ A simple way to model a building
+
+ The Pentagon
+
+ -77.05580139178142
+ 38.870832443487
+ 59.88865561738225
+ 48.09646074797388
+ 742.0552506670548
+
+
+ 1
+ relativeToGround
+
+
+ -77.05788457660967,38.87253259892824,100
+ -77.05465973756702,38.87291016281703,100
+ -77.05315536854791,38.87053267794386,100
+ -77.05552622493516,38.868757801256,100
+ -77.05844056290393,38.86996206506943,100
+ -77.05788457660967,38.87253259892824,100
+
+
+
+
+ -77.05668055019126,38.87154239798456,100
+ -77.05542625960818,38.87167890344077,100
+ -77.05485125901024,38.87076535397792,100
+ -77.05577677433152,38.87008686581446,100
+ -77.05691162017543,38.87054446963351,100
+ -77.05668055019126,38.87154239798456,100
+
+
+
+
+
+
+ Absolute and Relative
+ 0
+ Four structures whose roofs meet exactly. Turn on/off
+ terrain to see the difference between relative and absolute
+ positioning.
+
+ -112.3348969157552
+ 36.14845533214919
+ 0
+ -86.91235037566909
+ 49.30695423894192
+ 990.6761201087104
+
+
+ Absolute
+ 0
+ #transBluePoly
+
+ 1
+ absolute
+
+
+ -112.3372510731295,36.14888505105317,1784
+ -112.3356128688403,36.14781540589019,1784
+ -112.3368169371048,36.14658677734382,1784
+ -112.3384408457543,36.14762778914076,1784
+ -112.3372510731295,36.14888505105317,1784
+
+
+
+
+
+ Absolute Extruded
+ 0
+ #transRedPoly
+
+ 1
+ 1
+ absolute
+
+
+ -112.3396586818843,36.14637618647505,1784
+ -112.3380597654315,36.14531751871353,1784
+ -112.3368254237788,36.14659596244607,1784
+ -112.3384555043203,36.14762621763982,1784
+ -112.3396586818843,36.14637618647505,1784
+
+
+
+
+
+ Relative
+ 0
+
+ -112.3350152490417
+ 36.14943123077423
+ 0
+ -118.9214100848499
+ 37.92486261093203
+ 345.5169113679813
+
+ #transGreenPoly
+
+ 1
+ relativeToGround
+
+
+ -112.3349463145932,36.14988705767721,100
+ -112.3354019540677,36.14941108398372,100
+ -112.3344428289146,36.14878490381308,100
+ -112.3331289492913,36.14780840132443,100
+ -112.3317019516947,36.14680755678357,100
+ -112.331131440106,36.1474173426228,100
+ -112.332616324338,36.14845453364654,100
+ -112.3339876620524,36.14926570522069,100
+ -112.3349463145932,36.14988705767721,100
+
+
+
+
+
+ Relative Extruded
+ 0
+
+ -112.3351587892382
+ 36.14979247129029
+ 0
+ -55.42811560891606
+ 56.10280503739589
+ 401.0997279712519
+
+ #transYellowPoly
+
+ 1
+ 1
+ relativeToGround
+
+
+ -112.3348783983763,36.1514008468736,100
+ -112.3372535345629,36.14888517553886,100
+ -112.3356068927954,36.14781612679284,100
+ -112.3350034807972,36.14846469024177,100
+ -112.3358353861232,36.1489624162954,100
+ -112.3345888301373,36.15026229372507,100
+ -112.3337937856278,36.14978096026463,100
+ -112.3331798208424,36.1504472788618,100
+ -112.3348783983763,36.1514008468736,100
+
+
+
+
+
+
+
+
diff --git a/src/test/scala/com/phasmidsoftware/kmldoc/KmlSpec.scala b/src/test/scala/com/phasmidsoftware/kmldoc/KmlSpec.scala
index e67ce2d..b5e5a01 100644
--- a/src/test/scala/com/phasmidsoftware/kmldoc/KmlSpec.scala
+++ b/src/test/scala/com/phasmidsoftware/kmldoc/KmlSpec.scala
@@ -3520,7 +3520,7 @@ class KmlSpec extends AnyFlatSpec with should.Matchers {
ks.size shouldBe 1
val kml: KML = ks.head
val w = kml.toString
- w.length shouldBe 80808
+ w.length shouldBe 80813
case Failure(x) => fail(x)
}
}
@@ -3533,7 +3533,7 @@ class KmlSpec extends AnyFlatSpec with should.Matchers {
ks.size shouldBe 1
val kml: KML = ks.head
val w = kml.toString
- w.length shouldBe 4977
+ w.length shouldBe 4982
case Failure(x) => fail(x)
}
}
@@ -3584,5 +3584,28 @@ class KmlSpec extends AnyFlatSpec with should.Matchers {
case Failure(x) => fail(x)
}
}
+
+ ignore should "extract and render sample kml as XML from Google sample" in {
+ val renderer = new KmlRenderers {}.rendererKml_Binding
+ val url = KML.getClass.getResource("/KML_Samples.kml")
+ val xml: Elem = XML.loadFile(url.getFile)
+ extractorMultiKml.extract(xml) match {
+ case Success(ks) =>
+ ks.size shouldBe 1
+ val kml = KML_Binding(ks.head, xml.scope)
+ val w = renderer.render(kml, FormatXML(0), StateR().setName("kml"))
+ val filename = "xmlOutput.kml"
+ val fw = new FileWriter(filename)
+ fw.write(
+ """
+ |""".stripMargin)
+ fw.write(w)
+ fw.close()
+ val copy: Elem = parseUnparsed(w)
+ val ksy: Try[scala.Seq[KML]] = extractorMultiKml.extract(copy)
+ ksy should matchPattern { case Success(_ :: Nil) => }
+ case Failure(x) => fail(x)
+ }
+ }
}