]> pintos-os.org Git - pspp/commitdiff
Add module for symobls.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 5 May 2026 00:51:12 +0000 (17:51 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 5 May 2026 00:51:12 +0000 (17:51 -0700)
rust/pspp/build.rs
rust/pspp/src/spv/read/graph.rs
rust/pspp/src/spv/read/graph/symbols.rs [new file with mode: 0644]
rust/pspp/src/spv/read/graph/symbols.svg
rust/pspp/src/spv/read/graph/symbols/.gitignore [new file with mode: 0644]

index e93e1e0d695840afef369955c348233edf096b3f..09f2e017ef82645f8603fbfe7b2490c43b7aac7f 100644 (file)
 
 use anyhow::{Result as AnyResult, anyhow};
 use enum_map::{Enum, EnumMap};
-use quick_xml::events::{BytesStart, Event};
+use quick_xml::{Writer, events::Event};
 use serde::{Deserialize, Deserializer};
 use serde_json::{Value, from_value};
 use std::{
-    borrow::Cow,
     collections::{BTreeMap, HashMap, HashSet, VecDeque},
     env::var_os,
     ffi::OsStr,
     fmt::{Display, Write as _},
     fs::{File, read_to_string},
-    io::{Error as IoError, Write},
+    io::{Cursor, Error as IoError, Write},
     path::{Path, PathBuf},
 };
 use zip::ZipArchive;
@@ -670,18 +669,6 @@ fn build_patterns() -> AnyResult<()> {
     loop {
         let event = reader.read_event().unwrap();
 
-        fn id_attribute<'a>(start: &'a BytesStart) -> Option<Cow<'a, str>> {
-            for attribute in start.attributes() {
-                if let Ok(attribute) = attribute
-                    && attribute.key.local_name().as_ref() == b"id"
-                    && let Ok(value) = attribute.unescape_value()
-                {
-                    return Some(value);
-                }
-            }
-            None
-        }
-
         match &event {
             Event::Start(start) => {
                 let local_name = start.local_name();
@@ -754,11 +741,108 @@ pub static PATTERNS: [Pattern; 30] = ["
     Ok(())
 }
 
+/// Read `src/spv/read/graph/symbols.svg` and write
+/// `src/spv/read/graph/symbols/data.rs`.
+fn build_symbols() -> AnyResult<()> {
+    let input_file = Path::new(env!("CARGO_MANIFEST_DIR")).join("src/spv/read/graph/symbols.svg");
+    println!("cargo:rerun-if-changed={}", input_file.display());
+    let input = read_to_string(&input_file)
+        .map_err(|e| anyhow!("{}: read failed ({e})", input_file.display()))?;
+
+    let mut reader = quick_xml::Reader::from_str(&input);
+    let mut symbols = Vec::new();
+    reader.config_mut().expand_empty_elements = true;
+    let mut in_defs = false;
+    loop {
+        let event = reader.read_event().unwrap();
+
+        match &event {
+            Event::Start(start) => {
+                let local_name = start.local_name();
+                if local_name.as_ref() == b"defs" {
+                    in_defs = true;
+                } else if in_defs && local_name.as_ref() == b"g" {
+                    let span = reader.read_to_end(start.to_end().name()).unwrap();
+                    let content = &input[span.start as usize..span.end as usize];
+                    let mut attributes = start
+                        .attributes()
+                        .map(|attribute| {
+                            let attribute = attribute.unwrap();
+                            (
+                                String::from_utf8(Vec::from(attribute.key.0)).unwrap(),
+                                String::from_utf8(attribute.value.into_owned()).unwrap(),
+                            )
+                        })
+                        .collect::<BTreeMap<_, _>>();
+                    let name = attributes.remove("id").unwrap();
+                    let hollow = match attributes.remove("hollow").unwrap().as_str() {
+                        "true" => true,
+                        "false" => false,
+                        _ => unreachable!(),
+                    };
+                    symbols.push((name.clone(), hollow, content));
+
+                    if !hollow {
+                        let mut iter = name.chars();
+                        let first = iter.next().unwrap().to_ascii_uppercase();
+                        let rest = iter.as_str();
+                        symbols.push((format!("hollow{first}{rest}"), true, content));
+                    }
+                }
+            }
+            Event::End(end) => {
+                if end.local_name().as_ref() == b"defs" {
+                    in_defs = false;
+                }
+            }
+            Event::Eof => break,
+            _ => (),
+        }
+    }
+
+    let mut output = String::new();
+    writeln!(
+        &mut output,
+        "use super::Symbol;
+
+pub static SYMBOLS: [Symbol; {}] = [",
+        symbols.len()
+    )
+    .unwrap();
+    for (name, hollow, content) in &symbols {
+        let mut writer = Writer::new(Cursor::new(Vec::new()));
+        writer
+            .create_element("g")
+            .with_attribute(("id", name.as_str()))
+            .write_inner_content(|w| w.get_mut().write_all(content.as_bytes()))
+            .unwrap();
+        let definition = String::from_utf8(writer.into_inner().into_inner()).unwrap();
+
+        writeln!(
+            &mut output,
+            "    Symbol {{
+        name: {name:?},
+        hollow: {hollow:?},
+        definition: {definition:?},
+    }},"
+        )
+        .unwrap();
+    }
+    writeln!(&mut output, "];").unwrap();
+
+    let output_file_name =
+        Path::new(env!("CARGO_MANIFEST_DIR")).join("src/spv/read/graph/symbols/data.rs");
+    std::fs::write(output_file_name, &output)?;
+
+    Ok(())
+}
+
 fn main() -> AnyResult<()> {
     println!("cargo:rerun-if-changed=build.rs");
 
     build_encodings()?;
     build_patterns()?;
+    build_symbols()?;
     build_locales()?;
 
     Ok(())
index 421b7a0064ab361fd876f8afbd5decd13b01900e..7dd2adb1791f8a606770af6a1d3efaf8bfeb6dca 100644 (file)
@@ -74,6 +74,7 @@ use crate::{
 mod format;
 mod frames;
 mod patterns;
+mod symbols;
 
 #[derive(Debug)]
 struct Ref<T> {
diff --git a/rust/pspp/src/spv/read/graph/symbols.rs b/rust/pspp/src/spv/read/graph/symbols.rs
new file mode 100644 (file)
index 0000000..376fe03
--- /dev/null
@@ -0,0 +1,69 @@
+use crate::spv::read::graph::symbols::data::SYMBOLS;
+
+mod data;
+
+/// A symbol for marking points in a graph.
+#[derive(Clone, Debug)]
+pub struct Symbol {
+    /// The symbol's name.
+    pub name: &'static str,
+
+    /// Whether the symbol is hollow:
+    ///
+    /// - A hollow symbol has a stroke color.  It should not have a fill color.
+    /// - A non-hollow symbol has a stroke color and an optional fill color.
+    pub hollow: bool,
+
+    /// The XML definition of the symbol, as a complete XML element whose `id`
+    /// attribute is `name`.
+    ///
+    /// The definition does not include `fill` or `stroke` attributes.  It is
+    /// intended to be included in a `<defs>` element and instantiated with
+    /// `<use>`.
+    pub definition: &'static str,
+}
+
+impl Symbol {
+    /// Returns the symbol with the given name, or `None` if there is none.
+    ///
+    /// Symbol names are matched case-insensitively.  Use the `name` member of
+    /// the returned symbol for the canonical name.
+    pub fn for_name(name: &str) -> Option<&'static Self> {
+        SYMBOLS
+            .iter()
+            .find(|symbol| symbol.name.eq_ignore_ascii_case(name))
+    }
+
+    /// Returns true if the symbol is hollow.
+    pub fn is_hollow(&self) -> bool {
+        self.hollow
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::spv::read::graph::symbols::Symbol;
+
+    #[test]
+    fn symbol() {
+        let symbol = Symbol::for_name("SQUARE").unwrap();
+        assert_eq!(symbol.name, "square");
+        assert_eq!(symbol.hollow, false);
+        assert_eq!(
+            symbol.definition,
+            r#"<g id="square">
+      <rect x="0" y="0" width="10" height="10" />
+    </g>"#
+        );
+
+        let symbol = Symbol::for_name("hollowsquare").unwrap();
+        assert_eq!(symbol.name, "hollowSquare");
+        assert_eq!(symbol.hollow, true);
+        assert_eq!(
+            symbol.definition,
+            r#"<g id="hollowSquare">
+      <rect x="0" y="0" width="10" height="10" />
+    </g>"#
+        );
+    }
+}
index 4e153ec95d6d58a6e8b39502ce2f9d57e3ec9eab..cc8960f645a833eadfc8f32cafbf0c2ba6c2b210 100644 (file)
@@ -1,3 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+
 <svg xmlns="http://www.w3.org/2000/svg">
   <defs>
     <!--
@@ -6,60 +8,59 @@
         Each pattern nominally occupies the box (0,0)-(10,10), although a few
         spill over the margin.
     -->
-    <g id="square">
-      <rect x="0" y="0" width="10" height="10"/>
+    <g id="square" hollow="false">
+      <rect x="0" y="0" width="10" height="10" />
     </g>
-    <g id="none"/>
+    <g id="none" hollow="true" />
     <g id="arc" hollow="true">
-      <path d="M0,5 A5 5 180 1 1 10,5" fill="none"/>
+      <path d="M0,5 A5 5 180 1 1 10,5" fill="none" />
     </g>
     <g id="arcDown" hollow="true">
-      <path d="M0,5 A5 5 180 1 0 10,5" fill="none"/>
+      <path d="M0,5 A5 5 180 1 0 10,5" fill="none" />
     </g>
-    <g id="circle">
-      <circle cx="5" cy="5" r="5"/>
+    <g id="circle" hollow="false">
+      <circle cx="5" cy="5" r="5" />
     </g>
-    <g id="cross">
-      <line x1="0" y1="0" x2="10" y2="10"/>
-      <line x1="0" y1="10" x2="10" y2="0"/>
+    <g id="cross" hollow="true">
+      <line x1="0" y1="0" x2="10" y2="10" />
+      <line x1="0" y1="10" x2="10" y2="0" />
     </g>
     <g id="plus" hollow="true">
-      <line x1="0" y1="5" x2="10" y2="5"/>
-      <line x1="5" y1="0" x2="5" y2="10"/>
+      <line x1="0" y1="5" x2="10" y2="5" />
+      <line x1="5" y1="0" x2="5" y2="10" />
     </g>
     <g id="arrow" hollow="true">
       <!-- points up -->
-      <line x1="5" y1="0" x2="5" y2="10"/>
-      <line x1="5" y1="0" x2="2.5" y2="2.5"/>
-      <line x1="5" y1="0" x2="7.5" y2="2.5"/>
+      <line x1="5" y1="0" x2="5" y2="10" />
+      <line x1="5" y1="0" x2="2.5" y2="2.5" />
+      <line x1="5" y1="0" x2="7.5" y2="2.5" />
     </g>
     <g id="line" hollow="true">
-      <line x1="0" y1="5" x2="10" y2="5"/>
+      <line x1="0" y1="5" x2="10" y2="5" />
     </g>
-    <g id="male">
-      <circle cx="5" cy="5" r="3.33333"/>
-      <line x1="7.35702" y1="2.64298" x2="9.71404" y2="0.28596"/>
-      <line x1="9.71404" y1="0.28596" x2="7.35702" y2="0.28596"/>
-      <line x1="9.71404" y1="0.28596" x2="9.71404" y2="2.64298"/>
+    <g id="male" hollow="false">
+      <circle cx="5" cy="5" r="3.33333" />
+      <line x1="7.35702" y1="2.64298" x2="9.71404" y2="0.28596" />
+      <line x1="9.71404" y1="0.28596" x2="7.35702" y2="0.28596" />
+      <line x1="9.71404" y1="0.28596" x2="9.71404" y2="2.64298" />
     </g>
-    <g id="female">
-      <circle cx="5" cy="5" r="3.33333"/>
-      <line x1="5" y1="8.33333" x2="5" y2="11.66666"/>
-      <line x1="3.33333" y1="10" x2="6.66667" y2="10"/>
+    <g id="female" hollow="false">
+      <circle cx="5" cy="5" r="3.33333" />
+      <line x1="5" y1="8.33333" x2="5" y2="11.66666" />
+      <line x1="3.33333" y1="10" x2="6.66667" y2="10" />
     </g>
-    <g id="bowtie">
-      <path d="M5,5 L10,7.5 V2.5 Z"/>
-      <path d="M5,5 L0,7.5 V2.5 Z"/>
+    <g id="bowtie" hollow="false">
+      <path d="M5,5 L10,7.5 V2.5 Z" />
+      <path d="M5,5 L0,7.5 V2.5 Z" />
     </g>
     <g id="ibeam" hollow="true">
-      <line x1="2.5" y1="0" x2="7.5" y2="0"/>
-      <line x1="5" y1="0" x2="5" y2="10"/>
-      <line x1="2.5" y1="10" x2="7.5" y2="10"/>
+      <line x1="2.5" y1="0" x2="7.5" y2="0" />
+      <line x1="5" y1="0" x2="5" y2="10" />
+      <line x1="2.5" y1="10" x2="7.5" y2="10" />
     </g>
-    <g id="roundRectangle">
-      <rect x="0" y="0" width="10" height="10" rx="2.5" ry="2.5"/>
+    <g id="roundRectangle" hollow="false">
+      <rect x="0" y="0" width="10" height="10" rx="2.5" ry="2.5" />
     </g>
-
     <!--
         These flowers can be regenerated with the following Python program:
 
         from math import sin, cos, pi
 
         for n in range(3, 11):
-            print(f'    <g id="flower{n}" hollow="true">')
-            for i in range(n):
-                d = pi * 2 * i / n
-                x = 5 + 5 * sin(d)
-                y = 5 - 5 * cos(d)
-                print(f'        <line x1="5" y1="5" x2="{x}" y2="{y}"/>')
-            print("    </g>")
+        print(f'    <g id="flower{n}" hollow="true">')
+        for i in range(n):
+        d = pi * 2 * i / n
+        x = 5 + 5 * sin(d)
+        y = 5 - 5 * cos(d)
+        print(f'        <line x1="5" y1="5" x2="{x}" y2="{y}"/>')
+        print("    </g>")
     -->
-
     <g id="flower3" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="9.330127018922195" y2="7.499999999999999"/>
-        <line x1="5" y1="5" x2="0.6698729810778081" y2="7.500000000000002"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="9.330127018922195" y2="7.499999999999999" />
+      <line x1="5" y1="5" x2="0.6698729810778081" y2="7.500000000000002" />
     </g>
     <g id="flower4" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="10.0" y2="5.0"/>
-        <line x1="5" y1="5" x2="5.000000000000001" y2="10.0"/>
-        <line x1="5" y1="5" x2="0.0" y2="5.000000000000001"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="10.0" y2="5.0" />
+      <line x1="5" y1="5" x2="5.000000000000001" y2="10.0" />
+      <line x1="5" y1="5" x2="0.0" y2="5.000000000000001" />
     </g>
     <g id="flower5" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="9.755282581475768" y2="3.4549150281252627"/>
-        <line x1="5" y1="5" x2="7.938926261462367" y2="9.045084971874736"/>
-        <line x1="5" y1="5" x2="2.061073738537635" y2="9.045084971874738"/>
-        <line x1="5" y1="5" x2="0.2447174185242318" y2="3.4549150281252636"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="9.755282581475768" y2="3.4549150281252627" />
+      <line x1="5" y1="5" x2="7.938926261462367" y2="9.045084971874736" />
+      <line x1="5" y1="5" x2="2.061073738537635" y2="9.045084971874738" />
+      <line x1="5" y1="5" x2="0.2447174185242318" y2="3.4549150281252636" />
     </g>
     <g id="flower6" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="9.330127018922193" y2="2.4999999999999996"/>
-        <line x1="5" y1="5" x2="9.330127018922195" y2="7.499999999999999"/>
-        <line x1="5" y1="5" x2="5.000000000000001" y2="10.0"/>
-        <line x1="5" y1="5" x2="0.6698729810778081" y2="7.500000000000002"/>
-        <line x1="5" y1="5" x2="0.6698729810778072" y2="2.4999999999999996"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="9.330127018922193" y2="2.4999999999999996" />
+      <line x1="5" y1="5" x2="9.330127018922195" y2="7.499999999999999" />
+      <line x1="5" y1="5" x2="5.000000000000001" y2="10.0" />
+      <line x1="5" y1="5" x2="0.6698729810778081" y2="7.500000000000002" />
+      <line x1="5" y1="5" x2="0.6698729810778072" y2="2.4999999999999996" />
     </g>
     <g id="flower7" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="8.90915741234015" y2="1.8825509907063323"/>
-        <line x1="5" y1="5" x2="9.874639560909118" y2="6.112604669781572"/>
-        <line x1="5" y1="5" x2="7.169418695587791" y2="9.504844339512095"/>
-        <line x1="5" y1="5" x2="2.83058130441221" y2="9.504844339512097"/>
-        <line x1="5" y1="5" x2="0.12536043909088157" y2="6.1126046697815735"/>
-        <line x1="5" y1="5" x2="1.0908425876598504" y2="1.8825509907063331"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="8.90915741234015" y2="1.8825509907063323" />
+      <line x1="5" y1="5" x2="9.874639560909118" y2="6.112604669781572" />
+      <line x1="5" y1="5" x2="7.169418695587791" y2="9.504844339512095" />
+      <line x1="5" y1="5" x2="2.83058130441221" y2="9.504844339512097" />
+      <line x1="5" y1="5" x2="0.12536043909088157" y2="6.1126046697815735" />
+      <line x1="5" y1="5" x2="1.0908425876598504" y2="1.8825509907063331" />
     </g>
     <g id="flower8" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="8.535533905932738" y2="1.4644660940672622"/>
-        <line x1="5" y1="5" x2="10.0" y2="5.0"/>
-        <line x1="5" y1="5" x2="8.535533905932738" y2="8.535533905932738"/>
-        <line x1="5" y1="5" x2="5.000000000000001" y2="10.0"/>
-        <line x1="5" y1="5" x2="1.4644660940672627" y2="8.535533905932738"/>
-        <line x1="5" y1="5" x2="0.0" y2="5.000000000000001"/>
-        <line x1="5" y1="5" x2="1.4644660940672614" y2="1.4644660940672631"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="8.535533905932738" y2="1.4644660940672622" />
+      <line x1="5" y1="5" x2="10.0" y2="5.0" />
+      <line x1="5" y1="5" x2="8.535533905932738" y2="8.535533905932738" />
+      <line x1="5" y1="5" x2="5.000000000000001" y2="10.0" />
+      <line x1="5" y1="5" x2="1.4644660940672627" y2="8.535533905932738" />
+      <line x1="5" y1="5" x2="0.0" y2="5.000000000000001" />
+      <line x1="5" y1="5" x2="1.4644660940672614" y2="1.4644660940672631" />
     </g>
     <g id="flower9" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="8.213938048432697" y2="1.16977778440511"/>
-        <line x1="5" y1="5" x2="9.92403876506104" y2="4.131759111665348"/>
-        <line x1="5" y1="5" x2="9.330127018922195" y2="7.499999999999999"/>
-        <line x1="5" y1="5" x2="6.710100716628345" y2="9.69846310392954"/>
-        <line x1="5" y1="5" x2="3.289899283371657" y2="9.698463103929543"/>
-        <line x1="5" y1="5" x2="0.6698729810778081" y2="7.500000000000002"/>
-        <line x1="5" y1="5" x2="0.07596123493895934" y2="4.1317591116653505"/>
-        <line x1="5" y1="5" x2="1.786061951567302" y2="1.169777784405111"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="8.213938048432697" y2="1.16977778440511" />
+      <line x1="5" y1="5" x2="9.92403876506104" y2="4.131759111665348" />
+      <line x1="5" y1="5" x2="9.330127018922195" y2="7.499999999999999" />
+      <line x1="5" y1="5" x2="6.710100716628345" y2="9.69846310392954" />
+      <line x1="5" y1="5" x2="3.289899283371657" y2="9.698463103929543" />
+      <line x1="5" y1="5" x2="0.6698729810778081" y2="7.500000000000002" />
+      <line x1="5" y1="5" x2="0.07596123493895934" y2="4.1317591116653505" />
+      <line x1="5" y1="5" x2="1.786061951567302" y2="1.169777784405111" />
     </g>
     <g id="flower10" hollow="true">
-        <line x1="5" y1="5" x2="5.0" y2="0.0"/>
-        <line x1="5" y1="5" x2="7.938926261462366" y2="0.9549150281252627"/>
-        <line x1="5" y1="5" x2="9.755282581475768" y2="3.4549150281252627"/>
-        <line x1="5" y1="5" x2="9.755282581475768" y2="6.545084971874736"/>
-        <line x1="5" y1="5" x2="7.938926261462367" y2="9.045084971874736"/>
-        <line x1="5" y1="5" x2="5.000000000000001" y2="10.0"/>
-        <line x1="5" y1="5" x2="2.061073738537635" y2="9.045084971874738"/>
-        <line x1="5" y1="5" x2="0.24471741852423268" y2="6.545084971874738"/>
-        <line x1="5" y1="5" x2="0.2447174185242318" y2="3.4549150281252636"/>
-        <line x1="5" y1="5" x2="2.061073738537633" y2="0.9549150281252636"/>
+      <line x1="5" y1="5" x2="5.0" y2="0.0" />
+      <line x1="5" y1="5" x2="7.938926261462366" y2="0.9549150281252627" />
+      <line x1="5" y1="5" x2="9.755282581475768" y2="3.4549150281252627" />
+      <line x1="5" y1="5" x2="9.755282581475768" y2="6.545084971874736" />
+      <line x1="5" y1="5" x2="7.938926261462367" y2="9.045084971874736" />
+      <line x1="5" y1="5" x2="5.000000000000001" y2="10.0" />
+      <line x1="5" y1="5" x2="2.061073738537635" y2="9.045084971874738" />
+      <line x1="5" y1="5" x2="0.24471741852423268" y2="6.545084971874738" />
+      <line x1="5" y1="5" x2="0.2447174185242318" y2="3.4549150281252636" />
+      <line x1="5" y1="5" x2="2.061073738537633" y2="0.9549150281252636" />
     </g>
-
     <!--
         These polygons can be regenerated with the following Python program:
 
-         #! /usr/bin/env python
-         from math import sin, cos, pi
+        #! /usr/bin/env python
+        from math import sin, cos, pi
 
-         for n, name in (
-                 (3, "triangle"),
-                 (5, "pentagon"),
-                 (6, "hexagon"),
-                 (7, "heptagon"),
-                 (8, "octagon"),
-                 (9, "nonagon"),
-                 (10, "decagon"),
-         ):
-             points = []
-             for i in range(0, n + 1):
-                 d = i * 2 * pi / n
-                 points += [5 - 5 * sin(d), 5 - 5 * cos(d)]
-             print(f'    <g id="{name}">')
-             print(f'        <polygon points="{' '.join([str(p) for p in points])}"/>')
-             print("    </g>")
+        for n, name in (
+        (3, "triangle"),
+        (5, "pentagon"),
+        (6, "hexagon"),
+        (7, "heptagon"),
+        (8, "octagon"),
+        (9, "nonagon"),
+        (10, "decagon"),
+        ):
+        points = []
+        for i in range(0, n + 1):
+        d = i * 2 * pi / n
+        points += [5 - 5 * sin(d), 5 - 5 * cos(d)]
+        print(f'    <g id="{name}" hollow="false">')
+        print(f'        <polygon points="{' '.join([str(p) for p in points])}"/>')
+        print("    </g>")
     -->
-    <g id="triangle">
-        <polygon points="5.0 0.0 0.6698729810778064 7.499999999999999 9.330127018922191 7.500000000000002 5.000000000000001 0.0"/>
+    <g id="triangle" hollow="false">
+      <polygon points="5.0 0.0 0.6698729810778064 7.499999999999999 9.330127018922191 7.500000000000002 5.000000000000001 0.0" />
     </g>
-    <g id="pentagon">
-        <polygon points="5.0 0.0 0.24471741852423268 3.4549150281252627 2.0610737385376336 9.045084971874736 7.938926261462365 9.045084971874738 9.755282581475768 3.4549150281252636 5.000000000000001 0.0"/>
+    <g id="pentagon" hollow="false">
+      <polygon points="5.0 0.0 0.24471741852423268 3.4549150281252627 2.0610737385376336 9.045084971874736 7.938926261462365 9.045084971874738 9.755282581475768 3.4549150281252636 5.000000000000001 0.0" />
     </g>
-    <g id="hexagon">
-        <polygon points="5.0 0.0 0.6698729810778072 2.4999999999999996 0.6698729810778064 7.499999999999999 4.999999999999999 10.0 9.330127018922191 7.500000000000002 9.330127018922193 2.4999999999999996 5.000000000000001 0.0"/>
+    <g id="hexagon" hollow="false">
+      <polygon points="5.0 0.0 0.6698729810778072 2.4999999999999996 0.6698729810778064 7.499999999999999 4.999999999999999 10.0 9.330127018922191 7.500000000000002 9.330127018922193 2.4999999999999996 5.000000000000001 0.0" />
     </g>
-    <g id="heptagon">
-        <polygon points="5.0 0.0 1.0908425876598509 1.8825509907063323 0.12536043909088157 6.112604669781572 2.830581304412209 9.504844339512095 7.16941869558779 9.504844339512097 9.874639560909118 6.1126046697815735 8.90915741234015 1.8825509907063331 5.000000000000001 0.0"/>
+    <g id="heptagon" hollow="false">
+      <polygon points="5.0 0.0 1.0908425876598509 1.8825509907063323 0.12536043909088157 6.112604669781572 2.830581304412209 9.504844339512095 7.16941869558779 9.504844339512097 9.874639560909118 6.1126046697815735 8.90915741234015 1.8825509907063331 5.000000000000001 0.0" />
     </g>
-    <g id="octagon">
-        <polygon points="5.0 0.0 1.4644660940672627 1.4644660940672622 0.0 5.0 1.4644660940672622 8.535533905932738 4.999999999999999 10.0 8.535533905932738 8.535533905932738 10.0 5.000000000000001 8.535533905932738 1.4644660940672631 5.000000000000001 0.0"/>
+    <g id="octagon" hollow="false">
+      <polygon points="5.0 0.0 1.4644660940672627 1.4644660940672622 0.0 5.0 1.4644660940672622 8.535533905932738 4.999999999999999 10.0 8.535533905932738 8.535533905932738 10.0 5.000000000000001 8.535533905932738 1.4644660940672631 5.000000000000001 0.0" />
     </g>
-    <g id="nonagon">
-        <polygon points="5.0 0.0 1.7860619515673037 1.16977778440511 0.07596123493896023 4.131759111665348 0.6698729810778064 7.499999999999999 3.2898992833716556 9.69846310392954 6.710100716628343 9.698463103929543 9.330127018922191 7.500000000000002 9.924038765061042 4.1317591116653505 8.213938048432698 1.169777784405111 5.000000000000001 0.0"/>
+    <g id="nonagon" hollow="false">
+      <polygon points="5.0 0.0 1.7860619515673037 1.16977778440511 0.07596123493896023 4.131759111665348 0.6698729810778064 7.499999999999999 3.2898992833716556 9.69846310392954 6.710100716628343 9.698463103929543 9.330127018922191 7.500000000000002 9.924038765061042 4.1317591116653505 8.213938048432698 1.169777784405111 5.000000000000001 0.0" />
     </g>
-    <g id="decagon">
-        <polygon points="5.0 0.0 2.061073738537634 0.9549150281252627 0.24471741852423268 3.4549150281252627 0.2447174185242318 6.545084971874736 2.0610737385376336 9.045084971874736 4.999999999999999 10.0 7.938926261462365 9.045084971874738 9.755282581475768 6.545084971874738 9.755282581475768 3.4549150281252636 7.938926261462367 0.9549150281252636 5.000000000000001 0.0"/>
+    <g id="decagon" hollow="false">
+      <polygon points="5.0 0.0 2.061073738537634 0.9549150281252627 0.24471741852423268 3.4549150281252627 0.2447174185242318 6.545084971874736 2.0610737385376336 9.045084971874736 4.999999999999999 10.0 7.938926261462365 9.045084971874738 9.755282581475768 6.545084971874738 9.755282581475768 3.4549150281252636 7.938926261462367 0.9549150281252636 5.000000000000001 0.0" />
     </g>
-
     <!--
         These polygons can be regenerated with the following Python program:
 
         from math import sin, cos, pi
 
         for n in range(3, 11):
-            points = []
-            for i in range(1, n + 1):
-                d = (i * 2 - 1) * pi / n
-                d2 = i * 2 * pi / n
-                points += [5 + 2 * sin(d), 5 - 2 * cos(d)]
-                points += [5 + 5 * sin(d2), 5 - 5 * cos(d2)]
-            print(f'    <g id="star{n}">')
-            print(f'        <polygon points="{' '.join([str(p) for p in points])}"/>')
-            print("    </g>")
+        points = []
+        for i in range(1, n + 1):
+        d = (i * 2 - 1) * pi / n
+        d2 = i * 2 * pi / n
+        points += [5 + 2 * sin(d), 5 - 2 * cos(d)]
+        points += [5 + 5 * sin(d2), 5 - 5 * cos(d2)]
+        print(f'    <g id="star{n}">')
+        print(f'        <polygon points="{' '.join([str(p) for p in points])}"/>')
+        print("    </g>")
     -->
-    <g id="star3">
-        <polygon points="6.732050807568877 4.0 9.330127018922195 7.499999999999999 5.0 7.0 0.6698729810778081 7.500000000000002 3.267949192431123 4.0 4.999999999999999 0.0"/>
+    <g id="star3" hollow="false">
+      <polygon points="6.732050807568877 4.0 9.330127018922195 7.499999999999999 5.0 7.0 0.6698729810778081 7.500000000000002 3.267949192431123 4.0 4.999999999999999 0.0" />
     </g>
-    <g id="star4">
-        <polygon points="6.414213562373095 3.585786437626905 10.0 5.0 6.414213562373095 6.414213562373095 5.000000000000001 10.0 3.585786437626905 6.414213562373096 0.0 5.000000000000001 3.5857864376269046 3.585786437626905 4.999999999999999 0.0"/>
+    <g id="star4" hollow="false">
+      <polygon points="6.414213562373095 3.585786437626905 10.0 5.0 6.414213562373095 6.414213562373095 5.000000000000001 10.0 3.585786437626905 6.414213562373096 0.0 5.000000000000001 3.5857864376269046 3.585786437626905 4.999999999999999 0.0" />
     </g>
-    <g id="star5">
-        <polygon points="6.175570504584947 3.381966011250105 9.755282581475768 3.4549150281252627 6.902113032590307 5.618033988749895 7.938926261462367 9.045084971874736 5.0 7.0 2.061073738537635 9.045084971874738 3.0978869674096927 5.618033988749895 0.2447174185242318 3.4549150281252636 3.8244294954150533 3.381966011250105 4.999999999999999 0.0"/>
+    <g id="star5" hollow="false">
+      <polygon points="6.175570504584947 3.381966011250105 9.755282581475768 3.4549150281252627 6.902113032590307 5.618033988749895 7.938926261462367 9.045084971874736 5.0 7.0 2.061073738537635 9.045084971874738 3.0978869674096927 5.618033988749895 0.2447174185242318 3.4549150281252636 3.8244294954150533 3.381966011250105 4.999999999999999 0.0" />
     </g>
-    <g id="star6">
-        <polygon points="6.0 3.2679491924311224 9.330127018922193 2.4999999999999996 7.0 5.0 9.330127018922195 7.499999999999999 6.0 6.732050807568878 5.000000000000001 10.0 4.000000000000001 6.732050807568878 0.6698729810778081 7.500000000000002 3.0 5.0 0.6698729810778072 2.4999999999999996 3.999999999999999 3.2679491924311233 4.999999999999999 0.0"/>
+    <g id="star6" hollow="false">
+      <polygon points="6.0 3.2679491924311224 9.330127018922193 2.4999999999999996 7.0 5.0 9.330127018922195 7.499999999999999 6.0 6.732050807568878 5.000000000000001 10.0 4.000000000000001 6.732050807568878 0.6698729810778081 7.500000000000002 3.0 5.0 0.6698729810778072 2.4999999999999996 3.999999999999999 3.2679491924311233 4.999999999999999 0.0" />
     </g>
-    <g id="star7">
-        <polygon points="5.867767478235116 3.198062264195162 8.90915741234015 1.8825509907063323 6.949855824363647 4.554958132087371 9.874639560909118 6.112604669781572 6.56366296493606 6.246979603717467 7.169418695587791 9.504844339512095 5.0 7.0 2.83058130441221 9.504844339512097 3.4363370350639406 6.246979603717468 0.12536043909088157 6.1126046697815735 3.050144175636352 4.554958132087373 1.0908425876598504 1.8825509907063331 4.132232521764885 3.198062264195161 4.999999999999999 0.0"/>
+    <g id="star7" hollow="false">
+      <polygon points="5.867767478235116 3.198062264195162 8.90915741234015 1.8825509907063323 6.949855824363647 4.554958132087371 9.874639560909118 6.112604669781572 6.56366296493606 6.246979603717467 7.169418695587791 9.504844339512095 5.0 7.0 2.83058130441221 9.504844339512097 3.4363370350639406 6.246979603717468 0.12536043909088157 6.1126046697815735 3.050144175636352 4.554958132087373 1.0908425876598504 1.8825509907063331 4.132232521764885 3.198062264195161 4.999999999999999 0.0" />
     </g>
-    <g id="star8">
-        <polygon points="5.765366864730179 3.1522409349774265 8.535533905932738 1.4644660940672622 6.847759065022574 4.234633135269821 10.0 5.0 6.847759065022574 5.765366864730179 8.535533905932738 8.535533905932738 5.76536686473018 6.847759065022574 5.000000000000001 10.0 4.234633135269821 6.847759065022574 1.4644660940672627 8.535533905932738 3.152240934977427 5.765366864730181 0.0 5.000000000000001 3.152240934977427 4.23463313526982 1.4644660940672614 1.4644660940672631 4.234633135269819 3.152240934977427 4.999999999999999 0.0"/>
+    <g id="star8" hollow="false">
+      <polygon points="5.765366864730179 3.1522409349774265 8.535533905932738 1.4644660940672622 6.847759065022574 4.234633135269821 10.0 5.0 6.847759065022574 5.765366864730179 8.535533905932738 8.535533905932738 5.76536686473018 6.847759065022574 5.000000000000001 10.0 4.234633135269821 6.847759065022574 1.4644660940672627 8.535533905932738 3.152240934977427 5.765366864730181 0.0 5.000000000000001 3.152240934977427 4.23463313526982 1.4644660940672614 1.4644660940672631 4.234633135269819 3.152240934977427 4.999999999999999 0.0" />
     </g>
-    <g id="star9">
-        <polygon points="5.684040286651338 3.120614758428183 8.213938048432697 1.16977778440511 6.732050807568877 4.0 9.92403876506104 4.131759111665348 6.969615506024416 5.34729635533386 9.330127018922195 7.499999999999999 6.285575219373079 6.532088886237956 6.710100716628345 9.69846310392954 5.0 7.0 3.289899283371657 9.698463103929543 3.7144247806269224 6.532088886237957 0.6698729810778081 7.500000000000002 3.0303844939755837 5.347296355333861 0.07596123493895934 4.1317591116653505 3.267949192431122 4.000000000000002 1.786061951567302 1.169777784405111 4.315959713348663 3.120614758428183 4.999999999999999 0.0"/>
+    <g id="star9" hollow="false">
+      <polygon points="5.684040286651338 3.120614758428183 8.213938048432697 1.16977778440511 6.732050807568877 4.0 9.92403876506104 4.131759111665348 6.969615506024416 5.34729635533386 9.330127018922195 7.499999999999999 6.285575219373079 6.532088886237956 6.710100716628345 9.69846310392954 5.0 7.0 3.289899283371657 9.698463103929543 3.7144247806269224 6.532088886237957 0.6698729810778081 7.500000000000002 3.0303844939755837 5.347296355333861 0.07596123493895934 4.1317591116653505 3.267949192431122 4.000000000000002 1.786061951567302 1.169777784405111 4.315959713348663 3.120614758428183 4.999999999999999 0.0" />
     </g>
-    <g id="star10">
-        <polygon points="5.618033988749895 3.0978869674096927 7.938926261462366 0.9549150281252627 6.618033988749895 3.8244294954150537 9.755282581475768 3.4549150281252627 7.0 5.0 9.755282581475768 6.545084971874736 6.618033988749895 6.175570504584946 7.938926261462367 9.045084971874736 5.618033988749895 6.902113032590307 5.000000000000001 10.0 4.381966011250106 6.902113032590307 2.061073738537635 9.045084971874738 3.381966011250105 6.175570504584947 0.24471741852423268 6.545084971874738 3.0 5.0 0.2447174185242318 3.4549150281252636 3.381966011250105 3.824429495415054 2.061073738537633 0.9549150281252636 4.381966011250105 3.0978869674096927 4.999999999999999 0.0"/>
+    <g id="star10" hollow="false">
+      <polygon points="5.618033988749895 3.0978869674096927 7.938926261462366 0.9549150281252627 6.618033988749895 3.8244294954150537 9.755282581475768 3.4549150281252627 7.0 5.0 9.755282581475768 6.545084971874736 6.618033988749895 6.175570504584946 7.938926261462367 9.045084971874736 5.618033988749895 6.902113032590307 5.000000000000001 10.0 4.381966011250106 6.902113032590307 2.061073738537635 9.045084971874738 3.381966011250105 6.175570504584947 0.24471741852423268 6.545084971874738 3.0 5.0 0.2447174185242318 3.4549150281252636 3.381966011250105 3.824429495415054 2.061073738537633 0.9549150281252636 4.381966011250105 3.0978869674096927 4.999999999999999 0.0" />
     </g>
   </defs>
-
   <!-- A palette of symbols. -->
-  <use x="2" y="2" transform="scale(5)" stroke="black" fill="red" href="#square"/>
-  <use x="14" y="2" transform="scale(5)" stroke="black" fill="red" href="#plus"/>
-  <use x="26" y="2" transform="scale(5)" stroke="black" fill="red" href="#circle"/>
-  <use x="38" y="2" transform="scale(5)" stroke="black" fill="red" href="#arc"/>
-  <use x="50" y="2" transform="scale(5)" stroke="black" fill="red" href="#arcDown"/>
-  <use x="62" y="2" transform="scale(5)" stroke="black" fill="red" href="#cross"/>
-  <use x="2" y="14" transform="scale(5)" stroke="black" fill="red" href="#arrow"/>
-  <use x="14" y="14" transform="scale(5)" stroke="black" fill="red" href="#line"/>
-  <use x="26" y="14" transform="scale(5)" stroke="black" fill="red" href="#male"/>
-  <use x="38" y="14" transform="scale(5)" stroke="black" fill="red" href="#female"/>
-  <use x="50" y="14" transform="scale(5)" stroke="black" fill="red" href="#bowtie"/>
-  <use x="62" y="14" transform="scale(5)" stroke="black" fill="red" href="#ibeam"/>
-  <use x="2" y="26" transform="scale(5)" stroke="black" fill="red" href="#roundRectangle"/>
-  <use x="14" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower3"/>
-  <use x="26" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower4"/>
-  <use x="38" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower5"/>
-  <use x="50" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower6"/>
-  <use x="62" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower7"/>
-  <use x="2" y="38" transform="scale(5)" stroke="black" fill="red" href="#flower8"/>
-  <use x="14" y="38" transform="scale(5)" stroke="black" fill="red" href="#flower9"/>
-  <use x="26" y="38" transform="scale(5)" stroke="black" fill="red" href="#flower10"/>
-  <use x="38" y="38" transform="scale(5)" stroke="black" fill="red" href="#triangle"/>
-  <use x="50" y="38" transform="scale(5)" stroke="black" fill="red" href="#pentagon"/>
-  <use x="62" y="38" transform="scale(5)" stroke="black" fill="red" href="#hexagon"/>
-  <use x="2" y="50" transform="scale(5)" stroke="black" fill="red" href="#heptagon"/>
-  <use x="14" y="50" transform="scale(5)" stroke="black" fill="red" href="#octagon"/>
-  <use x="26" y="50" transform="scale(5)" stroke="black" fill="red" href="#nonagon"/>
-  <use x="38" y="50" transform="scale(5)" stroke="black" fill="red" href="#decagon"/>
-  <use x="50" y="50" transform="scale(5)" stroke="black" fill="red" href="#star3"/>
-  <use x="62" y="50" transform="scale(5)" stroke="black" fill="red" href="#star4"/>
-  <use x="2" y="62" transform="scale(5)" stroke="black" fill="red" href="#star5"/>
-  <use x="14" y="62" transform="scale(5)" stroke="black" fill="red" href="#star6"/>
-  <use x="26" y="62" transform="scale(5)" stroke="black" fill="red" href="#star7"/>
-  <use x="38" y="62" transform="scale(5)" stroke="black" fill="red" href="#star8"/>
-  <use x="50" y="62" transform="scale(5)" stroke="black" fill="red" href="#star9"/>
-  <use x="62" y="62" transform="scale(5)" stroke="black" fill="red" href="#star10"/>
+  <use x="2" y="2" transform="scale(5)" stroke="black" fill="red" href="#square" />
+  <use x="14" y="2" transform="scale(5)" stroke="black" fill="red" href="#plus" />
+  <use x="26" y="2" transform="scale(5)" stroke="black" fill="red" href="#circle" />
+  <use x="38" y="2" transform="scale(5)" stroke="black" fill="red" href="#arc" />
+  <use x="50" y="2" transform="scale(5)" stroke="black" fill="red" href="#arcDown" />
+  <use x="62" y="2" transform="scale(5)" stroke="black" fill="red" href="#cross" />
+  <use x="2" y="14" transform="scale(5)" stroke="black" fill="red" href="#arrow" />
+  <use x="14" y="14" transform="scale(5)" stroke="black" fill="red" href="#line" />
+  <use x="26" y="14" transform="scale(5)" stroke="black" fill="red" href="#male" />
+  <use x="38" y="14" transform="scale(5)" stroke="black" fill="red" href="#female" />
+  <use x="50" y="14" transform="scale(5)" stroke="black" fill="red" href="#bowtie" />
+  <use x="62" y="14" transform="scale(5)" stroke="black" fill="red" href="#ibeam" />
+  <use x="2" y="26" transform="scale(5)" stroke="black" fill="red" href="#roundRectangle" />
+  <use x="14" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower3" />
+  <use x="26" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower4" />
+  <use x="38" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower5" />
+  <use x="50" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower6" />
+  <use x="62" y="26" transform="scale(5)" stroke="black" fill="red" href="#flower7" />
+  <use x="2" y="38" transform="scale(5)" stroke="black" fill="red" href="#flower8" />
+  <use x="14" y="38" transform="scale(5)" stroke="black" fill="red" href="#flower9" />
+  <use x="26" y="38" transform="scale(5)" stroke="black" fill="red" href="#flower10" />
+  <use x="38" y="38" transform="scale(5)" stroke="black" fill="red" href="#triangle" />
+  <use x="50" y="38" transform="scale(5)" stroke="black" fill="red" href="#pentagon" />
+  <use x="62" y="38" transform="scale(5)" stroke="black" fill="red" href="#hexagon" />
+  <use x="2" y="50" transform="scale(5)" stroke="black" fill="red" href="#heptagon" />
+  <use x="14" y="50" transform="scale(5)" stroke="black" fill="red" href="#octagon" />
+  <use x="26" y="50" transform="scale(5)" stroke="black" fill="red" href="#nonagon" />
+  <use x="38" y="50" transform="scale(5)" stroke="black" fill="red" href="#decagon" />
+  <use x="50" y="50" transform="scale(5)" stroke="black" fill="red" href="#star3" />
+  <use x="62" y="50" transform="scale(5)" stroke="black" fill="red" href="#star4" />
+  <use x="2" y="62" transform="scale(5)" stroke="black" fill="red" href="#star5" />
+  <use x="14" y="62" transform="scale(5)" stroke="black" fill="red" href="#star6" />
+  <use x="26" y="62" transform="scale(5)" stroke="black" fill="red" href="#star7" />
+  <use x="38" y="62" transform="scale(5)" stroke="black" fill="red" href="#star8" />
+  <use x="50" y="62" transform="scale(5)" stroke="black" fill="red" href="#star9" />
+  <use x="62" y="62" transform="scale(5)" stroke="black" fill="red" href="#star10" />
 </svg>
diff --git a/rust/pspp/src/spv/read/graph/symbols/.gitignore b/rust/pspp/src/spv/read/graph/symbols/.gitignore
new file mode 100644 (file)
index 0000000..3100bf1
--- /dev/null
@@ -0,0 +1 @@
+data.rs