protected void setStrokeProperties(List<Object> name, Dict properties) {

            Vector4 color = (Vector4) name.get(1);
            if (color == null) color = properties.get(iLinearGraphicsContext.fillColor);
            if (color == null) color = properties.get(iLinearGraphicsContext.color);
            if (color == null) color = black;

            float thick = widthFor(context, properties);

            thick = remapProperties(color = new Vector4(color), null, thick);

            PdfContentByte o = context.getOutput();

            o.setColorFill(new Color(clamp(color.x), clamp(color.y), clamp(color.z)));

            if (opName.equals("Opaque")) {
              PdfGState gs1 = new PdfGState();
              gs1.setFillOpacity(1);
              gs1.setStrokeOpacity(1);
              gs1.setBlendMode(new PdfName("Normal"));
              o.setGState(gs1);
            }
            {
              PdfGState gs1 = new PdfGState();
              gs1.setFillOpacity(color.w);
              gs1.setStrokeOpacity(color.w);
              gs1.setBlendMode(new PdfName(opName));
              o.setGState(gs1);
            }
          }
    public DrawingResult accept(
        List<iUpdateable> soFar, final CachedLine line, final Dict properties) {
      if (!properties.isTrue(iLinearGraphicsContext.stroked, true)) return null;
      if (!properties.isTrue(iLinearGraphicsContext.containsDepth, false)) return null;

      Vector4 color = null;
      if (color == null) color = properties.get(iLinearGraphicsContext.strokeColor);
      if (color == null) color = properties.get(iLinearGraphicsContext.color);
      if (color != null) {
        if (color.w < 0.001) return null;
      }

      return new DrawingResult(
          DrawingResultCode.cont,
          new iUpdateable() {

            public void update() {
              if (!context.isLayer(line)) return;

              opName = properties.get(iLinearGraphicsContext.outputOpacityType);
              if (opName == null) opName = defaultOpType;

              // todo, transp

              path = context.getOutput();
              path.saveState();

              lineEmitter.setCanEmitCubic(false);

              lineEmitter.globalGeometricScale = 0;
              lineEmitter.globalFlatnessScale =
                  context.getGlobalProperties().getFloat(iLinearGraphicsContext.flatnessScale, 1);

              beginTransform(line, properties);

              drawInto(line, properties, null, context, lineEmitter);

              firstOut = true;

              Number dd = properties.get(PDFDash);
              if (dd != null) {
                context.getOutput().setLineDash(dd.floatValue(), dd.floatValue() * 1.4f, 0);
              }

              context.getOutput().stroke();
              context.getOutput().newPath();

              System.err.println(" submitting path ");
              path.restoreState();
            }
          });
    }
          @Override
          public void emitLinearFrame(
              Vector3 a,
              Vector3 b,
              java.util.List<Object> name,
              java.util.List<Object> name2,
              Dict properties,
              iLinearGraphicsContext contex) {
            Vector4 outputTransform = SimplePDFLineDrawing_3d.this.outputTransform;
            if (properties.isTrue(iLinearGraphicsContext.noTransform, false))
              outputTransform = new Vector4(1, 1, 0, 0);

            setStrokeProperties(name, properties);
            if (firstOut || lastOut.distanceFrom(a) > 1e-5) {
              Vector2 at = transform(a);
              path.moveTo(at.x, at.y);
              firstOut = false;
              lastOut = new Vector3(b);
            }
            Vector2 at = transform(b);

            ; // System.out.println(" line to <"+b+" -> "+at);
            if (!shouldClip) path.lineTo(at.x, at.y);
            lastOut.x = b.x;
            lastOut.y = b.y;
          }
  protected void beginTransform(CachedLine line, Dict properties) {
    iLinearGraphicsContext context = properties.get(iLinearGraphicsContext.context);

    ; // System.out.println(" line context is <" + context + ">");

    if (context instanceof iTransformingContext) {
      transformContext = (iTransformingContext) context;
    } else {
      transformContext = null;
    }
  }
    public DrawingResult accept(
        List<iUpdateable> soFar, final CachedLine line, final Dict properties) {

      if (!properties.isTrue(iLinearGraphicsContext.pointed, false)) return null;

      if (properties.isTrue(iLinearGraphicsContext.containsDepth, false)) return null;

      line.finish();

      unitSquare = null;

      DrawingResult res =
          new DrawingResult(
              DrawingResultCode.cont,
              new iUpdateable() {

                public void update() {
                  if (!context.isLayer(line)) return;

                  boolean notEnds = properties.isTrue(pointNotAtEnds, false);

                  for (CachedLine.Event e : line.events) {
                    if (notEnds
                        && e.attributes != null
                        && e.attributes.isTrue(isClippedEnd_v, false)) {
                      System.err.println(" skipped clipped end");
                      continue;
                    }

                    if (!e.method.equals(iLine_m.close_m)) {

                      float size = 1f / outputTransform.x;

                      Number ps = e.getAttributes().get(iLinearGraphicsContext.pointSize_v);
                      if (ps == null) ps = properties.get(iLinearGraphicsContext.pointSize);
                      if (ps != null) size = ps.floatValue() / outputTransform.x;

                      // size *= 0.25f;

                      Vector4 color = e.getAttributes().get(iLinearGraphicsContext.pointColor_v);
                      if (color == null) color = properties.get(iLinearGraphicsContext.pointColor);
                      if (color == null) color = properties.get(iLinearGraphicsContext.strokeColor);
                      if (color == null) color = properties.get(iLinearGraphicsContext.color);
                      if (color == null) color = new Vector4(0, 0, 0, 1);

                      color.w *= properties.getFloat(iLinearGraphicsContext.totalOpacity, 1f);

                      size *= context.getGlobalProperties().getFloat(pointSizeMul, 1);

                      remapProperties(null, color = new Vector4(color), 0);

                      if (unitSquare == null
                          || unitSquareLastColor.distanceFrom(color) > 0
                          || Math.abs(unitSquareLastSize - size) > 0.25f) {
                        constructUnitSquare(color, size);

                        unitSquareLastColor = color;
                        unitSquareLastSize = size;
                        PdfGState gs = new PdfGState();
                        gs.setFillOpacity(color.w);
                        String opName = properties.get(iLinearGraphicsContext.outputOpacityType);
                        if (opName == null) opName = defaultOpType;

                        gs.setBlendMode(new PdfName(opName));
                        context.getOutput().setGState(gs);
                      }

                      Vector2 at = transform(e.getDestination());

                      context
                          .getOutput()
                          .addTemplate(unitSquare, -size / 2 + at.x, -size / 2 + at.y);

                      // CachedLine markerLine
                      // = new CachedLine();
                      // iLine in =
                      // markerLine.getInput();
                      //
                      // Vector2 dest =
                      // e.getDestination();
                      // in.moveTo(dest.x -
                      // size / 2f, dest.y -
                      // size / 2);
                      // in.lineTo(dest.x +
                      // size / 2f, dest.y -
                      // size / 2);
                      // in.lineTo(dest.x +
                      // size / 2f, dest.y +
                      // size / 2);
                      // in.lineTo(dest.x -
                      // size / 2f, dest.y +
                      // size / 2);
                      // in.lineTo(dest.x -
                      // size / 2f, dest.y -
                      // size / 2);
                      // markerLine.getProperties().put(iLinearGraphicsContext.line_isStroked,
                      // false);
                      // markerLine.getProperties().put(iLinearGraphicsContext.line_isFilled,
                      // true);
                      // markerLine.getProperties().put(iLinearGraphicsContext.line_globalColor,
                      // color);
                      //
                      // System.err.println("
                      // point si8ze
                      // <"+size+">");
                      //
                      // System.err.println("
                      // making fill proxy ,,,
                      // ");
                      //
                      // new
                      // SimplePDFFill(context).accept(new
                      // ArrayList<iUpdateable>(),
                      // markerLine,
                      // markerLine.getProperties()).compute.update();
                      // System.err.println("
                      // making finished ,,,
                      // ");
                    }
                  }
                }
              });

      return res;
    }
    public float widthFor(BasePDFGraphicsContext context, Dict properties) {
      Number f = properties.get(iLinearGraphicsContext.thickness);
      Number m = context.getGlobalProperties().get(iLinearGraphicsContext.strokeThicknessMul);

      return (f == null ? 1 : f.floatValue()) * (m == null ? 1 : m.floatValue());
    }
    public DrawingResult accept(
        List<iUpdateable> soFar, final CachedLine line, final Dict properties) {
      if (!properties.isTrue(iLinearGraphicsContext.filled, false)) return null;
      if (properties.isTrue(iLinearGraphicsContext.needVertexShading, false)) return null;

      System.err.println(" -- non special fill -- ");

      Vector4 color = null;
      if (color == null) color = properties.get(iLinearGraphicsContext.fillColor);
      if (color == null) color = properties.get(iLinearGraphicsContext.color);
      if (color != null) {
        if (color.w < 0.001) {
          System.err.println(" rejected: too transparent <" + color + ">");
          return null;
        } else {
          System.err.println(" color is <" + color + ">");
        }
      }

      float w = widthFor(context, properties);
      if (w < 1e-5) {
        System.err.println(" rejected: too thin");
      }

      final DynamicMesh outputLine = DynamicMesh.unshadedMesh();

      final TessLine3dEmitter_long fillEmitter =
          new TessLine3dEmitter_long() {

            @Override
            protected void decorateVertex(int v1, List<Object> name) {
              Object color = name == null ? null : name.get(0);
              if (color == null) color = properties.get(iLinearGraphicsContext.fillColor);
              if (color == null) color = properties.get(iLinearGraphicsContext.color);
              if (color == null) color = black;

              if (color instanceof float[])
                color =
                    new Vector4(
                        ((float[]) color)[0],
                        ((float[]) color)[1],
                        ((float[]) color)[2],
                        ((float[]) color)[3]);

              remapProperties(null, (Vector4) (color = new Vector4((Vector4) color)), 0);

              mesh.setAux(
                  v1,
                  Base.color0_id,
                  ((Vector4) color).x,
                  ((Vector4) color).y,
                  ((Vector4) color).z,
                  ((Vector4) color).w);
            }
          };

      fillEmitter.addTrackedProperty(
          iLinearGraphicsContext.fillColor_v,
          new iMetric<Vector4, Vector4>() {
            public float distance(Vector4 from, Vector4 to) {
              if (from == null || to == null) return 0;

              float d = (from).distanceFrom((to)) * 100;
              return d;
            }
          });

      return new DrawingResult(
          DrawingResultCode.cont,
          new iUpdateable() {

            public void update() {

              ; // System.out.println(" will update fill ");

              if (!context.isLayer(line)) return;

              opName = properties.get(iLinearGraphicsContext.outputOpacityType);
              if (opName == null) opName = defaultOpType;

              path = context.getOutput();
              path.saveState();
              path.setMiterLimit(2);

              lineEmitter.setCanEmitCubic(false);

              // lineEmitter.globalGeometricScale = 0;
              lineEmitter.globalFlatnessScale =
                  context.getGlobalProperties().getFloat(iLinearGraphicsContext.flatnessScale, 1);

              ; // System.out.println(" begin transform ");
              beginTransform(line, properties);

              ; // System.out.println(" drawing now ");
              drawInto(line, properties, null, context, lineEmitter);

              firstOut = true;

              // context.getOutput().clip();
              context.getOutput().fill();

              ; // System.out.println(" call that a path ");
              context.getOutput().newPath();

              fillEmitter.globalFlatnessScale = 1;
              fillEmitter.globalGeometricScale = 1;

              // drawInto(line, properties, null,
              // context, fillEmitter);
              //
              // MeshToPdfType4.dilateMesh(fillEmitter.mesh.getUnderlyingGeometry(),
              // line);
              //
              // PdfShading_type4 shading = new
              // MeshToPdfType4.PdfShading_type4(context.getWriter(),
              // (TriangleMesh)
              // fillEmitter.mesh.getUnderlyingGeometry());
              // context.getOutput().saveState();
              // context.getOutput().paintShading(shading);
              // context.getOutput().restoreState();
              //
              //

              System.err.println(" submitting path ");
              path.restoreState();
            }
          });
    }
          protected void setStrokeProperties(List<Object> name, Dict properties) {

            Vector4 color = (Vector4) name.get(1);
            if (color == null) color = properties.get(iLinearGraphicsContext.strokeColor);
            if (color == null) color = properties.get(iLinearGraphicsContext.color);
            if (color == null) color = black;

            float thick = widthFor(context, properties);

            thick = remapProperties(color = new Vector4(color), null, thick);

            Pair<Float, Float> filtered = filteredThickness(thick, color.w);
            if (filtered != null) {
              thick = filtered.left;
              if (filtered.right != color.w) {
                color = new Vector4(color);
                color.w = filtered.right;
              }
            }

            if (lastStyle != null && ongoingStyle != null) {
              if (lastStyle.equals(ongoingStyle)
                  && (lastStyleOp != null && opName.equals(lastStyleOp))) {
                // System.err.println(" skipping
                // set stroke prop");
                // return;

              }
            }

            PdfContentByte o = context.getOutput();
            o.setMiterLimit(2);
            if (thick > 30) {
              o.setLineJoin(path.LINE_JOIN_ROUND);
              o.setLineCap(path.LINE_CAP_ROUND);
            }

            System.err.println(" set stoke properties <" + color + "> <" + opName + ">");
            o.setColorStroke(new Color(clamp(color.x), clamp(color.y), clamp(color.z)));
            o.setLineWidth(thick);

            if (opName.equals("Opaque")) {
              PdfGState gs1 = new PdfGState();
              gs1.setFillOpacity(1);
              gs1.setStrokeOpacity(1);
              gs1.setBlendMode(new PdfName("Normal"));
              o.setGState(gs1);
            } else {
              PdfGState gs1 = new PdfGState();
              // gs1.put(new PdfName("SA"), new
              // PdfName(PdfBoolean.FALSE));

              gs1.setFillOpacity(color.w);
              gs1.setStrokeOpacity(color.w);
              gs1.setBlendMode(new PdfName(opName));
              o.setGState(gs1);
            }

            ongoingStyle = lastStyle;
            lastStyleOp = opName;
          }
    public DrawingResult accept(
        List<iUpdateable> soFar, final CachedLine line, final Dict properties) {

      if (!properties.isTrue(iLinearGraphicsContext.pointed, false)) return null;

      if (!properties.isTrue(iLinearGraphicsContext.containsDepth, false)) return null;

      ; // System.out.println(" circular pointer 3d");

      line.finish();

      unitSquare = null;

      beginTransform(line, properties);

      DrawingResult res =
          new DrawingResult(
              DrawingResultCode.cont,
              new iUpdateable() {

                public void update() {
                  if (!context.isLayer(line)) return;

                  boolean notEnds = properties.isTrue(pointNotAtEnds, false);

                  for (CachedLine.Event e : line.events) {
                    if (notEnds
                        && e.attributes != null
                        && e.attributes.isTrue(isClippedEnd_v, false)) {
                      System.err.println(" skipped clipped end");
                      continue;
                    }

                    if (!e.method.equals(iLine_m.close_m)) {

                      float size = 1f / outputTransform.x;

                      Number ps = e.getAttributes().get(iLinearGraphicsContext.pointSize_v);
                      if (ps == null) ps = properties.get(iLinearGraphicsContext.pointSize);
                      if (ps != null) size = ps.floatValue() / outputTransform.x;

                      // size *= 0.25f;

                      Vector4 color = e.getAttributes().get(iLinearGraphicsContext.pointColor_v);
                      if (color == null) color = properties.get(iLinearGraphicsContext.pointColor);
                      if (color == null) color = properties.get(iLinearGraphicsContext.strokeColor);
                      if (color == null) color = properties.get(iLinearGraphicsContext.color);
                      if (color == null) color = new Vector4(0, 0, 0, 1);

                      color.w *= properties.getFloat(iLinearGraphicsContext.totalOpacity, 1f);

                      size *= context.getGlobalProperties().getFloat(pointSizeMul, 1);

                      remapProperties(null, color = new Vector4(color), 0);

                      if (unitSquare == null
                          || unitSquareLastColor.distanceFrom(color) > 0
                          || Math.abs(unitSquareLastSize - size) > 0.25f) {
                        constructUnitSquare(color, size);

                        unitSquareLastColor = color;
                        unitSquareLastSize = size;
                        PdfGState gs = new PdfGState();
                        gs.setFillOpacity(color.w);
                        String opName = properties.get(iLinearGraphicsContext.outputOpacityType);
                        if (opName == null) opName = defaultOpType;

                        gs.setBlendMode(new PdfName(opName));
                        context.getOutput().setGState(gs);
                      }

                      Vector2 a = e.getDestination();
                      float z = 0;
                      Object d = e.getAttributes().get(iLinearGraphicsContext.z_v);
                      if (d == null) z = 0;
                      else if (d instanceof Number) z = ((Number) d).floatValue();
                      else if (d instanceof Vector3) z = ((Vector3) d).z;

                      Vector2 at = transform(new Vector3(a.x, a.y, z));

                      ; // System.out.println(" transformed <"+a+" "+z+"> to <"+at+">
                        // <"+shouldClip+">");

                      if (!shouldClip)
                        context
                            .getOutput()
                            .addTemplate(unitSquare, -size / 2 + at.x, -size / 2 + at.y);
                    }
                  }
                }
              });

      return res;
    }